vue 面包屑导航 ,页面缓存功能

本文详细介绍如何在Vue项目中实现动态面包屑导航,包括利用store管理路由数据、配置路由参数、创建组件并实现页面缓存,适用于多页签应用的高效导航管理。

1.动态的面包屑导航可以使用store控制数据,先创建一个tagsview.js

 const tagsview = {
   state: {
     visitedviews: [], //存放所有浏览过的且不重复的路由数据
   },
   mutations: { //这
     ADD_VISITED_VIEWS: (state, view) => { //打开新页签--添加路由数据的方法   
       if (state.visitedviews.some(v => v.path == view.path)) return;

       state.visitedviews.push({
         name: view.name,
         path: view.path,
         title: view.meta.title || 'no-title'
       })
     },
     DEL_VISITED_VIEWS: (state, view) => { //关闭页签--删除路由数据的方法
        
       for (let [i, v] of state.visitedviews.entries()) {
         if (v.path == view.path) {
           state.visitedviews.splice(i, 1)
           break
         }
       }
     }
   },
   actions: { //调用这里去触发mutations,如何调用?在组件内使用this.$store.dispatch('action中对应名字', 参数)
     addVisitedViews({
       commit
     }, view) { //通过解构赋值得到commit方法
       commit('ADD_VISITED_VIEWS', view) //去触发ADD_VISITED_VIEWS,并传入参数
     },
     delVisitedViews({
       commit,
       state
     }, view) { //删除数组存放的路由之后,需要再去刷新路由,这是一个异步的过程,需要有回掉函数,所以使用并返回promise对象,也可以让组件在调用的时候接着使用.then的方法
       //commit('DEL_VISITED_VIEWS',view)
       return new Promise((resolve) => { //resolve方法:未来成功后回掉的方法
         commit('DEL_VISITED_VIEWS', view);
         resolve([...state.visitedviews]);
       })
     }

   }
 }

 export default tagsview

2.在store.js文件中引入模块tagsview

import Vue from 'vue'
import Vuex from 'vuex'
import tagsview from './tagsview'

Vue.use(Vuex);
const getters = {
   visitedviews: state => state.tagsview.visitedviews,
};

export default new Vuex.Store({
  modules: {
    tagsview
  },
  getters
  
})

3.创建一个文件TagsView.vue

<template id="">
  <div class="tags-view-container"  v-show='visitedViews.length>0'>
    <div class="tags-view-wrap">
      <router-link v-for="tag in Array.from(visitedViews)" :to="tag.path" :key="tag.path" class="tags-view-item"
        :class="isActive(tag)?'active':''">
        {{tag.title}}
        <span class="el-icon-circle-close-outline" @click.prevent.stop="delSelectTag(tag)"></span>
      </router-link>
    </div>
  </div>
</template>
<script>
  export default {
    computed: {
      visitedViews() {
        //store中取值
        return this.$store.state.tagsview.visitedviews;
      }
    },
    methods: {
      isActive(route) {
        return route.path == this.$route.path;
      },
      addViewTags() {
        //路由改变时执行的方法
        console.log(this.$route);
        if (this.$route.name) {
          const route = this.$route;
          this.$store.dispatch("addVisitedViews", route);
        }
      },
      delSelectTag(route) {
        //先提交删除数据的方法,数组删除出掉数据后,如果关闭的是当前打开的路由需要将路由改为数组最后一次push进去的路由
        this.$store.dispatch("delVisitedViews", route).then(views => {
          if (this.isActive(route)) {
            //只有在关闭当前打开的标签页才会有影响
            let lastView = views.slice(-1)[0]; //选取路由数组中的最后一位
            if (lastView) {
              this.$router.push(lastView);
            } else {
              this.$router.push("/");
            }
          }
        });
      }
    },
    watch: {
      $route() {
        this.addViewTags();
      }
    }
  };

</script>


<style scoped>
  .tags-view-wrap {
    background: #efeef0;
    position: absolute;
    top: 10px;
    left: 20px;
    width: 100%;
    height: 30px;
    overflow: hidden;
  }

  .tags-view-wrap .tags-view-item {
    height: 30px;
    line-height: 30px;
    display: inline-block;
    color: #fff;
    background-color: #409EFF;
    padding: 0 3px;
    border-radius: 5px;
    margin: 0 3px;
  }

  .tags-view-wrap .tags-view-item:hover {
    color: rgb(221, 247, 5);
  }

  .tags-view-wrap .active {
    color: rgb(221, 247, 5);
  }

