发出事件但 parent 未收听

Event emitting but parent not listening


[编辑]: 我最终只使用了 Vuex,并且使用这种方法效果很好。


我无法捕捉事件。

如果我查看 vue 开发工具,事件正在发出,但 parent 功能未被激活。每当我尝试在整个项目中使用 emit 时,我都会遇到这个问题。我试图避免使用 Vuex,因为这是一个 Vue/Inertia.js/Laravel 堆栈,其中包含从控制器和 Laravel 会话传递的所有登录数据和变量,所以我觉得添加 Vuex 是多余的。

很抱歉,我无法 post 完整代码,因为它是工作用的,而且我签署了保密协议,但如果需要更多部分,我可以提供片段。

PARENT (<Collection>)

<CollectionFooter v-if="itemsSelected > 0"
:itemsSelected="itemsSelected" @modifySelected="modifyItemsSelected(operation)" />
data(){
  return {
    itemsSelected: 0
  }
},
methods: {
   modifyItemsSelected(operation){
      if(operation === "add") {
         this.itemsSelected += 1;
      } else {
         this.itemsSelected -= 1;
      }
      console.log(this.itemsSelected)
   }
},

CHILD (<CollectionItemCard>)

<button v-if="active" color="sm-white" @click="changeState">added</button>
<button v-else color="sm-yellow" @click="changeState">add</button>
methods:{
  changeState(){
    this.active = !this.active;
    let operation;

    if(this.active) {
      operation = "add";
    } else {
      operation = "remove";
    }
      this.$emit('modifySelected', operation);
    }
},

vue 开发工具屏幕

TL;DR – 问题在于您编写内联处理程序的方式。

modifyItemsSelected(operation) 更改为 "modifyItemsSelected""modifyItemsSelected($event)",您应该可以开始了。关于原因的详细解释如下。


Vue 事件处理程序纲要


在 Vue 中使用 v-on 处理事件有两种方法:Inline Handlers 和 Method Handlers。很容易忽略差异,但这很重要。

内联处理程序


Inline handlers 可能是您最熟悉的内容,因为它正是您在示例中使用的内容。

这个处理程序类型就像它听起来的那样:你将一些 JavaScript 内联 传递给 v-on,然后 Vue 运行处理事件时的这段代码。

例如:

<button @click="alert('Hi!')">Click Me!</button>

当此按钮发出 click 事件时,代码 alert('Hi!') 是 运行,正如它所写的那样。
这是你的问题的关键——它 运行 就像它写的一样, 参考文献和所有

在您的事件处理程序中:

<CollectionFooter 
  ...
  @modifySelected="modifyItemsSelected(operation)"
/>

你告诉 Vue 在处理 modifySelected 时 运行 modifyItemsSelected(operation)。问题是你给了内联函数一个不存在的参数

Vue 不是将事件 中的 有效负载作为名为operation 的变量读取,而是将此语法解释为使用[= 对modifyItemsSelected 的调用98=]一些现有变量 命名为operation.

Vue 会在模板上下文中寻找 operation,然后在您的组件上下文中,当它找不到时,它会抛出错误,终止处理程序的执行。

方法处理程序


Method handlers 也正是它们听起来的样子:不是将 JavaScript 的内联片段传递给 v-on,而是将其传递给定义的 方法名称, only,Vue 直接将处理程序绑定到它。这种类型和内联类型之间的一个重要区别是您不在调用中包含参数– Vue 处理隐式传递的参数。

这意味着您提供的示例简单地变为:

<CollectionFooter 
  ...
  @modifySelected="modifyItemsSelected"
/>

有效负载将作为参数(或多个参数,您可以将任意数量的参数传递给 $emit())传递给 modifyItemsSelected 以供使用。

关于 $event

的注释

最后值得一提的是一些特殊的 Vue 语法:$event。这是一个占位符,您可以在内联处理程序中使用它来表示事件负载。

使用 @event="myHandler($event)" 会将事件负载作为第一个参数传递给 myHandler。当您需要一些只能从事件处理程序中的模板访问的关键数据时(例如,在 v-for 循环中),这尤其有用,因为它允许您将 both事件有效载荷 自定义数据立即进入您的处理函数。 (例如@event="myHandler($event, element.index)"

这意味着还有另一种方法来格式化您的事件处理程序并让它工作(在这种情况下纯粹是偏好问题):

<CollectionFooter 
  ...
  @modifySelected="modifyItemsSelected($event)"
/>

片段示例


最后,这里有一个例子来说明这个信息转储。

三个按钮,都以不同的方式调用相同的方法。给定的方法只是将消息和(字符串化的)事件打印到控制台。

使用当前处理程序单击按钮会向控制台抛出错误,而不会打印任何内容(Vue 的开发版本足以发出警告并仍然打印,但生产版本不是那么好)。另外两个打印成功。

new Vue({
  el: '#app',
  methods: {
    foo(e) {
      console.log('Handled!');
      console.log('Event:', JSON.stringify(e));
    },
  },
});
.as-console-wrapper { max-height: 85px !important; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
  <button @click="foo(bar)">Inline Handler:</button><span><code> @click="foo(bar)"</code> (Your example code)</span>
  <hr>
  <button @click="foo">Binded Handler:</button><span><code> @click="foo"</code> (Alternative #1)</span>
  <br><br>
  <button @click="foo($event)">Inline Handler w/ $event:</button><span><code> @click="foo($event)"</code> (Alternative #2)</span>
</div>

正如zcoop98上面提到的, 将 @modifySelected="modifyItemsSelected(operation)" 移动到 <CollectionItemCard> 组件是关键。 我必须在发出的 same 组件上设置监听器。不仅仅是 任何 父元素。