背景

在我的项目开发过程中,常常会遇到从上一个页面跳转到下一个页面的需要,俗称下钻。比方在概览页面的数据,须要查看详情,点击某个图表或按钮,即可跳转到详情页面查看详情数据。

目前为止,咱们的我的项目中还没有一个对立的页面跳转办法,实现页面跳转的形式也因人而异,并且现有的很多我的项目只能在两个页面之间来回跳转,根本没有残缺的实现多个页面相互跳转的性能。

关联页面跳转做为我的项目的罕用性能,并且执行的都是重复性高的代码逻辑,十分有必要把相干的逻辑抽出来,封装成简略易用的公共办法和公共组件。

目标

对立各个我的项目的关联跳转办法逻辑,封装成简略易用的公共组件。

方案设计

首先,剖析一下关联页面跳转大略的逻辑步骤:

  1. 进入页面 A;
  2. 页面A跳转到页面 B;
  3. 进入页面 B;
  4. 返回页面 A;
  5. 进入页面 A,即从新回到步骤 1 开始。

而后,对以上步骤进行细分:

  1. 假如步骤 1 是失常进入页面,这时候没有逻辑须要解决;
  2. 步骤 2 须要从页面 A 跳转到页面 B,要实现这一步,就必须晓得页面 B 的路由地址,通过 VueRouter 跳转到页面 B 的路由地址。并且如果页面 B 须要的一些查问数据,就要把页面 B 的数据保存起来,等到步骤 3 应用;
  3. 进入页面B后,如果要获取页面 A 传过来的一些查问数据,就要先判断是不是从页面 A 跳转过来的,如果是,就从保留数据的中央获取页面 A 传过来的数据;
  4. 页面 B 返回页面 A,就必须晓得页面 A 的路由地址,通过 VueRouter 跳转到页面 A 的路由地址。这里的路由地址,须要在步骤 2 跳转之前进行保留,这里才能够取到;
  5. 能够发现,步骤1和步骤5都是进入页面 A,然而执行的逻辑却不一样,所以,页面 A 如果要复原跳转到页面 B 之前的一些数据,就要先判断是不是从页面 B 跳转回来的,如果是,就从保留数据的中央获取跳转之前页面 A 的数据;这里的跳转之前的数据,须要在步骤 2 跳转之前进行保留,这里才能够取到。

接下来,为了实现上述的逻辑,咱们先确定用来保留页面 A页面 B 的数据的办法,这里采纳的是 VUEX。再梳理一下以上逻辑步骤,画出流程图。

流程图

源页面

指标页面

具体实现

源页面跳转到指标页面

这一步的逻辑写在 VUEX 中,每次须要进行这一步操作,间接调 VUEX 中对应的办法即可。具体实现逻辑,就是先把源页面和指标页面的标识增加到路由参数上(目标是为了辨别以后页面是进行的指标页面还是返回的源页面),再保留源页面和指标页面的数据,而后进行路由跳转。

在 store.js 中增加两个以下两个变量:

tgtPageParams: {}, // 关联跳转的指标页面数据(只保留一项数据)srcPageParams: [], // 关联跳转的源页面数据(数组类型,保留多个页面的数据,能够多层返回,直到返回初始页面)

而后增加以下办法:

// 关联跳转,跳转到指标页面,并保留源页面和指标页面的数据到 VuexgoTargetPage(state, options) {    // 在源页面的 query 增加 tgtPageName 标识,记住指标页面    options.srcParams.query = Object.assign({}, options.srcParams.query, { tgtPageName: options.tgtParams.name });    // 在指标页面的 query 增加 srcPageName 标识,记住源页面    options.tgtParams.query = Object.assign({}, options.tgtParams.query, { srcPageName: options.srcParams.name });    state.srcPageParams.push(options.srcParams); // 保留源页面数据    state.tgtPageParams = options.tgtParams; // 保留指标页面数据    router.push({ name: options.tgtParams.name, query: options.tgtParams.query }); // 跳转到指标页面},

指标页面返回源页面

这一步的逻辑写在 VUEX 中,每次须要进行这一步操作,间接调 VUEX 中对应的办法即可。具体实现逻辑,就是从 state.srcPageParams 中取到源页面的数据(包含路由地址和参数),而后进行路由跳转。

VUEX 中增加以下办法:

// 关联跳转,跳转回源页面goSourcePage(state, vm) {    let obj = state.srcPageParams.slice(-1)[0]; // 取数组的最初一项    // 如果 Vuex 有上一页的数据,则依据 Vuex 的数据返回上一面    if (obj && Object.keys(obj).length > 0) {        router.push({ name: obj.name, query: obj.query }); // 进行跳转    }    // 如果 Vuex 中没有上一页的数据,然而路由上有上一页的标记,则依据路由标记返回上一页(这是为了避免在详情页中刷新时,Vuex 数据失落,无奈返回上一页的问题)    else if (vm && vm.$route.query.srcPageName) {        router.push({ name: vm.$route.query.srcPageName });    }},

进入指标页面应用VUEX数据/返回源页面复原VUEX数据

这一步的逻辑是把下面方案设计中的步骤 3步骤 5 合并起来了,写在公共函数文件中,每次须要进行这一步操作,间接调 Vue.prototype 中对应的办法即可。具体实现逻辑是:判断以后页面是源页面还是指标页面,如果是指标页面,那就应用源页面传过来的数据,如果是源页面,就复原跳转之前的数据。

在公共函数文件 utils.js 中增加以下办法,并挂载到 Vue.prototype 上:

