Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/403.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript VueJs 2.0将事件从父级子级发射到其父级组件_Javascript_Vuejs2_Vue.js - Fatal编程技术网

Javascript VueJs 2.0将事件从父级子级发射到其父级组件

Javascript VueJs 2.0将事件从父级子级发射到其父级组件,javascript,vuejs2,vue.js,Javascript,Vuejs2,Vue.js,Vue.js 2.0似乎不会将事件从一个曾子组件发送到他的曾父组件 Vue.component('parent', { template: '<div>I am the parent - {{ action }} <child @eventtriggered="performAction"></child></div>', data(){ return { action: 'No action' } },

Vue.js 2.0似乎不会将事件从一个曾子组件发送到他的曾父组件

Vue.component('parent', {
  template: '<div>I am the parent - {{ action }} <child @eventtriggered="performAction"></child></div>',
  data(){
    return {
      action: 'No action'
    }
  },
  methods: {
    performAction() { this.action = 'actionDone' }
  }
})

Vue.component('child', {
  template: '<div>I am the child <grand-child></grand-child></div>'
})

Vue.component('grand-child', {
  template: '<div>I am the grand-child <button @click="doEvent">Do Event</button></div>',
  methods: {
    doEvent() { this.$emit('eventtriggered') }
  }
})

new Vue({
  el: '#app'
})
Vue.component('parent'{
模板:“我是父-{{action}}”,
数据(){
返回{
行动:“不行动”
}
},
方法:{
performAction(){this.action='actionDone'}
}
})
Vue.component('子'{
模板:“我是孩子”
})
Vue.组件(“孙子女”{
模板:“我是孙子做的事”,
方法:{
doEvent(){this.$emit('eventtriggered')}
}
})
新Vue({
el:“#应用程序”
})
这个JSFIDLE解决了这个问题,但是通过执行两个事件:

  • 一个是从孙子到中间的部分
  • 然后再次从中间组件发射到父级

添加这个中间事件似乎是重复的,不必要的。有没有一种我不知道的直接发送给祖父母的方法?

是的,你说得对,事件只会从一个孩子发送到另一个家长。他们不会走得更远,例如从孩子到祖父母

Vue文档(简要)在本节中介绍了这种情况

一般的想法是,在祖父母组件中创建一个空的
Vue
组件,该组件通过道具从祖父母传递给子女和孙辈。然后,祖父母监听事件,孙辈在“事件总线”上发出事件

有些应用程序使用全局事件总线而不是每个组件的事件总线。使用全局事件总线意味着您需要具有唯一的事件名称或命名空间,以便事件不会在不同组件之间发生冲突


以下是一个示例。

Vue社区通常倾向于使用Vuex来解决此类问题。对Vuex状态进行了更改,DOM表示就是从该状态开始的,在许多情况下不需要事件

除此之外,重新发射可能是下一个最佳选择,最后,您可能会选择使用事件总线,如对该问题的另一个投票率较高的答案中所述

下面的答案是我对这个问题的原始答案,而不是我现在会采用的方法,因为我有更多的Vue经验


在这种情况下,我可能不同意Vue的设计选择,而求助于DOM

孙儿

methods: {
    doEvent() { 
        try {
            this.$el.dispatchEvent(new Event("eventtriggered"));
        } catch (e) {
            // handle IE not supporting Event constructor
            var evt = document.createEvent("Event");
            evt.initEvent("eventtriggered", true, false);
            this.$el.dispatchEvent(evt);
        }
    }
}
父项中

mounted(){
    this.$el.addEventListener("eventtriggered", () => this.performAction())
}
否则,是的,您必须重新发射或使用总线


注意:我在doEvent方法中添加了代码来处理IE;该代码可以以可重用的方式提取。

另一个解决方案将在根节点打开/发出:

使用
vm.$root.$emit
grand child中,然后在祖先处(或您喜欢的任何地方)使用
vm.$root.$on

已更新:有时您希望在某些特定情况下禁用侦听器,请使用(例如:
vm.$root.off('event-name')
internal lifecycle hook=beforeDestroy

Vue.component('parent'{
模板:'Listener是{{eventEnable?'On':“Off”}我是父-{{action}},
数据(){
返回{
行动:1,
eventEnable:false
}
},
已创建:函数(){
this.addEventListener()中
},
beforeDestroy:函数(){
this.removeEventListener()
},
方法:{
performAction(){this.action+=1},
toggleEventListener:函数(){
if(this.eventEnable){
this.removeEventListener()
}否则{
this.addEventListener()中
}
},
addEventListener:函数(){
此.$root.$on('eventtriggered1',()=>{
这个
})
this.eventEnable=true
},
removeEventListener:函数(){
此.$root.$off('eventtriggered1'))
this.eventEnable=false
}
}
})
Vue.component('子'{
模板:“我是孩子”,
方法:{
doEvent(){
//此.$emit('eventtriggered')
}
}
})
Vue.组件(“孙子女”{
模板:“我是大孩子发射事件”,
方法:{
doEvent(){this.$root.$emit('eventtriggered1')}
}
})
新Vue({
el:“#应用程序”
})

新答案(2018年11月更新)

我发现我们实际上可以通过利用grand child组件中的
$parent
属性来实现这一点:

this.$parent.$emit("submit", {somekey: somevalue})
this.$parent["$parent"].$emit("myevent", { data: 123 });

更干净更简单。

这是我使用的唯一情况!!用于将数据从深度嵌套的子级传递到非直接父级的通信

首先:创建一个包含以下内容的js文件(我将其命名为eventbus.js):

:在子组件中发出事件:

第三个:在家长席上收听该事件:

注意:如果您不想再注册该事件,请取消注册:

this.$event.$off('event_name')
信息:无需阅读以下个人意见

我不喜欢将vuex用于孙子孙女与祖父母之间的沟通(或类似的沟通级别)

在vue.js中,用于将数据从父代传递给子代,您可以使用。但对于相反的事情,却没有类似的东西。(孙子孙女对孙子孙女)所以每当我需要进行这种交流时,我都会使用事件总线。
如果您希望变得灵活,只需向所有家长及其家长递归地广播一个事件到根,您可以执行以下操作:

let vm = this.$parent

while(vm) {
    vm.$emit('submit')
    vm = vm.$parent
}

Vue 2.4引入了一种使用
vm.$listeners

发件人:

包含父作用域
v-on
事件侦听器(不带
.native
修饰符)。这可以通过
v-on=“$listeners”
传递到内部组件-在创建透明包装器组件时非常有用

使用
child
模板中的
grand child
组件中的
v-on=“$listeners”
查看以下代码段:

Vue.component('parent'{
模板:
'' +
“我是父对象。值为{{displayVal
this.$event.$off('event_name')
let vm = this.$parent

while(vm) {
    vm.$emit('submit')
    vm = vm.$parent
}
window.Event = new class {

    constructor() {
        this.vue = new Vue();
    }

    fire(event, data = null) {
        this.vue.$emit(event, data);
    }

    listen() {
        this.vue.$on(event, callback);  
    }

}
Event.fire('do-the-thing');
Event.listen('do-the-thing', () => {
    alert('Doing the thing!');
});
Vue.mixin({
  methods: {
    $propagatedEmit: function (event, payload) {
      let vm = this.$parent;
      while (vm) {
        vm.$emit(event, payload);
        vm = vm.$parent;
      }
    }
  }
})
{
  methods: {
    tunnelEmit (event, ...payload) {
      let vm = this
      while (vm && !vm.$listeners[event]) {
        vm = vm.$parent
      }
      if (!vm) return console.error(`no target listener for event "${event}"`)
      vm.$emit(event, ...payload)
    }
  }
}
this.$parent["$parent"].$emit("myevent", { data: 123 });