Javascript VueJs 2.0将事件从父级子级发射到其父级组件
Vue.js 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.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 });