在Vue 2.0中,文档和others清楚地表明从父母到孩子的沟通是通过道具进行的。
父母如何告诉孩子一个事件是通过道具发生的?
我应该只看一个名为事件的道具吗?这感觉不对,也没有替代方案($emit
/ $on
用于孩子到父母,而轮毂模型用于远程元素)。
我有一个父容器,它需要告诉它的子容器,可以在API上使用某些操作。我需要能够触发功能。
给子组件一个ref
并使用$refs
直接调用子组件上的方法。
HTML:
<div id="app">
<child-component ref="childComponent"></child-component>
<button @click="click">Click</button>
</div>
JavaScript的:
var ChildComponent = {
template: '<div>{{value}}</div>',
data: function () {
return {
value: 0
};
},
methods: {
setValue: function(value) {
this.value = value;
}
}
}
new Vue({
el: '#app',
components: {
'child-component': ChildComponent
},
methods: {
click: function() {
this.$refs.childComponent.setValue(2.0);
}
}
})
有关更多信息,请参阅Vue documentation on refs。
你所描述的是父母的状态变化。你通过道具把它传给了孩子。正如你的建议,你会watch
那道具。当孩子采取行动时,它会通过emit
通知父母,然后父母可能会再次改变状态。
var Child = {
template: '<div>{{counter}}</div>',
props: ['canI'],
data: function () {
return {
counter: 0
};
},
watch: {
canI: function () {
if (this.canI) {
++this.counter;
this.$emit('increment');
}
}
}
}
new Vue({
el: '#app',
components: {
'my-component': Child
},
data: {
childState: false
},
methods: {
permitChild: function () {
this.childState = true;
},
lockChild: function () {
this.childState = false;
}
}
})
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.2.1/vue.js"></script>
<div id="app">
<my-component :can-I="childState" v-on:increment="lockChild"></my-component>
<button @click="permitChild">Go</button>
</div>
如果你真的想把事件传递给孩子,你可以通过creating a bus (which is just a Vue instance) and passing it to the child as a prop做到这一点。
你可以使用$emit
和$on
。使用@RoyJ代码:
HTML:
<div id="app">
<my-component></my-component>
<button @click="click">Click</button>
</div>
JavaScript的:
var Child = {
template: '<div>{{value}}</div>',
data: function () {
return {
value: 0
};
},
methods: {
setValue: function(value) {
this.value = value;
}
},
created: function() {
this.$parent.$on('update', this.setValue);
}
}
new Vue({
el: '#app',
components: {
'my-component': Child
},
methods: {
click: function() {
this.$emit('update', 7);
}
}
})
如果您有时间,请使用Vuex商店直接观察变量(也称为状态)或触发(也称为调度)操作。
在event-bus approach期间,不喜欢$on
在孩子身上使用create
绑定。为什么?随后的create
调用(我正在使用vue-router
)不止一次绑定消息处理程序 - 导致每个消息多个响应。
将道具从父母传给孩子并将物品观察者放在孩子身上的正统解决方案效果更好。唯一的问题是孩子只能对价值转变采取行动。多次传递相同的信息需要某种簿记来强制过渡,以便孩子可以接受改变。
我发现,如果我将消息包装在一个数组中,它将始终触发子监视器 - 即使值保持不变。
家长:
{
data: function() {
msgChild: null,
},
methods: {
mMessageDoIt: function() {
this.msgChild = ['doIt'];
}
}
...
}
儿童:
{
props: ['msgChild'],
watch: {
'msgChild': function(arMsg) {
console.log(arMsg[0]);
}
}
}
HTML:
<parent>
<child v-bind="{ 'msgChild': msgChild }"></child>
</parent>
在子组件上调用方法的简单解耦方法是从子组件中发出处理程序,然后从父组件调用它。
var Child = {
template: '<div>{{value}}</div>',
data: function () {
return {
value: 0
};
},
methods: {
setValue(value) {
this.value = value;
}
},
created() {
this.$emit('handler', this.setValue);
}
}
new Vue({
el: '#app',
components: {
'my-component': Child
},
methods: {
setValueHandler(fn) {
this.setter = fn
},
click() {
this.setter(70)
}
}
})
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<div id="app">
<my-component @handler="setValueHandler"></my-component>
<button @click="click">Click</button>
</div>
父级会在必要时跟踪子处理程序函数和调用。
以下示例是自解释的。其中refs和事件可用于从父级和子级调用函数。
// PARENT
<template>
<parent>
<child
@onChange="childCallBack"
ref="childRef"
:data="moduleData"
/>
<button @click="callChild">Call Method in child</button>
</parent>
</template>
<script>
export default {
methods: {
callChild() {
this.$refs.childRef.childMethod('Hi from parent');
},
childCallBack(message) {
console.log('message from child', message);
}
}
};
</script>
// CHILD
<template>
<child>
<button @click="callParent">Call Parent</button>
</child>
</template>
<script>
export default {
methods: {
callParent() {
this.$emit('onChange', 'hi from child');
},
childMethod(message) {
console.log('message from parent', message);
}
}
}
</script>
我认为我们应该考虑父母使用孩子方法的必要性。事实上,父母不需要关心孩子的方法,但可以将孩子组件视为FSA(有限状态机)。父母组件控制子组件的状态。因此,观察状态更改或仅使用计算功能的解决方案就足够了
您可以使用mixin来设置共享数据属性。在父级中更改它,在子级中查看它:
// mixin
export default {
data() {
return {
clicked: false
}
}
}
// parent
export default {
mixins: [myMixin],
methods: {
btnClick() {
this.clicked = true
}
}
}
// child
export default {
mixins: [myMixin],
watch: {
clicked(val) {
if(val) {
// yay
}
}
}
}