使用vue.js在父级和子级之间同步道具。问题是同步使用事件,每次更改值时,我都必须等待$ nextTick才能更新值。这是不理想的,因为我不想每次更改值时都放入$ nextTick。有没有办法使活动/道具更新立即发生?
HTML:
<div id="app">
<foo inline-template v-bind:bar.sync="bar">
<div>
<button v-on:click="handler_button_click">Set to 5</button>
</div>
</foo>
<span>bar: {{bar}}</span>
</div>
JS:
const EVENT_UPDATE_BAR = "update:bar";
Vue.component("foo", {
props:["bar"],
computed:{
_bar:{
get:function(){
return this.bar;
},
set:function(value){
//Mutating the prop here solves the problem, but then I get a warning about mutating the prop...
//this.bar = value;
this.$emit(EVENT_UPDATE_BAR, value);
}
}
},
methods:{
handler_button_click:function(){
//It seems that $nextTick must run before value is updated
this._bar = 5;
//This shows old value - event / prop has not fully propagated back down to child
alert("bar: " + this._bar);
}
}
});
new Vue({
el:"#app",
data:{
bar:1
}
});
请参阅CodePen上的工作示例:https://codepen.io/koga73/pen/MqLBXg
答案 0 :(得分:1)
让我们看一下您的示例。我为父组件和子组件以及bar
语句的console.log
属性值添加了监视程序,以注意两个组件之间数据传输的不同点:
const EVENT_UPDATE_BAR = "update:bar";
Vue.component("foo", {
props:["bar"],
computed:{
_bar:{
get:function(){
console.log('_bar getter is called')
return this.bar;
},
set:function(value){
console.log('_bar setter is called')
this.$emit(EVENT_UPDATE_BAR, value);
}
}
},
methods:{
handler_button_click:function(){
console.log('handler_button_click is called')
this._bar = 5;
console.log('this._bar is accessed with value: ', this._bar);
this.$nextTick(() => {
console.log('next tick handler is called')
})
console.log('handler_button_click finishes')
}
},
watch: {
bar() {
console.log('child bar watcher is called')
}
}
});
new Vue({
el:"#app",
data:{
bar:1
},
watch: {
bar() {
console.log('parent bar watcher is called')
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<foo inline-template v-bind:bar.sync="bar">
<div>
<button v-on:click="handler_button_click">Set to 5</button>
</div>
</foo>
<span>bar: {{bar}}</span>
</div>
您会注意到,首先触发handler_button_click
,然后触发用于计算的get
的{{1}}和set
方法。但是,_bar
函数完成之前,bar
的两个观察程序不会触发。这表明直到handler_button_click
函数执行完毕后,父级组件才处理子级$emit
调用传递的值。
Vue提供的等待handler_button_click
函数中父级和子级属性同步的唯一方法是调用handler_button_click
,如上所述。 $nextTick
函数将等待执行其处理程序,直到DOM完成更新为止。由于DOM必须等到父组件和子组件中的所有数据更改都解决后才能完成渲染,因此可以确保此时所有内容都将保持同步。
所有这些,似乎您只是希望孩子的$nextTick
属性在设置后立即更新,而不必一定要立即在父范围中更新该值。
在这种情况下,您可以使用观察程序来代替计算的getter和setter。这样,由于不计算孩子的财产,它将立即更新,而父母的财产将在下一个滴答之后更新。
这是一个例子:
_bar
const EVENT_UPDATE_BAR = "update:bar";
Vue.component("foo", {
props: ["bar"],
data() {
return {
value: this.bar,
};
},
methods: {
handler_button_click() {
this.value = 5;
alert("bar: " + this.value);
}
},
watch: {
value(val) {
this.$emit(EVENT_UPDATE_BAR, val);
},
bar(val) {
this.value = val;
}
}
});
new Vue({
el: "#app",
data() {
return {
bar: 1
}
}
});
请注意,我已将<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<foo inline-template v-bind:bar.sync="bar">
<div>
<button v-on:click="handler_button_click">Set to 5</button>
</div>
</foo>
<span>bar: {{bar}}</span>
</div>
属性的名称更改为_bar
,因为不能将带有下划线的属性视为they are not proxied to the Vue instance。