vue
vue copied to clipboard
The flush property of watch does not work when it is post
Version
2.7.14
Reproduction link
Steps to reproduce
https://codesandbox.io/s/quizzical-grass-85c9zw?file=/src/components/HelloWorld.vue
What is expected?
if watch has set flush to 'post', it's callback should be called after dom rerender,so that the callback function can get the latest dom
What is actually happening?
The parent component passes a test property to the child component,and the parent component will change this test property when the button is clicked
<template>
<div id="app">
<button @click="click">click me!</button>
<HelloWorld msg="Hello Vue in CodeSandbox!" :test="test" />
</div>
</template>
<script >
import HelloWorld from "./components/HelloWorld";
import { ref } from "vue";
export default {
components: { HelloWorld },
setup() {
const test = ref(false);
const click = () => {
console.log("click");
test.value = true;
};
return {
click,
test,
};
},
};
</script>
The child component will get the latest dom info in watch after the test property has changed,but it cannot get the latest dom. The {flush: "post"} config not work
<template>
<div class="hello" :class="{ test }">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
import { getCurrentInstance, watch, nextTick } from "vue";
export default {
name: "HelloWorld",
props: {
msg: String,
test: Boolean,
},
setup() {
const vm = getCurrentInstance().proxy;
console.log(vm.$props.test);
watch(
() => vm.$props.test,
() => {
// should print element but print null
console.log(document.querySelector(".test"));
nextTick(() => {
console.log(document.querySelector(".test"));
});
},
{
flush: "post",
}
);
},
};
</script>
Because when already flushing,no sorting of new incoming watchers based on the post attribute
// if already flushing, splice the watcher based on its id
// if already past its id, it will be run next immediately.
let i = queue.length - 1
while (i > index && queue[i].id > watcher.id) {
i--
}
queue.splice(i + 1, 0, watcher)