最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Vue 实现关联页面多级跳转(页面下钻)功能

    正文概述 掘金(Chieffo)   2021-03-15   510

    背景

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

    目前为止,我们的项目中还没有一个统一的页面跳转方法,实现页面跳转的方式也因人而异,并且现有的很多项目只能在两个页面之间来回跳转,基本没有完整的实现多个页面互相跳转的功能。

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

    目的

    统一各个项目的关联跳转方法逻辑,封装成简单易用的公共组件。

    方案设计

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

    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。再梳理一下以上逻辑步骤,画出流程图。

    流程图

    源页面

    Vue 实现关联页面多级跳转(页面下钻)功能

    目标页面

    Vue 实现关联页面多级跳转(页面下钻)功能

    具体实现

    源页面跳转到目标页面

    这一步的逻辑写在 VUEX 中,每次需要进行这一步操作,直接调 VUEX 中对应的方法即可。具体实现逻辑,就是先把源页面和目标页面的标识添加到路由参数上(目的是为了区分当前页面是进行的目标页面还是返回的源页面),再保存源页面和目标页面的数据,然后进行路由跳转。

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

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

    然后添加以下方法:

    // 关联跳转,跳转到目标页面,并保存源页面和目标页面的数据到 Vuex
    goTargetPage(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 中恢复。

    把这几个关键动作,封装成通用方法和组件,即统一了各个项目的关联页面跳转方式,也提高了代码的质量,更有利于后期维护。另外,文章中的容错部分,只写了一部分,如果后续需要继续完善该功能,可以把容错部分完善一下。

    最后,感谢大家的阅读,希望对大家有帮助,如果有不同的想法和建议,欢迎提出。


    起源地下载网 » Vue 实现关联页面多级跳转(页面下钻)功能

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元