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