【VUE】跨标签页多页数据传输的实现
前言需要借助后端实现,是个有效但不够优雅的笨办法。需求数据可视化分析。A页面是一张表单,在此填入各种筛选条件,然后点击提交。在新标签页B页面展示结果图表。可以在A页面更新提交表单,B页面实时更新图表结果,但不会弹出新的页面。关闭B页面,再点击A页面,会弹出新的B页面。可以点击侧边栏“图表分析”直接跳转到B页面,“数据选择”跳转到A页面,两个页面已经填入和已经展示的数据不能消失。简单地说,核心需求就
前言
下文第一段会给出多项解决方法。后文则详细展开了后端配合的网络请求方法。
实际项目中后续改用了setInterval的不断轮询脏检查与网络请求方法结合的方式,本文内容并不是最新内容,一般应该也不会修改更新本文内容了,最重要的是下面的“所有方法”,都懂并选择自己所需要的就行。
所有方法
准备面试的时候看到了跨标签页数据传输方法的总结——
不同标签页间的通讯,本质原理就是去运用一些可以共享的中间介质,因此比较常用的有以下方法:
-
通过父页面window.open()和子页面postMessage(h5的新特性,可以实现简单的跨域通信)
异步下,通过 window.open('about: blank') 和 tab.location.href = '*'
-
设置同域下共享的localStorage与监听window.onstorage(相当于浏览器端的小型数据库,但无法跨浏览器通信)
重复写入相同的值无法触发 会受到浏览器隐身模式等的限制
-
设置共享cookie与不断轮询脏检查(setInterval)
-
借助服务端或者中间层实现(我的理解是,与3一样都是需要网络请求,只不过3是用cookie来维护数据的更新,4则是具体的自定义的业务逻辑方法)
参考资料:中高级前端大厂面试秘籍,为你保驾护航金三银四,直通大厂(上)
需求
数据可视化分析。
A页面是一张表单,在此填入各种筛选条件,然后点击提交。在新标签页B页面展示结果图表。
可以在A页面更新提交表单,B页面实时更新图表结果,但不会弹出新的页面。
关闭B页面,再点击A页面,会弹出新的B页面。
可以点击侧边栏“图表分析”直接跳转到B页面,“数据选择”跳转到A页面,两个页面已经填入和已经展示的数据不能消失。
简单地说,核心需求就是,在一个页面输入表单,在另一个页面实时更新数据。
解决思路
排除的解决方法
显然,以下方法可以轻易排除:
- 组件通信。不能跨页面传递数据。
- vuex。每个页面的vuex是不通的。
- 路由参数。可行,但是无法实时更新数据。
要解决的问题
对需求进行抽象,总结出需要解决的若干环节,并逐一解决,具体需要解决的环节如下:
- 页面跳转,并打开新的页面。
- 记录页面数量,阻止多次打开同一页面。
- A页面更新数据之后,B页面能够实时更新数据。
- 不因离开页面而丢失A页面或者B页面已填入或展示的数据。
- 如果能不同浏览器数据互通最好。(所以选用了网络请求的方法)
解决办法
下文读大标题,关注一下生命周期就行。
1 页面跳转,并打开新的页面
核心代码:
window.open(
this.$router.resolve({path: "/compcharts",}).href, '_blank'
);
用window.open方法打开页面
$router的resolve解析路由
_blank实现在新标签页打开页面
把这段代码挂载到方法中即可
2 页面计数及实时更新数据
2.1 解决思路
在后端用一个变量,记录B页面已经打开的数量。
并用一个接口,实现不同页面的数量记录的查询、增加、减少。
在打开新页面前,先查询数量,小于1则打开新页面。
A页面,只负责,发送表单数据,判断是否需要打开新页面。
B页面,只负责,获取结果数据,更新页面数量。
在A页面中,发送所有的表单数据,由后端进行存储。
在B页面中,每秒向后端发送一次请求,获取最新数据,这个最新数据是后端使用存储的最新的表单数据,调用方法函数计算出的数据。
2.2 前端
页面跳转方法:
jumppage() {
commonApi
.page_count(0, 'comp')
.then((res) => {
console.log(res)
if (res < 1) {
pagefunc
.open_new_window(this.$router.resolve({
path: "/compcharts",
}))
} else {
console.log("页面已经打开")
}
}).catch((err) => {
console.log(err)
})
},
其中的page_count是:
page_count(changenum,changepage){
console.log("page_count")
return request({
url: config.url.common.pageCount,
method: 'post',
data: {
changenum: changenum,
changepage: changepage
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
},
而pagefunc中的open_new_window其实就是上文页面跳转的一个简单封装罢了:
open_new_window(chartsData) {
window.open(chartsData.href, '_blank');
},
由此,实现了前端在页面跳转之前的判断。
而在页面跳转之后的新页面中:
data() {
return {
intervalId:'',
}
},
methods: {
findData(){
compApi
.comp_catch_data()
.then((response) => {
console.log("response")
console.log(response)
let dataIn = transformTableData(response[1])
setTimeout(() => {
//把数据传给父组件
this.outTableData = dataIn
}, 300);
}).catch((err) => {
console.log(err);
});
},
catachData(){
this.intervalId = setInterval(() => {
setTimeout(() => {
///调取接口
this.findData()
}, 0)
}, 1000)
}
},
mounted(){
window.addEventListener('unload', () => page_change(-1,'comp'))
},
activated() {
this.catachData()
page_change(1,'comp')
},
deactivated(){
clearInterval(this.intervalId)
page_change(-1,'comp')
},
beforeDestroy() {
window.removeEventListener('unload', page_change(-1,'comp'))
},
其中的page_change是对前文那个page_count的一个封装。
两个核心问题,一个是页面数量的计数,第二个是定时器每秒发送一个请求。
要解决的关键场景是两个,第一个是在同一页面中的组件切换,第二个是新标签页的创建和关闭。
同一页面组件切换场景,keep-alive的情况下,会触发activated和deactivated生命周期函数。即,将组件丢进缓存和把组件从缓存里取出来的时候会触发。以此来进行页面计数、定时器开启与关闭。
新标签也的创建和关闭场景,需要监控标签页window,mounted挂载时要开始对页面的unload事件进行监控,页面关闭组件销毁前要把监控给关闭掉。而对于定时器,随着页面的打开,activated也会触发,随着页面关闭,一切都销毁了,更遑论定时器。
选用合适的生命周期函数和浏览器事件,是此中关键。
2.3 后端
建一个变量,对页面数量进行存储:
pagecount = {
'test': 0,
'comp': 0,
'freq': 0,
'quie': 0
}
返回更新后的数据:
class PageCountHandler(BaseHandler):
def post(self, *args, **kwargs):
changenum = self.get_argument('changenum')
changepage = self.get_argument('changepage')
global pagecount
pagecount[changepage] = pagecount[changepage] + int(changenum)
json_str = json.dumps(pagecount[changepage])
self.write(json_str)
对于查询的,changenum=0即可,增加是1,减少是-1,返回的是更新后的数据。查询不会更改数量。
至于数据的实时更新。
就是一个接口,响应“comp_filter
”,并像上文pagecount
一样,更新一个保存请求参数数据的变量compquest
。
再加一个接口,响应“comp_catch_data
”接口,根据保存的请求参数数据的变量,调用业务方法,计算出需要的数据,返回给前端即可。
业务代码就不放了。
用全局变量是行之有效的笨办法,有条件的朋友最好改成更好的暂存方式,比如缓存之类的。目前版本是不支持也不需要支持多用户的,要改成支持并不麻烦但无必要。
3 缓存页面数据
用keep-alive
即可实现A页面去了别的页面之后,回来数据还在。
而因为后台保存了最新提交的一次表单的数据,所以B页面只要不停发送请求,就能由最新的表单数据获得所需的制图数据。
值得注意的是,后端的这两个接口要分开设计,不能合并成一个接口,否则在业务上、代码上,都会增加不小的复杂性,增加出各种bug的可能性,增加不同需求矛盾的可能性,并且使代码显得冗长、杂乱、不干净。
总结
并不是页面数据之间的传递,因为这无法实现。
而是将后端作为中转站,一个页面将重要数据发给后端暂存。
另一个页面发出请求,获取由后端暂存的实时数据计算出的结果。
从而实现了A页面数据更新,B页面实时更新,这样的多页面数据传输的效果。
更多推荐
所有评论(0)