對(duì)于互聯(lián)網(wǎng)發(fā)展的今天,IT行業(yè)慢慢變成大多數(shù)年輕人發(fā)展的目標(biāo),不僅前景好,薪資也是越來(lái)越高的,而web前端是行業(yè)中需要的技術(shù),也促進(jìn)了大多數(shù)朋友在學(xué)習(xí)html5,今天小猿圈講師給你分享基于iview的router常用控制方式,在學(xué)的過(guò)程中不浪費(fèi)時(shí)間少走彎路。
1、iview的router控制需求
最近在使用iview框架寫項(xiàng)目,遇到了一些路由控制上的問(wèn)題,解決過(guò)程中也有一些心得,故在此記錄下來(lái).
每個(gè)項(xiàng)目在開(kāi)發(fā)時(shí),對(duì)于類似tags(標(biāo)簽頁(yè))的控制需求都不盡相同,故以下先列出本文所述項(xiàng)目對(duì)標(biāo)簽頁(yè)的控制要求(如有不同需求,本文當(dāng)也可提供一些思路):
對(duì)于同名(name)的路由標(biāo)簽頁(yè),不能打開(kāi)多個(gè).譬如說(shuō)從商品列表中打開(kāi)商品展示標(biāo)簽頁(yè),如果已經(jīng)有在打開(kāi)的商品編輯頁(yè)面,則替換之.新打開(kāi)的,未保存,已保存的標(biāo)簽頁(yè),同時(shí)只能存在一個(gè)(即不同params相同name的route只能有一個(gè));
替換掉一個(gè)新的頁(yè)面時(shí),通過(guò)切換的方式切換回來(lái)(先切到其他標(biāo)簽頁(yè)再切換回來(lái)),仍是原來(lái)頁(yè)面的內(nèi)容(即實(shí)際記錄的params在替換后應(yīng)變化).類似的情況,還應(yīng)包含單據(jù)從未保存到已保存,以及保存并新增功能;
2、基于vue的router控制
iview是基于vue的框架,故vue本身自帶的router控制方法是必然可行的.
vue變更路由的常用方式參考以下(該方法在官方api中有更詳細(xì)的介紹):
//變更當(dāng)前路由(有歷史記錄,建議使用此方式)
this.$router.push({
? name:'routerName',
? params:routerParam
})
//變更當(dāng)前路由(無(wú)歷史記錄)
this.$router.replace({
? name:'routerName',
? routerParam
})
官方路由變更確實(shí)可以正常打開(kāi)標(biāo)簽頁(yè),但在實(shí)現(xiàn)1中所提到的各種需求的時(shí)候,就有些不滿足需求了.為此,需要參考3中,如何基于iview的outer控制.
3、基于iview的router控制
iview在控制路由的時(shí)候,使用vuex中的app.js來(lái)記錄標(biāo)簽頁(yè)路由信息,如果對(duì)vuex還是很了解的話,可以通過(guò)這篇博文來(lái)先打一下基礎(chǔ).
3.1如何實(shí)現(xiàn)需求1.1
想要實(shí)現(xiàn)不同params相同name的route在iview中只能有一個(gè),關(guān)鍵是改變iview對(duì)路由相等的判斷方法,即'/src/libs/util.js'里的routeEqual方法:
/**
* @description 根據(jù)name/params/query判斷兩個(gè)路由對(duì)象是否相等
* @param {*} route1 路由對(duì)象
* @param {*} route2 路由對(duì)象
*/
export const routeEqual = (route1, route2) => {
return route1.name === route2.name
// 此處改變相同路由的判斷方式,改為name相同即認(rèn)為相同
// const params1 = route1.params || {}
// const params2 = route2.params || {}
// const query1 = route1.query || {}
// const query2 = route2.query || {}
// return (route1.name === route2.name) && objEqual(params1, params2) && objEqual(query1, query2)
}
這里稍微解釋下(如果不關(guān)注原因,可以直接看3.2).當(dāng)改變路由時(shí),'src\components\main\main.vue'作為近乎頂層的組件控制著近乎所有的全局邏輯,其中就有對(duì)路由的監(jiān)控:
...
<side-menu
accordion
ref="sideMenu"
:active-name="$route.name"
:collapsed="collapsed"
@on-select="turnToPage"
:menu-list="menuList"
>
...
? //此方法隸屬于methods,用以監(jiān)控side-menu的選擇事件,即平時(shí)從左側(cè)菜單打開(kāi)標(biāo)簽頁(yè)的邏輯
? turnToPage (route) {
? let { name, params, query } = {}
? if (typeof route === 'string') name = route
? else {
? ? name = route.name
? ? params = route.params
? ? query = route.query
? }
? if (name.indexOf('isTurnByHref_') > -1) {
? ? window.open(name.split('_')[1])
? ? return
? }
? this.$router.push({
? ? name,
? ? params,
? ? query
? })
? },
...
watch: {
? // 檢測(cè)route的變化
? $route (newRoute) {
? const { name, query, params, meta } = newRoute
? this.addTag({
? ? route: { name, query, params, meta },
? ? type: 'push'
? })
? this.setBreadCrumb(newRoute)
? this.setTagNavList(getNewTagList(this.tagNavList, newRoute))
? this.$refs.sideMenu.updateOpenName(newRoute.name)
? }
},
...
從以上代碼可推測(cè)出,main.vue通過(guò)turnToPage方法實(shí)現(xiàn)打開(kāi)標(biāo)簽頁(yè)的邏輯,但方法內(nèi)部并沒(méi)有體現(xiàn)便簽頁(yè)顯示效果變化(包含內(nèi)部數(shù)據(jù)變化,以下同)的邏輯,這是由于顯示效果變化的邏輯,由對(duì)$router的監(jiān)控實(shí)現(xiàn).
這樣,不止從左側(cè)菜單打開(kāi)新標(biāo)簽頁(yè)可以實(shí)現(xiàn)顯示變化效果,其他只要使用vue的原版push等方法改變r(jià)outer的方法,均可監(jiān)測(cè)到.
逐步查看下各個(gè)方法,其中影響當(dāng)前標(biāo)簽頁(yè)顯示效果的,是'src/store/module/app.js'的addTag方法.
addTag (state, { route, type = 'unshift' }) {
let router = getRouteTitleHandled(route)
if (!routeHasExist(state.tagNavList, router)) {
? if (type === 'push') state.tagNavList.push(router)
? else {
? if (router.name === homeName) state.tagNavList.unshift(router)
? else state.tagNavList.splice(1, 0, router)
? }
? setTagNavListInLocalstorage([...state.tagNavList])
}
},
盡管方法內(nèi)部仍調(diào)用了很多,其中一個(gè)很重要的判斷,就是routeHasExist(路由是否存在),這個(gè)方法也是判斷是否為相同標(biāo)簽頁(yè)的一個(gè)關(guān)鍵節(jié)點(diǎn)(該方法同樣在util.js):
/**
* 判斷打開(kāi)的標(biāo)簽列表里是否已存在這個(gè)新添加的路由對(duì)象
*/
export const routeHasExist = (tagNavList, routeItem) => {
let len = tagNavList.length
let res = false
doCustomTimes(len, (index) => {
? if (routeEqual(tagNavList[index], routeItem)) res = true
})
return res
}
明顯可以看出,這個(gè)方法內(nèi)調(diào)用routeEqual,就是用以判斷是否為相同路由的實(shí)際方法(當(dāng)然是通過(guò)比較新路由與已有路由進(jìn)行比較),如此,僅需改變r(jià)outeEqual即可.
以防萬(wàn)一,全局搜索下調(diào)用這個(gè)routeEqual的所有方法,發(fā)現(xiàn)所有調(diào)用的地方再routeEqual在改變后不會(huì)出現(xiàn)新的問(wèn)題.
3.2如何實(shí)現(xiàn)需求1.2
在進(jìn)行3.1的操作后,問(wèn)題得到了部分解決.余下的問(wèn)題在于需求1.2沒(méi)有得到實(shí)現(xiàn)和解決.
首先是,如何實(shí)現(xiàn)從列表中打開(kāi)或新建的,替換原來(lái)的標(biāo)簽頁(yè),在來(lái)回切換后不會(huì)回到原來(lái)的標(biāo)簽頁(yè).只需在app.js中注冊(cè)改變標(biāo)簽頁(yè)參數(shù)的方法:
// 變更指定路由的參數(shù)
changeTagParams (state, route) {
let routeOldIndex = state.tagNavList.findIndex(m => routeEqual(m, route))
if (routeOldIndex !== -1) {
? let routeOld = state.tagNavList[routeOldIndex]
? routeOld.params = route.params
? state.tagNavList.splice(routeOldIndex, 1, routeOld)
? setTagNavListInLocalstorage([...state.tagNavList])
}
},
然后在main.vue中對(duì)$route的監(jiān)控最后引用即可.
watch: {
? // 檢測(cè)route的變化
? $route (newRoute) {
? const { name, query, params, meta } = newRoute
? this.addTag({
? ? route: { name, query, params, meta },
? ? type: 'push'
? })
? this.setBreadCrumb(newRoute)
? this.setTagNavList(getNewTagList(this.tagNavList, newRoute))
? this.$refs.sideMenu.updateOpenName(newRoute.name)
? // 增加路由參數(shù)變更環(huán)節(jié)
? this.changeTagParams(newRoute)
? }
},
其次,如果出現(xiàn)像保存并新增,或者從未保存到已保存,這兩種情況來(lái)回切換后不會(huì)回到原來(lái)的情況.
保存并新增,關(guān)鍵是"新增"效果:
// 清空數(shù)據(jù),該方法在保存后調(diào)用
clearData () {
//該部分是用來(lái)清除當(dāng)前route的參數(shù)
this.$router.push({
? params: Object.assign(this.$route.params, { id: undefined })
})
//這部分代碼是用來(lái)清空當(dāng)前頁(yè)面內(nèi)容,每個(gè)模塊都不盡相同,不必模仿
this.mOtherExpense = JSON.parse(JSON.stringify(this.mOtherExpenseInitial))
this.tableData = [{}]
this.loadCode()
this.mOtherExpense.openingDate = new Date()
},
從未保存到已保存,關(guān)鍵同樣是如何讓route記住新的id(或其他參數(shù)):
// 設(shè)置路由id,該方法在第一次保存后調(diào)用
setData (id) {
//這里的id是保存后從后臺(tái)傳來(lái)的新id
this.$router.push({
? params: Object.assign(this.$route.params, { id })
})
}
文中已將本人常用的iviewrouter控制方式提出,或有未涉及者,根據(jù)以下了解大概也可解決:
app.js中的state.tagNavList是標(biāo)簽頁(yè)中顯示的標(biāo)簽集合;如果要改變一些內(nèi)容,main.vue中對(duì)$route的監(jiān)控是事件發(fā)起的開(kāi)端,可考慮從這里修改;
以上就是小猿圈web前端講師對(duì)于基于iview的router常用控制方式的介紹,記住一定要練習(xí),多學(xué)多看多練這才是學(xué)習(xí)一門新技術(shù)好的開(kāi)始,如果沒(méi)有系統(tǒng)的視頻可以觀看小猿圈,里面有更完善更全的視頻。