发出事件但 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 组件上设置监听器。不仅仅是 任何 父元素。
[编辑]: 我最终只使用了 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 组件上设置监听器。不仅仅是 任何 父元素。