因项目需求,在原网站内须要嵌入另外一个关联网站的内容,很天然的想到用iframe去解决。可是进入内联网站依赖于主网站的accessToken进行身份验证,所以就涉及到传递token的方式,以及传递的时机这两方面,而内联网站的首次渲染速度过慢问题,在排除webpack打包优化这方面影响后,颇有可能就是接受token不及时致使延迟渲染。vue
另外,这两个都是vue项目。webpack
先上案例代码web
// 父页面
<template>
<iframe ref="framePage" @load="deliverToken"></iframe>
</template>
<script>
export default {
computed: {
token() {
return token // 简单举例
}
},
methods: {
deliverToken() {
this.refs.framePage.contentWindow.postMessage({type: 'token', data: this.token}, '*')
}
}
}
</script>
// 子页面
<template>
<div id="app"></div>
</template>
<script>
let token = null
Http() // 这个函数里,设置了一些http请求头信息,以及用postMessage设置的语言、主题等信息传递方法
window.addEventListener('message', function(evt) {
const msg = evt.data
if (msg.type !== token) { return }
if (token !== msg.data) {
token = msg.data
new Vue({
el: '#app'
})
}
})
</script>复制代码
(上述代码让子项目的渲染时间在网络状态良好状况下3-20秒内不按期发生。。。)bash
两个项目直接传递和接收消息,是使用postMessage达成的。咱们知道,postMessage是一个异步方法,他的执行排在同步方法后面。postMessage只负责传递消息,并不负责监听消息是否被接收,而是在消息一旦传递就马上给传递者返回成功状态。 网络
问题一:token的传递依赖于load函数的触发,若触发时机不正确,会致使token获取不到。app
划重点异步
缘由:使用单页面开发的Vue程序,在Vue代码开始执行以前就已经触发了onload()。此时iframe中包含的是一个空的document。虽然在子项目完成挂载以后,依旧会再次触发onload事件,但传递token的最佳时机已经错过。能够想到,传递token的最佳时机是在页面一挂载的时候。函数
问题二:子页面是一个独立的vue项目,在子组件挂载以前就有同步函数、项目自身的postMessage执行。父页面传递的消息须要排队等待被接收。post
缘由:因为子项目中同步函数的执行,会阻塞异步postMessage的消息接收,此时就算传递了消息也没办法及时获取。优化
因而可知,在vue项目中用onload事件并不靠谱(--!!,原来坑在这)
那应该什么时候向子项目传递token才能确保页面能够正常加载呢?
由子页面通知父页面能够传递消息了,替代onload事件
改良案例以下
// 父页面
<template>
<iframe ref="framePage"></iframe>
</template>
<script>
export default {
data() {
return {
isChildReady: false
}
},
computed: {
token() {
return token // 简单举例
}
},
beforeMount() {
addEventListener('message', function (evt) {
if (evt.data.type !== 'childStatus') { return }
this.isChildReady = evt.data.data
})
},
methods: {
deliverToken() {
this.refs.framePage.contentWindow.postMessage({type: 'token', data: this.token}, '*')
}
},
watch: {
isChildReady(isReady) {
if (!isReady) { return }
this.deliverToken()
}
}
}
</script>
// 子页面
<template>
<div id="app"></div>
</template>
<script>
let token = null
Http() // 这个函数里,设置了一些http请求头信息,以及用postMessage设置的语言、主题等信息传递方法
window.parent.postMessage({type: 'childStatus', data: 'isReady'}, '*')
window.addEventListener('message', function(evt) {
const msg = evt.data
if (msg.type !== token) { return }
if (token !== msg.data) {
token = msg.data
new Vue({
el: '#app'
})
}
})
</script>复制代码
当子项目的根节点挂载后,postMessage通知父项目传递token
其一,避免了onload事件触发不许确的问题;
第二,避免消息队列的等待致使的接收不及时问题。
最终结果,子项目的渲染时间在网络状态良好状况下,被控制在0-2秒内。
以上就是本周遇到并解决的vue中iframe内嵌项目,因为postMessage接收不到致使的首页加载过慢的问题。除了postMessage自己的没法监听是否接收到消息问题以外,还有onload事件在Vue项目中的问题。