在 Vue 3
开发中,我们常常需要创建可复用的组件,但传统的组件封装方式有时会带来限制。比如,一个表格组件可能需要支持不同的数据结构,一个弹窗组件可能需要动态更改内容。面对这种需求,我们通常会通过 slots
或 Scoped Slots
来解决,但它们的灵活性仍然有限。
有没有更好的方法?答案是:直接让组件接受一个渲染函数,让父组件完全控制渲染逻辑,而 RenderFunction
组件仅负责调用这个函数。这样,我们就能实现 更高自由度的组件定制能力,避免重复封装多个类似的 UI
组件。
实现
tsx
import type { PropType, VNodeTypes } from "vue";
import { defineComponent } from "vue";
export type RenderFunc = (props: Record<string, unknown>) => VNodeTypes;
export default defineComponent({
name: "RenderFunction",
props: {
renderFunc: {
type: Function as PropType<RenderFunc>,
required: true,
},
},
render() {
return this.renderFunc(this.$attrs);
},
});
Props
Prop 名称 | 类型 | 是否必填 | 说明 |
---|---|---|---|
renderFunc | (props: Record<string, unknown>) => VNodeTypes | 是 | 传递自定义渲染函数,返回 Vue 虚拟 DOM 节点 |
v-bind="$attrs" | Record<string, unknown> | 否 | 组件外部传入的额外属性,作为 renderFunc 的参数 |
适用场景
场景 | 说明 |
---|---|
动态组件渲染 | 让父组件决定如何渲染,而不是硬编码 UI 结构 |
自定义 UI 组件 |
适用于开发可定制的 UI 库,如动态表单、可变布局组件 |
高阶组件(HOC ) |
让 RenderFunction 作为通用的渲染容器,实现不同 UI 逻辑 |
JSX 支持 |
结合 JSX ,使渲染逻辑更简洁 |
示例
vue
<template>
<RenderFunction :renderFunc="myRenderFunc" :message="'Hello, Vue!'" />
</template>
<script setup lang="ts">
import { h } from "vue";
import RenderFunction from "./RenderFunction.vue";
const myRenderFunc = (props: Record<string, unknown>) => {
return h("div", { class: "custom-class" }, `Message: ${props.message}`);
};
</script>
说明
renderFunc
负责定义组件的渲染方式。props
参数用于传递动态数据。
结合 JSX 语法
如果你喜欢 JSX 语法,可以这样写:
vue
<script setup lang="tsx">
import RenderFunction from "./RenderFunction.vue";
const myRenderFunc = (props: Record<string, unknown>) => (
<div style="color: blue;">{props.message}</div>
);
</script>
<template>
<RenderFunction :renderFunc="myRenderFunc" :message="'Hello JSX!'" />
</template>
说明
JSX
语法使代码更加直观,可读性更高。- 适用于
Vue 3
的<script setup>
语法。
适用于动态 UI
可以使用
RenderFunction
渲染不同结构的UI
,比如表格:
vue
<template>
<RenderFunction :renderFunc="tableRender" :data="items" />
</template>
<script setup lang="ts">
import { h } from "vue";
import RenderFunction from "./RenderFunction.vue";
const items = [
{ id: 1, name: "Vue" },
{ id: 2, name: "React" },
{ id: 3, name: "Svelte" },
];
const tableRender = (props: Record<string, unknown>) => {
return h("table", { border: 1 }, [
h("tr", [h("th", "ID"), h("th", "Name")]),
...props.data.map((item: any) =>
h("tr", [h("td", item.id), h("td", item.name)])
),
]);
};
</script>
说明
RenderFunction
组件使表格结构可以动态配置,无需创建新的子组件。
总结
- RenderFunction 组件是一种 高阶渲染组件,提供极大的灵活性。
- 适用于 动态 UI、JSX、自定义渲染逻辑 的场景。
- 避免创建多个类似的 UI 组件,提高代码复用性。
如果你的项目有 动态内容渲染需求 ,这个组件将是一个 高效且优雅的解决方案!