Vue 给槽添加事件监听器
Vue add event listener to slot
所以我有这个 <Dialog />
组件扩展了 vuetify 的 <v-dialog />
默认值。
为了避免必须将 onClose
方法传递给 DialogContent
组件,我宁愿它 $emit('close')
.
但是我不能让我的槽听这个事件。 :(
代码如下:
// Dialog.vue
<template>
<v-dialog
v-bind="$attrs"
v-model="dialog"
>
<!-- forward other slots -->
<template
v-for="(_, slot) of otherSlots"
v-slot:[slot]="scope"
>
<slot :name="slot" v-bind="scope" />
</template>
<template v-slot:default="{ on, attrs }">
<slot name="default" v-on="on" v-bind="attrs" @close="onClose" />
</template>
</v-dialog>
</template>
<script>
import {reject} from '@/utils/object';
export default {
inheritAttrs: false,
computed: {
otherSlots() {
return reject(this.$scopedSlots, 'default');
},
},
data() {
return {
dialog: false,
}
},
methods: {
onClose() {
this.dialog = false;
}
},
}
</script>
用法:
<Dialog persistent>
<template v-slot:activator="{ on, attrs }">
<v-btn
v-bind="attrs"
v-on="on"
>
My button
</v-btn>
</template>
<DialogContent />
</Dialog>
onClose
从未被调用。
知道为什么吗?
这里是重现问题的沙盒:https://codesandbox.io/s/pass-event-listener-to-slot-ktemg9
谢谢
你的问题来自于 $emit
将函数发送给父 div,你的情况是 App.vue
而不是 Dialog.vue
。
要解决您的问题,您可以在对话框中添加一个 ref 并从 div
触发关闭功能
<div class="text-center my-12">
<Dialog persistent ref="myDiv">
<template v-slot:activator="{ on, attrs }">
<v-btn color="primary" v-bind="attrs" v-on="on"> Click me </v-btn>
</template>
<DialogContent @close="onCloseFromParent" />
</Dialog>
</div>
...
methods: {
onCloseFromParent() {
this.$refs.myDiv.onClose();
},
},
太好了终于如愿以偿了:
Dialog.vue
:
<template>
<v-dialog>
<slot name="default" :onClose="onClose" />
</v-dialog>
</template>
用法:
<template v-slot:default="{onClose}">
<DialogContent @close="onClose" />
</template>
或使用更多 vuetify-like 语法:
Dialog.vue
:
<template>
<v-dialog>
<slot name="default" :on="{close: onClose}" />
</v-dialog>
</template>
用法:
<template v-slot:default="{on}">
<DialogContent v-on="on" />
</template>
我希望那些道具(或事件)可以被转发而不必明确地传递它们,但不幸的是这似乎是不可能的。 :( 否则 vuetify 会为其 activator
插槽执行此操作。
所以我有这个 <Dialog />
组件扩展了 vuetify 的 <v-dialog />
默认值。
为了避免必须将 onClose
方法传递给 DialogContent
组件,我宁愿它 $emit('close')
.
但是我不能让我的槽听这个事件。 :(
代码如下:
// Dialog.vue
<template>
<v-dialog
v-bind="$attrs"
v-model="dialog"
>
<!-- forward other slots -->
<template
v-for="(_, slot) of otherSlots"
v-slot:[slot]="scope"
>
<slot :name="slot" v-bind="scope" />
</template>
<template v-slot:default="{ on, attrs }">
<slot name="default" v-on="on" v-bind="attrs" @close="onClose" />
</template>
</v-dialog>
</template>
<script>
import {reject} from '@/utils/object';
export default {
inheritAttrs: false,
computed: {
otherSlots() {
return reject(this.$scopedSlots, 'default');
},
},
data() {
return {
dialog: false,
}
},
methods: {
onClose() {
this.dialog = false;
}
},
}
</script>
用法:
<Dialog persistent>
<template v-slot:activator="{ on, attrs }">
<v-btn
v-bind="attrs"
v-on="on"
>
My button
</v-btn>
</template>
<DialogContent />
</Dialog>
onClose
从未被调用。
知道为什么吗?
这里是重现问题的沙盒:https://codesandbox.io/s/pass-event-listener-to-slot-ktemg9
谢谢
你的问题来自于 $emit
将函数发送给父 div,你的情况是 App.vue
而不是 Dialog.vue
。
要解决您的问题,您可以在对话框中添加一个 ref 并从 div
触发关闭功能<div class="text-center my-12">
<Dialog persistent ref="myDiv">
<template v-slot:activator="{ on, attrs }">
<v-btn color="primary" v-bind="attrs" v-on="on"> Click me </v-btn>
</template>
<DialogContent @close="onCloseFromParent" />
</Dialog>
</div>
...
methods: {
onCloseFromParent() {
this.$refs.myDiv.onClose();
},
},
太好了终于如愿以偿了:
Dialog.vue
:
<template>
<v-dialog>
<slot name="default" :onClose="onClose" />
</v-dialog>
</template>
用法:
<template v-slot:default="{onClose}">
<DialogContent @close="onClose" />
</template>
或使用更多 vuetify-like 语法:
Dialog.vue
:
<template>
<v-dialog>
<slot name="default" :on="{close: onClose}" />
</v-dialog>
</template>
用法:
<template v-slot:default="{on}">
<DialogContent v-on="on" />
</template>
我希望那些道具(或事件)可以被转发而不必明确地传递它们,但不幸的是这似乎是不可能的。 :( 否则 vuetify 会为其 activator
插槽执行此操作。