leafer-x-tooltip-canvas 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,52 +1,63 @@
1
1
  {
2
- "name": "leafer-x-tooltip-canvas",
3
- "version": "1.0.0",
4
- "author": "214L",
5
- "license": "MIT",
6
- "type": "module",
7
- "main": "dist/index.esm.js",
8
- "exports": {
9
- "import": "./dist/index.esm.js",
10
- "require": "./dist/index.cjs"
11
- },
12
- "types": "types/index.d.ts",
13
- "files": ["src", "types", "dev", "dist"],
14
- "repository": {
15
- "type": "git",
16
- "url": "https://github.com/214L/leafer-x-popup-canvas"
17
- },
18
- "homepage": "https://github.com/214L/leafer-x-popup-canvas",
19
- "bugs": "https://github.com/214L/leafer-x-popup-canvas/issues",
20
- "scripts": {
21
- "start": "cross-env NODE_ENV=development rollup -c -w",
22
- "build": "cross-env PLATFORM=all rollup -c",
23
- "test": "vitest"
24
- },
25
- "devDependencies": {
26
- "@rollup/plugin-commonjs": "^25.0.4",
27
- "@rollup/plugin-html": "^1.0.2",
28
- "@rollup/plugin-multi-entry": "^6.0.0",
29
- "@rollup/plugin-node-resolve": "^15.2.1",
30
- "@rollup/plugin-terser": "^0.4.3",
31
- "@rollup/plugin-typescript": "^11.1.3",
32
- "@typescript-eslint/eslint-plugin": "^5.54.1",
33
- "@typescript-eslint/parser": "^5.54.1",
34
- "rollup": "^3.29.2",
35
- "rollup-plugin-dts": "^6.0.2",
36
- "rollup-plugin-livereload": "^2.0.5",
37
- "rollup-plugin-serve": "^2.0.2",
38
- "rollup-plugin-string": "^3.0.0",
39
- "tslib": "^2.6.2",
40
- "typescript": "^5.2.2",
41
- "vite": "^4.4.9",
42
- "vitest": "^0.34.4",
43
- "jsdom": "^22.0.0",
44
- "cross-env": "^7.0.3",
45
- "eslint": "^8.49.0",
46
- "leafer-ui": "^1.0.0-rc.22"
47
- },
48
- "dependencies": {
49
- "@leafer-ui/core": "^1.0.0-rc.22"
50
- },
51
- "publishConfig": { "registry": "https://registry.npmjs.org" }
52
- }
2
+ "name": "leafer-x-tooltip-canvas",
3
+ "description": "A tooltip plugin for Leafer-ui.",
4
+ "version": "1.0.2",
5
+ "author": "214L",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "dist/index.esm.js",
9
+ "exports": {
10
+ "import": "./dist/index.esm.js",
11
+ "require": "./dist/index.cjs"
12
+ },
13
+ "types": "types/index.d.ts",
14
+ "files": [
15
+ "src",
16
+ "types",
17
+ "dev",
18
+ "dist"
19
+ ],
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/214L/leafer-x-tooltip-canvas"
23
+ },
24
+ "homepage": "https://github.com/214L/leafer-x-tooltip-canvas",
25
+ "bugs": "https://github.com/214L/leafer-x-tooltip-canvas/issues",
26
+ "scripts": {
27
+ "start": "cross-env NODE_ENV=development rollup -c -w",
28
+ "build": "cross-env PLATFORM=all rollup -c",
29
+ "test": "vitest"
30
+ },
31
+ "devDependencies": {
32
+ "@rollup/plugin-commonjs": "^28.0.9",
33
+ "@rollup/plugin-html": "^2.0.0",
34
+ "@rollup/plugin-multi-entry": "^6.0.0",
35
+ "@rollup/plugin-node-resolve": "^16.0.3",
36
+ "@rollup/plugin-terser": "^0.4.4",
37
+ "@rollup/plugin-typescript": "^12.3.0",
38
+ "@typescript-eslint/eslint-plugin": "^5.54.1",
39
+ "@typescript-eslint/parser": "^5.54.1",
40
+ "cross-env": "^7.0.3",
41
+ "eslint": "^8.49.0",
42
+ "jsdom": "^22.0.0",
43
+ "leafer-ui": "^1.12.2",
44
+ "rollup": "^4.54.0",
45
+ "rollup-plugin-copy": "^3.5.0",
46
+ "rollup-plugin-dts": "^6.3.0",
47
+ "rollup-plugin-livereload": "^2.0.5",
48
+ "rollup-plugin-serve": "^2.0.2",
49
+ "rollup-plugin-string": "^3.0.0",
50
+ "tslib": "^2.6.2",
51
+ "typescript": "^5.2.2",
52
+ "vite": "^4.4.9",
53
+ "vitest": "^0.34.4"
54
+ },
55
+ "dependencies": {
56
+ "@leafer-in/flow": "^1.12.2",
57
+ "@leafer-ui/core": "^1.12.2",
58
+ "leafer-ui": "^1.12.2"
59
+ },
60
+ "publishConfig": {
61
+ "registry": "https://registry.npmjs.org"
62
+ }
63
+ }
package/src/Tooltip.ts CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  } from 'leafer-ui'
10
10
  import { IPos, IUserConfig } from './interface'
