实现基于Vue的面包屑导航+链接可跳转组件

4,844 阅读3分钟

简单的来说,面包屑导航的作用就是告诉用户他们在网站中的位置,方便用户确定下一步去留,对于用户来说这是很好的体验。

静态路由-面包屑导航

需要手动配置路由和菜单。

项目路由如下

const routes = [
 {
    path: '/home1',
    name: 'home1',
    meta: {
      breadID: '0'
    }
  },
  {
    path: '/home2',
    name: 'home2',
    meta: {
      breadID: '0-0'
    }
  },
  {
    path: '/home3',
    name: 'home3',
    meta: {
      breadID: '0-0-0'
    }
  },
  {
    path: '/home4',
    name: 'home4',
    meta: {
      breadID: '1'
    }
  },
  {
    path: '/home5',
    name: 'home5',
    meta: {
      breadID: '1-0'
    }
  },
  {
    path: '/home6',
    name: 'home6',
    meta: {
      breadID: '1-0-0'
    }
  }
]

菜单配置如下

面包屑导航有一个层级的菜单。

let breadNavList = [
    {
        id:"0",
        name:'0-第一级',
        url:'/home1',
        menu:[
            {
                id:'0-0',
                name:'0-第二级',
                url:'/home2',
                menu:[
                  {
                    id:'0-0-0',
                    name:'0-第三级',
                    url:'/home3',
                  }
                ]
            }
        ]
    },
    {
        id:"1",
        name:'1-第一级',
        url:'/home3',
        menu:[
            {
                id:'1-0',
                name:'0-第二级',
                url:'/home4',
                menu:[
                  {
                    id:'1-0-0',
                    name:'0-第三级',
                    url:'/home5',
                  }
                ]
            }
        ]
    }
]

可以看到在路由的meta字段中加入了属性breadID,详情解说一下这个属性

breadID表明当前路由在menu菜单中的位置。

'0' 当前面包屑有一级,0代表该路由在在菜单栏中的位置breadNavList[0]
'0-0' 代表当前面包屑有两级,breadNavList[0].menu[0]
'0-0-0' 代表当前面包屑有三级,breadNavList[0].menu[0].menu[0]
'0-1-0' 代表当前面包屑有三级,breadNavList[0].menu[1].menu[0]
.....以此类推

实现

实现一个容器

数组bread用来装载需要展现的路由。如:

bread = ['第一级','第二级','第三级']
bread = ['第一级','第二级']

效果:

第一级 > 第二级 > 第三级
第一级 > 第二级

监听路由变化

当路由变化的时候,面包屑也会发生变化。

  • 判断当前是否有路由
  • 判断当前路由是否有字段breadID
  • 如若有,调用getBread函数递归获取面包屑
 watch:{
      '$route':{
        handler(){
          this.bread = []
          if(this.$route && this.$route.meta && this.$route.meta.breadID){
            let arr = this.$route.meta.breadID.split('-')
            this.getBread(arr,this.breadNavList)
          } else {
            console.error('字段`this.$route.meta.breadID`没有设置')
          }
        },
        immediate:true
      }
    }

递归获取面包屑

getBread参数:

  • 当前路由属性breadID,转化成数组arr,如:'0-1-0' -> ['0','1','0']
  • 菜单menu,当前层级下的菜单。

思路:

  • 获取arr的长度,如果小于0,说明这个层级不存在,不往下递归。
  • 如果大于0,说明层级存在,将这一层的name以及url加入容器bread。
  • 取出arr第一个元素。
  • 循环第一,二,三步,直到arr的长度为0。
getBread(arr,menu){
    if(arr.length < 0){
       return;
    }
    this.bread.push(menu[arr[0]])
    menu = menu[arr[0]].menu
    arr.shift()
    this.getBread(arr,menu)
}

全部代码

<template>
  <div class="bread-wrap">
    <div class="bread-item" v-for="(item,index) in bread" :key="index">
      <span @click="toBreadRouter(item)">{{item.name}}</span><i v-if="index !== bread.length - 1"> > </i></div>
  </div>
</template>

<script>
  export default {
    name: "breadNav",
    data() {
      return {
        bread:[],//面包屑容器
        breadNavList:[]// 面包屑菜单
      }
    },
    watch:{
      '$route':{
        handler(){
          this.bread = []
          if(this.$route && this.$route.meta && this.$route.meta.breadID){
            let arr = this.$route.meta.breadID.split('-')
            this.getBread(arr,this.breadNavList)
          } else {
            console.error('字段`this.$route.meta.breadID`没有设置')
          }
        }
      }
    },
    methods: {
      getBread(arr,menu){
        if(arr.length > 0){
          this.bread.push(menu[arr[0]])
          menu = menu[arr[0]].menu
          arr.shift()
          if(arr.length > 0){
            return this.getBread(arr,menu)
          }
        }
      },
      toBreadRouter(item){
        this.$emit('changeRoute',item)
      }
    }
  }
</script>

<style scoped>
  .bread-wrap{
    color:#606266;
    font-size:14px;
  }
  .bread-wrap .bread-item{
    display: inline-block;
  }
  .bread-wrap .bread-item span:hover{
    cursor: pointer;
    color:#409EFF;
  }
  .bread-wrap .bread-item:last-child{
    cursor: auto;
    color:#303133;
  }
  .bread-wrap .bread-item:last-child span{
    cursor: auto;
  }
  .bread-wrap .bread-item i{
    font-style: normal;
  }
</style>

demo演示

缺点

  • 路由的breadID必须和menu菜单的子项位置一一对应。
  • 如果项目中有两个面包屑,路由的breadID将会混乱。
  • 不适用一个产品可能属于多个类目的项目。(也就是说你根据不同的类目路径进行点击都可能得到同一个产品。)

总结

该面包屑组件封装上了npm有兴趣的可以下载试试看。gitHub地址-面包屑导航使用教程