Vue.js - 来自指令的Emit事件

euv*_*uvl 16 javascript vue.js vue-component

是否有可能发出一个自定义事件,从该指令到该指令所连接的组件.

我希望它能像示例中所描述的那样工作,但事实并非如此.

例:

//Basic Directive
<script>
  Vue.directive('foo', {
    bind(el, binding, vnode) {
      setTimeout(() => {
        //vnode.context.$emit('bar'); <- this will trigger in parent
        vnode.$emit('bar');
      }, 3000);
    }
  });
</script>


//Basic Component
<template>
  <button v-foo @bar="change">{{label}}</button>
</template>
<script>
  export default{
    data() {
      return {
        label: 'i dont work'
      }
    },
    methods: {
      change() {
        this.label = 'I DO WORK!';
      }
    }
  }
</script>
Run Code Online (Sandbox Code Playgroud)

关于此事的任何想法?我错过了什么吗?

JSFiddle:https://jsfiddle.net/0aum3osq/4/

更新1:

好吧,我发现如果我在指令中调用vnode.data.on.bar.fn();(或fns()在最新的Vue版本中)它将触发bar事件处理程序.

更新2:

临时解决方案:

  /*temp. solution*/
  var emit = (vnode, name, data) => {
    var handlers = vnode.data.on;

    if (handlers && handlers.hasOwnProperty(name)) {
      var handler = handlers[name];
      var fn = handler.fns || handler.fn;

      if (typeof fn === 'function') {
        fn(data);
      }
    }
  } 

//Basic Directive
<script>
  Vue.directive('foo', {
    bind(el, binding, vnode) {
      setTimeout(() => {
        emit(vnode, 'bar');
      }, 3000);
    }
  });
</script>
Run Code Online (Sandbox Code Playgroud)

euv*_*uvl 23

所以我在Vue 2+中使用的解决方案(考虑到目前为止没有答案):

在指令中添加方法:

var emit = (vnode, name, data) => {
  var handlers = (vnode.data && vnode.data.on) ||
    (vnode.componentOptions && vnode.componentOptions.listeners);

  if (handlers && handlers[name]) {
    handlers[name].fns(data);
  }
}
Run Code Online (Sandbox Code Playgroud)

并这样称呼它:

bind(el, binding, vnode) {
  emit(vnode, 'bar' , {some: 'event', data: 'here'});
}
Run Code Online (Sandbox Code Playgroud)

方法的好处:

1在项目中保持相同的代码样式,这意味着每个处理程序都可以声明为
v-on:handler_name有意义的(以开发人员的方式)处理.其他解决方案,例如将回调作为参数发送,有时会让人感到困惑,而且如果不深入研究文档/代

2使用内置事件系统还可以优雅地处理事件对象.例如,此代码将完美地工作:

<button v-foo @bar="bar(1, $event, 2)">{{label}}</button>
...
methods: {
  bar(one, event, two) { console.log(one, event, two); }
} 
Run Code Online (Sandbox Code Playgroud)

编辑:

在v2.1 +中你可以使用这个内部指令绑定:

vnode.context.$emit(eventname)
Run Code Online (Sandbox Code Playgroud)

  • 以我的经验,您只能在事件调度后调用vnode.context。$ emit('name')... element.addEvenetListener('click',()=&gt; {vnode.context。$ emit( 'handleClick');});`有效!但是,在事件触发器之外执行简单的`vnode.context。$ emit('handleClick')`实际上并不能正确调用emit,因此您无法收听。我可能是错的,但这就是我刚刚在vue@2.5中经历过的。 (4认同)
  • 在vue@v2.5下的示例中,`vnode.context。$ emit()`不起作用,如何解决?但是发射功能仍然可以正常使用。 (2认同)
  • 不适用于 Vue 3 (2认同)