节点复制 上

486 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

前言

DOM的操作主要是增删改查,其实还有一个很有意思的操作,就是节点的复制。

复制比新建节点理论是要高效一些的,我们之后也会进行性能测试。

今天我们就进入正题吧,DOM节点的复制。

Node.cloneNode

语法

var dupNode = node.cloneNode(deep);

其有一个参数,表示是不是深度克隆。
true, 则该节点的所有后代节点也都会被克隆,
false, 则只克隆该节点本身。

来看一场经常,复制9个节点,并且里面的值递归增长

<div id="root">
    <div class="item">1</div>
</div>

<script type="text/javascript">
    const rootEl = document.getElementById("root");
    const nodeEl = rootEl.firstChild;

    let newNode;
    for (let i = 0; i < 10; i++) {
        newNode = nodeEl.cloneNode(true);
        rootEl.appendChild(newNode);
    }  

</script>

咋眼一看没问题,其实有两个问题:

  1. rootEl.firstChild其 实拿到的是Text节点,并不是我们的div节点
    div前后都有你看不到的Text节点,所以应该用 firstElementChild属性

截图_20210812080814.png

  1. 第二个参数为true, 采用了深度复制,结果内容都是1
    我们这里只需要浅复制就可以,以节约性能。

换成如下代码:


    <div id="root">
        <div class="item">1</div>
    </div>

    <script type="text/javascript">
        const rootEl = document.getElementById("root");
        const nodeEl = rootEl.firstChild;

        let newNode;
        for (let i = 0; i < 10; i++) {
            newNode = nodeEl.cloneNode(false);
            newNode.innerText = i + 1;
            rootEl.appendChild(newNode);
        }  
    </script>

完美!!!

完美了吗? 没有啊,兄弟!, 事件呢?

事件的复制

我们先看看一个简单的例子:

我们复制一个button,这个button通过addEventListener注册了一个事件,我们对这个button进行深复制。

<div id="root">
    <button class="item">点我啊</button>
</div>

<script>
    const rootEl = document.getElementById("root");
    const nodeEl = rootEl.firstElementChild;

    function onClick(){
        alert("clicked")
    }
    nodeEl.addEventListener("click", onClick);

    const newEl = rootEl.cloneNode(true);
    rootEl.appendChild(newEl);
</script>

image.png

确实得到了两个按钮,但是被复制的按钮被点击后,并没有弹出alert框。 说明,通过addEventListener添加的事件并不能被复制。

我们稍作改动:

<div id="root">
    <button class="item" onclick="alert('clicked')">点我啊</button>
</div>

<script>
    const rootEl = document.getElementById("root");
    const nodeEl = rootEl.firstElementChild;
    const newEl = rootEl.cloneNode(true);
    rootEl.appendChild(newEl);
</script>

image.png 被复制的按钮点击事件生效了,哈哈,不错不错。

我们再稍作改动:

   <div id="root">
      <button class="item">点我啊</button>
    </div>

    <script>
      function onClick() {
        alert("clicked");
      }
      const rootEl = document.getElementById("root");
      const nodeEl = rootEl.firstElementChild;
      nodeEl.onclick = onClick;
      
      const newEl = rootEl.cloneNode(true);
      rootEl.appendChild(newEl);
    </script>

经过测试也没有弹出alert框

结论:

  1. DOM2 addEventListener注册的事件不会被复制
  2. DOM0 节点上onclick属性的事件会被复制,但是通过JS动态添加的onclick不会被复制。

小结

当然复制节点的方法不止有cloneNode方法,下期再见。

今天你收获了吗?