为什么 v-on 在外部模板中使用时不适用于 Vue 组件?

Rob*_*ier 2 vue.js vue-component

情况

假设我有一个组件BaseButton,它只是一个围绕<button>元素的简单包装器:

Vue.component('base-button', {
  template: `
    <button>
      <slot />
    </button>
  `
});
Run Code Online (Sandbox Code Playgroud)

使用按钮时,我想将处理程序绑定到此按钮上的点击事件:

<base-button @click="handler">
  Click me
</base-button>
Run Code Online (Sandbox Code Playgroud)

带有上述代码的笔

问题

上述解决方案不起作用。处理程序根本不会被触发。

有人可以解释我为什么吗?我猜在它被组件模板替换之前,处理程序绑定到元素,但这只是一个猜测 - 我在 vue.js 文档中找不到任何关于它的信息。除了该文档 状态:

非道具属性是传递给组件的属性,但没有定义相应的道具。

虽然显式定义的 props 更适合将信息传递给子组件,但组件库的作者不能总是预见可能使用其组件的上下文。这就是组件可以接受任意属性的原因,这些属性被添加到组件的根元素中。

@click( v-on:click) 在我看来是一个非道具属性,根据上面的文字应该被继承。但事实并非如此。

道具解决方案

我知道我可以声明一个 prop 并在组件内部传递处理程序(下面的代码)。然后它按预期工作。

对我来说,这个解决方案的问题是我对如何声明处理程序没有细粒度的控制。如果BaseButton我想在@click Vue.js 公开的一些事件修饰符(例如.stop, .prevent, .capture)上使用一种用法怎么办?我必须使用另一个道具(如capture)并使用v-if,但它会使组件模板变得非常混乱。如果我将处理程序保留在我使用它的模板中,我可以根据需要以干净灵活的方式修改事件声明。

Vue.component('base-button', {
  prop: {
    clickHandler: {
      type: Function,
      required: true
    }
  },
  template: `
    <button>
      <slot />
    </button>
  `
});

<base-button :click-handler="handler">
  Click me
</base-button>
Run Code Online (Sandbox Code Playgroud)

ghy*_*ybs 5

v-on指令在普通/原生 DOM 元素或 Vue 自定义元素组件上使用时表现不同,如 API 文档中所述:

在普通元素上使用时,它仅侦听本机 DOM 事件。在自定义元素组件上使用时,它会侦听在该子组件上发出的自定义事件

在您的情况下,您将它应用于您的自定义<base-button>元素组件,因此它只会侦听自定义事件,即您$emit在此组件实例上明确显示的事件。

"click"来自底层的本地事件冒泡阶段<button>不会触发你的@click监听器......

...除非你使用.native修饰符:

.native - 侦听组件根元素上的本机事件。

Vue.component('base-button', {
  template: `
    <button>
      <slot />
    </button>
  `
});

new Vue({
  el: '#app',
  data: {
    handler(event) {
      console.log('submit from where the component was used');
      //console.log(event);
    }
  }
});
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.min.js"></script>

<div id="app">
  <base-button @click.native="handler">
    Click
  </base-button>
</div>
Run Code Online (Sandbox Code Playgroud)