当前位置:首页 » 《休闲阅读》 » 正文

若依 vue前端 动态设置路由path不同参数 在页面容器里打开新页面(新路由),面包屑和标签页标题根据参数动态改变,面包屑多级标题,侧边栏对应菜单亮起

10 人参与  2024年04月17日 14:18  分类 : 《休闲阅读》  评论

点击全文阅读


前言

因为是在vue源码的基础上进行修改,所以,就没有复制代码在文章上,采取的是截图对比源码和我修改的代码片段。要麻烦你们自己手敲了。

先来看看效果:

场景:在费用配置列表中,点击每一项的配置,都会在页面容器内部打开一个新页面,所以新页面的路径一样,根据传的参数不同,面包屑和标签页标题动态改变

二级路由效果(这是用菜单管理新建一条隐藏的路由做法,不推荐)

http://localhost/feeManage/feeConfigDetail?id=4&metaTitle=3253的费用配置http://localhost/feeManage/feeConfigDetail?id=1&metaTitle=eww的费用配置

三级路由效果(推荐)

路由跳转方法:

// 方法1this.$router.push({path: '/feeManage/feeConfig/feeConfigDetail',query: {id: row.id,},})// 方法2<router-link :to="'/system/dict-data/index/' + scope.row.dictId" class="link-type">    <span>点击跳转</span></router-link>

若依路由简单介绍:

若依vue前端能跳转到新页面路由的方法,我暂且知道这三种形式:

1 在若依的菜单项添加(不推荐)

缺点:因为路由暴露在外面,会发生被误删或者修改错误的情况,造成严重缺陷。

优点:不用写路由配置的代码,可以直接进行路由跳转了。

同时还要注意,这是详细页面,不应该在左侧菜单栏出现,所以要隐藏

2 在router的constantRoutes里添加路由(推荐)

 3 在router的dynamicRoutes里添加路由(推荐)

