Vue實現(xiàn)關(guān)聯(lián)頁面多級跳轉(zhuǎn)(頁面下鉆)功能的完整實例
背景
在項目開發(fā)過程中,經(jīng)常會遇到從上一個頁面跳轉(zhuǎn)到下一個頁面的需求,俗稱 下鉆 。比如在概覽頁面的數(shù)據(jù),需要查看詳情,點擊某個圖表或按鈕,即可跳轉(zhuǎn)到詳情頁面查看詳情數(shù)據(jù)。
目前為止,我們的項目中還沒有一個統(tǒng)一的頁面跳轉(zhuǎn)方法,實現(xiàn)頁面跳轉(zhuǎn)的方式也因人而異,并且現(xiàn)有的很多項目只能在兩個頁面之間來回跳轉(zhuǎn),基本沒有完整的實現(xiàn)多個頁面互相跳轉(zhuǎn)的功能。
關(guān)聯(lián)頁面跳轉(zhuǎn)做為項目的常用功能,并且執(zhí)行的都是重復性高的代碼邏輯,非常有必要把相關(guān)的邏輯抽出來,封裝成簡單易用的公共方法和公共組件。
目的
統(tǒng)一各個項目的關(guān)聯(lián)跳轉(zhuǎn)方法邏輯,封裝成簡單易用的公共組件。
方案設(shè)計
首先,分析一下關(guān)聯(lián)頁面跳轉(zhuǎn)大概的邏輯步驟:
- 進入 頁面 A ;
- 從 頁面A 跳轉(zhuǎn)到 頁面 B ;
- 進入 頁面 B ;
- 返回 頁面 A ;
- 進入 頁面 A ,即重新回到步驟 1 開始。
然后,對以上步驟進行細分:
- 假設(shè)步驟 1 是正常進入頁面,這時候沒有邏輯需要處理;
- 步驟 2 需要從 頁面 A 跳轉(zhuǎn)到 頁面 B ,要實現(xiàn)這一步,就必需知道 頁面 B 的路由地址,通過 VueRouter 跳轉(zhuǎn)到 頁面 B 的路由地址。并且如果 頁面 B 需要的一些查詢數(shù)據(jù),就要把 頁面 B 的數(shù)據(jù)保存起來,等到步驟 3 使用;
- 進入 頁面B 后,如果要獲取 頁面 A 傳過來的一些查詢數(shù)據(jù),就要先判斷是不是從 頁面 A 跳轉(zhuǎn)過來的,如果是,就從保存數(shù)據(jù)的地方獲取 頁面 A 傳過來的數(shù)據(jù);
- 從 頁面 B 返回 頁面 A ,就必需知道 頁面 A 的路由地址,通過 VueRouter 跳轉(zhuǎn)到 頁面 A 的路由地址。這里的路由地址,需要在步驟 2 跳轉(zhuǎn)之前進行保存,這里才可以取到;
- 可以發(fā)現(xiàn),步驟1和步驟5都是進入 頁面 A ,但是執(zhí)行的邏輯卻不一樣,所以, 頁面 A 如果要恢復跳轉(zhuǎn)到 頁面 B 之前的一些數(shù)據(jù),就要先判斷是不是從 頁面 B 跳轉(zhuǎn)回來的,如果是,就從保存數(shù)據(jù)的地方獲取跳轉(zhuǎn)之前 頁面 A 的數(shù)據(jù);這里的跳轉(zhuǎn)之前的數(shù)據(jù),需要在步驟 2 跳轉(zhuǎn)之前進行保存,這里才可以取到。
接下來,為了實現(xiàn)上述的邏輯,我們先確定用來保存 頁面 A 和 頁面 B 的數(shù)據(jù)的方法,這里采用的是 VUEX 。再梳理一下以上邏輯步驟,畫出流程圖。
流程圖
源頁面

目標頁面