</style>

4.配置路由文件参数router.js

{
        path: '/index',
        name: 'index',//需要配置name,
        component: resolve => require(['../components/xxx.vue'], resolve),
        meta: {
          title: 'xxx', 
          keepAlive: true, //控制页面缓存参数
        }
      }

5.在主页面将TagsView.vue按组件引入,

<template>
  <div class="content-box">
    <el-container class="box">      
      <div class="content">        
        <el-main class="main">
          <tags></tags>
         
          <keep-alive>
            <router-view v-if="$route.meta.keepAlive">
              <!-- 这里是会被缓存的视图组件 -->
            </router-view>
          </keep-alive>
          <router-view v-if="!$route.meta.keepAlive">
            <!-- 这里是不被缓存的视图组件-->
          </router-view>
          
        </el-main>
      </div>
    </el-container>
  </div>
</template>
<script>
   
  import tags from '../components/xx/TagsView.vue';
  
  export default {
    components: {
     
      tags,
    },
    data() {
      return {

      }
    },
    methods: {

    },
    computed: {
       
    }
  }

</script>
 

添加页面缓存

          <keep-alive>
            <router-view v-if="$route.meta.keepAlive">
              <!-- 这里是会被缓存的视图组件 -->
            </router-view>
          </keep-alive>
          <router-view v-if="!$route.meta.keepAlive">
            <!-- 这里是不被缓存的视图组件-->
          </router-view>

 

 

