背景
可视化页面搭建场景,需要支持配置富文本内容并在页面中渲染,富文本编辑器SDK采用了@tinymce/tinymce-react
。
问题场景
问题1 :文本数据转义
富文本编辑器生成的HTML富文本在服务端存储时会对字符串进行转义,比如:
'<p>3245003</p>' ----> "<p>3245003</p>"
解决方案:
利用浏览器默认行为,通过innerHTML方法生成dom节点进行转义,然后通过DOMParser将html文本转化成dom树
参考:https://developer.mozilla.org/zh-CN/docs/Web/API/DOMParser
const htmlToElement = (html) => {const parser = new DOMParser();const doc = parser.parseFromString(html, 'text/html');return doc.body.firstChild;}
const transformStr = (content) => {let div = document.createElement('div');div.innerHTML = content;return htmlToElement(`<div>${div.innerText}</div>`)
}
问题2:SSR场景hydrate模式禁用了innerHTML或者dangerouslySetInnerHTML直接渲染
使用最原始的js API
方案1:innerHTML
const C = props => {const {content, isSSR} = props;const wrapRef = useRef<any>();useEffect(() => {if(wrapRef.current && !isSSR) {wrapRef.current.innerHTML = content;}}, []);return (<div ref={wrapRef} />)
}export default C;
方案2:appendChild
const C = props => {const {content, isSSR} = props;const wrapRef = useRef<any>();useEffect(() => {if (wrapRef.current) {function htmlToElement(html) {const parser = new DOMParser();const doc = parser.parseFromString(html, 'text/html');console.log('htmlToElement', doc, doc.body.firstChild);return doc.body.firstChild;}//@ts-ignoreif (!isSSR) {let div = document.createElement('div');div.innerHTML = content;wrapRef.current.appendChild(htmlToElement(`<div>${div.innerText}</div>`));}}}, []);return (<div ref={wrapRef} />)
}
问题3:生成富文本体积太大
方案1
生成的富文本内容,生成文件,然后上传至oss,富文本编辑器和渲染页面分别通过cdn拉取数据内容进行渲染,
方案2
文本简化压缩,采用类似html-minifier-terser
的库对生成的html文本进行处理压缩,删除无用标签、空格等内容减少体积
方案3
成本略高,只提供思路,小型编译器通过将html内容解析转化成AST,分析css样式结构进行优化,减少css样式内容,分析dom结构减少无用dom和层级