Skip to content

文本间距属性 (letter/wordSpacing) 在测量层缺失且在业务组件层未透传,导致排版功能不可用 #184

@xxMudCloudxx

Description

@xxMudCloudxx

问题描述

官方文档声明 Text 原语(原语节点)支持 letterSpacing 和 wordSpacing。但是该功能似乎不可用,问题贯穿了从底层的 测量算法 到中间的 样式解析 再到上层的 业务组件封装 的完整链路。

代码分析

1. 底层:测量函数忽略(measureText)

  • measureText 实现忽略:src/utils/measure-text.ts 中,逻辑只解构了 fontFamily, fontSize, fontWeight, lineHeight,完全忽略了 letterSpacingwordSpacing
  • 调用链路截断: src/utils/text.ts 中的 updateTextElement 在调用 measureText 时,显式解构并过滤了样式属性,直接丢弃了这两个属性。

2.中间层: 样式解析不一致

  • 渲染属性白名单缺失:在 src/renderer/composites/text.tsgetTextAttributes 函数中,使用了白名单机制提取 SVG 属性。

    • 现状: 该白名单包含 'letter-spacing',但漏掉了 'word-spacing'
    • 后果: 即使上层传入了 wordSpacing,它也会在最终生成 SVG foreignObject 内容时被剥离,无法渲染出视觉效果。
  • src/utils/text.ts中的getTextStyle函数对letterSpacing做了处理,加上了px,但是没有对wordSpacing做处理。

3.顶层:业务组件透传阻断

​ 虽然原子组件 ItemLabel/ItemValue /ItemDes支持透传 TextProps,但在 SimpleItemBadgeCard 等业务组件中,并没有开放接口来配置内部文本的间距,也没有将letterSpacingwordSpacing透传给文本节点。

4.总结:文本属性支持情况对比表

层级 问题 letterSpacing wordSpacing
底层 (measureText) 测量忽略间距属性 ❌ 不支持 ❌ 不支持
中间层 (text.ts getTextStyle) px 后缀处理 ✅ 有处理 ❌ 无处理
中间层 (composites/text.ts) 渲染白名单 ✅ 已包含 ❌ 缺失
原语层 (jsx Text) 属性透传 ✅ 正确 ✅ 正确
业务组件层 接口暴露 ❌ 未暴露 ❌ 未暴露

建议方案

Step 1: 修复核心渲染与测量 (Core Fix)

  • Refactor measureText: 升级函数签名,支持传入 letterSpacingwordSpacing
  • Fix utils/text.ts: 在 updateTextElement 中正确透传这两个属性给测量函数。并且在getTextStyle函数中添加对wordSpacing的处理。
  • Fix renderer/composites/text.ts: 在 getTextAttributes 的白名单数组中添加 'word-spacing'

Step 2: 修复组件层数据流 (Component Fix)

  • Update Business Components: 修改 SimpleItem 等组件,允许通过 props (如 labelStyle) 传入间距属性,并将其透传给内部的 ItemLabel / ItemDesc

Step 3:性能优化 (Performance Optimization - 可选)

  • 实现 LRU 缓存: 我发现 measureText 在每次调用时都会触发 Canvas/DOM 测量,而没有任何缓存机制。我建议引入 LRU (Least Recently Used) 缓存机制(例如通过项目现有的 flru 库实现)。

备注: 我已经准备好了一套本地实现LRU的方案。

如果维护者同意,我愿意参与第一步(核心修复)和第三步(性能优化)。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions