当nextTick不起作用时,如何从.vue文件中获取Vue立即更新实际DOM?

时间:2018-12-07 19:26:20

标签: javascript dom vue.js

当我在.vue文件中包含数据成员isLoading: false和模板的Vue组件时:

<div v-show="isLoading" id="hey" ref="hey">Loading...</div>
<button @click="loadIt()">Load it</button>

和一种方法:

loadIt() {
  this.isLoading = true
  this.$nextTick(() => {
    console.log(this.$refs.hey)                  // virtual DOM
    console.log(document.getElementById('hey'))  // actual DOM
    // ...other work here
  })
}

我认为nextTick函数将允许虚拟DOM和实际DOM都进行更新,因此两条console.log行将输出相同的结果。但是,它们没有这样做:似乎真实的DOM并没有立即更新,因此第二个日志的结果是带有display: none;的元素,而第一个日志的结果没有-我在控制台上得到了:

<div id="hey" data-v-964d645e="" style="">
<div id="hey" data-v-964d645e="" style="display: none;">

(顺便说一句,即使我使用setTimeout而不是this.$nextTick,我也从console.log获得了相同的结果。我也尝试使用updated钩子,但是如果在.js文件中编写任何变体形式,问题都会消失,但是在.vue文件中时,问题仍然存在。)

Vue如何从虚拟DOM更新实际DOM是否存在某种优化或进一步的异步性? 我如何立即获取实际的DOM?

3 个答案:

答案 0 :(得分:1)

请查看文档中的Vue lifecycle。值得注意的是,这两个事件之间存在脱节。另外请注意,nextTick()等待下一个DOM更新周期,而不必等待虚拟DOM。

通常通过使用updated生命周期挂钩来解决此问题,该挂钩在虚拟DOM已更新后在之后执行代码。如果您需要执行某些代码以确保虚拟DOM已被更新,则可以在此进行。

您可能也对reactivity in depth感兴趣。这应该是生命周期图的很好补充。

答案 1 :(得分:1)

这几乎可以按预期工作,并且在DOM更新之前和之后都匹配消息。

我认为您对refs调用返回的是虚拟节点而不是实际的DOM元素的理解是错误的。

new Vue({
  el: '#app',
  data: {
    isLoading: false
  },
  methods: {
    loadIt() {
      this.isLoading = true;
      this.tellMeAboutIt('before');
      this.$nextTick(() => this.tellMeAboutIt('after'));
    },
    tellMeAboutIt(when) {
        console.log(`Virtual ${when}:`, this.$refs.hey) // virtual DOM
        console.log(`Actual ${when}:`, document.getElementById('hey')) // actual DOM
    }
  }
});
<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <div v-show="isLoading" id="hey" ref="hey">Loading...</div>
  <button @click="loadIt()">Load it</button>
</div>

答案 2 :(得分:0)

结果证明,eslint-loader缓存或babel-loader缓存出现问题导致了这种怪异。我只能通过删除所有node_modules\.cache来解决此问题。太糟糕了,我不知道为什么会首先发生。