主题色 灰色 夜间模式 组件大小小(1) 中(2) 大(3) 组件圆角 组件缩放90% 95% 100% 105% 110%
none
small
medium
large
full
customElement 的一个局限性便在于很难自定义其内容,slot 也无法做到像 vue 那样的作用域插槽,该组件便是为了去渲染需要高度自定义的内容。由于本组件库高度绑定了Vue,即使在其他框架下使用,也可以通过Vnode来自定义渲染节点。不过为了可以更好得兼容其他框架,l-custom-renderer
提供了自定义渲染器的能力
通过调用registerCustomRenderer
可自定义其他渲染器,自定义渲染器需要提供的函数如下所示,必须提供isValidContent
和onMounted
export type CustomRendererRegistry = {
isValidContent: (content: any) => boolean;
onMounted: (content: any, target: HTMLDivElement, otherProps: Record<string | symbol, unknown>) => void;
onUpdated?: (content: any, target: HTMLDivElement, otherProps: Record<string | symbol, unknown>) => void;
onBeforeUnmount?: (content: any, target: HTMLDivElement) => void;
clone?: (content?: any) => any;
};
export function registerCustomRenderer(type: string, registry: CustomRendererRegistry);
具体可参考下面的示例渲染React
l-custom-renderer
具有如下属性:
export type CustomRendererProps = {
content: unknown;
type?: string;
preferHtml?: boolean;
};
content
属性来指定需要自定义渲染的内容。其可以为函数,当为函数时视为 getter,可以在函数参数中获取 Vue 的 h 函数;当其为Vnode时会直接渲染,其还可以为 HTMLTemplateElement,会以特殊规则进行渲染type
属性来指定渲染的类型(默认支持vnode
, html
和text
),若不指定则会自动检测,HTMLTemplateElement 不需要指定 type组件库内很多组件支持自定义渲染,例如 Callout 的 message 和 description,它既有这两个属性,也有这两个插槽。属性优先,其接受这样的值:
content
属性传递给 CustomRenderer当没有使用这两个属性时则支持使用插槽
通过如下代码注册 React 自定义渲染器,使得组件库支持渲染 ReactElement
import { registerCustomRenderer } from '@lun-web/components';
import { isValidElement, cloneElement } from 'react';
import { createRoot } from 'react-dom/client';
const reactRootMap = new WeakMap();
registerCustomRenderer('react', {
isValidContent(content) {
return isValidElement(content);
},
onMounted(content, target) {
if (reactRootMap.has(target)) return;
const root = createRoot(target);
reactRootMap.set(target, root);
root.render(content);
},
onUpdated(content, target) {
reactRootMap.get(target)?.render(content);
},
onBeforeUnmount(target) {
reactRootMap.get(target)?.unmount();
reactRootMap.delete(target);
},
clone(content) {
return cloneElement(content);
},
});
注
虽然可以通过这种方式渲染 React 元素,但这样效率堪忧,不如直接使用 Vnode 渲染,除非是想要利用已有的React组件
警告
该功能高度实验性,如果有类似于这样的提案进入标准,可能直接废弃该功能并转为支持标准
为了使template
能够动态渲染某些内容,内部有如下的生成替换规则:
template
有data-element
属性,则其为动态模板,data-element
属性指定另一个 html 元素的名字,会将模板替换为该元素data-*
属性,会将它们全部通过 prop 或 attr 设置到生成的元素上,例如data-inner-text="text"
意味着会将元素的 innerText 设为 text{}
包裹,则其为动态属性,会从l-custom-renderer
的 attrs 上取对应值,例如data-label="{text}"
意味着会将l-custom-renderer
的 text 属性的值设为其值推荐直接使用 Vnode 渲染,如content={({ h }) => h('div', 'test')}