React中安全渲染含HTML标签文本及Medium式高亮实现方案
React安全渲染带HTML标签的内容(无需dangerouslySetInnerHTML)
你已经有了拆分后的令牌数组(比如["Te", "<span>", "x", "</span>", "t"]),可以通过解析令牌并转换成React元素的方式安全渲染,避免直接使用dangerouslySetInnerHTML带来的XSS风险。核心思路是遍历令牌,区分文本和标签,构建嵌套的React元素结构:
import React from 'react'; function parseTokensToReactNodes(tokens) { const stack = []; const rootNodes = []; let currentChildren = rootNodes; // 遍历所有令牌,构建DOM结构树 for (const token of tokens) { if (token.startsWith('<') && token.endsWith('>')) { const tagMatch = token.match(/<\/?([a-z0-9]+)>/i); if (!tagMatch) continue; // 跳过无效标签 const tagName = tagMatch[1]; if (token.startsWith('</')) { // 处理闭合标签:弹出栈,回到父元素的子节点列表 stack.pop(); currentChildren = stack.length ? stack[stack.length - 1].children : rootNodes; } else { // 处理开始标签:创建元素节点,推入栈 const elementNode = { type: tagName, children: [] }; currentChildren.push(elementNode); stack.push(elementNode); currentChildren = elementNode.children; } } else { // 处理文本节点:直接添加到当前子节点列表 currentChildren.push(token); } } // 将结构树转换为React元素 function convertToJSX(node) { if (typeof node === 'string') return node; return React.createElement(node.type, {}, node.children.map(convertToJSX)); } return rootNodes.map(convertToJSX); } // 使用示例 const tokens = ["Te", "<span>", "x", "</span>", "t"]; function HighlightedText() { return <div>{parseTokensToReactNodes(tokens)}</div>; }
这个方法完全基于React的虚拟DOM机制,所有标签都是可控创建的,不会引入未知的HTML风险。
实现类似Medium的文本高亮的其他方法
除了掩码数组算法,还有几种更贴合Medium交互式高亮体验的实现思路:
1. Range API直接操作选区
Medium的高亮核心是基于用户选区,利用浏览器原生的Range和Selection API可以直接处理选区:
- 通过
window.getSelection()获取用户选中的文本范围 - 创建Range对象后,调用
surroundContents()方法给选中内容包裹高亮元素(比如<mark>或自定义组件) - 在React中配合
useRef获取文本容器的DOM节点,确保操作的是真实DOM,同时通过状态同步高亮信息到虚拟DOM
优点:直接对接浏览器原生选区能力,交互流畅;缺点:需要处理React虚拟DOM与真实DOM的同步冲突,适合轻量场景。
2. 基于富文本编辑器库
如果需要支持高亮的编辑、删除、移动等复杂交互,直接基于成熟的富文本编辑器库是更高效的选择:
- Draft.js:通过自定义
InlineStyle标记高亮文本,渲染时映射为对应的样式组件 - Slate.js:用自定义的
mark节点类型存储高亮信息,编辑器自带选区处理和节点管理能力
优点:无需自己处理选区拆分、文本嵌套、编辑同步等复杂逻辑;缺点:需要引入第三方库,学习成本较高,但稳定性和扩展性更强。
3. 文本位置标记法
存储高亮在原始文本中的起始/结束索引,渲染时根据索引拆分文本并包裹高亮组件:
- 比如原始文本为
"Hello World",高亮范围是[3,7],则拆分为["Hel", <mark>lo W</mark>, "orld"] - 当文本内容修改时,需要更新高亮的位置索引(可以通过差分算法计算偏移)
优点:数据结构简单,高亮信息易持久化;缺点:需要处理文本编辑后的位置偏移问题,适合文本内容不频繁修改的场景。
内容的提问来源于stack exchange,提问作者IVOBOT
相关产品推荐
相关产品推荐

