javascript - How to get Vue to update the actual DOM right away when nextTick doesn't work, from a .vue file? - Stack Ov

When I have a Vue ponent in a .vue file with a data member isLoading: false, and a template:<div v-s

When I have a Vue ponent in a .vue file with a data member isLoading: false, and a template:

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

And a method:

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

I thought that the nextTick function would allow both the virtual and real DOM to update, and thus the two console.log lines would output the same results. However, they do not: it seems that the real DOM isn't being updated right away, and thus the second log results in a element with display: none; whereas the first log doesn't--I get this on the console:

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

(By the way, even if I use setTimeout instead of this.$nextTick, I get the very same results from console.log. I also tried using the updated hook, but the same symptoms happen there. If I code any variation in a .js file, the problem goes away, but it persists when in a .vue file.)

Is there some kind of optimization or further asynchrony in how Vue updates the actual DOM from the virtual DOM? How do I get the actual DOM to update right away?

When I have a Vue ponent in a .vue file with a data member isLoading: false, and a template:

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

And a method:

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

I thought that the nextTick function would allow both the virtual and real DOM to update, and thus the two console.log lines would output the same results. However, they do not: it seems that the real DOM isn't being updated right away, and thus the second log results in a element with display: none; whereas the first log doesn't--I get this on the console:

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

(By the way, even if I use setTimeout instead of this.$nextTick, I get the very same results from console.log. I also tried using the updated hook, but the same symptoms happen there. If I code any variation in a .js file, the problem goes away, but it persists when in a .vue file.)

Is there some kind of optimization or further asynchrony in how Vue updates the actual DOM from the virtual DOM? How do I get the actual DOM to update right away?

Share edited Dec 7, 2018 at 21:43 Patrick Szalapski asked Dec 7, 2018 at 19:26 Patrick SzalapskiPatrick Szalapski 9,48012 gold badges83 silver badges153 bronze badges 4
  • 1 Note that console can update the display after the fact (usually see an info icon). To be precise, you should save the state of this.$refs.hey.getAttribute("style") for an accurate snapshot. Does not negate your issue, though. – Richard Matsen Commented Dec 7, 2018 at 22:53
  • 1 I can't reproduce on Codesandbox. Are you able to alter it to reproduce? – Richard Matsen Commented Dec 7, 2018 at 22:55
  • 1 this.$refs.hey is not a virtual DOM element; it's an actual DOM element – Stephen Thomas Commented Dec 8, 2018 at 0:43
  • I think all of you are right. Thanks for helping me find the problem. My follow-up is here: stackoverflow./questions/53707415 – Patrick Szalapski Commented Dec 10, 2018 at 14:10
Add a ment  | 

3 Answers 3

Reset to default 3

This works pretty much as expected, with messages matching both before and after DOM update.

I think your understanding that the refs call returns a virtual node rather than an actual DOM element is incorrect.

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./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>

Please review Vue lifecycle in the documentation. Of note is that there is a disconnect between these two events. Also note that nextTick() waits for the next DOM update cycle, not necessarily the virtual DOM.

This is typically addressed by using the updated lifecycle hook, which executes code after the virtual DOM has already been updated. If you need to execute some code with the guarantee that the virtual DOM has already been updated, you will want to do it there.

You may also be interested in reactivity in depth. This should act as a good plement to the lifecycle diagram.

Turns out that problems with either the eslint-loader cache or the babel-loader cache caused this weirdness. I could only fix it by deleting all of node_modules\.cache. Too bad I don't know why it happened in the first place.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744910762a4600536.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信