<think>我们即将生成关于如何在Vue项目中利用vue-router实现面包屑导航的教程。面包屑导航是一种常见的导航辅助工具,它显示用户当前在网站中的位置,并提供返回上级页面的快捷方式。在Vue项目中,我们可以通过vue-router的路由信息来动态生成面包屑导航。根据问题要求,我们将:1.使用组合式API(CompositionAPI)和VueRouter2.实现动态面包屑导航,能够根据路由变化自动更新3.包含路由权限控制和动态路由的处理(如引用[3]中提到的权限控制)4.展示一个完整的示例,包括代码和解释##实现思路1.**路由配置**:在路由配置中添加`meta`属性,用于存储面包屑所需的文本信息,以及可能需要的前置权限信息。2.**面包屑组件**:创建一个面包屑组件,它能够从当前路由中提取匹配的路由记录,并根据这些记录生成面包屑导航。3.**处理动态路由**:对于动态路由(如`/user/:id`),我们需要将动态参数解析为对应的名称(例如根据id获取用户名),这可以通过在路由记录中添加额外的属性或使用全局状态管理来实现。4.**权限控制**:根据用户权限过滤面包屑中显示的路由,可以参考引用[3]中提到的权限控制方法。##代码实现###步骤1:配置路由在定义路由时,我们在`meta`属性中添加`breadcrumb`字段,用于显示面包屑的文本,还可以添加`roles`字段进行权限控制。```javascript//router/index.jsconstroutes=[{path:'/',name:'Home',component:Home,meta:{breadcrumb:'首页'}},{path:'/books',name:'Books',component:Books,meta:{breadcrumb:'图书列表'}},{path:'/book/:id',name:'BookDetail',component:BookDetail,meta:{breadcrumb:(route)=>{//动态获取图书名称,这里假设有全局状态存储了图书信息constbook=bookStore.getBook(route.params.id);returnbook?book.title:'图书详情';}}}];```注意:在动态路由的情况下,`breadcrumb`可以是一个函数,它接收当前路由对象作为参数,返回一个字符串。###步骤2:创建面包屑组件我们创建一个`Breadcrumb.vue`组件,使用VueRouter的`route.matched`来获取当前路由匹配的所有记录。```vue<template><navclass="breadcrumb"><ol><liv-for="(record,index)inbreadcrumbs":key="record.path"><router-linkv-if="index< breadcrumbs.length-1":to="record.path">{{record.meta.breadcrumb}}</router-link><spanv-else>{{typeofrecord.meta.breadcrumb==='function'?record.meta.breadcrumb(record):record.meta.breadcrumb}}</span></li></ol></nav></template><scriptsetup>import{computed}from'vue';import{useRoute}from'vue-router';constroute=useRoute();//计算属性生成面包屑数组constbreadcrumbs=computed(()=>{constmatched=route.matched;returnmatched.map(item=>{return{path:item.path,meta:item.meta};});});</script>```###步骤3:处理动态路由的显示在步骤1中我们已经展示了如何通过函数形式动态生成面包屑文本。但注意,在组件中我们通过调用该函数并传入当前路由记录来获取具体值。###步骤4:权限控制在面包屑导航中,我们可能需要根据用户权限来决定是否显示某个层级。我们可以参考引用[3]中的权限控制方案,在生成面包屑之前对路由记录进行过滤。修改面包屑组件的计算属性:```javascriptconstbreadcrumbs=computed(()=>{//获取过滤后的路由记录,过滤掉没有权限的记录constmatched=route.matched.filter(item=>{//假设我们有一个检查权限的函数checkPermission,该函数返回布尔值returncheckPermission(item.meta.roles);});returnmatched.map(item=>{return{path:item.path,meta:item.meta};});});```其中,`checkPermission`函数的实现需要结合项目中的权限系统。例如,可以这样实现:```javascript//假设当前用户角色存储在全局状态中constuserStore=useUserStore();constuserRoles=computed(()=>userStore.roles);functioncheckPermission(requiredRoles){//如果路由记录中不需要特定权限(即未设置roles),则直接允许if(!requiredRoles)returntrue;//检查用户角色是否满足要求returnuserRoles.value.some(role=>requiredRoles.includes(role));}```###步骤5:在布局中使用面包屑组件将面包屑组件放在布局的合适位置,例如顶部导航栏下方。```vue<template><div><AppHeader/><Breadcrumb/><router-view/></div></template>```##完整示例下面是一个结合了上述思路的完整示例:###路由配置(router/index.js)```javascriptimport{createRouter,createWebHistory}from'vue-router';constroutes=[{path:'/',name:'Home',component:()=>import('@/views/Home.vue'),meta:{breadcrumb:'首页'}},{path:'/books',name:'Books',component:()=>import('@/views/Books.vue'),meta:{breadcrumb:'图书列表'}},{path:'/book/:id',name:'BookDetail',component:()=>import('@/views/BookDetail.vue'),meta:{breadcrumb:(route)=>{//在实际项目中,可能需要从store中获取图书信息//这里简化为一个演示constbook=bookStore.getBook(route.params.id);returnbook?book.title:'图书详情';}}}];constrouter=createRouter({history:createWebHistory(),routes});exportdefaultrouter;```###面包屑组件(components/Breadcrumb.vue)```vue<template><navclass="breadcrumb"><olclass="flex"><liv-for="(record,index)inbreadcrumbs":key="index"class="flexitems-center"><templatev-if="index< breadcrumbs.length-1"><router-link:to="record.path"class="text-blue-600hover:underline">{{displayBreadcrumbText(record)}}</router-link><spanclass="mx-2">/</span></template><spanv-elseclass="text-gray-500">{{displayBreadcrumbText(record)}}</span></li></ol></nav></template><scriptsetup>import{computed}from'vue';import{useRoute}from'vue-router';import{useBookStore}from'@/stores/book';//假设有存储图书的storeconstroute=useRoute();constbookStore=useBookStore();//获取图书storeconstbreadcrumbs=computed(()=>{//过滤掉没有breadcrumb字段的路由记录constmatched=route.matched.filter(item=>item.meta&&item.meta.breadcrumb);returnmatched;});//根据路由记录计算要显示的面包屑文本functiondisplayBreadcrumbText(record){constmeta=record.meta;if(typeofmeta.breadcrumb==='function'){returnmeta.breadcrumb(route);}else{returnmeta.breadcrumb;}}</script>```**注意**:上面的示例中,我们假设有一个管理图书状态的store(Pinia或Vuex),在动态路由中通过图书id获取图书信息。如果使用组合式API,你也可以直接在路由记录中定义如何获取动态参数对应的文本。###权限过滤(可选)如果面包屑需要权限过滤,则可以在计算属性`breadcrumbs`中加入权限检查。```javascriptconstbreadcrumbs=computed(()=>{returnroute.matched.filter(item=>{returncheckPermission(item.meta.requiredRoles);}).map(item=>{//保留meta和pathreturnitem;});});```##总结通过VueRouter提供的路由匹配信息(`route.matched`),我们可以轻松构建动态面包屑导航。通过路由配置中的`meta`字段,我们可以控制每个路由的面包屑文本以及权限要求。在面包屑组件中,我们根据当前路由匹配结果生成面包屑列表,并通过函数支持动态文本生成,同时也可以整合权限控制系统。这种方法简洁有效,并且能够适应动态路由和权限控制的需求[^1][^3]。§§相关问题§§1.如何在没有全局状态管理的情况下实现动态路由参数的面包屑文本?2.如何实现面包屑导航缓存和动画效果?3.如何结合权限控制系统动态显示面包屑导航?</think> # Vue Router实现面包屑导航功能详解 在Vue项目中实现面包屑导航功能,可以使用Vue Router提供的路由信息和自定义逻辑动态生成导航路径。下面我将详细介绍实现方案,并提供一个完整的示例。 ## 实现思路 1. **路由配置**:在路由配置中添加`meta`属性,存储面包屑所需信息(标题、层级等) 2. **面包屑组件**:创建一个可复用的面包屑组件 3. **路由信息解析**:从路由匹配记录中提取面包屑信息 4. **权限控制**:结合权限系统过滤显示的面包屑项 ## 代码实现 ### 路由配置 (router/index.js) ```javascript import { createRouter, createWebHistory } from 'vue-router' const routes = [ { path: '/', name: 'Home', component: () => import('@/views/Home.vue'), meta: { breadcrumb: '首页' } }, { path: '/books', name: 'Books', component: () => import('@/views/BookList.vue'), meta: { breadcrumb: '图书列表' } }, { path: '/book/:id', name: 'BookDetail', component: () => import('@/views/BookDetail.vue'), meta: { breadcrumb: (route) => { // 动态获取图书名称,实际项目中从store获取 const book = bookStore.getBook(route.params.id) return book ? `${book.title}` : '图书详情' } } } ] const router = createRouter({ history: createWebHistory(), routes }) export default router ``` ### 面包屑组件 (components/Breadcrumb.vue) ```vue <template> <nav class="breadcrumb"> <ol class="flex"> <li v-for="(item, index) in items" :key="index" class="flex items-center"> <router-link v-if="index < items.length - 1" :to="item.path" class="text-blue-600 hover:underline" > {{ item.title }} </router-link> <span v-else class="text-gray-500"> {{ item.title }} </span> <span v-if="index < items.length - 1" class="mx-2">/</span> </li> </ol> </nav> </template> <script setup> import { computed } from 'vue' import { useRoute } from 'vue-router' import { useBookStore } from '@/stores/book' const route = useRoute() const bookStore = useBookStore() // 计算面包屑项目 const items = computed(() => { return route.matched .filter(record => record.meta && record.meta.breadcrumb) .map(record => { return { title: typeof record.meta.breadcrumb === 'function' ? record.meta.breadcrumb(route) : record.meta.breadcrumb, path: record.path } }) }) </script> <style scoped> .breadcrumb { padding: 12px 0; border-bottom: 1px solid #eee; margin-bottom: 20px; } </style> ``` ### 使用面包屑组件 (App.vue) ```vue <template> <div class="app-container"> <header> <!-- 顶部导航--> </header> <div class="container mx-auto px-4 py-6"> <!-- 面包屑导航 --> <Breadcrumb /> <!-- 路由视图 --> <router-view /> </div> <footer> <!-- 底部信息 --> </footer> </div> </template> <script setup> import Breadcrumb from '@/components/Breadcrumb.vue' </script> ``` ### 权限控制集成 对于需要权限控制的路由,可以在路由守卫中添加权限验证: ```javascript // 动态路由注册函数 function setupDynamicRoutes() { const userRoles = getUserRoles() const filteredRoutes = asyncRoutes.filter(route => { return checkPermission(userRoles, route.meta?.roles) }) filteredRoutes.forEach(route => { router.addRoute('Layout', route) }) } // 检查权限 function checkPermission(userRoles, requiredRoles) { if (!requiredRoles) return true return userRoles.some(role => requiredRoles.includes(role)) } ``` ## 工作原理 1. Vue Router会自动生成当前路由的匹配记录数组 (`route.matched`) 2. 面包屑组件遍历这些路由记录 3. 对每个记录检查其`meta.breadcrumb`属性 4. 如果`breadcrumb`是函数,则调用该函数生成显示文本 5. 最后生成面包屑导航项 这种实现方式可以: - 自动跟随路由变化更新导航 [^1] - 支持动态参数(如商品详情页面- 与权限控制系统集成 [^3] - 提供清晰的页面位置指示 [^2] ## 总结 Vue Router提供了强大的路由管理能力,结合组合式API可以轻松实现动态面包屑导航功能。关键点包括: - 在路由配置中定义面包屑元信息 - 利用`route.matched`获取路由层级信息 - 创建可复用的面包屑组件 - 结合权限系统控制显示 这种方法简单高效,能很好地满足后台管理系统的导航需求[^1][^3]。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值