最近的项目里,有这样一个需求:
在 A 页面里插入 B 页面的内容,且要求:
- B 的内容格式不能乱
- A 的内容和 B 的内容要无缝衔接,像一个页面一样
- B 页面里有很多
script
标签,功能要正常可用。 - B 页面不会为了适配 A 页面,去做改动优化
方案 1:iframe
要在一个页面插入另一个页面的内容,首先想到的方案肯定是 iframe,只要简单填一个 src 就 ok 了。但存在三个问题:
- 高度问题
如果给 iframe 设置了宽高,那么 B 页面的内容只能在 iframe 里滚动显示。这与需求 2 不符。
如果要让 iframe 的宽高由内容决定,应该设置如下:
1 | const iframeAutoHeight = iframe => { |
- 链接跳转问题
如果 B 页面里有 a 标签之类的跳转,使用 iframe 的方式,只能在 iframe 里跳转,而不能在整个页面里进行跳转。
如果只是少数几个明确的跳转方式,
比如 a 标签,可以改
target='_top'
location.href 跳转,改为
1 | <script language="JavaScript"> |
但因为需求 4 以及 B 页面存在大量我们无法预知的跳转方式,这些无法满足。
- 跨域问题
这个是更大的问题,如果 A、B 两个页面存在跨域问题,那么 A 页面处理问题 1,2 的方案就不可用 😭
方案 2:react 的 dangerouslySetInnerHTML
让我们靠谱的后端同学,在接口返回数据里直接把 B 页面的内容返回给 A,然后在 A 里使用 dangerouslySetInnerHTML,但这样子可以满足需求 1,2,4,但是需求 3 出问题了。
因为 dangerouslySetInnerHTML 无法解析出里面的 script 标签,并进行执行。
dangerouslySetInnerHTML 其实就是 react 给我们写的一个dom.innerHMTL = xxx
的语法糖,innerHTML 是不会执行 script 标签里的内容的。
方案 3:createContextualFragment + appendChild
仍然让我们靠谱的后端同学,把 B 页面的内容用接口的形式发给我们,然后
1 | import React, {useEffect, useRef} from 'react' |
完美!