具體實現(xiàn)
源頁面跳轉(zhuǎn)到目標頁面
這一步的邏輯寫在 VUEX 中,每次需要進行這一步操作,直接調(diào) VUEX 中對應的方法即可。具體實現(xiàn)邏輯,就是先把源頁面和目標頁面的標識添加到路由參數(shù)上(目的是為了區(qū)分當前頁面是進行的目標頁面還是返回的源頁面),再保存源頁面和目標頁面的數(shù)據(jù),然后進行路由跳轉(zhuǎn)。
在 store.js 中添加兩個以下兩個變量:
tgtPageParams: {}, // 關(guān)聯(lián)跳轉(zhuǎn)的目標頁面數(shù)據(jù)(只保留一項數(shù)據(jù))
srcPageParams: [], // 關(guān)聯(lián)跳轉(zhuǎn)的源頁面數(shù)據(jù)(數(shù)組類型,保留多個頁面的數(shù)據(jù),可以多層返回,直到返回初始頁面)
然后添加以下方法:
// 關(guān)聯(lián)跳轉(zhuǎn),跳轉(zhuǎn)到目標頁面,并保存源頁面和目標頁面的數(shù)據(jù)到 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); // 保存源頁面數(shù)據(jù)
state.tgtPageParams = options.tgtParams; // 保存目標頁面數(shù)據(jù)
router.push({ name: options.tgtParams.name, query: options.tgtParams.query }); // 跳轉(zhuǎn)到目標頁面
},
目標頁面返回源頁面
這一步的邏輯寫在 VUEX 中,每次需要進行這一步操作,直接調(diào) VUEX 中對應的方法即可。具體實現(xiàn)邏輯,就是從 state.srcPageParams 中取到源頁面的數(shù)據(jù)(包括路由地址和參數(shù)),然后進行路由跳轉(zhuǎn)。
在 VUEX 中添加以下方法:
// 關(guān)聯(lián)跳轉(zhuǎn),跳轉(zhuǎn)回源頁面
goSourcePage(state, vm) {
let obj = state.srcPageParams.slice(-1)[0]; // 取數(shù)組的最后一項
// 如果 Vuex 有上一頁的數(shù)據(jù),則根據(jù) Vuex 的數(shù)據(jù)返回上一面
if (obj && Object.keys(obj).length > 0) {
router.push({ name: obj.name, query: obj.query }); // 進行跳轉(zhuǎn)
}
// 如果 Vuex 中沒有上一頁的數(shù)據(jù),但是路由上有上一頁的標志,則根據(jù)路由標志返回上一頁(這是為了防止在詳情頁中刷新時,Vuex 數(shù)據(jù)丟失,無法返回上一頁的問題)
else if (vm && vm.$route.query.srcPageName) {
router.push({ name: vm.$route.query.srcPageName });
}
},
進入目標頁面使用VUEX數(shù)據(jù)/返回源頁面恢復VUEX數(shù)據(jù)
這一步的邏輯是把上面方案設(shè)計中的 步驟 3 和 步驟 5 合并起來了,寫在公共函數(shù)文件中,每次需要進行這一步操作,直接調(diào) Vue.prototype 中對應的方法即可。具體實現(xiàn)邏輯是:判斷當前頁面是源頁面還是目標頁面,如果是目標頁面,那就使用源頁面?zhèn)鬟^來的數(shù)據(jù),如果是源頁面,就恢復跳轉(zhuǎn)之前的數(shù)據(jù)。
在公共函數(shù)文件 utils.js 中添加以下方法,并掛載到 Vue.prototype 上:
/**
* 關(guān)聯(lián)跳轉(zhuǎn)相關(guān)的頁面可以使用此方法
* 1、源頁面:可以把保存到 Vuex 中的數(shù)據(jù)恢復到 data 中使用
* 2、目標頁面:可以把源頁面?zhèn)鬟f到 Vuex 中的數(shù)據(jù)放到 data 中使用
* 3、源頁面數(shù)據(jù)恢復后,刪除 Vuex 中對應的備份數(shù)據(jù),刪除路由上保存的目標頁標識
* @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 || {}); // 將 源頁面?zhèn)鬟^來的數(shù)據(jù) 更新到當前頁面的 data(),以便頁面進行查詢
}
// 如果當前頁面是源頁面
if (isSrcPage) {
Object.assign(vm.$data, srcParams.data || {}); // 跳轉(zhuǎn)前保存的數(shù)據(jù) 更新到當前頁面的 data(),以便頁面進行還原
store.commit('popSourcePage'); // 將 srcPageParams 的最后一項數(shù)據(jù)刪除
// 源頁面關(guān)聯(lián)跳轉(zhuǎn)邏輯結(jié)束后,清除掉當前頁路由上的目標頁標識,防止刷新頁面有問題
delete query.tgtPageName;
vm.$router.push({ name, query });
}
},
返回上一頁按鈕
為了更方便的使用關(guān)聯(lián)跳轉(zhuǎn)功能,把返回上一頁按鈕封裝成了一個組件,具體實現(xiàn)代碼如下:
// 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: () => '上一步'
},
// 返回上一頁的函數(shù)
backFn: {
type: Function,
default: () => {}
}
},
data() {
return {
showBackBtn: false,
};
},
mounted() {
this.setBackBtnShow();
},
activated() {
this.setBackBtnShow();
},
methods: {
// 更新返回上一頁按鈕的狀態(tài)
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>
容錯部分
考慮到關(guān)聯(lián)跳轉(zhuǎn)的過程中,有可能用戶會突然中斷,或者刷新頁面等異常操作,設(shè)計了部分容錯機制:
// 根組件 App.vue
/*...省略的代碼...*/
watch: {
// 監(jiān)聽,當路由發(fā)生變化的時候執(zhí)行
$route(to, from) {
// 如果即不是源頁面,也不是目標頁面,則清空 Vuex 中保存的數(shù)據(jù)
// 防止在關(guān)聯(lián)跳轉(zhuǎn)的過程中切換菜單或者進行其他操作,導致 Vuex 中有上一次關(guān)聯(lián)跳轉(zhuǎn)殘留的數(shù)據(jù)
if (!to.query.srcPageName && !to.query.tgtPageName) {
this.$store.commit('clearTargetPage');
this.$store.commit('clearSourcePage');
}
},
},
/*...省略的代碼...*/
使用示例
根據(jù)上述方案設(shè)計部分的步驟:
步驟 1 和步驟 5 ,進入 頁面 A ,邏輯在同個頁面,代碼如下:
// 頁面 A.vue
/*...省略的代碼...*/
mounted() {
vm = this;
vm.$changeVueData(vm); // 關(guān)聯(lián)跳轉(zhuǎn)相關(guān)頁面,每次進入頁面,必需執(zhí)行 $changeVueData 函數(shù),具體用法參考調(diào)用方法的注釋
vm.ready();
},
/*...省略的代碼...*/
步驟 2,從 頁面A 跳轉(zhuǎn)到 頁面 B ,代碼如下:
// 頁面 A.vue
/*...省略的代碼...*/
methods: {
// 跳轉(zhuǎn)到 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); // 關(guān)聯(lián)跳轉(zhuǎn)相關(guān)頁面,每次進入頁面,必需執(zhí)行 $changeVueData 函數(shù),具體用法參考調(diào)用方法的注釋
vm.ready();
},
/*...省略的代碼...*/
步驟 4,返回 頁面 A ,代碼如下:
// 頁面 B.vue
/*...省略的代碼...*/
<template>
<div>
<backButton :backFn="$goSourcePage"></backButton>
/*...省略的代碼...*/
</div>
</template>
/*...省略的代碼...*/
總結(jié)
本文詳細介紹了關(guān)聯(lián)頁面多級跳轉(zhuǎn)(頁面下鉆)功能的實現(xiàn),核心思想便是通過 VUEX 全局狀態(tài)管理,保存關(guān)聯(lián)跳轉(zhuǎn)源頁面和目標頁面的數(shù)據(jù),在跳轉(zhuǎn)之前,把需要的數(shù)據(jù)保存起來,跳轉(zhuǎn)到目標頁面時,把目標頁面需要的數(shù)據(jù)從 VUEX 中獲取,跳轉(zhuǎn)回源頁面時,把源頁面的數(shù)據(jù)從 VUEX 中恢復。
把這幾個關(guān)鍵動作,封裝成通用方法和組件,即統(tǒng)一了各個項目的關(guān)聯(lián)頁面跳轉(zhuǎn)方式,也提高了代碼的質(zhì)量,更有利于后期維護。另外,文章中的容錯部分,只寫了一部分,如果后續(xù)需要繼續(xù)完善該功能,可以把容錯部分完善一下。
到此這篇關(guān)于Vue實現(xiàn)關(guān)聯(lián)頁面多級跳轉(zhuǎn)(頁面下鉆)功能的文章就介紹到這了,更多相關(guān)Vue關(guān)聯(lián)頁面多級跳轉(zhuǎn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue使用@scroll監(jiān)聽滾動事件時,@scroll無效問題的解決方法詳解
這篇文章主要介紹了vue使用@scroll監(jiān)聽滾動事件時,@scroll無效問題的解決方法,結(jié)合實例形式分析了@scroll監(jiān)聽滾動事件無效問題的原因及相應的解決方法,需要的朋友可以參考下2019-10-10
vue.js+ElementUI實現(xiàn)進度條提示密碼強度效果
這篇文章主要介紹了vue.js+ElementUI實現(xiàn)進度條提示密碼強度效果,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2020-01-01
vue項目啟動出現(xiàn)cannot GET /服務錯誤的解決方法
這篇文章主要介紹了vue項目啟動出現(xiàn)cannot GET /服務錯誤的解決方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-04-04
Vue2 Element el-table多選表格控制選取的思路解讀
這篇文章主要介紹了Vue2 Element el-table多選表格控制選取的思路解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07
vue使用video插件vue-video-player詳解
這篇文章主要為大家詳細介紹了vue使用video插件vue-video-player,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-10-10
vue+axios實現(xiàn)圖片上傳識別人臉的示例代碼
本文主要介紹了vue+axios實現(xiàn)圖片上傳識別人臉,這里采用的是vant的文件上傳組件,通過上傳圖片后端識別圖片里的人臉,感興趣的可以了解一下2021-11-11
vue中的任務隊列和異步更新策略(任務隊列,微任務,宏任務)
這篇文章主要介紹了vue中的任務隊列和異步更新策略(任務隊列,微任務,宏任務),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08