11
11
  import { handleTextStyle } from './utils'
12
+ import { TOOLTIP_TAG, TOOLTIP_CLASS_NAME } from './constants'
12
13
 
13
14
  interface ITooltip extends IPen {
14
15
  target?: ILeaf
@@ -40,9 +41,9 @@ export class TooltipData extends PenData implements ITooltipData {
40
41
  @registerUI()
41
42
  export class Tooltip extends Pen implements ITooltip {
42
43
  public get __tag() {
43
- return 'Tooltip'
44
+ return TOOLTIP_TAG
44
45
  }
45
- public className: 'leafer-x-tooltip'
46
+ public className: typeof TOOLTIP_CLASS_NAME
46
47
  @dataProcessor(TooltipData)
47
48
  public declare __: ITooltipData
48
49
 
@@ -93,7 +94,7 @@ export class Tooltip extends Pen implements ITooltip {
93
94
  })
94
95
  this.add(
95
96
  new Text({
96
- className: 'leafer-x-tooltip',
97
+ className: TOOLTIP_CLASS_NAME,
97
98
  fill: color,
98
99
  fontSize,
99
100
  fontWeight,
@@ -130,8 +131,7 @@ export class Tooltip extends Pen implements ITooltip {
130
131
  this.clearShowHideTimers()
131
132
  this.showTimerId = setTimeout(() => {
132
133
  this.createShapes(pos)
133
- clearTimeout(this.showTimerId)
134
- this.showTimerId = null
134
+ this.showTimerId = null // 定时器执行完毕,清空引用
135
135
  }, this.config.showDelay)
136
136
  }
137
137
 
@@ -140,19 +140,21 @@ export class Tooltip extends Pen implements ITooltip {
140
140
  if (immediate) {
141
141
  this.destroy()
142
142
  } else {
143
- if (!this.hideTimerId) {
144
- this.hideTimerId = setTimeout(() => {
145
- this.destroy()
146
- }, this.config.hideDelay)
147
- }
143
+ // 移除 if 判断,确保每次 hide() 都能正确设置定时器
144
+ this.hideTimerId = setTimeout(() => {
145
+ this.destroy()
146
+ this.hideTimerId = null
147
+ }, this.config.hideDelay)
148
148
  }
149
149
  }
150
150
 
151
151
  public update(pos: IPos) {
152
152
  this.clearShowHideTimers()
153
153
  if (this.isShow) {
154
+ // 已显示,立即更新位置
154
155
  this.createShapes(pos)
155
156
  } else {
157
+ // 未显示,启动 show 定时器
156
158
  this.show(pos)
157
159
  }
158
160
  }
@@ -1,13 +1,10 @@
1
1
  import { App, PointerEvent } from '@leafer-ui/core'
2
- import type {
3
- IEventListenerId,
4
- ILeaf,
5
- ILeafer,
6
- } from '@leafer-ui/interface'
2
+ import type { IEventListenerId, ILeaf, ILeafer } from '@leafer-ui/interface'
7
3
  import { IUserConfig } from './interface'
8
4
  import { Tooltip } from './Tooltip'
9
5
  import { getTooltipId } from './utils'
10
6
  import { defaultConfig } from './defaultConfig'
7
+ import { TOOLTIP_TAG, TOOLTIP_CLASS_NAME } from './constants'
11
8
 
12
9
  export class TooltipPlugin {
13
10
  /**
@@ -28,39 +25,100 @@ export class TooltipPlugin {
28
25
  */
29
26
  private readonly pointEventId: IEventListenerId
30
27
 
28
+ /**
29
+ * @param tooltipCache - Tooltip 实例缓存,避免重复 DOM 查询
30
+ * @private
31
+ */
32
+ private tooltipCache: Map<string, Tooltip> = new Map()
33
+
34
+ /**
35
+ * @param 类型过滤 Set 缓存,将数组转为 Set 提升查询性能 O(n) -> O(1)
36
+ * @private
37
+ */
38
+ private includesTypeSet: Set<string> = new Set()
39
+ private excludesTypeSet: Set<string> = new Set()
40
+ private ignoreTypeSet: Set<string> = new Set()
41
+
31
42
  constructor(instance: ILeafer | App, config?: IUserConfig) {
32
43
  this.instance = instance
33
- this.config = Object.assign({}, defaultConfig, config)
44
+ this.config = this.mergeConfig(defaultConfig, config)
34
45
  this.handleConfig()
35
46
  this.initState()
36
47
  this.pointEventId = this.initEvent()
37
48
  }
38
49
 
50
+ /**
51
+ * @description 深度合并配置,避免实例间相互影响
52
+ * @private
53
+ */
54
+ private mergeConfig(base: IUserConfig, override?: IUserConfig): IUserConfig {
55
+ if (!override) {
56
+ // 深拷贝默认配置
57
+ return {
58
+ ...base,
59
+ style: { ...base.style },
60
+ includesType: [...(base.includesType || [])],
61
+ excludesType: [...(base.excludesType || [])],
62
+ ignoreType: [...(base.ignoreType || [])],
63
+ info: [...(base.info || [])],
64
+ }
65
+ }
66
+
67
+ // 深度合并用户配置
68
+ return {
69
+ ...base,
70
+ ...override,
71
+ style: {
72
+ ...base.style,
73
+ ...override.style,
74
+ },
75
+ includesType: override.includesType || base.includesType,
76
+ excludesType: override.excludesType || base.excludesType,
77
+ ignoreType: override.ignoreType || base.ignoreType,
78
+ info: override.info || base.info,
79
+ }
80
+ }
81
+
82
+ /**
83
+ * @description 类型守卫: 判断实例是否为 App
84
+ * @private
85
+ */
86
+ private isAppInstance(instance: ILeafer | App): instance is App {
87
+ return instance.isApp === true
88
+ }
89
+
39
90
  /**
40
91
  * @description 初始化状态
41
92
  */
42
93
  private initState() {
43
- if (this.instance.isApp) {
44
- const app = this.instance as App
45
- if (app.sky === undefined) {
46
- app.sky = app.addLeafer({
94
+ if (this.isAppInstance(this.instance)) {
95
+ // TypeScript 自动推断 this.instance App 类型
96
+ if (this.instance.sky === undefined) {
97
+ this.instance.sky = this.instance.addLeafer({
47
98
  type: 'draw',
48
99
  usePartRender: false,
49
100
  })
50
101
  }
51
- this.aimLeafer = app.sky
102
+ this.aimLeafer = this.instance.sky
52
103
  } else if (this.instance.isLeafer) {
53
104
  this.aimLeafer = this.instance
105
+ } else {
106
+ throw new Error('TooltipPlugin: Instance must be either App or Leafer')
54
107
  }
55
108
  }
56
109
 
57
- private handleConfig(){
58
- if(this.config.theme==='dark'){
59
- this.config.style.backgroundColor = "black"
60
- this.config.style.color = "white"
61
- }
110
+ private handleConfig() {
111
+ if (this.config.theme === 'dark') {
112
+ this.config.style.backgroundColor = 'black'
113
+ this.config.style.color = 'white'
62
114
  }
63
-
115
+
116
+ // 初始化类型过滤 Set,提升查询性能
117
+ this.includesTypeSet = new Set(this.config.includesType || [])
118
+ this.excludesTypeSet = new Set(this.config.excludesType || [])
119
+ this.ignoreTypeSet = new Set(this.config.ignoreType || [])
120
+ }
121
+
64
122
  /**
65
123
  * @description 初始化事件处理
66
124
  * @private
@@ -95,14 +153,19 @@ export class TooltipPlugin {
95
153
  }
96
154
  this.handleTooltip(event, target)
97
155
  }
98
-
99
156
  private filterTarget(list: ILeaf[]): ILeaf | null {
100
- const ignoreTag = ['Leafer', 'App']
157
+ const { throughExcludes } = this.config
158
+
101
159
  const pureResult = list.filter((item) => {
160
+ // 使用 Set.has() 代替 Array.includes(),性能提升
161
+ const shouldIgnore = this.ignoreTypeSet.has(item?.tag)
162
+ const shouldExclude = throughExcludes && this.excludesTypeSet.has(item?.tag)
163
+
102
164
  if (
103
- ignoreTag.includes(item?.tag) ||
104
- item?.parent?.tag === 'Tooltip' ||
105
- item?.className === 'leafer-x-tooltip'
165
+ shouldIgnore ||
166
+ shouldExclude ||
167
+ item?.parent?.tag === TOOLTIP_TAG ||
168
+ item?.className === TOOLTIP_CLASS_NAME
106
169
  ) {
107
170
  return false
108
171
  }
@@ -117,28 +180,48 @@ export class TooltipPlugin {
117
180
  * @param target 目标节点
118
181
  * @returns
119
182
  */
120
- private handleAllowed(target: ILeaf) {
121
- const infoArr = ['#' + target.id, '.' + target.className, target.tag]
122
- const { includesType, excludesType } = this.config
183
+ private handleAllowed(target: ILeaf): boolean {
184
+ const targetIdentifiers = ['#' + target.id, '.' + target.className, target.tag]
123
185
 
124
- if (includesType.length === 0 && excludesType.length === 0) return true
186
+ const hasIncludesRule = this.includesTypeSet.size > 0
187
+ const hasExcludesRule = this.excludesTypeSet.size > 0
188
+
189
+ // 如果没有配置任何过滤规则,默认允许
190
+ if (!hasIncludesRule && !hasExcludesRule) {
191
+ return true
192
+ }
125
193
 
126
- const isInclude = infoArr.some((string) => includesType.includes(string))
127
- const isExclude = infoArr.some((string) => excludesType.includes(string))
194
+ const matchesInclude = targetIdentifiers.some((id) => this.includesTypeSet.has(id))
195
+ const matchesExclude = targetIdentifiers.some((id) => this.excludesTypeSet.has(id))
128
196
 
129
- if (!isExclude && includesType.length === 0) return true
130
- if (!isInclude && excludesType.length === 0) return false
131
- return isInclude || !isExclude
197
+ // includes 优先级高于 excludes
198
+ if (matchesInclude) return true // 匹配白名单,直接允许(即使也在黑名单中)
199
+ if (matchesExclude) return false // 不在白名单但在黑名单,拒绝
200
+
201
+ // 两者都不匹配的情况
202
+ if (hasIncludesRule) return false // 有白名单规则但不匹配 → 拒绝
203
+ return true // 只有黑名单规则且不匹配 → 允许
132
204
  }
133
205
 
134
206
  /**
135
207
  * @description 隐藏 tooltip
136
208
  */
137
209
  private hideTooltip() {
138
- const tooltipList = this.aimLeafer.find('Tooltip') as Tooltip[]
139
- tooltipList.forEach((tooltip: Tooltip) => {
140
- tooltip.hide()
210
+ // 使用缓存而不是 DOM 查询,提升性能
211
+ // 同时清理已销毁的实例
212
+ const invalidIds: string[] = []
213
+
214
+ this.tooltipCache.forEach((tooltip, id) => {
215
+ if (tooltip.parent) {
216
+ tooltip.hide()
217
+ } else {
218
+ // 标记无效的缓存条目
219
+ invalidIds.push(id)
220
+ }
141
221
  })
222
+
223
+ // 清理无效缓存
224
+ invalidIds.forEach(id => this.tooltipCache.delete(id))
142
225
  }
143
226
 
144
227
  /**
@@ -146,26 +229,33 @@ export class TooltipPlugin {
146
229
  */
147
230
  private handleTooltip(event: PointerEvent, target: ILeaf) {
148
231
  const id = getTooltipId(target)
149
- const tooltipList = this.aimLeafer.find('Tooltip') as Tooltip[]
150
- let processed = false
151
- for (const tooltip of tooltipList) {
152
- if (tooltip.id === id) {
153
- tooltip.update({ x: event.x, y: event.y })
154
- processed = true
155
- } else {
232
+
233
+ // 隐藏其他 tooltip
234
+ this.tooltipCache.forEach((tooltip, cacheId) => {
235
+ if (cacheId !== id) {
156
236
  tooltip.hide()
157
237
  }
158
- }
238
+ })
159
239
 
160
- if (!processed) {
161
- this.aimLeafer.add(
162
- new Tooltip({
163
- id,
164
- pointerPos: { x: event.x, y: event.y },
165
- target,
166
- config: this.config,
167
- })
168
- )
240
+ // 检查缓存中的实例是否仍然有效(未被销毁)
241
+ const cachedTooltip = this.tooltipCache.get(id)
242
+ if (cachedTooltip && cachedTooltip.parent) {
243
+ // 实例有效,直接更新
244
+ cachedTooltip.update({ x: event.x, y: event.y })
245
+ } else {
246
+ // 实例已被销毁或不存在,移除无效缓存并创建新实例
247
+ if (cachedTooltip) {
248
+ this.tooltipCache.delete(id)
249
+ }
250
+
251
+ const tooltip = new Tooltip({
252
+ id,
253
+ pointerPos: { x: event.x, y: event.y },
254
+ target,
255
+ config: this.config,
256
+ })
257
+ this.aimLeafer.add(tooltip)
258
+ this.tooltipCache.set(id, tooltip)
169
259
  }
170
260
  }
171
261
 
@@ -173,14 +263,24 @@ export class TooltipPlugin {
173
263
  * @description 销毁
174
264
  */
175
265
  public destroy() {
176
- const tooltipList = this.aimLeafer.find('Tooltip') as Tooltip[]
177
- if (tooltipList) {
178
- tooltipList.forEach((tooltip) => {
266
+ // 防止重复销毁
267
+ if (!this.instance) return
268
+
269
+ // 清理缓存中的所有 tooltip
270
+ if (this.tooltipCache) {
271
+ this.tooltipCache.forEach((tooltip) => {
179
272
  tooltip.destroyTooltip()
180
- tooltip.parent.remove(tooltip)
273
+ // 使用可选链,防止 parent 为 null/undefined
274
+ tooltip.parent?.remove(tooltip)
181
275
  })
276
+ this.tooltipCache.clear()
182
277
  }
183
- this.instance.off_(this.pointEventId)
278
+
279
+ // 确保事件被正确清理
280
+ if (this.pointEventId) {
281
+ this.instance.off_(this.pointEventId)
282
+ }
283
+
184
284
  this.instance = null
185
285
  this.aimLeafer = null
186
286
  }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @description 插件常量定义
3
+ */
4
+
5
+ /**
6
+ * Tooltip 标签名
7
+ */
8
+ export const TOOLTIP_TAG = 'Tooltip'
9
+
10
+ /**
11
+ * Tooltip class 名称
12
+ */
13
+ export const TOOLTIP_CLASS_NAME = 'leafer-x-tooltip'
14
+
15
+ /**
16
+ * 显示类型枚举
17
+ */
18
+ export enum ShowType {
19
+ VALUE = 'value',
20
+ KEY_VALUE = 'key-value',
21
+ }
@@ -12,6 +12,8 @@ export const defaultConfig: IUserConfig = {
12
12
  preventOverflow: false,
13
13
  includesType: [],
14
14
  excludesType: [],
15
+ ignoreType:['Leafer','App','Flow'],
16
+ throughExcludes:false,
15
17
  theme: 'light',
16
18
  style: {
17
19
  backgroundColor: 'white',
@@ -24,6 +24,8 @@ interface IUserConfig {
24
24
  preventOverflow?: boolean
25
25
  includesType?: Array<string>
26
26
  excludesType?: Array<string>
27
+ ignoreType?: Array<string>
28
+ throughExcludes?: boolean
27
29
  theme?: 'light' | 'dark'
28
30
  style?: IStyleConfig
29
31
  }
package/src/utils.ts CHANGED
@@ -1,6 +1,13 @@
1
1
  import { Box } from 'leafer-ui'
2
2
  import { ILeaf } from '@leafer-ui/interface'
3
3
  import { IUserConfig } from './interface'
4
+ import { ShowType } from './constants'
5
+
6
+ /**
7
+ * @description 文本尺寸缓存,避免重复计算
8
+ */
9
+ const textSizeCache = new Map<string, { width: number; height: number }>()
10
+
4
11
  /**
5
12
  * @description 获取uuid 考虑兼容性问题采用此方法
6
13
  * @param length id长度
@@ -9,44 +16,98 @@ import { IUserConfig } from './interface'
9
16
  export const getTooltipId = function (target: ILeaf) {
10
17
  return target.tag + target.innerId
11
18
  }
19
+
12
20
  export const handleTextStyle = function (target: ILeaf, config: IUserConfig) {
21
+ // 参数校验
22
+ if (!target || !config) {
23
+ console.error('handleTextStyle: Invalid parameters')
24
+ return { width: 100, height: 30, text: '' }
25
+ }
26
+
13
27
  const str = handleContent(target, config)
14
28
  const { fontSize, fontFamily, fontWeight, padding } = config.style
15
- const box = new Box({
16
- children: [
17
- {
18
- tag: 'Text',
19
- text: str,
20
- fontSize,
21
- fontFamily,
22
- fontWeight,
23
- padding,
24
- },
25
- ],
26
- })
27
-
28
- const { width, height } = box.getBounds()
29
- return { width, height, text: str }
29
+
30
+ // 生成缓存 key,包含所有影响尺寸的因素
31
+ const cacheKey = `${str}:${fontSize}:${fontFamily}:${fontWeight}:${padding}`
32
+
33
+ // 检查缓存
34
+ if (textSizeCache.has(cacheKey)) {
35
+ const cached = textSizeCache.get(cacheKey)!
36
+ return { ...cached, text: str }
37
+ }
38
+
39
+ try {
40
+ const box = new Box({
41
+ children: [
42
+ {
43
+ tag: 'Text',
44
+ text: str,
45
+ fontSize,
46
+ fontFamily,
47
+ fontWeight,
48
+ padding,
49
+ },
50
+ ],
51
+ })
52
+
53
+ const bounds = box.getBounds()
54
+ // 检查 bounds 是否有效
55
+ if (!bounds || bounds.width === undefined || bounds.height === undefined) {
56
+ console.warn('handleTextStyle: Invalid bounds, using default size')
57
+ return { width: 100, height: 30, text: str }
58
+ }
59
+
60
+ const { width, height } = bounds
61
+
62
+ // 存入缓存
63
+ textSizeCache.set(cacheKey, { width, height })
64
+
65
+ return { width, height, text: str }
66
+ } catch (error) {
67
+ console.error('handleTextStyle: Failed to calculate text size', error)
68
+ return { width: 100, height: 30, text: str }
69
+ }
30
70
  }
31
71
 
32
72
  function handleContent(target: ILeaf, config: IUserConfig) {
33
73
  let str = ''
34
- const data = target as { [key: string]: any }
35
-
74
+ // 保持 ILeaf 类型,使用 Record 进行更安全的索引访问
75
+ const data = target as ILeaf & Record<string, unknown>
76
+
36
77
  // 如果formatter函数存在,则使用formatter函数进行格式化
37
- if (config.formatter(data) !== undefined) {
38
- str = config.formatter(data)
39
- } else {
40
- // 如果formatter函数不存在,则根据showType进行默认格式化
41
- if (config.showType == 'value') {
78
+ if (config.formatter && typeof config.formatter === 'function') {
79
+ try {
80
+ const formatted = config.formatter(data)
81
+ if (formatted !== undefined) {
82
+ str = formatted
83
+ }
84
+ } catch (error) {
85
+ console.error('handleContent: Formatter function error', error)
86
+ // formatter 失败时降级到默认格式化
87
+ }
88
+ }
89
+
90
+ // 如果formatter函数不存在或执行失败,则根据showType进行默认格式化
91
+ if (!str) {
92
+ if (config.showType === ShowType.VALUE) {
42
93
  str += config.info
43
- .map((dataName: string) => `${data[dataName]}`)
94
+ .map((dataName: string) => {
95
+ const value = data[dataName]
96
+ // 检查值是否存在且可转换为字符串
97
+ return value !== null && value !== undefined ? String(value) : ''
98
+ })
44
99
  .join('\n')
45
- } else if (config.showType == 'key-value') {
100
+ } else if (config.showType === ShowType.KEY_VALUE) {
46
101
  str += config.info
47
- .map((dataName: string) => `${dataName} : ${data[dataName]}`)
102
+ .map((dataName: string) => {
103
+ const value = data[dataName]
104
+ // 检查值是否存在且可转换为字符串
105
+ const displayValue = value !== null && value !== undefined ? String(value) : ''
106
+ return `${dataName} : ${displayValue}`
107
+ })
48
108
  .join('\n')
49
109
  }
50
110
  }
111
+
51
112
  return str
52
113
  }