Vue 3 - 插槽上的独立事件传播
Vue 3 - Independent event propagation on slots
今天我有一个关于 Vue 的棘手问题,涉及槽和事件传播。 Here is a codesample
一些背景信息:我有一个订单,有n个订单仓位。这些订单及其头寸显示在不同的页面上。为了实现一致的 UI,我为 Order.vue
和 Position.vue
创建了 vue 组件。这些组件不包含任何业务逻辑,只负责在我的应用程序中保持一致的样式。
此外,我还有一个订单详情视图,其中显示了我的订单信息及其仓位。
此外,我还有另一个视图,其中显示相同的信息并且应该可以 select 一些 order/positions 取消。
数据包含在页面组件中并作为道具传递给 order/position。对于取消页面,我在插槽中传递复选框组件:
// OrderCancellationPage.vue
<Order v-for="order in orders" :key="order.id" :id="order.id" :positions="order.positions">
<InvoiceCancellationCheckbox :order-id="order.id" @isCancelled="onCancelledEvent($event)" />
</Order>
// Order.vue
<div>
<h3>Order: # {{ id }}</h3>
<slot></slot>
</div>
<OrderPosition
v-for="position in positions"
:key="position.posIndex"
:pos-index="position.posIndex"
>
<InvoiceCancellationCheckbox :orderId="id" :posIndex="position.posIndex" @isCancelled="$emit('isCancelled', $event)"/> //propagate the event to order
</OrderPosition>
// OrderPosition.vue
<div>
<span>Position {{ posIndex }}</span>
<slot></slot>
</div>
我想实现,我的 order/positions 组件不包含任何取消逻辑。 因此,InvoiceCancellationCheckbox
正在发出一个事件,如果它已被检查。 Order
和 Position
正在使用 @isCancelled=...
监听此事件,该事件已在我的插槽组件中声明。最后,OrderCancellationPage
应该监听所有这些事件并存储 selected 订单及其位置。
问题: 我收到此警告:
[Vue warn]: Extraneous non-emits event listeners (isCancelled) were passed to component but could not be automatically inherited because component renders fragment or text root nodes. If the listener is intended to be a component custom event listener only, declare it using the "emits" option.
at <Order key="2021-9064-9333-9803" id="2021-9064-9333-9803" positions=
我可以解决这个警告,如果我将 emits: ['isCancelled']
添加到 Order
。但是,比订单加上我不想要的取消复选框。还有其他解决方案吗?
编辑:该示例似乎不适用于 stackblitz,但它适用于本地计算机。我在这段代码中没有看到任何错误...
v-model
挽救了局面。
我用解决方案分叉了旧代码:https://stackblitz.com/edit/vue-t6ekts
基本上是关于使用 v-model
作为复选框:
<template>
<span>
<input type="checkbox" :id="id" v-model="modelValue" />
<label :for="id">Select for cancellation</label>
</span>
</template>
<script>
...
props: {
modelValue: Boolean,
orderId: String,
posIndex: Number
},
emits: ['update:modelValue'],
watch: {
modelValue() {
this.$emit('update:modelValue', this.modelValue);
},
},
并将其作为插槽传递:
<Order v-for="order in orders" :key="order.id" :id="order.id" :order="order">
<CancellationCheckbox :order-id="order.id" v-model="order.isCancelled"/>
</Order>
<OrderPosition v-for="position in order.positions" :key="position.posIndex" :position="position">
<CancellationCheckbox :orderId="order.id" :posIndex="position.posIndex" v-model="position.isCancelled"/>
</OrderPosition>
今天我有一个关于 Vue 的棘手问题,涉及槽和事件传播。 Here is a codesample
一些背景信息:我有一个订单,有n个订单仓位。这些订单及其头寸显示在不同的页面上。为了实现一致的 UI,我为 Order.vue
和 Position.vue
创建了 vue 组件。这些组件不包含任何业务逻辑,只负责在我的应用程序中保持一致的样式。
此外,我还有一个订单详情视图,其中显示了我的订单信息及其仓位。
此外,我还有另一个视图,其中显示相同的信息并且应该可以 select 一些 order/positions 取消。
数据包含在页面组件中并作为道具传递给 order/position。对于取消页面,我在插槽中传递复选框组件:
// OrderCancellationPage.vue
<Order v-for="order in orders" :key="order.id" :id="order.id" :positions="order.positions">
<InvoiceCancellationCheckbox :order-id="order.id" @isCancelled="onCancelledEvent($event)" />
</Order>
// Order.vue
<div>
<h3>Order: # {{ id }}</h3>
<slot></slot>
</div>
<OrderPosition
v-for="position in positions"
:key="position.posIndex"
:pos-index="position.posIndex"
>
<InvoiceCancellationCheckbox :orderId="id" :posIndex="position.posIndex" @isCancelled="$emit('isCancelled', $event)"/> //propagate the event to order
</OrderPosition>
// OrderPosition.vue
<div>
<span>Position {{ posIndex }}</span>
<slot></slot>
</div>
我想实现,我的 order/positions 组件不包含任何取消逻辑。 因此,InvoiceCancellationCheckbox
正在发出一个事件,如果它已被检查。 Order
和 Position
正在使用 @isCancelled=...
监听此事件,该事件已在我的插槽组件中声明。最后,OrderCancellationPage
应该监听所有这些事件并存储 selected 订单及其位置。
问题: 我收到此警告:
[Vue warn]: Extraneous non-emits event listeners (isCancelled) were passed to component but could not be automatically inherited because component renders fragment or text root nodes. If the listener is intended to be a component custom event listener only, declare it using the "emits" option.
at <Order key="2021-9064-9333-9803" id="2021-9064-9333-9803" positions=
我可以解决这个警告,如果我将 emits: ['isCancelled']
添加到 Order
。但是,比订单加上我不想要的取消复选框。还有其他解决方案吗?
编辑:该示例似乎不适用于 stackblitz,但它适用于本地计算机。我在这段代码中没有看到任何错误...
v-model
挽救了局面。
我用解决方案分叉了旧代码:https://stackblitz.com/edit/vue-t6ekts
基本上是关于使用 v-model
作为复选框:
<template>
<span>
<input type="checkbox" :id="id" v-model="modelValue" />
<label :for="id">Select for cancellation</label>
</span>
</template>
<script>
...
props: {
modelValue: Boolean,
orderId: String,
posIndex: Number
},
emits: ['update:modelValue'],
watch: {
modelValue() {
this.$emit('update:modelValue', this.modelValue);
},
},
并将其作为插槽传递:
<Order v-for="order in orders" :key="order.id" :id="order.id" :order="order">
<CancellationCheckbox :order-id="order.id" v-model="order.isCancelled"/>
</Order>
<OrderPosition v-for="position in order.positions" :key="position.posIndex" :position="position">
<CancellationCheckbox :orderId="order.id" :posIndex="position.posIndex" v-model="position.isCancelled"/>
</OrderPosition>