Vue2实现关闭新打开的填报页面,刷新旧页面表格数据
方法一: 使用window对象的opener属性
window.opener:返回打开当前窗口的那个窗口的引用,例如:在 window A 中打开了 window B,B.opener 返回 A.
案例:旧页面是填报表格(包含状态:比如待填报、已填报),点击“填报”按钮后,跳转到新页面进行信息填报。填报完成,点击新页面的“填报完成”按钮后,刷新旧页面的表格请求(刷新后,新请求回的表格数据的状态变为“已填报”),关闭新页面。
以下为vue示例:
旧页面:
// mounted时,给window对象赋值属性reflashTable
mounted() {
window.reflashTable = this.reflashTable
},
/**
* beforeDestroy时,进行垃圾回收,
* 因为在window挂了全局对象,要及时清空,确保可维护性
*/
beforeDestroy() {
// 清空window.reflashTabl
if (window.reflashTable) {
window.reflashTable = null
}
},
methods: {
reflashTable() {
// 请求表格数据方法
},
add() {
// 填报,打开新页面
const href = '...'
window.open(href, '_blank')
}
}
新页面:
methods: {
async submit() {
// 新页面,提交信息成功后
const res = await ...
if (res.code === 200) {
// 刷新父页面数据
if (window.opener) {
window.opener.reflashTable()
}
// 关闭新页面
window.close()
}
}
}
注意:方法一如果新打开的页面和旧页面存在跨域,例如新页面和旧页面的域名不同时,js代码window.opener.reflashTable是不执行的,解决跨域问题,见方法三window的postMessage方法实现跨源通信。
参考文献:
window.opener - Web API | MDN (mozilla.org)
方法二:使用document的visibilitychange事件
Document:visibilitychange 事件:当其选项卡的内容变得可见或被隐藏时,会在 document 上触发 visibilitychange 事件。注意:该事件不可取消。
同样,给出对应方法二的示例,vue示例如下:
旧页面:
// mounted时,监听visibilitychange事件
mounted() {
// 监听当前tab是否可见,可见性变化事件,用于跳转到新页面时,返回自动刷新页面
// 注意:visibilitychange事件不能清除
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
// console.log('visible')
// 可见时,重新查询。
// 请求表格数据方法
this.reflashTable()
} else {
// console.log('hidden')
}
})
},
methods: {
reflashTable() {
// 请求表格数据方法
},
add() {
// 填报,打开新页面
const href = '...'
window.open(href, '_blank')
}
}
新页面:
methods: {
async submit() {
// 新页面,提交信息成功后
const res = await ...
if (res.code === 200) {
// 直接关闭新页面就行
window.close()
}
}
}
方法二与方法一的区别:方法二是由旧页面监听visibilitychange事件来自行控制自己,只要重新切换回旧页面的选项卡时,就会重新请求表格数据;而方法一是新页面通过window的opener属性,拿到旧页面的window对象,由新页面控制触发旧页面的重新请求。
参考文献:
Document:visibilitychange 事件 - Web API | MDN (mozilla.org)
方法三: 使用window对象的postMessage方法和message事件
window.postMessage() 方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为 https),端口号(443 为 https 的默认值),以及主机 (两个页面的模数 Document.domain
设置为相同的值) 时,这两个脚本才能相互通信。window.postMessage() 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。强烈建议阅读一下mdn对该部分的描述。
同样,给出对应方法三的示例,vue示例如下(注意:以下代码未真实试验过,请辨别使用):
旧页面:
// mounted时,旧页面监听message事件
mounted() {
window.addEventListener("message", this.receiveMessage, false);
},
methods: {
receiveMessage(event) {
// For Chrome, the origin property is in the event.originalEvent
var origin = event.origin || event.originalEvent.origin;
// 为了安全,使用 origin 属性验证发件人的身份
if (origin !== "http://example.org:8080") return; // "http://example.org:8080"改为新页面的对应的。注意:部署后,域名等的改变,配置为部署后的
// if (origin !== window.location.origin) return; // 不跨域时,直接判断
// 请求表格数据方法
this.reflashTable(event)
},
reflashTable(event) {
// 请求表格数据方法
},
add() {
// 填报,打开新页面
const href = '...'
window.open(href, '_blank')
}
}
新页面:
methods: {
async submit() {
// 新页面,提交信息成功后
const res = await ...
if (res.code === 200) {
// 向父页面通信
if (window.opener) {
const targetOrigin = window.opener.location.origin
window.opener.postMessage("message", targetOrigin)
}
// 关闭新页面
window.close()
}
}
}
方法三与方法一:方法三解决了方法一不能跨源通信的问题。
参考文献:
window.postMessage - Web API | MDN (mozilla.org)
总结
在真实项目应用上
-
若新页面和旧页面不存在跨域问题,直接使用方法一或方法二(方法三也行,相对方法一和方法二复杂些)。方法一相对简单点,但存在跨源通信问题。方法二的visibilitychange事件不能取消且只要重新切换回旧页面该tab,就会触发事件。
-
若新页面和旧页面存在跨域问题,使用方法三。但旧页面为了安全(使用 origin 属性验证发件人的身份),判断时,需改为部署后新页面的origin。
如果文章存在什么问题,或者还有其他实现思路,欢迎在评论区讨论