Skip to content

Commit b165d8e

Browse files
committed
feat(tnode): optimize render tnode
1 parent 56c6404 commit b165d8e

File tree

4 files changed

+30
-103
lines changed

4 files changed

+30
-103
lines changed

jsx.d.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
/* eslint-disable */
21
import { HTMLAttributes } from 'vue';
32

43
declare global {

src/hooks/tnode.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,25 @@
11
import { h, getCurrentInstance, VNode, isVNode } from 'vue';
22
import isEmpty from 'lodash/isEmpty';
3+
import isString from 'lodash/isString';
34
import isFunction from 'lodash/isFunction';
45
import isObject from 'lodash/isObject';
56

67
interface JSXRenderContext {
7-
defaultNode?: VNode;
8+
defaultNode?: VNode | string;
89
params?: Record<string, any>;
910
}
1011

11-
type OptionsType = VNode | JSXRenderContext;
12+
export type OptionsType = VNode | JSXRenderContext | string;
1213

1314
export function getDefaultNode(options?: OptionsType) {
14-
const params = isObject(options) && 'params' in options ? options.params : null;
15-
1615
let defaultNode;
1716
if (isObject(options) && 'defaultNode' in options) {
1817
defaultNode = options.defaultNode;
19-
} else if (isVNode(options)) {
18+
} else if (isVNode(options) || isString(options)) {
2019
defaultNode = options;
2120
}
2221

23-
return {
24-
params,
25-
defaultNode,
26-
};
22+
return defaultNode;
2723
}
2824

2925
export function getParams(options?: OptionsType) {

src/utils/render-tnode.ts

Lines changed: 25 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,7 @@
1-
/* eslint-disable no-undef */
2-
import { h, isVNode, createTextVNode, VNode, ComponentPublicInstance, Slots } from 'vue';
3-
import { TNode } from '../common';
4-
5-
// 组件render属性的ts类型
6-
type RenderTsTypesSimple = string | number | boolean;
7-
type RenderTsTypesObject = Record<string, any> | Array<any>;
8-
type RenderTsTypes = VNode | TNode | RenderTsTypesSimple | RenderTsTypesObject;
9-
10-
// 定义组件内容的渲染方式
11-
enum RenderWay {
12-
Text = 'text',
13-
JsonString = 'jsonstring',
14-
VNode = 'vnode',
15-
Unknown = 'unknown',
16-
}
17-
18-
/**
19-
* 根据传入的值(对象),判断渲染该值(对象)的方式
20-
* @param value 传入的值(对象)
21-
*/
22-
const getValueRenderWay = (value: RenderTsTypes): RenderWay => {
23-
// 简单类型
24-
if (['string', 'number', 'boolean'].includes(typeof value)) return RenderWay.Text;
25-
// 复杂对象
26-
if (typeof value === 'object') {
27-
// 虚拟dom对象
28-
if (isVNode(value)) {
29-
return RenderWay.VNode;
30-
}
31-
// 其他复杂对象或数组
32-
return RenderWay.JsonString;
33-
}
34-
// 未知类型(兜底)
35-
return RenderWay.Unknown;
36-
};
37-
38-
// 通过template的方式渲染TNode
39-
export const RenderTNodeTemplate = (props: { render: Function; params: Record<string, any> }) => {
40-
const { render, params } = props;
41-
const renderResult = typeof render === 'function' ? render(h, params) : render;
42-
const renderWay = getValueRenderWay(renderResult);
43-
44-
const renderText = (c: RenderTsTypesSimple | RenderTsTypesObject) => createTextVNode(`${c}`);
45-
const renderMap = {
46-
[RenderWay.Text]: (c: RenderTsTypesSimple) => renderText(c),
47-
[RenderWay.JsonString]: (c: RenderTsTypesObject) => renderText(JSON.stringify(c, null, 2)),
48-
[RenderWay.VNode]: (c: VNode) => c,
49-
};
50-
51-
return renderMap[renderWay] ? renderMap[renderWay](renderResult) : h(null);
52-
};
53-
54-
interface JSXRenderContext {
55-
defaultNode?: VNode;
56-
params?: Record<string, any>;
57-
}
1+
import { h, ComponentPublicInstance } from 'vue';
2+
import isFunction from 'lodash/isFunction';
3+
import isEmpty from 'lodash/isEmpty';
4+
import { getDefaultNode, getParams, OptionsType } from '../hooks/tnode';
585

596
/**
607
* 通过JSX的方式渲染 TNode,props 和 插槽同时处理,也能处理默认值为 true 则渲染默认节点的情况
@@ -66,29 +13,30 @@ interface JSXRenderContext {
6613
* @example renderTNodeJSX(this, 'closeBtn', { defaultNode: <close-icon />, params })。 params 为渲染节点时所需的参数
6714
*/
6815

69-
export const renderTNodeJSX = (
70-
instance: ComponentPublicInstance,
71-
name: string,
72-
options?: Slots | JSXRenderContext | JSX.Element,
73-
) => {
74-
const params = typeof options === 'object' && 'params' in options ? options.params : null;
75-
const defaultNode = typeof options === 'object' && 'defaultNode' in options ? options.defaultNode : options;
16+
export const renderTNodeJSX = (instance: ComponentPublicInstance, name: string, options?: OptionsType) => {
17+
// assemble params && defaultNode
18+
const params = getParams(options);
19+
const defaultNode = getDefaultNode(options);
20+
21+
// 处理 props 类型的Node
7622
let propsNode;
7723
if (name in instance) {
7824
propsNode = instance[name];
7925
}
26+
27+
// propsNode 为 false 不渲染
8028
if (propsNode === false) return;
8129

8230
// 同名优先处理插槽
8331
if (instance.$slots[name]) {
8432
return instance.$slots[name](params);
8533
}
34+
if (isFunction(propsNode)) return propsNode(h, params);
35+
8636
if (propsNode === true && defaultNode) {
8737
return instance.$slots[name] ? instance.$slots[name](params) : defaultNode;
8838
}
89-
if (typeof propsNode === 'function') return propsNode(h, params);
90-
const isPropsEmpty = [undefined, params, ''].includes(propsNode);
91-
if (isPropsEmpty && instance.$slots[name]) return instance.$slots[name](params);
39+
9240
return propsNode;
9341
};
9442

@@ -100,12 +48,8 @@ export const renderTNodeJSX = (
10048
* @example renderTNodeJSX(this, 'closeBtn', <close-icon />)。this.closeBtn 为空时,则兜底渲染 <close-icon />
10149
* @example renderTNodeJSX(this, 'closeBtn', { defaultNode: <close-icon />, params }) 。params 为渲染节点时所需的参数
10250
*/
103-
export const renderTNodeJSXDefault = (
104-
vm: ComponentPublicInstance,
105-
name: string,
106-
options?: Slots | JSXRenderContext | JSX.Element,
107-
) => {
108-
const defaultNode = typeof options === 'object' && 'defaultNode' in options ? options.defaultNode : options;
51+
export const renderTNodeJSXDefault = (vm: ComponentPublicInstance, name: string, options?: OptionsType) => {
52+
const defaultNode = getDefaultNode(options);
10953
return renderTNodeJSX(vm, name, options) || defaultNode;
11054
};
11155

@@ -119,17 +63,15 @@ export const renderTNodeJSXDefault = (
11963
* @example renderContent(this, 'default', 'content', '我是默认内容')
12064
* @example renderContent(this, 'default', 'content', { defaultNode: '我是默认内容', params })
12165
*/
122-
export const renderContent = (
123-
vm: ComponentPublicInstance,
124-
name1: string,
125-
name2: string,
126-
options?: VNode | JSXRenderContext | JSX.Element,
127-
) => {
128-
const params = typeof options === 'object' && 'params' in options ? options.params : null;
129-
const defaultNode = typeof options === 'object' && 'defaultNode' in options ? options.defaultNode : options;
66+
export const renderContent = (vm: ComponentPublicInstance, name1: string, name2: string, options?: OptionsType) => {
67+
const params = getParams(options);
68+
const defaultNode = getDefaultNode(options);
69+
13070
const toParams = params ? { params } : undefined;
71+
13172
const node1 = renderTNodeJSX(vm, name1, toParams);
13273
const node2 = renderTNodeJSX(vm, name2, toParams);
133-
const r = [undefined, null, ''].includes(node1) ? node2 : node1;
134-
return [undefined, null, ''].includes(r) ? defaultNode : r;
74+
75+
const res = isEmpty(node1) ? node2 : node1;
76+
return isEmpty(res) ? defaultNode : res;
13577
};

tsconfig.json

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,6 @@
4141
"lib",
4242
"esm",
4343
"es",
44-
"tools",
45-
"types/index.ts",
46-
"src/addon/**",
47-
"src/locale/**",
48-
"src/upload/**",
49-
"src/dropdown/**",
50-
"src/transfer/**",
51-
"src/time-picker/**",
52-
"src/textarea/**",
53-
"src/utils/**"
5444
],
5545
"compileOnSave": false
5646
}

0 commit comments

Comments
 (0)