Как вызвать функцию дочернего компонента в родительских событиях
контекст
В Vue 2.0 документация и другие четко указывают, что связь от родителя к ребенку происходит через реквизиты.
Вопрос
Как родитель говорит своему ребенку, что событие произошло через реквизит?
Должен ли я просто посмотреть опору, называемую событием? Это не так, как и альтернативы ($emit
/$on
- от ребенка к родительскому, а модель-концентратор - для удаленных элементов).
пример
У меня есть родительский контейнер, и ему нужно сообщить его дочернему контейнеру, что он может задействовать определенные действия над API. Мне нужно иметь возможность запускать функции.
Ответы
Ответ 1
Дайте дочернему компоненту 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 по ссылкам.
Ответ 2
То, что вы описываете, - это изменение состояния родителя. Вы передаете это ребенку через опору. Как вы предположили, вы будете 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>
Ответ 3
Вы можете использовать $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);
}
}
})
Пример выполнения: https://jsfiddle.net/rjurado/m2spy60r/1/
Ответ 4
Если у вас есть время, используйте хранилище Vuex для просмотра переменных (aka state) или триггера (aka dispatch) непосредственно.
Ответ 5
Приведенный ниже пример говорит сам за себя. где ссылки и события могут использоваться для вызова функции от и к родителю и потомку.
// 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>
Ответ 6
Не понравился подход event-bus с использованием $on
bindings в дочернем элементе во время 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>
Ответ 7
Простой разъединенный способ вызова методов на дочерних компонентах заключается в отправке обработчика из дочернего элемента и последующем вызове его из родительского компонента.
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>
Ответ 8
Я думаю, что нам нужно учитывать необходимость использования родительских методов childs. На самом деле родители не должны относиться к методу дочернего процесса, но могут относиться к дочернему компоненту как к FSA (конечный автомат). Параметр компонент для управления состояние дочернего компонента. Таким образом, решение для просмотра изменения статуса или просто использования вычислительной функции достаточно
Ответ 9
Вы можете использовать миксин, чтобы установить общий атрибут данных. Измените это в родительском, смотрите это в дочернем:
// 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
}
}
}
}