React中如何将contentEditable占位符替换为渲染后的FontAwesome组件?
解决可编辑Div中FontAwesome表情占位符替换问题
问题场景
我在使用contentEditable的Div时,希望将输入内容中类似#fa-face-smile#的占位符替换为FontAwesome表情图标。当前代码逻辑是插入占位符后,通过convertEmoticons函数尝试替换,但实际页面显示为,[object object],,完全不符合预期。
我的可编辑Div代码:
<div contentEditable="true" ref={newMessageRef} className={`form-control ${errors.message ? 'is-invalid' : ''}`} data-raw="" onBlur={e => setNewEditableContent(e.target.textContent)} />
输入示例:
I would be so happy if #fa-face-smile# would be converted to the actual emoticon
预期替换结果对应的组件:
<FontAwesomeIcon size="2x" icon="fa-solid fa-face-smile" />
当前的转换及设置函数:
function convertEmoticons(string) { let replacedText = string .split(new RegExp(/\#(.*?)\#/, "gi")) .map((node, i) => (i % 2 ? <FontAwesomeIcon style={{color: '#a70000'}} size="2x" icon={getEmoticon(node)}/> : node)); return (replacedText); } const _setMessageText = (text) => { newMessageRef.current.setAttribute("data-raw", text); newMessageRef.current.textContent = convertEmoticons(text); }
错误原因
convertEmoticons返回的是React元素与字符串混合的数组,直接赋值给textContent时,React元素会被强制转换为字符串[object Object]。- 数组转字符串时,默认会用逗号分隔元素,所以出现了前后带逗号的情况。
textContent只能设置纯文本,无法识别React组件或HTML标签。
解决方案
要实现占位符转图标,需要将转换后的内容以HTML形式插入可编辑Div,有两种可行方案:
方案1:将React组件转为静态HTML字符串
利用ReactDOMServer.renderToStaticMarkup把FontAwesomeIcon组件转为对应的HTML字符串,再拼接成完整内容后设置到innerHTML。
步骤:
- 导入
ReactDOMServer:
import ReactDOMServer from 'react-dom/server';
- 修改
convertEmoticons函数:
function convertEmoticons(string) { return string .split(new RegExp(/\#(.*?)\#/, "gi")) .map((node, i) => { if (i % 2 === 1) { // 将React组件转为HTML字符串 const iconComponent = <FontAwesomeIcon style={{color: '#a70000'}} size="2x" icon={getEmoticon(node)}/>; return ReactDOMServer.renderToStaticMarkup(iconComponent); } // 纯文本部分转义,避免HTML注入 return node.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); }).join(''); // 数组转字符串,去掉默认逗号分隔 }
- 修改
_setMessageText,使用innerHTML而非textContent:
const _setMessageText = (text) => { newMessageRef.current.setAttribute("data-raw", text); newMessageRef.current.innerHTML = convertEmoticons(text); }
方案2:直接构建FontAwesome的HTML标签
跳过React组件,直接根据占位符生成FontAwesome对应的<i>标签字符串,这种方式更轻量,不需要依赖ReactDOMServer。
修改convertEmoticons函数:
function convertEmoticons(string) { return string.replace(/\#(.*?)\#/gi, (match, iconName) => { // 假设getEmoticon返回完整的类名,比如"fa-solid fa-face-smile" const fullIconClass = getEmoticon(iconName); return `<i class="${fullIconClass}" style="color:#a70000; font-size:2em"></i>`; }); }
同样修改_setMessageText使用innerHTML即可。
额外注意事项
- 处理纯文本时要做HTML转义,避免用户输入的特殊字符破坏页面结构。
- 替换后如果需要保留光标位置,需要重新计算并设置光标,可在
_setMessageText末尾添加光标定位逻辑。
内容的提问来源于stack exchange,提问作者Yolo
相关产品推荐
相关产品推荐

