前言
有时候,我们需要提供一个富文本编辑器给用户进行内容输入,最后还要将这段内容在某个地方展示出来。我们知道,我们通过富文本编辑器取到的内容,实际上就是一段html字符串。在展示的时候,有可能受到外部样式的影响,导致预览效果和编辑的效果有较多不一致的地方。那我们如果隔离样式去渲染这一段html呢?接下来,探讨两种可行方案,供大家参考。
iframe
毫无疑问,iframe有着特别强的隔离性。我们常用的方式如下:
<iframe frameborder="0" src="https://baidu.com">
<p>您的浏览器不支持 iframe 标签。</p>
</iframe>
那可能就有人问了:我要渲染一段html,我还要去新建一个页面专门用来渲染吗?
其实这里的src我们可以使用 Data URI。举个栗子:
我们要渲染的html如下:
<p>闷声发大财</p>
那我们在iframe中预览可以这样写:
<iframe
frameborder="0"
src="data:text/html;charset=UTF-8,<p>闷声发大财</p>"
></iframe>
当然我们应该要进行一下URL编码,最后应该长这样:
<iframe
frameborder="0"
src="data:text/html;charset=UTF-8,%3Cp%3E%E9%97%B7%E5%A3%B0%E5%8F%91%E5%A4%A7%E8%B4%A2%3C%2Fp%3E"
></iframe>
这种方案看起来比较简单,但也有一个比较明显的缺点:我们不确定富文本内容的高度,有可能在这个iframe内部出现滚动条。
Shadow DOM
第二种方案,我们可以通过Web Components技术,自定义一个用于渲染html的标签,并且使用Shadow dom的方式去实现,从而达到隔离样式的效果。
代码示例如下:
<script>
customElements.define(
'my-html',
class extends HTMLElement {
connectedCallback() {
this.attachShadow({ mode: 'open' });
const content = this.getAttribute('content');
const wrapper = document.createElement('div');
wrapper.innerHTML = content;
this.shadowRoot.append(wrapper);
}
}
);
</script>
// html
<my-html content="<p>闷声发大财</p>"></my-html>
通过这种方式,我们就可以将需要渲染的html字符串传给my-html
组件,从而实现隔离样式渲染。
需要注意的是,这里的样式隔离,并不是隔离所有的样式。一些会继承的样式,还是会受到影响。下面这个例子,字体颜色会显示成红色:
<div style="color: red">
<my-html content="<p>闷声发大财</p>"></my-html>
</div>
总结
以上两种方案,各有优缺点。如果你还有更好的方式,欢迎一起交流。