预览富文本的两种方式

2,642 阅读2分钟

前言

有时候,我们需要提供一个富文本编辑器给用户进行内容输入,最后还要将这段内容在某个地方展示出来。我们知道,我们通过富文本编辑器取到的内容,实际上就是一段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>

总结

以上两种方案,各有优缺点。如果你还有更好的方式,欢迎一起交流。