Vue.js - 道具同步不是即时的
Vue.js - prop sync not instant
使用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
让我们来看看你的例子。我为 parent 和 child 组件和 console.log
语句的 bar
属性 的值添加了观察者,以注意传输中的不同点两个组件之间的数据:
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
首先触发,然后是计算 _bar
的 get
和 set
方法。但是, bar
的两个观察者直到 handler_button_click
函数完成后才会触发。这表明 child 的 $emit
调用传递的值在 handler_button_click
函数完成执行之前不会被 parent 组件处理。
Vue 提供的等待 parent 和 child 的属性在 handler_button_click
函数内同步的唯一方法是调用 $nextTick
,正如你所描述的。 $nextTick
函数将等待执行其处理程序,直到 DOM 完成更新。由于 DOM 在 parent 和 child 组件中的所有数据更改都得到解决之前不会完成渲染,因此您可以确定此时一切都会同步。
综上所述,您似乎只是想让 child 的 _bar
属性 在设置后立即更新,您不一定需要立即在 parent 范围内更新值。
在那种情况下,您可以使用观察者而不是计算的 getter 和 setter。这样,由于未计算 child 的 属性,它将立即更新,而 parent 的 属性 将在下一次报价后更新。
这是一个例子:
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
属性 的名称更改为 value
,因为无法将带有下划线的属性视为 they are not proxied to the Vue instance。
使用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
让我们来看看你的例子。我为 parent 和 child 组件和 console.log
语句的 bar
属性 的值添加了观察者,以注意传输中的不同点两个组件之间的数据:
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
首先触发,然后是计算 _bar
的 get
和 set
方法。但是, bar
的两个观察者直到 handler_button_click
函数完成后才会触发。这表明 child 的 $emit
调用传递的值在 handler_button_click
函数完成执行之前不会被 parent 组件处理。
Vue 提供的等待 parent 和 child 的属性在 handler_button_click
函数内同步的唯一方法是调用 $nextTick
,正如你所描述的。 $nextTick
函数将等待执行其处理程序,直到 DOM 完成更新。由于 DOM 在 parent 和 child 组件中的所有数据更改都得到解决之前不会完成渲染,因此您可以确定此时一切都会同步。
综上所述,您似乎只是想让 child 的 _bar
属性 在设置后立即更新,您不一定需要立即在 parent 范围内更新值。
在那种情况下,您可以使用观察者而不是计算的 getter 和 setter。这样,由于未计算 child 的 属性,它将立即更新,而 parent 的 属性 将在下一次报价后更新。
这是一个例子:
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
属性 的名称更改为 value
,因为无法将带有下划线的属性视为 they are not proxied to the Vue instance。