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
3 Answers
Reset to default 3This 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条)