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 插槽执行此操作。