如何在 parent 事件上调用 child 组件的函数

How to call function on child component on parent events

上下文

在 Vue 2.0 中,文档和 others 清楚地表明从 parent 到 child 的通信是通过 props 进行的。

问题

parent 如何通过道具告诉它 child 事件已经发生?

我应该只看一个叫做事件的道具吗?这感觉不对,替代方案也不对($emit/$on 用于 child 到 parent,而集线器模型用于远距离元素)。

示例

我有一个 parent 容器,它需要告诉它的 child 容器可以对 API 进行某些操作。 我需要能够触发功能。

您所描述的是 parent 中的状态变化。您通过道具将其传递给 child 。正如你所建议的,你会watch那个道具。当 child 采取行动时,它会通过 emit 通知 parent,然后 parent 可能会再次更改状态。

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>

如果您真的想将事件传递给 child,您可以通过 来实现。

您可以使用 $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/

给子组件一个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

如果你有时间,使用 Vuex store 来观察变量(又名状态)或直接触发(又名调度)一个动作。

不喜欢 event-bus approachcreate 期间在 child 中使用 $on 绑定。为什么?随后的 create 调用(我正在使用 vue-router)多次绑定消息处理程序——导致每条消息有多个响应。

将道具从 parent 向下传递到 child 并在 child 中放置一个 属性 观察者的正统解决方案 有点 更好。唯一的问题是 child 只能作用于值转换。多次传递同一条消息需要某种簿记来强制转换,以便 child 可以获取更改。

我发现如果我将消息包装在一个数组中,它将始终触发 child 观察器——即使值保持不变。

Parent:

{
   data: function() {
      msgChild: null,
   },
   methods: {
      mMessageDoIt: function() {
         this.msgChild = ['doIt'];
      }
   }   
   ...
}

Child:

{
   props: ['msgChild'],
   watch: {
      'msgChild': function(arMsg) {
         console.log(arMsg[0]);
      }
   }
}

HTML:

<parent>
   <child v-bind="{ 'msgChild': msgChild }"></child>
</parent>

我认为我们应该考虑parent使用child的methods.In事实的必要性,parent不必担心child的方法,但是可以把child组件当作一个FSA(有限状态机)。Parents组件来控制childcomponent.So的状态观看状态变化或仅使用计算功能的解决方案就足够了

在子组件上调用方法的一种简单的解耦方法是从子组件发出处理程序,然后从父组件调用它。

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/vue@2.5.17/dist/vue.js"></script>

<div id="app">
  <my-component @handler="setValueHandler"></my-component>
  <button @click="click">Click</button>  
</div>

父级跟踪子处理函数并在必要时调用。

下面的例子是不言自明的。其中 refs 和 events 可用于从父子和父子调用函数。

// 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>

您可以使用 key 来使用 key 重新加载子组件

<component :is="child1" :filter="filter" :key="componentKey"></component>

如果你想用新的过滤器重新加载组件,如果按钮点击过滤子组件

reloadData() {            
   this.filter = ['filter1','filter2']
   this.componentKey += 1;  
},

并使用过滤器触发函数

在父组件中调用子组件

<component :is="my_component" ref="my_comp"></component>
<v-btn @click="$refs.my_comp.alertme"></v-btn>

在子组件中

mycomp.vue

    methods:{     
    alertme(){
            alert("alert")
            }
    }

您可以通过切换父项中的布尔属性来模拟向子项发送事件。

家长代码:

...
<child :event="event">
...
export default {
  data() {
    event: false
  },
  methods: {
    simulateEmitEventToChild() {
      this.event = !this.event;
    },
    handleExample() {
      this.simulateEmitEventToChild();
    }
  } 
}

儿童代码:

export default {
  props: {
    event: {
      type: Boolean
    }
  },
  watch: {
    event: function(value) {
      console.log("parent event");
    }
  }
}