vue3 TSX slots简单记录

3,718 阅读2分钟

实际应用中的例子

import { defineComponent, renderSlot } from "vue";
import type { SetupContext } from "vue";
import utils from "@/utils/index";

const header = defineComponent({
  props: {
    root: { type: Boolean, default: false }, // 如果为true则调用原生关闭页面
    title: { type: String, default: "标题" }, // 标题
    leftText: { type: String, default: "返回" }, // 左侧显示
    rightText: { type: String, default: "按钮" }, // 右侧按钮
    clickLeft: { type: Function, default() {} } // 拦截左侧点击事件,Promise.resove或true时执行返回或关闭
  },
  setup(props: Readonly<any>, { slots }: SetupContext) {
    //! 返回确认
    let go = () => {
      if (props.root) {
        // 调用原生关闭页面
      } else {
        window.$router.go(-1);
      }
    };
    //! 点击返回
    let eventClickLeft = () => {
      let fn = props.clickLeft();

      if (utils.isType(fn) === "Promise") {
        fn.then(() => {
          go();
        });
      } else if (fn === true) {
        go();
      }
    };

    // debugger;
    return () => (
      <header>
        <van-nav-bar title={props.title} left-text={props.leftText} right-text={props.rightText} left-arrow onClickLeft={eventClickLeft}>
          {/* {{
            right: () => (slots["right"] ? slots["right"]() : "")
          }} */}
          {{
            right: renderSlot(slots, "right")
          }}
        </van-nav-bar>
        {renderSlot(slots, "right")}
      </header>
    );
  }
});

export default header;

还有一种简单直观对象注入

执行参数为传入父级的对象

{{
            right: () => (slots["right"] ? slots["right"]({data:"test1"}) : "")
 }}

vue3中slot注入的方式renderSlot

源码中对其解释,slots 为当前上下文 slots,name为要查找的slot名称,props为传给父级的数据, fallback中判断currentRenderingInstance为上下文具体参见下面ComponentInternalInstance部分代码,使用方式为再setup中通过getCurrentInstance获取当前实例的类型,fallback需返回一个VNodeArrayChildren类型的数组,数组包含getCurrentInstance实例,按说明看不对外开放(看着想是嵌套子集),具体使用方式持续跟进中,noSlotted与上下文ctx相关具体用法跟进中。

function renderSlot(slots, name, props = {}, 
// this is not a user-facing function, so the fallback is always generated by
// the compiler and guaranteed to be a function returning an array
fallback, noSlotted) {
    if (currentRenderingInstance.isCE) {
        return createVNode('slot', name === 'default' ? null : { name }, fallback && fallback());
    }
    let slot = slots[name];
    if (slot && slot.length > 1) {
        warn(`SSR-optimized slot function detected in a non-SSR-optimized render ` +
            `function. You need to mark this component with $dynamic-slots in the ` +
            `parent template.`);
        slot = () => [];
    }
    // a compiled slot disables block tracking by default to avoid manual
    // invocation interfering with template-based block tracking, but in
    // `renderSlot` we can be sure that it's template-based so we can force
    // enable it.
    if (slot && slot._c) {
        slot._d = false;
    }
    openBlock();
    const validSlotContent = slot && ensureValidVNode(slot(props));
    const rendered = createBlock(Fragment, { key: props.key || `_${name}` }, validSlotContent || (fallback ? fallback() : []), validSlotContent && slots._ === 1 /* STABLE */
        ? 64 /* STABLE_FRAGMENT */
        : -2 /* BAIL */);
    if (!noSlotted && rendered.scopeId) {
        rendered.slotScopeIds = [rendered.scopeId + '-s'];
    }
    if (slot && slot._c) {
        slot._d = true;
    }
    return rendered;
}
export declare interface ComponentInternalInstance {
    uid: number;
    type: ConcreteComponent;
    parent: ComponentInternalInstance | null;
    root: ComponentInternalInstance;
    appContext: AppContext;
    /**
     * Vnode representing this component in its parent's vdom tree
     */
    vnode: VNode;
    /* Excluded from this release type: next */
    /**
     * Root vnode of this component's own vdom tree
     */
    subTree: VNode;
    /**
     * Render effect instance
     */
    effect: ReactiveEffect;
    /**
     * Bound effect runner to be passed to schedulers
     */
    update: SchedulerJob;
    /* Excluded from this release type: render */
    /* Excluded from this release type: ssrRender */
    /* Excluded from this release type: provides */
    /* Excluded from this release type: scope */
    /* Excluded from this release type: accessCache */
    /* Excluded from this release type: renderCache */
    /* Excluded from this release type: components */
    /* Excluded from this release type: directives */
    /* Excluded from this release type: filters */
    /* Excluded from this release type: propsOptions */
    /* Excluded from this release type: emitsOptions */
    /* Excluded from this release type: inheritAttrs */
    /**
     * is custom element?
     */
    isCE?: boolean;
    /**
     * custom element specific HMR method
     */
    ceReload?: (newStyles?: string[]) => void;
    proxy: ComponentPublicInstance | null;
    exposed: Record<string, any> | null;
    exposeProxy: Record<string, any> | null;
    /* Excluded from this release type: withProxy */
    /* Excluded from this release type: ctx */
    data: Data;
    props: Data;
    attrs: Data;
    slots: InternalSlots;
    refs: Data;
    emit: EmitFn;
    /* Excluded from this release type: emitted */
    /* Excluded from this release type: propsDefaults */
    /* Excluded from this release type: setupState */
    /* Excluded from this release type: devtoolsRawSetupState */
    /* Excluded from this release type: setupContext */
    /* Excluded from this release type: suspense */
    /* Excluded from this release type: suspenseId */
    /* Excluded from this release type: asyncDep */
    /* Excluded from this release type: asyncResolved */
    isMounted: boolean;
    isUnmounted: boolean;
    isDeactivated: boolean;
    /* Excluded from this release type: bc */
    /* Excluded from this release type: c */
    /* Excluded from this release type: bm */
    /* Excluded from this release type: m */
    /* Excluded from this release type: bu */
    /* Excluded from this release type: u */
    /* Excluded from this release type: bum */
    /* Excluded from this release type: um */
    /* Excluded from this release type: rtc */
    /* Excluded from this release type: rtg */
    /* Excluded from this release type: a */
    /* Excluded from this release type: da */
    /* Excluded from this release type: ec */
    /* Excluded from this release type: sp */
}