美文网首页
vue3 给slot 统一添加 click事件

vue3 给slot 统一添加 click事件

作者: holidayPenguin | 来源:发表于2023-11-08 01:26 被阅读0次

lib/SlotEvents.ts · Nick Zhang/vue3-slot-event - 码云 - 开源中国 (gitee.com)

用法

// 子组件中
<slot-events @click="handleClick">
    <slot name="referer"/>
  </slot-events>
// 父组件中
<component>test</component>

SlotEvents.ts

import {cloneVNode, Comment, defineComponent, Fragment, h, Text, VNode} from "vue";

/**
 * 对于文本或SVG,需要用span包裹一下
 * @param s
 */
const wrapTextContent = (s: string | VNode): VNode => {
  return h('span', null, s);
};

/**
 * 判断是否为Object
 * @param val
 */
const isObject = (val: any) => val !== null && typeof val === 'object';

/**
 * 找出第一个合法的子元素
 * @param node
 */
const findFirstLegitChild = (node: VNode[] | undefined): VNode | null => {
  if (!node) return null;
  for (const child of node) {
    if (isObject(child)) {
      switch (child.type) {
        case Comment:
          continue;
        case Text:
        case 'svg':
          return wrapTextContent(child);
        case Fragment:
          return findFirstLegitChild(child.children as VNode[]);
        default:
          return child;
      }
    }
    return wrapTextContent(child);
  }
  return null;
};

const NAME = 'SlotEvents';

const SlotEvents = defineComponent({
  name: NAME,
  setup(_, {slots, attrs}) {
    return () => {
      const defaultSlot = slots.default?.(attrs);
      if (!defaultSlot) return null;
      if (defaultSlot.length > 1) {
        console.warn(`${NAME}: 只需要一个子元素`);
        return null;
      }
      const firstLegitChild = findFirstLegitChild(defaultSlot);
      if (!firstLegitChild) {
        console.warn(`${NAME}: 没有可用的子元素`);
        return null;
      }
      return cloneVNode(firstLegitChild, attrs);
    };
  }
});
export default SlotEvents;

相关文章

网友评论

      本文标题:vue3 给slot 统一添加 click事件

      本文链接:https://www.haomeiwen.com/subject/kbtqwdtx.html