[ Vue ] 给 slot 插槽绑定事件

本文探讨了在Vue中实现下拉组件的两种方法:通过slot-scope传递方法和直接操作VNode中的元素。对比分析了两种方案的优缺点,并详细介绍了如何在不使用插槽作用域的情况下,为组件的触发元素添加点击事件来控制组件的显示状态。

最近写了一个下拉组件,希望任意形式的触发源点击都可以展开这个组件。

最终效果图如下:

方案一:slot-scope 传方法

<!-- 伪代码:下拉框组件 -->

<template>
    <div>
        <slot :change-display="changeDisplay"></slot>
        <div v-show="mVisiable">*下拉框代码省略*</div>
    </div>
</template>

<script>
export default {
    data(){
        return {
            mVisiable: false
        }
    },

    methods:{
        changeDisplay(){
            this.mVisiable = !this.mVisiable
        }
    }
}
</script>
<!--使用下拉弹窗组件-->
<dropdown v-model="value" :list="list">
      <button slot-scope="{changeDisplay}" 
        @click="changeDisplay">{{value}}</button>
</dropdown>

不过这就导致每次用插槽都要写 slot-scope 去取修改显示状态的函数。

方案二:找 VNode 中对应的页面元素

插曲:

<!-- 伪代码:下拉框组件 -->
<template>
    <div>
        <slot></slot>
        <div v-show="mVisiable">*下拉框代码省略*</div>
    </div>
</template>

<script>
export default {
    data(){
        return {
            mVisiable: false
        }
    },

    methods:{
        changeDisplay(){
            this.mVisiable = !this.mVisiable
        }
    },

    mounted() {
      console.log(this.$slots)
    }
}
</script>


<!--使用下拉弹窗组件-->
<dropdown v-model="value" :list="list">
  <template v-slot>
    <button>{{value}}</button>
  </template>
</dropdown>

根据vue文档 slot 被废弃了(但还是兼容的)使用 v-slot 指定插槽,但是输出VNode 中的 elm 是 undefined。

然后去查找 github vue issues 找到如下回答, 传送门: issue

最后换回旧的插槽方法

<!--使用下拉弹窗组件-->
<dropdown v-model="value" :list="list">
    <button>{{value}}</button>
</dropdown>

此时得到了插槽内的元素


修改下拉组件。为VNode中的elm增加点击事件。

<!-- 伪代码:下拉框组件 -->
<template>
    <div>
        <slot></slot>
        <div v-show="mVisiable">*下拉框代码省略*</div>
    </div>
</template>

<script>
export default {
    data(){
        return {
            mVisiable: false,
            reference: undefined
        }
    },

    methods:{
        changeDisplay(){
            this.mVisiable = !this.mVisiable
        }
    },

    mounted() {
        if (this.$slots.default) {
          this.reference = this.$slots.default[0].elm
        }
        if (this.reference) {
          this.reference.addEventListener('click', this.changeVisiable, false)
        }
    },

    beforeDestroy() {
        if (this.reference) {
          this.reference.removeEventListener('click', this.changeVisiable, false)
        }
    }
}
</script>

### Vue.js 中 Slot 插槽事件处理 在 Vue.js 中,`<slot>` 是一种用于分发内容的强大工具。当涉及到事件处理时,父组件可以通过作用域插槽向子组件传递数据并监听来自子组件内的事件。 #### 使用具名插槽和作用域插槽实现事件绑定 为了更好地理解如何操作这些功能,在此提供一个具体的例子来展示怎样利用 `v-on` 来捕获由子组件触发的自定义事件: ```html <!-- 子组件 ChildComponent.vue --> <template> <button @click="handleClick"> Click me to emit event </button> </template> <script> export default { name: "ChildComponent", methods: { handleClick() { this.$emit('custom-event', 'Event Message from child'); } } } </script> ``` ```html <!-- 父组件 ParentComponent.vue --> <template> <div class="parent-component"> <!-- 使用具名插槽并将事件处理器作为 prop 传入 --> <child-component v-slot="{ customEvent }"> <p>Message received:</p> <span>{{ message }}</span> <!-- 监听来自子组件的自定义事件 --> <component :is="currentTag" v-bind="$attrs" v-on="{ 'custom-event': onCustomEventReceived }"></component> </child-component> </div> </template> <script> import ChildComponent from './ChildComponent'; export default { components: { ChildComponent }, data() { return { currentTag: 'child-component', message: '' }; }, methods: { onCustomEventReceived(payload) { this.message = payload; } } }; </script> ``` 在这个案例里,每当点击按钮时会触发名为 `custom-event` 的事件,并携带消息参数给到父级组件中的回调函数 `onCustomEventReceived()` 处理[^1]。 #### 动态分配事件监听器 除了静态地指定要监听哪些事件外,还可以动态地设置它们。这允许更灵活的应用场景,比如根据条件决定是否附加某些特定行为。 上述代码片段展示了如何通过对象语法将多个事件映射至相应的处理程序上。对于单个事件而言,则可以直接采用如下方式简化写法: ```vue <child-component @custom-event="onCustomEventReceived"/> ``` 这种做法不仅提高了可读性也减少了冗余度[^2]。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值