作为一款专注于有声内容创作的工具,「呦呦有声」 在画本编辑功能上一直追求更自然、更高效的创作体验。在有声书制作过程中,因为文本中多音字、偏僻字而导致CV读错是返音中的重灾区,所以,拼音标注功能的优化成为了我们近期迭代的重点。
传统画本工具的拼音标注方式(如「魑(chī)魅(mèi)魍(wǎng)魉(liǎng)」)不仅影响阅读流畅度,还会干扰字数统计,给内容制作和结算带来诸多麻烦。
今天就来分享 「呦呦有声」 是如何基于 Tiptap 实现拼音标注的优雅展示,以及我们在数据结构设计、交互体验上的技术思考。
传统拼音标注的痛点:为什么我们要重构?
在做 「呦呦有声」 的画本工具时,我们调研了市面上主流画本的拼音标注方式,发现大家几乎都采用 「文字 + 括号拼音」 的形式,例如:
魑(chī)魅(mèi)魍(wǎng)魉(liǎng)
虽然只有4个字,但明显已经影响阅读了,再让我们看一个更极端的案例:
纯文字版:
茕茕孑立 沆瀣一气
踽踽独行 醍醐灌顶
绵绵瓜瓞 奉为圭臬
龙行龘龘 犄角旮旯
拼音版:
茕(qióng)茕(qióng)孑(jié)立(lì) 沆(hàng)瀣(xiè)一(yī)气(qì)
踽(jǔ)踽(jǔ)独(dú)行(xíng) 醍(tí)醐(hú)灌(guàn)顶(dǐng)
绵(mián)绵(mián)瓜(guā)瓞(dié) 奉(fèng)为(wéi)圭(guī)臬(niè)
龙(lóng)行(xíng)龘(dá)龘(dá) 犄(jī)角(jiǎo)旮(gā)旯(lá)
在多组文字进行传统拼音标注后,已经完全丧失了可阅读性,原本的辅助功能反而成了CV配音的干扰项,并且这种方式还存在3个致命问题:
-
阅读与配音障碍 括号和拼音会打断文本连贯性,尤其在 CV 配音时,配音演员需要跳过括号内容,严重影响朗读节奏;
-
字数统计不准确
在 「呦呦有声」 的结算系统中,字数直接关系到制作成本。如果按照传统的拼音标注方式,则拼音会被计入总字数,导致内容创作者按字数结算时出现偏差(比如「魑(chī)」实际算 1 个汉字,却被统计为6个字符,即便不统计标点符号,也有4个字符); -
破坏文本数据结构
在传统模式中,拼音与正文混合存储,容易破坏段落结构,影响后台解析与二次加工。
为了解决这些问题,我们将目光投向了 Ruby 标签(<ruby>)—— 这是一种 HTML 原生的注音格式,能将拼音显示在文字上方,既不干扰阅读,又能保持文本结构完整。
技术实现:基于 Tiptap 的 Ruby 标注方案
「呦呦有声」 的拼音标注功能基于 Tiptap(一款基于 ProseMirror 的富文本编辑框架)实现,核心是自定义 Ruby 标记(Mark)和配套的交互逻辑。
1. 自定义 Tiptap Mark:RubyMark 的设计
Tiptap 中,「标记(Mark)」用于描述文本的附加属性(如加粗、斜体)。我们通过自定义 RubyMark,让编辑器支持拼音标注的存储和渲染:
// RubyMark.js
import { Mark } from '@tiptap/core'
export const RubyMark = Mark.create({
name: 'ruby', // 标记名称,用于后续调用
// 定义属性:存储需要标注的文本(anchor)和对应的拼音(pinyin)
addAttributes() {
return {
anchor: {
default: null, // 存储标注的文本(如 ["魑", "魅"])
parseHTML: element => {
// 从 HTML 解析时,读取自定义属性
return JSON.parse(element.getAttribute('data-anchor') || '[]')
},
renderHTML: attributes => {
// 渲染时,将属性存入自定义数据属性
return { 'data-anchor': JSON.stringify(attributes.anchor) }
}
},
pinyin: {
default: null, // 存储对应的拼音(如 ["chī", "mèi"])
parseHTML: element => {
return JSON.parse(element.getAttribute('data-pinyin') || '[]')
},
renderHTML: attributes => {
return { 'data-pinyin': JSON.stringify(attributes.pinyin) }
}
}
}
},
// 解析 HTML 时识别 <ruby> 标签
parseHTML() {
return [{ tag: 'ruby' }]
},
// 渲染时返回基础结构,实际样式由装饰器处理
renderHTML({ mark, HTMLAttributes, children }) {
return [
'ruby',
HTMLAttributes,
// 文本内容
children,
// 拼音标签(<rt> 是 Ruby 标签中用于显示注音的部分)
['rt', null, mark.attrs.pinyin.join('、')]
]
}
})
设计思路:
- 通过
anchor和pinyin两个属性,一对一存储「需要标注的文本」和「对应的拼音」,支持多组标注(如一段文本中多个词语需要标音)。 - 渲染时使用原生
<ruby>和<rt>标签,确保拼音显示在文字上方(需配合 CSS 调整样式)。
效果展示:
- 极端文本展示:
- 常规文本展示:
2. 拼音标注的交互逻辑:从选中到展示
为了让用户能直观地添加 / 删除拼音,我们在 「呦呦有声」 中封装了 useAiPinyinUtils 工具函数,处理选中文本、调用接口生成拼音、更新标记等逻辑,具体提供了以下3个核心功能:
- pinyinAnnotation:获取用户选中的文字,用于定位其在段落内的绝对位置。
- setPinyinMark:将拼音写入到
RubyMark的anchor和pinyin属性中,可多次追加。 - removeRubyMarkInSelection:删除选中部分的拼音标注,不影响其他标注。
部分核心代码:
const setPinyinMark = (params) => {
if (!params || params.code !== 200 || !params.data) return
const editor = getEditor()
const { keyword, data: pinyinArray, selection } = params.data
const { from, to } = selection
editor.commands.setTextSelection({ from, to })
const { $from } = editor.state.selection
const paragraph = $from.node()
const rubyMark = paragraph?.marks?.find(mark => mark.type.name === 'ruby')
let existingAnchor = rubyMark?.attrs.anchor || []
let existingPinyin = rubyMark?.attrs.pinyin || []
if (existingAnchor.includes(keyword)) return
existingAnchor.push(keyword)
existingPinyin.push(pinyinArray)
editor
.chain()
.focus()
.setMark('ruby', { anchor: existingAnchor, pinyin: existingPinyin })
.run()
}
3. 数据结构设计:为什么拼音不影响字数统计?
核心设计亮点在于:拼音信息存储在 Mark 的属性中,而非文本节点内。
- Tiptap 中,字数统计 基于文本节点的
textContent计算,而Mark的属性属于元数据,不会被计入。 - 即使删除或修改拼音,文本节点本身不会被破坏,避免了「标注后文本结构错乱」的问题。
例如,标注「魑魅」后,编辑器的文档结构如下(简化版):
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "魑魅", // 文本内容(字数统计只看这里)
"marks": [
{
"type": "ruby",
"attrs": {
"anchor": ["魑", "魅"],
"pinyin": ["chī", "mèi"] // 拼音存储在属性中,不影响字数
}
}
]
}
]
}
实际效果:「呦呦有声」的拼音标注体验
在 「呦呦有声」 的画本工具中,用户可以:
- 选中任意文本,一键添加拼音(自动调用 AI 生成准确拼音);
- 同一段文本可标注多个拼音;
- 选中带拼音的文本,一键删除指定拼音;
- 拼音显示在文字正上方,支持自定义样式(如字号、颜色)。
这种方式既解决了传统标注的阅读障碍,又保证了字数统计的准确性,让有声书内容的创作符合人类自然的阅读习惯。
总结:技术选型与产品思考
-
产品层面的取舍
我们没有采用
「拼音嵌入文本」的方案,而是通过Ruby标签和元数据存储,本质上是为了「分离内容与标注」—— 内容创作者只需要关注文本本身,标注信息作为附加属性存在,既不干扰创作,又便于后续处理(如配音、字数统计)。 -
未来规划
下一步,我们计划在 「呦呦有声」 中接入 AI 批量智能拼音标注,进一步降低人工成本。之后也会陆续推出多语言标注、方言标注等功能,进一步提升CV配音的准确和高效性。
产品介绍
呦呦有声 是一款集有声书画本、审听、对轨和后期于一体的有声书在线制作工具,致力于为有声书创作者们提供高效、优雅的使用体验。本文介绍的拼音标注功能,已经在 呦呦有声 正式上线,我们将持续深耕有声书创作工具领域,为有声书创作者提供更多专业且易用的产品功能。
如果你也在做富文本编辑相关的产品,或者对 呦呦有声 的技术实现感兴趣,欢迎在评论区交流!也可以直接体验我们的产品,感受更高效的有声书创作工具~