Javascript 如何使用Vue js 2在组件子组件链上冒泡事件?
我的vue应用程序使用: 组件父组件由组件子组件组成的组件 在组件父级中,我有一些按钮,当有人单击某个按钮时,我希望发出一个事件,以便由vue处理并传递给另一个组件 到目前为止我所做的:Javascript 如何使用Vue js 2在组件子组件链上冒泡事件?,javascript,vuejs2,Javascript,Vuejs2,我的vue应用程序使用: 组件父组件由组件子组件组成的组件 在组件父级中,我有一些按钮,当有人单击某个按钮时,我希望发出一个事件,以便由vue处理并传递给另一个组件 到目前为止我所做的: var vm = new Vue({ el: '#app', methods: { itemSelectedListener: function(item){ console.log('itemSelectedListener', item);
var vm = new Vue({
el: '#app',
methods: {
itemSelectedListener: function(item){
console.log('itemSelectedListener', item);
}
}
});
Vue.component('component-child', {
template: ' <span v-on:click="chooseItem(pty )" >Button </span>',
methods: {
chooseItem: function(pty){
console.log(pty);
this.$emit('itemSelected', {
'priority' : pty
});
}
}
});
Vue.component('component-parent', {
template: '<component-child v-for="q in items" ></component-child>'
});
暗示
我应该从child->parent->Vue实例冒泡事件吗?(我也试过了,但没有成功)您的
组件父级
模板有一个问题,因为它试图渲染多个子组件。Vue通常在组件中需要一个根div,因此需要将其包装在div或其他标记中
<div>
<component-child v-for="q in items"></component-child>
</div>
你有两个选择。从组件子级发出
在组件父级
中侦听该事件,然后向上传播该事件。拨弄
第二个选项是注册一个全局的所谓的总线
,它是一个空的vue实例,当您需要在非子父组件之间进行通信时,您可以将其用于此类情况。拨弄
通常,在父组件和子组件之间,您通过使用v-on:event name=“handler”
从子组件发出并在父组件中侦听来直接使用事件,但对于组件之间级别更高的情况,您使用第二种方法
第一个案例的文档链接:
第二个案例的文档链接:
PS:事件名称更倾向于使用烤肉串大小写,这意味着您用
-
而不是大写字母书写。用大写字母书写可能会导致一些奇怪的情况,你的事件没有被记录在根中。有点晚了,但我是这样做的:
Root //but you listen to the event up here 1 level above
Component 1 //you should listen to the event here
Component 2 //your try to emit it from here
子组件:
this.$root.$emit('foobar',{...});
组件父级:
this.$root.$on('foobar')
在子组件中,只需使用
$emit
向$root
发送事件,如下所示:
v-on:click="$root.$emit('hamburger-click')"
export default {
<snip...>
mounted: function() {
this.$root.$on('hamburger-click', function() {
console.log(`Hamburger clicked!`);
});
}
}
然后,在父组件(例如:“应用程序”)中,在Vuemounted
lifecycle钩子中设置侦听器,如下所示:
v-on:click="$root.$emit('hamburger-click')"
export default {
<snip...>
mounted: function() {
this.$root.$on('hamburger-click', function() {
console.log(`Hamburger clicked!`);
});
}
}
导出默认值{
挂载:函数(){
此.$root.$on('hamburger-click',函数(){
log(`Hamburger clicked!`);
});
}
}
您可以使用浏览器的事件API。它需要比Vue内置的东西多一点脚本编写,但它也可以帮助您解决这些冒泡的问题(与公认的答案中创建“总线”的代码量差不多)
关于子组件:
this.$el.dispatchEvent(new CustomEvent('itemSelected', { detail: { 'priority' : pty }, bubbles: true, composed: true });
在父组件上,在装入的生命周期部件中:
mounted() {
this.$el.addEventListener('itemSelected', e => console.log('itemSelectedListener', e.detail));
}
为冒泡创建一个函数,并在子组件中使用它
指令样本:
// Add this to main.ts when initializing Vue
Vue.directive('bubble', {
bind(el, { arg }, {context, componentInstance}) {
if (!componentInstance || !context || !arg) {
return;
}
// bubble the event to the parent
componentInstance.$on(v, context.$emit.bind(context, arg));
}
});
子组件可以使用该指令通过父组件发出(我切换到kabob大小写和事件简写)
我有点惊讶没有人建议使用事件总线组件。在高度解耦的系统中,有一个共享的事件总线,然后使用它将多个断开连接的组件链接在一起,这是一种相当常见的模式
//eventbus.js
import Vue from 'vue'
export const EventBus = new Vue()
一旦有了一个,从任何地方发布事件都很简单
// component1.js
import { EventBus } from '@/services/eventbus'
...
EventBus.$emit('do-the-things')
从别的地方听他们说话
// component2.js
import { EventBus } from '@/services/eventbus'
...
EventBus.$on('do-the-things', this.doAllTheThings)
请注意,这两个组件互不了解任何信息,它们也不需要真正关心事件是如何或为什么引发的
这种方法有一些潜在的不良副作用。事件名称必须是全局唯一的,这样你就不会混淆你的应用程序。除非您做一些更复杂的事情,否则您还可能通过单个对象引导每个事件。您可以在自己的应用程序源上进行成本/收益分析,看看它是否适合您。第二个案例的文档链接不再存在。您有更新的链接吗?我甚至可以说:Vue中的事件与浏览器中的本机事件不同。Vue中的事件作为对父级的回调,而子级中的$emit只是对父级回调的调用。我是对的?P.S.I翻阅了Vue中的所有文档,但在任何地方都没有明确说明。在我看来,他们把新手和“事件”这个词混淆了。我发现了一个很好的工作链接:“定制事件”和“事件总线”部分。我已经多次看到总线建议,并且在第三方模块中使用,但是,对于我和我的用例来说,使用总线不是正确的模式,要让它按照我想要的方式工作,需要做很多工作。这就是我想要的,很明显你已经说过了,但我想不起来。常规vue事件绑定v-bind:itemSelected有效在某些情况下,这是唯一的解决方案。我在Vue项目中使用了Rete框架,Rete也使用了Vue,但作为Vue组件的Rete节点没有$root和$parent,而本机CustomEvents是将事件传递给我的应用程序的唯一方法。但应该是这样的。$el.addEventListener('itemSelected',e=>console.log('itemSelectedListener',e.detail));addEventListener而不是AddListener这对我有用!简单的解决方案。我使用v-on:itemSelected.native
使其工作。如果没有.native
后缀,它就无法工作。谢谢@YamiOdymel我会修复您还需要调用this.$root.$off('foorbar',fn)
中的beforeDestroy()
或destroy()
为避免内存泄漏,fn变量必须与中的值匹配。$root.$on('foorbar',fn)
因此回调函数不能是匿名函数。注意:$on
和$off
已被弃用,因为Vue 3.0事件总线是更复杂组件层次结构的良好解决方案。但这与问题主题无关。@slf FYI,Cristi Jora在他的回答中已经提到了事件总线。这是一个用作中介的全局发布/订阅,从长远来看,它可以演变为一个god对象,并使组件与中介耦合,或至少其接口。在我看来,Vue应该提供事件冒泡。我看到这个解决方案被否决了,但没有任何评论说明原因。它是d
//eventbus.js
import Vue from 'vue'
export const EventBus = new Vue()
// component1.js
import { EventBus } from '@/services/eventbus'
...
EventBus.$emit('do-the-things')
// component2.js
import { EventBus } from '@/services/eventbus'
...
EventBus.$on('do-the-things', this.doAllTheThings)