/** * 关联跳转相干的页面能够应用此办法 * 1、源页面:能够把保留到 Vuex 中的数据恢复到 data 中应用 * 2、指标页面:能够把源页面传递到 Vuex 中的数据放到 data 中应用 * 3、源页面数据恢复后,删除 Vuex 中对应的备份数据,删除路由上保留的指标页标识 * @param vm {object} 必填 以后 Vue 组件实例 */$changeVueData: (vm) => {    let tgtParams = store.state.tgtPageParams;    let srcParams = vm.$store.state.srcPageParams.slice(-1)[0] || {}; // 取最初一个元素值    let name = vm.$route.name;    let query = vm.$deepCopyJSON(vm.$route.query); // 这里深拷贝是因为 $route.query 须要更新    // 判断当前页是 指标页面 还是 源页面    // 判断条件是 先判断路由名是否统一,再判断指定的 query 的属性值是否也统一    let isTgtPage = tgtParams.name === name &&        (tgtParams.checkKeys ? tgtParams.checkKeys.every(key => tgtParams.query[key] === query[key]) : true);    let isSrcPage = srcParams.name === name &&        (srcParams.checkKeys ? srcParams.checkKeys.every(key => srcParams.query[key] === query[key]) : true);    // 如果以后页面是指标页面    if (isTgtPage) {        Object.assign(vm.$data, tgtParams.data || {}); // 将 源页面传过来的数据 更新到以后页面的 data(),以便页面进行查问    }    // 如果以后页面是源页面    if (isSrcPage) {        Object.assign(vm.$data, srcParams.data || {}); // 跳转前保留的数据 更新到以后页面的 data(),以便页面进行还原        store.commit('popSourcePage'); // 将 srcPageParams 的最初一项数据删除        // 源页面关联跳转逻辑完结后,革除掉当前页路由上的指标页标识,避免刷新页面有问题        delete query.tgtPageName;        vm.$router.push({ name, query });    }},

返回上一页按钮

为了更不便的应用关联跳转性能,把返回上一页按钮封装成了一个组件,具体实现代码如下:

// back-button.vue<template>    <button class="primary-btn return-btn" v-if="showBackBtn" @click="backFn">        <i class="return-icon"></i>{{ backText }}    </button></template><script>export default {    name: 'back-button',    props: {        // 返回上一页的文字        backText: {            type: String,            default: () => '上一步'        },        // 返回上一页的函数        backFn: {            type: Function,            default: () => {}        }    },    data() {        return {            showBackBtn: false,        };    },    mounted() {        this.setBackBtnShow();    },    activated() {        this.setBackBtnShow();    },    methods: {        // 更新返回上一页按钮的状态        setBackBtnShow() {            this.$nextTick(() => {                let srcPage = this.$store.state.srcPageParams.slice(-1)[0];                this.showBackBtn = Boolean(srcPage && Object.keys(srcPage).length > 0);            });        },    },};</script><style scoped lang="scss"></style>

容错局部

思考到关联跳转的过程中,有可能用户会忽然中断,或者刷新页面等异样操作,设计了局部容错机制:

// 根组件 App.vue/*...省略的代码...*/watch: {    // 监听,当路由发生变化的时候执行    $route(to, from) {        // 如果即不是源页面,也不是指标页面,则清空 Vuex 中保留的数据        // 避免在关联跳转的过程中切换菜单或者进行其余操作,导致 Vuex 中有上一次关联跳转残留的数据        if (!to.query.srcPageName && !to.query.tgtPageName) {            this.$store.commit('clearTargetPage');            this.$store.commit('clearSourcePage');        }    },},/*...省略的代码...*/

应用示例

根据上述方案设计局部的步骤:
步骤 1 和步骤 5 ,进入页面 A,逻辑在同个页面,代码如下:

// 页面 A.vue/*...省略的代码...*/mounted() {    vm = this;    vm.$changeVueData(vm); // 关联跳转相干页面,每次进入页面,必须执行 $changeVueData 函数,具体用法参考调用办法的正文    vm.ready();},/*...省略的代码...*/

步骤 2,从页面A跳转到页面 B,代码如下:

// 页面 A.vue/*...省略的代码...*/methods: {    // 跳转到 B 页面    goUserSituation: function (name) {        let srcParams = {            name: vm.$route.name,            query: vm.$route.query        };        let tgtParams = {            name: 'user-situation',            data: {                checkedSystem: name            }        };        vm.$goTargetPage(srcParams, tgtParams);    },},/*...省略的代码...*/

步骤 3,进入页面 B,代码如下:

// 页面 B.vue/*...省略的代码...*/mounted() {    vm = this;    vm.$changeVueData(vm); // 关联跳转相干页面,每次进入页面,必须执行 $changeVueData 函数,具体用法参考调用办法的正文    vm.ready();},/*...省略的代码...*/

步骤 4,返回页面 A,代码如下:

// 页面 B.vue/*...省略的代码...*/<template>    <div>        <backButton :backFn="$goSourcePage"></backButton>        /*...省略的代码...*/    </div></template>/*...省略的代码...*/

总结

本文具体介绍了关联页面多级跳转(页面下钻)性能的实现,核心思想便是通过 VUEX 全局状态治理,保留关联跳转源页面和指标页面的数据,在跳转之前,把须要的数据保存起来,跳转到指标页面时,把指标页面须要的数据从 VUEX 中获取,跳转回源页面时,把源页面的数据从 VUEX 中复原。

把这几个要害动作,封装成通用办法和组件,即对立了各个我的项目的关联页面跳转形式,也进步了代码的品质,更有利于前期保护。另外,文章中的容错局部,只写了一部分,如果后续须要持续欠缺该性能,能够把容错局部欠缺一下。

最初,感激大家的浏览,心愿对大家有帮忙,如果有不同的想法和倡议,欢送提出。