如何让Draft.js linkify插件生成的链接在HTML渲染中可点击
从你提供的rawContent可以看到,输入"cnn.com"后,entityMap为空,也没有对应的entityRanges。这说明linkify插件仅在编辑器渲染层把文本样式化成链接,但没有将其转化为Draft.js的链接实体(Link Entity)。Draft.js的富文本格式依赖实体存储链接这类带元数据的内容,缺少实体的话,导出HTML时自然不会生成可点击的<a>标签。
需要修改编辑器配置,让linkify插件识别到链接文本时,自动创建Draft.js的链接实体,而非仅做样式渲染,具体步骤如下:
添加链接实体创建逻辑
自定义处理函数,在linkify插件识别到链接时,为文本创建对应的链接实体:import { EditorState, Modifier, Entity } from 'draft-js'; // 处理链接转化为实体的函数 const handleLinkify = (editorState, match) => { const contentState = editorState.getCurrentContent(); const url = match.url; const text = match.text; // 创建链接实体 const contentWithEntity = contentState.createEntity( 'LINK', 'MUTABLE', { url: url.startsWith('http') ? url : `http://${url}` } ); const entityKey = contentWithEntity.getLastCreatedEntityKey(); // 将匹配到的文本替换为带实体的内容 const newContent = Modifier.replaceText( contentWithEntity, editorState.getSelection().merge({ anchorOffset: match.start, focusOffset: match.end, }), text, null, entityKey ); return EditorState.push(editorState, newContent, 'apply-entity'); };然后在linkify插件中配置这个回调(参数名根据插件API调整):
const linkifyPlugin = createLinkifyPlugin({ onTransform: handleLinkify, });配置HTML导出的实体转换器
如果你使用draft-js-export-html这类工具,需要添加实体转换规则,让它把LINK实体转化为<a>标签:import { stateToHTML } from 'draft-js-export-html'; const htmlContent = stateToHTML(editorState.getCurrentContent(), { entityTransformers: { LINK: (entity) => ({ element: 'a', attributes: { href: entity.data.url, target: '_blank', rel: 'noopener noreferrer', }, }), }, });验证实体创建结果
修改后,输入"cnn.com"再查看rawContent,应该会出现类似如下的实体数据:"rawContent:" { "blocks": [ { "key": "66gvt", "text": "cnn.com ", "type": "unstyled", "depth": 0, "inlineStyleRanges": [], "entityRanges": [ { "offset": 0, "length": 7, "key": 0 } ], "data": {} } ], "entityMap": { "0": { "type": "LINK", "mutability": "MUTABLE", "data": { "url": "http://cnn.com" } } } }此时导出的HTML会生成
<a href="http://cnn.com">cnn.com</a>,渲染卡片时就能显示可点击的链接。
Draft.js的linkify插件默认可能仅做视觉渲染,不会修改底层的ContentState,因此必须手动添加实体创建逻辑,把链接文本转化为带实体的内容——实体是Draft.js存储元数据(如链接URL)的核心方式,缺少实体的话,导出HTML时无法区分普通文本和链接。
内容的提问来源于stack exchange,提问作者Neil Girardi

