JS移动DOM节点,将某节点下所有子节点移动(剪切)到另一个节点下。新手很容易踩的坑!
重点:移动完一个非尾部节点之后,后面的节点会依次部位上来,并且节点数据的长度会实时变化!!
题目(新手练习题)
将上方绿色实线框中的两个列表移动(剪切)到下方绿色虚线框中。
ps:
1、绿色实线框被一个div包裹,绿色虚线框被一个div包裹;
2、绿色实线框中的子节点有两个,分别是圆点样式的列表和圆圈样式的列表。
3、要求点击下方的剪切按钮,将绿色实线框中的两个子节点移动到绿色虚线框中。
4、若div中仅有一个节点,那么这道题很简单,没有什么坑,但是多个节点就可能会踩坑~~~
BUG
先行知识点:
1、节点A.appendChild(节点B);若B为新创建的节点,则将节点B添加为节点A的子节点。
1、节点A.appendChild(节点B);若B为另外一个节点的子节点,则将节点B剪切到节点A的子节点。
第一种错误
代码如下:
function cut_bug(){
var upperDiv = document.getElementById("div1"); //通过id获取上方div节点
var upperUl = upperDiv.children; //取上方div节点的所有子节点
var belowNode = document.getElementById("div2"); //通过id获取下方div节点
//我们先不用循环,用最简单的方式,试着将子节点移动过去
belowNode.appendChild(upperUl[0]);
belowNode.appendChild(upperUl[1]);
}
运行结果如下:
解析:
UncaughtTypeError: Failed to execute ‘appendChild’ on ‘Node’: parameter 1 is not of type ‘Node’.
未捕获的类型错误:不能在节点上执行appendChild操作:参数1不是节点类型。
从错误中可以看出,参数0没有问题,而参数1出了问题;利用upperDiv.childElementCount方法获取upperUl数组的长度,可以看出长度为2,确实是应该从upperUl数组中获取两次数据。
实际上,每执行一次移动操作,节点就会实时减少,我们从首部直接取出第0个,那么第1个元素会直接补位来到第0个。
所以,我们可以每次都取0,取upperUl数组的长度次;我们还可以从尾部取到头部(注意:尾部这样的方式会使剪切之后所有元素倒过来)。具体实现代码在后面。
第二种错误
代码如下:
function cut_bug(){
var upperDiv = document.getElementById("div1");
var upperUl = upperDiv.children;
var belowNode = document.getElementById("div2");
//我们不妨试试从上面吸取教训,每次取0,再加入循环的操作
for (var i = 0; i < upperUl.length; i++) {
belowNode.appendChild(upperUl[0]);
}
}
运行结果如下:
解析:
这次没有报错,但是运行结果好像有点差强人意啊,怎么就只移动了一个呢?
问题出在for (var i = 0; i < upperUl.length; i++) 的i < upperUl.length,因为upperUl.length是实时变化的,i每增加一次(append成功一次),upperUl.length就减少一次,结果就是,如果共有n个子节点,最后只能移动n/2个子节点。
所以,我们可以每次利用一个变量在循环之前(append操作之前)存储upperUl.length,保证i的循环终止条件不变。
解决方案
第一种解决方案(无循环)
//这个剪切完之后是正序的。
function cut(){
var upperDiv = document.getElementById("div1");
var upperUl = upperDiv.children;
var len = upperDiv.childElementCount;
var belowNode = document.getElementById("div2");
belowNode.appendChild(upperUl[0]);
belowNode.appendChild(upperUl[0]);
}
//这个剪切完之后是反序的。
function cut(){
var upperDiv = document.getElementById("div1");
var upperUl = upperDiv.children;
var belowNode = document.getElementById("div2");
belowNode.appendChild(upperUl[1]);
belowNode.appendChild(upperUl[0]);
}
第二种解决方案
//这个剪切完之后是反序的。
function cut(){
var upperDiv = document.getElementById("div1");
var upperUl = upperDiv.children;
var len = upperDiv.childElementCount;
var belowNode = document.getElementById("div2");
for (var i = len - 1; i >=0; i--) {
belowNode.appendChild(upperUl[i]);
}
}
第三种解决方案(推荐)
function cut(){
var upperDiv = document.getElementById("div1");
var upperUl = upperDiv.children;
var len = upperDiv.childElementCount;
var belowNode = document.getElementById("div2");
for (var i = 0; i < len; i++) {
belowNode.appendChild(upperUl[0]);
}
}
总结
移动完一个非尾部节点之后,后面的节点会依次部位上来,并且节点数据的长度会实时变化!!
刚刚接触JS,想着记录一下自己遇到的问题,如果能帮到大家就更好了,有错误希望大家提出来~~