本网站(662p.com)打包出售,且带程序代码数据,662p.com域名,程序内核采用TP框架开发,需要联系扣扣:2360248666 /wx:lianweikj
精品域名一口价出售:1y1m.com(350元) ,6b7b.com(400元) , 5k5j.com(380元) , yayj.com(1800元), jiongzhun.com(1000元) , niuzen.com(2800元) , zennei.com(5000元)
需要联系扣扣:2360248666 /wx:lianweikj
基于iview的router常用控制方式
追忆似水年华 · 998浏览 · 发布于2019-06-03 +关注

1 iview的router控制需求

最近在使用iview框架写项目,遇到了一些路由控制上的问题,解决过程中也有一些心得,故在此记录下来.
每个项目在开发时,对于类似tags(标签页)的控制需求都不尽相同,故以下先列出本文所述项目对标签页的控制要求(如有不同需求,本文当也可提供一些思路):

  1. 对于同名(name)的路由标签页,不能打开多个.譬如说从商品列表中打开商品展示标签页,如果已经有在打开的商品编辑页面,则替换之.新打开的,未保存,已保存的标签页,同时只能存在一个(即不同params相同name的route只能有一个);

  2. 替换掉一个新的页面时,通过切换的方式切换回来(先切到其他标签页再切换回来),仍是原来页面的内容(即实际记录的params在替换后应变化).类似的情况,还应包含单据从未保存到已保存,以及保存并新增功能;


2 基于vue的router控制

iview是基于vue的框架,故vue本身自带的router控制方法是必然可行的.
vue变更路由的常用方式参考以下(该方法在官方api中有更详细的介绍):

//变更当前路由(有历史记录,建议使用此方式)this.$router.push({
   name:'routerName',    params:routerParam
})//变更当前路由(无历史记录)this.$router.replace({
   name:'routerName',
   routerParam
})


官方路由变更确实可以正常打开标签页,但在实现1中所提到的各种需求的时候,就有些不满足需求了.为此,需要参考3中,如何基于iview的outer控制.


3 基于iview的router控制

iview在控制路由的时候,使用vuex中的app.js来记录标签页路由信息。

3.1 如何实现需求1.1

想要实现不同params相同name的route在iview中只能有一个,关键是改变iview对路由相等的判断方法,即'/src/libs/util.js'里的routeEqual方法:

/**
* @description 根据name/params/query判断两个路由对象是否相等
* @param {*} route1 路由对象
* @param {*} route2 路由对象
*/export const routeEqual = (route1, route2) => {  return route1.name === route2.name  // 此处改变相同路由的判断方式,改为name相同即认为相同
 // 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)}


这里稍微解释下(如果不关注原因,可以直接看3.2).当改变路由时,'src\components\main\main.vue'作为近乎顶层的组件控制着近乎所有的全局逻辑,其中就有对路由的监控:

...
<side-menu
accordionref="sideMenu":active-name="$route.name":collapsed="collapsed"@on-select="turnToPage":menu-list="menuList">
...    //此方法隶属于methods,用以监控side-menu的选择事件,即平时从左侧菜单打开标签页的逻辑
   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: {    // 检测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)
   }
},
...


从以上代码可推测出,main.vue通过turnToPage方法实现打开标签页的逻辑,但方法内部并没有体现便签页显示效果变化(包含内部数据变化,以下同)的逻辑,这是由于显示效果变化的逻辑,由对$router的监控实现.
这样,不止从左侧菜单打开新标签页可以实现显示变化效果,其他只要使用vue的原版push等方法改变router的方法,均可监测到.

逐步查看下各个方法,其中影响当前标签页显示效果的,是'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])
 }
},


尽管方法内部仍调用了很多,其中一个很重要的判断,就是routeHasExist(路由是否存在),这个方法也是判断是否为相同标签页的一个关键节点(该方法同样在util.js):

/**
* 判断打开的标签列表里是否已存在这个新添加的路由对象
*/export const routeHasExist = (tagNavList, routeItem) => {  let len = tagNavList.length  let res = false
 doCustomTimes(len, (index) => {    if (routeEqual(tagNavList[index], routeItem)) res = true
 })  return res
}


明显可以看出,这个方法内调用routeEqual,就是用以判断是否为相同路由的实际方法(当然是通过比较新路由与已有路由进行比较),如此,仅需改变routeEqual即可.
以防万一,全局搜索下调用这个routeEqual的所有方法,发现所有调用的地方再routeEqual在改变后不会出现新的问题.

3.2 如何实现需求1.2

在进行3.1的操作后,问题得到了部分解决.余下的问题在于需求1.2没有得到实现和解决.
首先是,如何实现从列表中打开或新建的,替换原来的标签页,在来回切换后不会回到原来的标签页. 只需在app.js中注册改变标签页参数的方法:

// 变更指定路由的参数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中对$route的监控最后引用即可.

watch: {    // 检测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)      // 增加路由参数变更环节
     this.changeTagParams(newRoute)
   }
},


其次,如果出现像保存并新增,或者从未保存到已保存,这两种情况来回切换后不会回到原来的情况.
保存并新增,关键是"新增"效果:

// 清空数据,该方法在保存后调用clearData () {  //该部分是用来清除当前route的参数
 this.$router.push({    params: Object.assign(this.$route.params, { id: undefined })
 })  //这部分代码是用来清空当前页面内容,每个模块都不尽相同,不必模仿
 this.mOtherExpense = JSON.parse(JSON.stringify(this.mOtherExpenseInitial))  this.tableData = [{}]  this.loadCode()  this.mOtherExpense.openingDate = new Date()
},


从未保存到已保存,关键同样是如何让route记住新的id(或其他参数):

// 设置路由id,该方法在第一次保存后调用setData (id) {  //这里的id是保存后从后台传来的新id
 this.$router.push({    params: Object.assign(this.$route.params, { id })
 })
}


相关推荐

RN开发环境的npm私库本地debug调试

manongba · 698浏览 · 2019-05-09 17:03:46
你不知道的浏览器渲染原理

追忆似水年华 · 1372浏览 · 2019-05-09 22:47:56
编程小知识之 JavaScript 文件读取

manongba · 717浏览 · 2019-06-10 09:16:16
10个省时间的 PyCharm 技巧 赶快收藏!

· 702浏览 · 2019-06-10 09:32:01
面试常问到的QT创建对话框三方法

manongba · 1629浏览 · 2019-06-13 09:48:17
加载中

0评论

评论
分类专栏
小鸟云服务器
扫码进入手机网页