现象
最近有一个项目内嵌了一个iframe,会在一定条件下动态切换其的src达到切换页面的效果。同时页面父页面中有回退按钮,直接调用的go(-1)。此时就产生了一个奇怪的现象:点击回退按钮,iframe出现了后退,而父页面没有回退。
类似于下面这样:
// 动态切换src
let iframeSrc: string = 'http://example1.com'
setTimeout(() => {
iframeSrc = 'http://example2.com'
}, 1000)
// vue.js
this.$router.go(-1)
// react.js
history = useHistory()
history.go(-1)
原因
在网上查找了相关资料,原来动态切换iframe的src会导致增加一条iframe的历史浏览记录,无论vue还是react都是基于window.history做路由跳转,所以回退一步就是回退iframe的历史浏览记录。
解决办法
方法一
找到原因后,第一想法就是直接整个替换iframe,于是单独写了一个renderIframe
的方法,每次生成一个新的iframe,然而事与愿违。虚拟dom在diff过程中发现只有src变了,于是patch的时候直接更换src,最终回到了最初的起点。
// 写法一
const renderIframe = (src: string) => {
return <iframe src={
src} />
}
因为上面JSX最终调用的React.createElement,还是生成的虚拟节点,遂改成了下面这种写法:
// 写法二
const renderIframe = (src: string) => {
const iframe = document.createELement('iframe')
iframe.src = src
return iframe
}
方法二
巧用key
特性,在虚拟dom的diff算法中,key有着超高的地位,如果同一类型的虚拟节点的key不相同,就会直接销毁重新挂载,而没有key区分时就会尽可能的复用打补丁(patch)。根据这个特性,只需在iframe上增加不同的key
即可,本人直接使用的src。
// vue.js
<iframe :key="src" :src="src" />
// react.js
<iframe key={
src} src={
src} />