若依字典管理的动态路由配置(如果是想实现像若依字典这样的路由跳转效果,就可以直接参考若依的源码去做: 

 

如果需要权限,需要自己写权限标识(很麻烦,,对接很累)

先是后端写上。。。

 然后前端。。。

代码实现

路由配置

实现三级标题的路由怎么写?

{    path: '/feeManage',    component: Layout, // 一级这个component: Layout必填,除非是不需要在页面容器里打开的页面    hidden: true, // false:显示在侧边栏菜单    redirect: 'noRedirect', // noRedirect:面包屑不可点击,不写这个,父级标题样式就和首页一样,黑字可点击跳转    meta: { title: '费用管理'}, // 一级标题,写了才能显示在面包屑上    children: [        {            path: '',            component:{ render: (e) => e("router-view") }, // 如果你的'feeConfig'路径已经在系统菜单中设置过了,这里的path和component就写得和我一样就行,直接跳转三级路由            hidden: true, // false:显示在侧边栏菜单            redirect: 'noRedirect', // noRedirect:面包屑不可点击,不写这个,父级标题样式就和首页一样,黑字可点击跳转            meta: { title: '费用配置'}, // 二级标题,写了才能显示在面包屑上            // 如果你不需要二级的父级标题,那你就直接把第二个children的内容写在第一个children就行            children: [              {                path: 'feeConfig/feeConfigDetail',                component: () => import('@/views/feeManage/feeConfigDetail/index'),                name: 'feeConfigDetail',                meta: { title: '费用配置', activeMenu: '/feeManage/feeConfig' } // meta.title:三级标题,meta.activeMenu:侧边栏父级菜单高亮              }            ]        }    ]  }

也可以这样写(这样写是建立在之前写的跳转路径不规范,如果不想改代码那么多,只能自己在路由这里改,就不用动业务代码里的跳转路径,当然我强迫症,我最后都改了)

  {    path: '',    component: Layout,    hidden: true,    redirect: 'noRedirect',    meta: { title: '运营中心' },    children: [        {            path: '/overseas-collocation',            component:{ render: (e) => e("router-view") }, // 如果你的'merchant'路径已经在系统菜单中设置过了,这里的path和component就写得和我一样就行,直接跳转三级路由            hidden: true, // false:显示在侧边栏菜单            redirect: 'noRedirect', // noRedirect:面包屑不可点击,不写这个,父级标题样式就和首页一样,黑字可点击跳转            meta: { title: '海外拼柜'}, // 二级标题,写了才能显示在面包屑上            // 如果你不需要二级的父级标题,那你就直接把第二个children的内容写在第一个children就行            children: [                {                  path: 'detail/:id(\\d+)',                  component: () => import('@/views/operation-center/overseas-collocation/collocation-detail'),                  name: 'overseasCollocationDetail',                  meta: { title: '拼柜详情', activeMenu: '/operation-center/overseas-collocation/overseas-collocation' }                }            ]        }    ]  }
<router-link :to="'/overseas-collocation/detail/' + scope.row.id"><el-button type="text">查看</el-button></router-link>

改后

面包屑和标签页动态标题配置

配置完路由后,就要讲,如何动态设置路由path不同参数 在页面容器里打开新页面,面包屑和标签页标题根据参数动态改变

 使用1方法创建好路由后,然后用$router.push设置传的参数,我们使用metaTitle来当页面标题

this.$router.push({path: '/feeManage/feeConfigDetail',query: {id: row.id,metaTitle: row.chargeName + '的费用配置'},})

如果你只做到了这里,你就会发现,它确实跳转页面了,但是它是同一个页面进行了不同参数的刷新,然后页面的标题也没有动态改变,而是你之前菜单配置时写的标题,如图:

                  

 下面就需要改改若依的源码了:

1、先改面包屑

 2、在页面容器中,打开新的标签页,改标签页标题(把要修改文件和修改内容框出来,有个明显的对比,知道改哪里)

 

 最后在新页面取出参数

最后效果

有bug

也是写完上面的内容以后,才发现有bug,路径一样,参数不一样的标签,去单击的时候,没有刷新内容,而是保留第一次点击的标签的页面。。。如图

bug解决

原因:若依vue前端源码中用的<router-link>标签进行页面跳转,因为路径一样,参数不一样的页面本质上都是同一个vue,而这个vue已经加载出来就不会进行销毁重新加载了,所以我们要做的就是监听参数然后重新渲染,达到刷新页面的效果

在自己的跳转页面vue中监听路由参数:

二级路由效果

三级路由效果

ps: 找到更好的写法就又补充了一下,所以截图上有些不统一,记得看字看描述哈! 

修改过的若依代码

ruoyi 3.8.3

src\components\Breadcrumb\index.vue

<template>  <el-breadcrumb class="app-breadcrumb" separator="/">    <transition-group name="breadcrumb">      <el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">        <span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">            <!-- {{ item.meta.title }} -->            {{item.metaTitle ? item.metaTitle : item.meta.title  }}        </span>        <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>      </el-breadcrumb-item>    </transition-group>  </el-breadcrumb></template><script>export default {  data() {    return {      levelList: null    }  },  watch: {    $route(route) {      // if you go to the redirect page, do not update the breadcrumbs      if (route.path.startsWith('/redirect/')) {        return      }      this.getBreadcrumb()    }  },  created() {    this.getBreadcrumb()  },  methods: {    getBreadcrumb() {      // only show routes with meta.title      let matched = this.$route.matched.filter(item => item.meta && item.meta.title)      matched.forEach(element => {          if(element.path == this.$route.path ) {              if(this.$route.query.metaTitle) {                    element.metaTitle = this.$route.query.metaTitle               }          }       });      const first = matched[0]      if (!this.isDashboard(first)) {        matched = [{ path: '/index', meta: { title: '首页' }}].concat(matched)      }      this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)    },    isDashboard(route) {      const name = route && route.name      if (!name) {        return false      }      return name.trim() === 'Index'    },    handleLink(item) {      const { redirect, path } = item      if (redirect) {        this.$router.push(redirect)        return      }      this.$router.push(path)    }  }}</script><style lang="scss" scoped>.app-breadcrumb.el-breadcrumb {  display: inline-block;  font-size: 14px;  line-height: 50px;  margin-left: 8px;  .no-redirect {    color: #97a8be;    cursor: text;  }}</style>

src\layout\components\TagsView\index.vue

 

<template>  <div id="tags-view-container" class="tags-view-container">    <scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll">      <router-link        v-for="tag in visitedViews"        ref="tag"        :key="tag.fullPath"        :class="isActive(tag)?'active':''"        :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"        tag="span"        class="tags-view-item"        :style="activeStyle(tag)"        @click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"        @contextmenu.prevent.native="openMenu(tag,$event)"      >        {{ tag.title }}        <span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />      </router-link>    </scroll-pane>    <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">      <li @click="refreshSelectedTag(selectedTag)"><i class="el-icon-refresh-right"></i> 刷新页面</li>      <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"><i class="el-icon-close"></i> 关闭当前</li>      <li @click="closeOthersTags"><i class="el-icon-circle-close"></i> 关闭其他</li>      <li v-if="!isFirstView()" @click="closeLeftTags"><i class="el-icon-back"></i> 关闭左侧</li>      <li v-if="!isLastView()" @click="closeRightTags"><i class="el-icon-right"></i> 关闭右侧</li>      <li @click="closeAllTags(selectedTag)"><i class="el-icon-circle-close"></i> 全部关闭</li>    </ul>  </div></template><script>import ScrollPane from './ScrollPane'import path from 'path'export default {  components: { ScrollPane },  data() {    return {      visible: false,      top: 0,      left: 0,      selectedTag: {},      affixTags: []    }  },  computed: {    visitedViews() {      return this.$store.state.tagsView.visitedViews    },    routes() {      return this.$store.state.permission.routes    },    theme() {      return this.$store.state.settings.theme;    }  },  watch: {    $route() {      this.addTags()      this.moveToCurrentTag()    },    visible(value) {      if (value) {        document.body.addEventListener('click', this.closeMenu)      } else {        document.body.removeEventListener('click', this.closeMenu)      }    }  },  mounted() {    this.initTags()    this.addTags()  },  methods: {    isActive(route) {    //   return route.path === this.$route.path      return route.fullPath === this.$route.fullPath    },    activeStyle(tag) {      if (!this.isActive(tag)) return {};      return {        "background-color": this.theme,        "border-color": this.theme      };    },    isAffix(tag) {      return tag.meta && tag.meta.affix    },    isFirstView() {      try {        return this.selectedTag.fullPath === this.visitedViews[1].fullPath || this.selectedTag.fullPath === '/index'      } catch (err) {        return false      }    },    isLastView() {      try {        return this.selectedTag.fullPath === this.visitedViews[this.visitedViews.length - 1].fullPath      } catch (err) {        return false      }    },    filterAffixTags(routes, basePath = '/') {      let tags = []      routes.forEach(route => {        if (route.meta && route.meta.affix) {          const tagPath = path.resolve(basePath, route.path)          tags.push({            fullPath: tagPath,            path: tagPath,            name: route.name,            meta: { ...route.meta }          })        }        if (route.children) {          const tempTags = this.filterAffixTags(route.children, route.path)          if (tempTags.length >= 1) {            tags = [...tags, ...tempTags]          }        }      })      return tags    },    initTags() {      const affixTags = this.affixTags = this.filterAffixTags(this.routes)      for (const tag of affixTags) {        // Must have tag name        if (tag.name) {        //   this.$store.dispatch('tagsView/addVisitedView', tag)        }      }    },    addTags() {      const { name } = this.$route      if (name) {        this.$store.dispatch('tagsView/addView', this.$route)      }      return false    },    moveToCurrentTag() {      const tags = this.$refs.tag      this.$nextTick(() => {        for (const tag of tags) {          if (tag.to.path === this.$route.path) {              if(tag.to.query.metaTitle) {                  if(tag.to.query.metaTitle === this.$route.query.metaTitle) {                      this.$refs.scrollPane.moveToTarget(tag)                       // when query is different then update                      if (tag.to.fullPath !== this.$route.fullPath) {                        this.$store.dispatch('tagsView/updateVisitedView', this.$route)                      }                  }              } else {                  this.$refs.scrollPane.moveToTarget(tag)                  // when query is different then update                  if (tag.to.fullPath !== this.$route.fullPath) {                    this.$store.dispatch('tagsView/updateVisitedView', this.$route)                  }              }            break          }        }      })    },    refreshSelectedTag(view) {      this.$tab.refreshPage(view);    },    closeSelectedTag(view) {      this.$tab.closePage(view).then(({ visitedViews }) => {        if (this.isActive(view)) {          this.toLastView(visitedViews, view)        }      })    },    closeRightTags() {      this.$tab.closeRightPage(this.selectedTag).then(visitedViews => {        if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) {          this.toLastView(visitedViews)        }      })    },    closeLeftTags() {      this.$tab.closeLeftPage(this.selectedTag).then(visitedViews => {        if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) {          this.toLastView(visitedViews)        }      })    },    closeOthersTags() {      this.$router.push(this.selectedTag).catch(()=>{});      this.$tab.closeOtherPage(this.selectedTag).then(() => {        this.moveToCurrentTag()      })    },    closeAllTags(view) {      this.$tab.closeAllPage().then(({ visitedViews }) => {        if (this.affixTags.some(tag => tag.path === this.$route.path)) {          return        }        this.toLastView(visitedViews, view)      })    },    toLastView(visitedViews, view) {      const latestView = visitedViews.slice(-1)[0]      if (latestView) {        this.$router.push(latestView.fullPath)      } else {        // now the default is to redirect to the home page if there is no tags-view,        // you can adjust it according to your needs.        if (view.name === 'Dashboard') {          // to reload home page          this.$router.replace({ path: '/redirect' + view.fullPath })        } else {          this.$router.push('/')        }      }    },    openMenu(tag, e) {      const menuMinWidth = 105      const offsetLeft = this.$el.getBoundingClientRect().left // container margin left      const offsetWidth = this.$el.offsetWidth // container width      const maxLeft = offsetWidth - menuMinWidth // left boundary      const left = e.clientX - offsetLeft + 15 // 15: margin right      if (left > maxLeft) {        this.left = maxLeft      } else {        this.left = left      }      this.top = e.clientY      this.visible = true      this.selectedTag = tag    },    closeMenu() {      this.visible = false    },    handleScroll() {      this.closeMenu()    }  }}</script><style lang="scss" scoped>.tags-view-container {  height: 34px;  width: 100%;  background: #fff;  border-bottom: 1px solid #d8dce5;  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);  .tags-view-wrapper {    .tags-view-item {      display: inline-block;      position: relative;      cursor: pointer;      height: 26px;      line-height: 26px;      border: 1px solid #d8dce5;      color: #495060;      background: #fff;      padding: 0 8px;      font-size: 12px;      margin-left: 5px;      margin-top: 4px;      &:first-of-type {        margin-left: 15px;      }      &:last-of-type {        margin-right: 15px;      }      &.active {        background-color: #42b983;        color: #fff;        border-color: #42b983;        &::before {          content: '';          background: #fff;          display: inline-block;          width: 8px;          height: 8px;          border-radius: 50%;          position: relative;          margin-right: 2px;        }      }    }  }  .contextmenu {    margin: 0;    background: #fff;    z-index: 3000;    position: absolute;    list-style-type: none;    padding: 5px 0;    border-radius: 4px;    font-size: 12px;    font-weight: 400;    color: #333;    box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);    li {      margin: 0;      padding: 7px 16px;      cursor: pointer;      &:hover {        background: #eee;      }    }  }}</style><style lang="scss">//reset element css of el-icon-close.tags-view-wrapper {  .tags-view-item {    .el-icon-close {      width: 16px;      height: 16px;      vertical-align: 2px;      border-radius: 50%;      text-align: center;      transition: all .3s cubic-bezier(.645, .045, .355, 1);      transform-origin: 100% 50%;      &:before {        transform: scale(.6);        display: inline-block;        vertical-align: -3px;      }      &:hover {        background-color: #b4bccc;        color: #fff;      }    }  }}</style>

src\store\modules\tagsView.js

const state = {  visitedViews: [],  cachedViews: []}const mutations = {//   ADD_VISITED_VIEW: (state, view) => {//     if (state.visitedViews.some(v => v.path === view.path)) return//     state.visitedViews.push(//       Object.assign({}, view, {//         title: view.meta.title || 'no-name'//       })//     )//   },  ADD_VISITED_VIEW: (state, view) => {    if (state.visitedViews.some(v => v.path === view.path)) {        // 路径一样,因为参数不同,打开新的页面        if(view.query && view.query.metaTitle) {            let list = state.visitedViews.filter(v => v.query && v.query.metaTitle && v.query.metaTitle == view.query.metaTitle)            if(list.length > 0) {                return            }        } else {            return        }    }     state.visitedViews.push(      Object.assign({}, view, {        title: view.query && view.query.metaTitle ? view.query.metaTitle:(view.meta.title || 'no-name')      })    )  },  ADD_CACHED_VIEW: (state, view) => {    if (state.cachedViews.includes(view.name)) return    if (view.meta && !view.meta.noCache) {      state.cachedViews.push(view.name)    }  },  DEL_VISITED_VIEW: (state, view) => {    for (const [i, v] of state.visitedViews.entries()) {      if (v.path === view.path) {        state.visitedViews.splice(i, 1)        break      }    }  },  DEL_CACHED_VIEW: (state, view) => {    const index = state.cachedViews.indexOf(view.name)    index > -1 && state.cachedViews.splice(index, 1)  },  DEL_OTHERS_VISITED_VIEWS: (state, view) => {    state.visitedViews = state.visitedViews.filter(v => {      return v.meta.affix || v.path === view.path    })  },  DEL_OTHERS_CACHED_VIEWS: (state, view) => {    const index = state.cachedViews.indexOf(view.name)    if (index > -1) {      state.cachedViews = state.cachedViews.slice(index, index + 1)    } else {      state.cachedViews = []    }  },  DEL_ALL_VISITED_VIEWS: state => {    // keep affix tags    const affixTags = state.visitedViews.filter(tag => tag.meta.affix)    state.visitedViews = affixTags  },  DEL_ALL_CACHED_VIEWS: state => {    state.cachedViews = []  },  UPDATE_VISITED_VIEW: (state, view) => {    for (let v of state.visitedViews) {      if (v.path === view.path) {        v = Object.assign(v, view)        break      }    }  },    DEL_RIGHT_VIEWS: (state, view) => {    const index = state.visitedViews.findIndex(v => v.path === view.path)    if (index === -1) {      return    }    state.visitedViews = state.visitedViews.filter((item, idx) => {      if (idx <= index || (item.meta && item.meta.affix)) {        return true      }      const i = state.cachedViews.indexOf(item.name)      if (i > -1) {        state.cachedViews.splice(i, 1)      }      return false    })  },  DEL_LEFT_VIEWS: (state, view) => {    const index = state.visitedViews.findIndex(v => v.path === view.path)    if (index === -1) {      return    }    state.visitedViews = state.visitedViews.filter((item, idx) => {      if (idx >= index || (item.meta && item.meta.affix)) {        return true      }      const i = state.cachedViews.indexOf(item.name)      if (i > -1) {        state.cachedViews.splice(i, 1)      }      return false    })  }}const actions = {  addView({ dispatch }, view) {    dispatch('addVisitedView', view)    dispatch('addCachedView', view)  },  addVisitedView({ commit }, view) {    commit('ADD_VISITED_VIEW', view)  },  addCachedView({ commit }, view) {    commit('ADD_CACHED_VIEW', view)  },  delView({ dispatch, state }, view) {    return new Promise(resolve => {      dispatch('delVisitedView', view)      dispatch('delCachedView', view)      resolve({        visitedViews: [...state.visitedViews],        cachedViews: [...state.cachedViews]      })    })  },  delVisitedView({ commit, state }, view) {    return new Promise(resolve => {      commit('DEL_VISITED_VIEW', view)      resolve([...state.visitedViews])    })  },  delCachedView({ commit, state }, view) {    return new Promise(resolve => {      commit('DEL_CACHED_VIEW', view)      resolve([...state.cachedViews])    })  },  delOthersViews({ dispatch, state }, view) {    return new Promise(resolve => {      dispatch('delOthersVisitedViews', view)      dispatch('delOthersCachedViews', view)      resolve({        visitedViews: [...state.visitedViews],        cachedViews: [...state.cachedViews]      })    })  },  delOthersVisitedViews({ commit, state }, view) {    return new Promise(resolve => {      commit('DEL_OTHERS_VISITED_VIEWS', view)      resolve([...state.visitedViews])    })  },  delOthersCachedViews({ commit, state }, view) {    return new Promise(resolve => {      commit('DEL_OTHERS_CACHED_VIEWS', view)      resolve([...state.cachedViews])    })  },  delAllViews({ dispatch, state }, view) {    return new Promise(resolve => {      dispatch('delAllVisitedViews', view)      dispatch('delAllCachedViews', view)      resolve({        visitedViews: [...state.visitedViews],        cachedViews: [...state.cachedViews]      })    })  },  delAllVisitedViews({ commit, state }) {    return new Promise(resolve => {      commit('DEL_ALL_VISITED_VIEWS')      resolve([...state.visitedViews])    })  },  delAllCachedViews({ commit, state }) {    return new Promise(resolve => {      commit('DEL_ALL_CACHED_VIEWS')      resolve([...state.cachedViews])    })  },  updateVisitedView({ commit }, view) {    commit('UPDATE_VISITED_VIEW', view)  },  delRightTags({ commit }, view) {    return new Promise(resolve => {      commit('DEL_RIGHT_VIEWS', view)      resolve([...state.visitedViews])    })  },  delLeftTags({ commit }, view) {    return new Promise(resolve => {      commit('DEL_LEFT_VIEWS', view)      resolve([...state.visitedViews])    })  },}export default {  namespaced: true,  state,  mutations,  actions}


点击全文阅读


本文链接:http://zhangshiyu.com/post/96551.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1