Как вызвать функцию дочернего компонента в родительских событиях

контекст

В 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
      }
    }
  }
}