0
点赞
收藏
分享

微信扫一扫

【VUE】跨标签页多页数据传输的实现

霸姨 2022-01-25 阅读 55

前言

需求

数据可视化分析。
A页面是一张表单,在此填入各种筛选条件,然后点击提交。在新标签页B页面展示结果图表。
可以在A页面更新提交表单,B页面实时更新图表结果,但不会弹出新的页面。
关闭B页面,再点击A页面,会弹出新的B页面。
可以点击侧边栏“图表分析”直接跳转到B页面,“数据选择”跳转到A页面,两个页面已经填入和已经展示的数据不能消失。
简单地说,核心需求就是,在一个页面输入表单,在另一个页面实时更新数据。

解决思路

排除的解决方法

vue是单页面开发框架,也就是说,无法通过框架内部的方法来进行数据的传输(至少我没找到),因此有一下几种方法是无效或者不可行的:

  1. 组件通信。不能跨页面传递数据。
  2. vuex。每个页面的vuex是不通的。
  3. 路由参数。可行,但是无法实时更新数据。

要解决的问题

对需求进行抽象,总结出需要解决的若干环节,并逐一解决,具体需要解决的环节如下:

  1. 页面跳转,并打开新的页面。
  2. 记录页面数量,阻止多次打开同一页面。
  3. A页面更新数据之后,B页面能够实时更新数据。
  4. 不因离开页面而丢失A页面或者B页面已填入或展示的数据。

解决办法

1 页面跳转,并打开新的页面

核心代码:

window.open(
	this.$router.resolve({
    	path: "/compcharts",
        }).href,'_blank');

用window.open方法打开页面
$router的resolve解析路由
_blank实现在新标签页打开页面
把这段代码挂载到方法中即可

this.$router不能分离到utils文件夹下的.js文件中使用,只能在main.js声明了全局变量之后的.vue中使用,所以我暂时没能把其完全抽象剥离,后续如果花时间解决了再来更新此处博客,或者有朋友知道的话欢迎评论区评论,不胜感激。

2 记录页面数量,阻止多次打开同一页面

2.1 解决思路

在后端用一个变量,记录某页面已经打开的数量。
并用一个接口,实现不同页面的数量记录的查询、增加、减少。
在打开新页面前,先查询数量,小于1则打开新页面。
打开新页面后,在组件创建时调用接口增加数量(后续可能需要修改为页面打开,如修改了会来更新此处文章),在页面关闭时减少数量,在页面刷新时会在生命过程中使用上述两个方法所以数量不变。

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');
    },

由此,实现了前端在页面跳转之前的判断。
而在页面跳转之后的新页面中:
需要创建一个方法:

unloadHandler(){
            commonApi
                .page_count(-1, 'comp')
                .then((res) => {
                    console.log(res)
                }).catch((err) => {
                    console.log(err)
            })
        }

如果是增加数量则是把"-1"改成1即可,放在created中(可能需要改到页面的生命周期中,而不是vue的生命周期中,完成修改后更新本文)

然后,在mounted中挂载:

window.addEventListener('unload', () => this.unloadHandler())

最后,在beforeDestroy中卸载:

window.removeEventListener('unload', this.unloadHandler())

值得注意的是,你不能直接在vue的生命周期函数中使用方法,因为准确地触发事件的并不是组件的生命,而是这个标签页的生命。如果绑在了组件上,那么由于B页面的访问方式既有新标签页访问,又有单页面方式访问,所以组件的生命周期会出现Bug,需要再做分析处理。
(目前销毁的我已经改好了,但是新建的那个+1的计数绑在了created里,已经出现单页面组件keep-alive,未销毁组件的bug了,所以前文多次提到需要修改)
重中之重,要分析清楚触发事件的关键环节是组件的生命周期,还是浏览器页面的生命周期,他们是 不 一 样 的 。

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,返回的是更新后的数据。查询不会更改数量。
查询应当放在创建新页面之前(A页面),而对页面数量的增减应当放在新页面的生命周期中(B页面),不能在创建的同时进行增减。因为正如上文所言,行为应与事件紧密相关,如果放置在A页面查询之后,会引起与B页面数量增减的在逻辑上的不清晰乃至混乱,是更加不优雅难看的代码,也是不当的。

3 A页面更新数据之后,B页面能够实时更新数据

3.1 解决思路

A页面,只负责,发送表单数据,判断是否需要打开新页面。
B页面,只负责,获取结果数据,更新页面数量。
因此,在A页面中,发送所有的表单数据,由后端进行存储。
在B页面中,每秒向后端发送一次请求,获取最新数据,这个最新数据是后端使用存储的最新的表单数据,调用方法函数计算出的数据。
即,A页面,发送数据,更新后端的表单;B页面,发送请求,后端由存储的表单计算出图表数据,发给B页面。

3.2 要注意的点

为什么说这篇文章的解决办法有点笨呢,就是因为这个B页面每秒发一次请求的方式有点笨。
但是用vue这种单页面框架,A页面不能给B页面直接多页面跨页面地发送或者共享数据,B页面也无法不用网络请求就获取不同的(即实时的)后端计算出的数据,所以就目前我的技术而言便只能使用这一种笨笨的办法了。
值得注意的是,记得销毁计时器,否则单页面中切换组件,不会销毁组件,计时器就不会自动销毁,大量的定时请求计时器,就会把内存爆掉,也会把后端给爆掉。
这部分代码没其实没什么东西了

3.3 前端

首先,在A页面,就是调用一个“comp_filter”接口,发送表单数据。
业务代码不放了,就是个普通接口。
然后,在B页面,就是调用一个“comp_catch_data”接口,发送请求。然后使用定时器就好了。

window.setInterval(() => {
            setTimeout(() => {
			//调取接口
            }, 0)
        }, 1000)

记得销毁定时器

3.4 后端

业务代码就不放了。
就是一个接口,响应“comp_filter”,并像上文一样,更新一个保存请求参数数据的变量。
再加一个接口,响应“comp_catch_data”接口,根据保存的请求参数数据的变量,调用业务方法,计算出需要的数据,返回给前端即可。

4 不因离开页面而丢失A页面或者B页面已填入或展示的数据

keep-alive即可实现A页面去了别的页面之后,回来数据还在。
而因为后台保存了最新提交的一次表单的数据,所以B页面只要不停发送请求,就能由最新的表单数据获得所需的制图数据。
值得注意的是,后端的这两个接口要分开设计,不能合并成一个接口,否则在业务上、代码上,都会增加不小的复杂性,增加出各种bug的可能性,增加不同需求矛盾的可能性,并且使代码显得冗长、杂乱、不干净。

总结

并不是页面数据之间的传递,因为这无法实现。
而是将后端作为中转站,一个页面将重要数据发给后端暂存。
另一个页面发出请求,获取由后端暂存的实时数据计算出的结果。
从而实现了A页面数据更新,B页面实时更新,这样的多页面数据传输的效果。

举报

相关推荐

0 条评论