和上一个版本相比,增加了快捷键操作,增加了批量删除功能,改变了操作方式。
<html>
<head>
<title>纯JS控制DIV选择范围移动与复制 改进版</title>

<style type="text/css">...

.newbtn{...}{margin-right:10px;border:solid 1px green;cursor:pointer;padding:2px;background:#efd;}
body,table

{...}{
font-size: 12px;
}

/**//*DIV未被选择时样式*/
div.noSelected

{...}{
text-align: center;
position: absolute;
background-color: #f5f5f5;
border: #000000 1px solid;
}

/**//*DIV已被选择时样式*/
div.isSelected

{...}{
text-align: center;
position: absolute;
background-color: #f5f5f5;
border: #996600 3px solid;
}


/**//*选择虚线框样式*/
div#selectArea

{...}{
position: absolute;
border: #FF6600 1px dashed;
}
</style>
</head>
<body>
<div style="margin:10px;">
<span class="newbtn" onclick="AllSelect()">全选(Ctrl+A)</span>
<span class="newbtn" onclick="ReverseSelect()">反选(Ctrl+X)</span>
<span class="newbtn" onclick="deleteNodes()">删除选中(Delete)</span>
<span class="newbtn" onclick="CancelSelect()">取消选择(Ctrl+Z)</span>
<input id="move" type="radio" name="moveOrCopy" checked="checked" /><label for="move">移动(-)</label>
<input id="copy" type="radio" name="moveOrCopy" /><label for="copy">复制(+)</label>
</div>
<div id="WorkFlowSpan"></div>

<script type="text/javascript" language="javascript">...
//范围选择
var saveDiv = new Array();
var areaDiv = new Array();
var cloneNodes;
var oLeft, oTop;
var panel = $("WorkFlowSpan");
var groupName = "GroupItem";
var eventStatus = "nothing"; //"nothing"未选择状态,"selected"选择完毕状态,"selecting"范围选择中状态,"move"移动状态
var selectArea;
var oX,oY; //鼠标按下位置
var moveSize = 30; //单位移动的大小(动画的速度),越大越快
var copyNo = 0;

//通过名称删除数组元素
Array.prototype.remove = function()

...{
var removeIndex = -1;
if (arguments.length == 1)

...{
//存储预删除的所在位置
for (var i = 0; i < this.length; i++)

...{
if (this[i] == arguments[0])

...{
removeIndex = i;
break;
}
}
//删除
if (removeIndex >= 0)

...{
for(var i = removeIndex; i < this.length; i++)

...{
this[i] = this[i + 1];
}
this.length -= 1;
}
}
}

//进栈(只进栈非重复的)
Array.prototype.insert = function()

...{
var removeIndex = -1;
if (arguments.length == 1)

...{
//存储预重复的所在位置
for (var i = 0; i < this.length; i++)

...{
if (this[i] == arguments[0])

...{
removeIndex = i;
break;
}
}
//进栈
if (removeIndex == -1)

...{
this[this.length] = arguments[0];
}
}
}

function $(controlId)

...{
return document.getElementById(controlId);
}

//创建DIV
function createDiv(divID, divLeft, divTop)

...{
var div = document.createElement("div");
div.id = divID;
div.group = "GroupItem"; //所在组
div.isSelected = false; //是否是被选中状态
div.className = "noSelected";
div.style.cursor = "default";
div.style.width = "250px";
div.style.height = "50px";
div.style.left = divLeft;
div.style.top = divTop;
div.innerHTML = "<table style="width: 100%; height: 100%; text-align: center; vertical-align: middle"><tr><td>coding by pippe<br /><a href='mailto:pippe@163.com'>pippe@163.com</a></td></tr>";
panel.appendChild(div);
}

//创建三个DIV
createDiv("oldDiv1", "100px", "400px");
createDiv("oldDiv2", "400px", "400px");
createDiv("oldDiv3", "700px", "400px");

//设置空间选择的样式
function SelectStyle(objControl, isSelected)

...{
objControl.className = isSelected ? "isSelected" : "noSelected";
objControl.isSelected = isSelected;
}

//选择范围开始
function AreaCreate()

...{
if (event.button == 1 && (eventStatus == "nothing" || event.ctrlKey))

...{
oX = event.x;
oY = event.y;
//通过鼠标位置取对象
var element = document.elementFromPoint(oX, oY);
while (element.tagName != "undefined" && element.tagName.toUpperCase() != "BODY")

...{
//可移动或复制的组里面
if (element.group == groupName)

...{
if (event.ctrlKey)

...{
//按住CTRL添加或减少选择
if (element.isSelected)

...{
saveDiv.remove(element.id);
SelectStyle(element, false);
eventStatus = saveDiv.length == 0 ? "nothing" : "selected";
}
else

...{
saveDiv.insert(element.id);
SelectStyle(element, true);
eventStatus = "selected";
}
}
else

...{
//未按住CTRL
saveDiv.insert(element.id);
SelectStyle(element, true);
eventStatus = "selected";
MouseDown();
}
return;
}
element = element.parentNode;
}
//范围选择
selectArea = document.createElement("div");
selectArea.id = "selectArea";
selectArea.style.left = oX + "px";
selectArea.style.top = oY + "px";
selectArea.setCapture();
panel.appendChild(selectArea);
eventStatus = "selecting";
return;
}
}

function AreaSelecting()

...{
//范围选择中
if (event.button == 1 && eventStatus == "selecting")

...{
var nX = event.x;
var nY = event.y;
selectArea.style.left = nX <= oX ? nX + "px" : oX + "px";
selectArea.style.top = nY <= oY ? nY + "px" : oY + "px";
selectArea.style.width = nX >= oX ? nX - oX : oX - nX;
selectArea.style.height = nY >= oY ? nY - oY : oY - nY;
var elements = document.all;
var len = elements.length;
var thisLeft, thisTop, thisRight, thirBottom;
var x1,y1,x2,y2;
x2 = nX <= oX ? oX : nX;
x1 = nX <= oX ? nX : oX;
y2 = nY <= oY ? oY : nY;
y1 = nY <= oY ? nY : oY;
for (var i = 0; i < len; i++)

...{
if (elements[i].group != groupName)

...{
continue;
}
thisLeft = parseInt(elements[i].style.left);
thisRight = thisLeft + parseInt(elements[i].childNodes[0].offsetWidth);
thisTop = parseInt(elements[i].style.top);
thisBottom = thisTop + parseInt(elements[i].childNodes[0].offsetHeight);
//判断是否在选择框范围内
if ((((thisLeft > x1 && thisLeft < x2) || (thisRight > x1 && thisRight < x2)) && ((thisTop > y1 && thisTop < y2) || (thisBottom > y1 && thisBottom < y2)))
|| (((x1 > thisLeft && x1 < thisRight) || (x2 > thisLeft && x2 < thisRight)) && ((y1 > thisTop && y1 < thisBottom) || (y2 > thisTop && y2 < thisBottom))))

...{
if (!elements[i].isSelected)

...{
areaDiv.insert(elements[i].id);
SelectStyle(elements[i], true);
}
}
else if (elements[i].isSelected)

...{
//不在选择框范围内
var isTrue = false;
for (var j = 0; j < saveDiv.length; j++)

...{
if (elements[i].isSelected && elements[i].id == saveDiv[j])

...{
isTrue = true;
break;
}
}
if (!isTrue)

...{
areaDiv.remove(elements[i].id);
SelectStyle(elements[i], false);
}
}
}
}
}

//范围选择结束
function AreaSelected()

...{
if (eventStatus == "selecting")

...{
selectArea.parentNode.removeChild(selectArea);
selectArea = null;
//将选择框内的数组存到移动/复制的数组里面
for (var i = 0; i < areaDiv.length; i++)

...{
saveDiv.insert(areaDiv[i]);
}
areaDiv.length = 0;
eventStatus = saveDiv.length == 0 ? "nothing" : "selected";
}
}

//鼠标按下移动开始
function MouseDown()

...{
if (event.button == 1 && !event.ctrlKey && eventStatus == "selected")

...{
oX = event.x;
oY = event.y;
cloneNodes = new Array();
oLeft = new Array();
oTop = new Array();
for (var i = 0; i < saveDiv.length; i++)

...{
cloneNodes[i] = $(saveDiv[i]).cloneNode(true);
$(saveDiv[i]).parentNode.appendChild(cloneNodes[i]);
cloneNodes[i].childNodes[0].style.filter = "alpha(opacity=50)";
cloneNodes[i].childNodes[0].src = cloneNodes[i].childNodes[0].img2;
oLeft[i] = parseInt(cloneNodes[i].style.left);
oTop[i] = parseInt(cloneNodes[i].style.top);
cloneNodes[i].childNodes[0].setCapture();
}
document.body.style.cursor = "move";
eventStatus = "move";
}
}

//鼠标移动
function MouseMove()

...{
if (event.button == 1 && eventStatus == "move")

...{
var nX = event.x;
var nY = event.y;
//移动中
var len = cloneNodes.length;
for (var i = 0; i < len; i++)

...{
cloneNodes[i].style.left = (oLeft[i] + nX - oX) + "px";
cloneNodes[i].style.top = (oTop[i] + nY - oY) + "px";
}
}
}

//鼠标弹起移动结束
function MouseUp()

...{
if (eventStatus == "move")

...{
eventStatus = "moving";
var aimLeft, aimTop;
var xmlStr = "<nodes>";
for (var i = cloneNodes.length - 1; i >= 0 ; i--)

...{
cloneNodes[i].childNodes[0].releaseCapture();
aimLeft = parseInt(cloneNodes[i].style.left);
aimTop = parseInt(cloneNodes[i].style.top);
if ($("move").checked)

...{
//移动操作
MoveNodes(i, aimLeft, aimTop);
}
else

...{
//复制操作
aimLeft = parseInt(cloneNodes[i].style.left);
aimTop = parseInt(cloneNodes[i].style.top);
cloneNodes[i].style.left = $(saveDiv[i]).style.left;
cloneNodes[i].style.top = $(saveDiv[i]).style.top;
CopyNodes(i, aimLeft, aimTop);
}
}
document.body.style.cursor = "default";
}
}

//移动位置
function MoveNodes(saveIndex, aimLeft, aimTop)

...{
var nowLeft = parseInt($(saveDiv[saveIndex]).style.left);
var nowTop = parseInt($(saveDiv[saveIndex]).style.top);
if (nowLeft > aimLeft + moveSize || nowLeft < aimLeft - moveSize || nowTop > aimTop + moveSize || nowTop < aimTop - moveSize)

...{
$(saveDiv[saveIndex]).style.left = aimLeft > nowLeft + moveSize ? (nowLeft + moveSize) + "px" : aimLeft < nowLeft - moveSize ? (nowLeft - moveSize) + "px" : nowLeft + "px";
$(saveDiv[saveIndex]).style.top = aimTop > nowTop + moveSize ? (nowTop + moveSize) + "px" : aimTop < nowTop - moveSize ? (nowTop - moveSize) + "px" : nowTop + "px";
setTimeout("MoveNodes(" + saveIndex + ", " + aimLeft + ", " + aimTop + ")", 1);
}
else

...{
$(saveDiv[saveIndex]).style.left = aimLeft;
$(saveDiv[saveIndex]).style.top = aimTop;
cloneNodes[saveIndex].parentNode.removeChild(cloneNodes[saveIndex]);
cloneNodes.remove(cloneNodes[saveIndex]);
if (cloneNodes.length == 0)

...{
eventStatus = "selected";
}
}
}

//复制
function CopyNodes(saveIndex, aimLeft, aimTop)

...{
var nowLeft = parseInt(cloneNodes[saveIndex].style.left);
var nowTop = parseInt(cloneNodes[saveIndex].style.top);
if (nowLeft > aimLeft + moveSize || nowLeft < aimLeft - moveSize || nowTop > aimTop + moveSize || nowTop < aimTop - moveSize)

...{
cloneNodes[saveIndex].style.left = aimLeft > nowLeft + moveSize ? (nowLeft + moveSize) + "px" : aimLeft < nowLeft - moveSize ? (nowLeft - moveSize) + "px" : nowLeft + "px";
cloneNodes[saveIndex].style.top = aimTop > nowTop + moveSize ? (nowTop + moveSize) + "px" : aimTop < nowTop - moveSize ? (nowTop - moveSize) + "px" : nowTop + "px";
setTimeout("CopyNodes(" + saveIndex + ", " + aimLeft + ", " + aimTop + ")", 1);
}
else

...{
cloneNodes[saveIndex].style.left = aimLeft;
cloneNodes[saveIndex].style.top = aimTop;
cloneNodes[saveIndex].id = "copyDiv" + (++copyNo);
cloneNodes[saveIndex].isSelected = false;
cloneNodes[saveIndex].childNodes[0].style.filter = null;
SelectStyle(cloneNodes[saveIndex], false);
cloneNodes.remove(cloneNodes[saveIndex]);
if (cloneNodes.length == 0)

...{
eventStatus = "selected";
}
}
}

//取消选择
function CancelSelect()

...{
for (var saveIndex = 0; saveIndex < saveDiv.length; saveIndex++)

...{
SelectStyle($(saveDiv[saveIndex]), false);
}
saveDiv.length = 0;
eventStatus = "nothing";
}

//全选
function AllSelect()

...{
var elements = document.all;
var len = elements.length;
saveDiv.length = 0;
for(var i = 0; i < len; i++)

...{
if (elements[i].group == groupName)

...{
saveDiv.insert(elements[i].id);
SelectStyle(elements[i], true);
}
}
eventStatus = "selected";
}

//反选
function ReverseSelect()

...{
var elements = document.all;
var len = elements.length;
var tempDiv = new Array();
for(var i = 0; i < saveDiv.length; i++)

...{
tempDiv.insert(saveDiv[i]);
}
var isExist = false;
CancelSelect();
for (var i = 0; i < len; i++)

...{
if (elements[i].group == groupName)

...{
for(var j = 0; j < tempDiv.length; j++)

...{
if (elements[i].id == tempDiv[j])

...{
isExist = true;
break;
}
}
if (isExist)

...{
isExist = false;
continue;
}
saveDiv.insert(elements[i].id);
SelectStyle(elements[i], true);
}
}
}

//删除选中
function deleteNodes()

...{
var saveLen = saveDiv.length;
for (var saveIndex = saveLen - 1; saveIndex >= 0; saveIndex--)

...{
$(saveDiv[saveIndex]).parentNode.removeChild($(saveDiv[saveIndex]));
}
saveDiv.length = 0;
eventStatus = "nothing";
}


document.body.onselectstart = function() ...{return false};
document.body.onmousedown = AreaCreate;
document.body.onmousemove = AreaSelecting;
document.body.onmouseup = AreaSelected;
panel.onmousedown = MouseDown;
panel.onmousemove = MouseMove;
panel.onmouseup = MouseUp;

//快捷键
document.onkeydown = function()

...{
event.ctrlKey && event.keyCode == 65 ? AllSelect() : null; //CTRL+A全选
event.ctrlKey && event.keyCode == 88 ? ReverseSelect() : null; //CTRL+X反选
event.ctrlKey && event.keyCode == 90 ? CancelSelect() : null; //CTRL+Z取消选择
event.keyCode == 189 ? $("move").checked = true : null; //- 选中移动
event.keyCode == 187 ? $("copy").checked = true : null; //+ 选中复制
event.keyCode == 46 || event.keyCode == 110 ? deleteNodes() : null; //Delete或者Del删除选中节点
}
</script>
</body>
</html>

操作说明:
-
未选择状态下,单击DIV上可选中此DIV。
-
未选择状态下,单击在背景上按住左键拖动产生范围虚线框,在此范围虚线框内的DIV边框变粗变色为被选中,虚线框外的则不被选中。
-
已选择状态下,按住Ctrl可再次选择,按住Ctrl的同时,单击在DIV上,如果DIV已被选中则取消本节点选择,反之选中此节点。
-
已选择状态下,按住Ctrl的同时,如果单击在背景上按住左键拖动产生范围虚线框,在此范围虚线框内的DIV边框变粗变色为被选中,虚线框外的如果为上次已选中的则不仍然选中,否则不选中。
-
释放后虚线消失,需要添加选择可重复第“3”,“4”步操作,多次选择的节点选中。
-
快捷键选择,Ctrl +A全选,Ctrl +X反选,Ctrl +Z取消选择。
-
移动位置,选中DIV后,如果单选组选中移动(-)(默认,快捷键为“-”)按住左键拖动位置后释放可批量移动位置,产生一段过度动画,不撤销选择的DIV可多次移动,如已移动完毕按Ctrl+Z撤销选择即可。
-
复制节点,选中DIV后,如果单选组选中复制(+,快捷键为“+”),按住左键拖动位置后释放,产生一段过度动画,即复制选中的DIV,如复制完毕按Ctrl+Z取消选择即可。
-
删除选中DIV,选中DIV后,按下按钮或者快捷键“Delete”、“.”可删除所有选中的DIV。