背景
可视化页面搭建场景,需要支持配置富文本内容并在页面中渲染,富文本编辑器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-ignore
if (!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和层级