简体   繁体   English

如何在父事件上调用子组件的函数

[英]How to call function on child component on parent events

Context语境

In Vue 2.0 the documentation and others clearly indicate that communication from parent to child happens via props.在 Vue 2.0 中,文档和其他文档清楚地表明,父母与孩子之间的交流是通过 props 发生的。

Question问题

How does a parent tell its child an event has happened via props?父母如何通过道具告诉孩子事件发生了?

Should I just watch a prop called event?我应该只看一个叫做事件的道具吗? That doesn't feel right, nor do alternatives ( $emit / $on is for child to parent, and a hub model is for distant elements).这感觉不对,替代方案也不对( $emit / $on用于子到父,集线器模型用于远距离元素)。

Example例子

I have a parent container and it needs to tell its child container that it's okay to engage certain actions on an API.我有一个父容器,它需要告诉它的子容器可以在 API 上执行某些操作。 I need to be able to trigger functions.我需要能够触发功能。

Give the child component a ref and use $refs to call a method on the child component directly.给子组件一个ref并使用$refs直接调用子组件上的方法。

html: html:

<div id="app">
  <child-component ref="childComponent"></child-component>
  <button @click="click">Click</button>  
</div>

javascript: 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);
    }
  }
})

For more info, see Vue documentation on refs .有关更多信息,请参阅refs 上的 Vue 文档

What you are describing is a change of state in the parent.您所描述的是父母的状态变化。 You pass that to the child via a prop.您通过道具将其传递给孩子。 As you suggested, you would watch that prop.正如你所建议的,你会watch那个道具。 When the child takes action, it notifies the parent via an emit , and the parent might then change the state again.当孩子采取行动时,它会通过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>

If you truly want to pass events to a child, you can do that by creating a bus (which is just a Vue instance) and passing it to the child as a prop .如果你真的想将事件传递给孩子,你可以通过创建一个总线(它只是一个 Vue 实例)并将其作为 prop 传递给孩子来做到这一点。

You can use $emit and $on .您可以使用$emit$on Using @RoyJ code:使用@RoyJ 代码:

html: html:

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

javascript: 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);
    }
  }
})

Running example: https://jsfiddle.net/rjurado/m2spy60r/1/运行示例: https ://jsfiddle.net/rjurado/m2spy60r/1/

A simple decoupled way to call methods on child components is by emitting a handler from the child and then invoking it from 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/vue@2.5.17/dist/vue.js"></script> <div id="app"> <my-component @handler="setValueHandler"></my-component> <button @click="click">Click</button> </div>

The parent keeps track of the child handler functions and calls whenever necessary.父进程跟踪子处理函数并在必要时调用。

Did not like the event-bus approach using $on bindings in the child during create .不喜欢在create期间在孩子中使用$on绑定的事件总线方法 Why?为什么? Subsequent create calls (I'm using vue-router ) bind the message handler more than once--leading to multiple responses per message.随后的create调用(我正在使用vue-router )不止一次绑定消息处理程序——导致每条消息有多个响应。

The orthodox solution of passing props down from parent to child and putting a property watcher in the child worked a little better.将 props 从 parent 传递给 child 并在 child 中放置 property watcher 的正统解决方案效果更好一些 Only problem being that the child can only act on a value transition.唯一的问题是孩子只能对价值转变采取行动。 Passing the same message multiple times needs some kind of bookkeeping to force a transition so the child can pick up the change.多次传递相同的消息需要某种簿记来强制转换,以便孩子可以接受更改。

I've found that if I wrap the message in an array, it will always trigger the child watcher--even if the value remains the same.我发现如果我将消息包装在一个数组中,它总是会触发子观察者——即使值保持不变。

Parent:家长:

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

Child:孩子:

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

HTML: HTML:

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

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

The below example is self explainatory.下面的例子是自我解释的。 where refs and events can be used to call function from and to parent and child.其中 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>

Calling child component in parent在父组件中调用子组件

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

in Child component在子组件中

mycomp.vue mycomp.vue

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

我认为我们应该考虑一下 parent 使用 child 的方法的必要性。实际上,父母不必关心 child 的方法,而是可以将 child 组件视为 FSA(finite state machine)。Parents 组件控制子组件的状态。所以观察状态变化或只使用计算功能的解决方案就足够了

You could use a mixin to set a shared data attribute. 您可以使用mixin设置共享数据属性。 Change it in the parent, watch it in the child: 在父级中对其进行更改,在子级中对其进行监视:

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

you can use key to reload child component using key您可以使用 key 使用 key 重新加载子组件

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

If you want to reload component with new filter, if button click filter the child component如果要使用新过滤器重新加载组件,如果单击按钮过滤子组件

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

and use the filter to trigger the function并使用过滤器触发功能

You can simulate sending event to child by toggling a boolean prop in parent.您可以通过切换父级中的布尔属性来模拟向子级发送事件。

Parent code :父代码:

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

Child code :子代码:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM