在Vue中,手动更改DOM内容和通过虚拟DOM更新DOM内容,哪个优先级更高?

h9vpoimq  于 2023-04-21  发布在  Vue.js
关注(0)|答案(1)|浏览(127)

我最近一直在研究Vue的nextTick,我自己写了下面的演示代码:

<html>
  <head>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  </head>
  <body>
    <div id="root"></div>
  </body>
  <script>
    const vue = new Vue({
      el: '#root',
      template: '<div><div id="dom">{{msg}}</div><button @click="add">add</button></div>',
      data() {
        return {
          msg: 1
        }
      },
      watch: {
        msg(value) {
          console.log('msg>>>>>', value);
        }
      },
      methods: {
        add() {
          const dom = document.getElementById('dom');
          dom.textContent = '30'
          for(let i = 0; i < 3; i ++) {
            this.msg ++
          }
          this.$nextTick(() => {
            console.log('msg.content2>>>>>>', dom.textContent)
          })
        }
      }
    })
  </script>
</html>

liveDemo:jsfiddle
结果真的让我很困惑。正如我所料,点击添加按钮后,dom.textContent = '30'将dom元素的textConent更改为30。下一个for循环,将msg添加为4,因为Vue将异步更新页面,我们无法在页面中看到最新的结果。在this.$nextTick之后,Vue将使用更新后的msg立即重新渲染dom元素,我们知道现在是4。所以dom元素的textContent现在应该是4,但它仍然是30。为什么会发生这种情况?我错在哪里?

bhmjp9jg

bhmjp9jg1#

我想我知道是怎么回事了
当执行dom.textContent = '30'时,它将元素的文本内容更改为'30'。
但它并不像我之前想的那样,直接将dom元素的Text子节点的textContent修改为新的内容,而是生成一个新的Text子节点,并替换原来的子节点。
稍后,在$nextTick函数中,Vue使用最新的msg值(现在为4)来更新Text节点的内容。然而,Vue现在使用的Text节点是存储在el属性中的旧节点,而不是更新后的dom元素的Text子节点。因此,这种更改是无用的。页面和console.log语句都无法显示预期结果。
在将演示代码更改为以下版本后,我终于得到了我想要的:

<html>
  <head>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  </head>
  <body>
    <div id="root"></div>
  </body>
  <script>
    const vue = new Vue({
      el: '#root',
      template: '<div><div id="dom">{{msg}}</div><button @click="add">add</button></div>',
      data() {
        return {
          msg: 1
        }
      },
      watch: {
        msg(value) {
          console.log('msg>>>>>', value);
        }
      },
      methods: {
        add() {
          const dom = document.getElementById('dom');
          dom.childNodes[0].textContent = '30'; //change dom's child node's textContent, not dom's own textContent; 
          for(let i = 0; i < 3; i ++) {
            this.msg ++
          }
          this.$nextTick(() => {
            console.log('msg.content2>>>>>>', dom.textContent)
          })
        }
      }
    })
  </script>
</html>

live demo
另一个demo:
change div's textContent creates a new Text node

相关问题