vue+element-ui实现el-tab标签的动态面包屑

发布时间 2023-04-03 13:51:29作者: Amyel

以下内容仅供学习使用

前言: 下面是最终实现的效果图
image

  1. 首先在router.js里面配置meta:

image

  1. 封装一个el-tab面包屑的子组件 通过v-for指令和tags数组中的数据进行渲染
<template>
  <div>
    <el-tag :key="index" v-for="(tag, index) in tags" :closable="tag.name !== 'users'" :disable-transitions="false" @close="handleClose(tag, index)" @click="changeMenu(tag)" :effect="isActive(tag) ? 'dark' : 'plain'">
      {{ tag.label }}
    </el-tag>
  </div>
</template>
  1. 组件实例的data中定义了一个tags数组,用于存储标签页的数据
  data () {
    return {
      tags: [],
    };
  },
  1. watch监听$route变量的变化来添加新的标签页,同时使用localStorage保存了当前打开的标签页信息,以便刷新页面后仍能保持原来的状态。
    watch: {
    tags: {
      handler (newTags) {
        localStorage.setItem('tags', JSON.stringify(newTags));
      },
	  //deep: true 表示在监听属性变化时,将会递归遍历所有嵌套的子属性,而不仅仅是监听对象的直接属性变化。
      deep: true,(可以不用)
    },
    $route (to) {
      if (to.matched.some((record) => record.meta.requiresAuth)) {
        // 如果需要验证身份,则在异步组件加载完成后再添加标签
        const tag = { name: to.name, label: to.meta.title };
        About().then(() => {
          const isTagExist = this.tags.some((t) => t.name === tag.name);
          if (!isTagExist) {
            this.tags.push(tag);
          }
        });
      } else {
        // 否则直接添加标签
        const tag = { name: to.name, label: to.meta.title };
        const isTagExist = this.tags.some((t) => t.name === tag.name);
        if (!isTagExist) {
          this.tags.push(tag);
        }
      }
    },
  },
  1. mounted从本地存储中获取之前保存的标签数组,如果有值就将其赋给组件的tags属性,否则就添加一个默认的首页标签。
  mounted () {
  	//从本地存储中获取tags,如果不存在则返回一个空数组[]。
    const tags = JSON.parse(localStorage.getItem('tags') || '[]');
	//判断获取到的tags数组的长度,如果大于0,则将它赋值给组件的tags属性。
    if (tags.length) {
      this.tags = tags;
    } else {
	//如果获取到的tags数组的长度等于0,则添加一个默认的首页标签,包括其路径、名称和标签文字,然后将它添加到tags数组中。
      this.tags.push({ path: '/users', name: 'users', label: '首页' });
    }
  },
  1. methods
methods: {
	//handleClose(tag, index):处理关闭标签的逻辑。如果标签不是首页('users'),则从标签数组中移除该标签。
	//如果关闭的标签不是当前路由的话,则不进行路由跳转。如果关闭的标签是最右边的标签,则往左边跳转一个,否则往右边跳转。
    handleClose (tag, index) {
      // 处理关闭标签的逻辑
      if (tag.name !== 'users') {
        this.tags.splice(index, 1);
      }
      // 如果关闭的标签不是当前路由的话,就不跳转
      if (tag.name !== this.$route.name) {
        return;
      }
      const length = this.tags.length;
      // 关闭的标签是最右边的话,往左边跳转一个
      if (index === length) {
        this.$router.push({ name: this.tags[index - 1].name });
      } else {
        // 否则往右边跳转
        this.$router.push({ name: this.tags[index].name });
      }
    },
	//changeMenu(tag):处理点击标签的逻辑。如果点击的是首页标签,则跳转到首页。
	//如果点击的不是首页标签,则根据标签的 name 属性获取该标签对应的路由路径,并跳转到该路径。如果点击的标签已经是当前路由的话,则不进行跳转。
    changeMenu (tag) {
      // 跳转首页
      if (tag.name === 'users') {
        if (this.$route.path !== '/users') {
          this.$router.push({ path: '/users' });
        }
        return;
      }
      // 处理点击标签的逻辑
      if (tag.name !== 'users') {
        const toPath = this.$router.resolve({ name: tag.name }).href;
        if (this.$route.path !== toPath) {
          this.$router.push({ name: tag.name });
        }
      }
    },
	//isActive(tag):判断当前标签是否为当前路由。如果是,则返回 true,否则返回 false。
    isActive (tag) {
      // 判断当前标签是否为当前路由
      return tag.name === this.$route.name;
    },
  },
  1. 样式
<style lang="scss" scoped>
.el-tag--dark,
.el-tag--plain {
  cursor: pointer;
  margin-left: 10px;
}
.el-tag:nth-child(2n) {
  cursor: pointer;
  margin-left: 10px;
}
</style>
  1. 在点击退出的时候清除localStorage.clear('tags')
localStorage.clear('tags')
  1. 调用封装好的子组件
    import MyTag from '../../components/MyTag.vue'
    components: {MyTag},
    image

  2. 效果图
    image

  3. 完整的子组件代码,需要自取

<template>
  <div>
    <el-tag :key="index" v-for="(tag, index) in tags" :closable="tag.name !== 'users'" :disable-transitions="false" @close="handleClose(tag, index)" @click="changeMenu(tag)" :effect="isActive(tag) ? 'dark' : 'plain'">
      {{ tag.label }}
    </el-tag>
  </div>
</template>
<script>
export default {
  data () {
    return {
      tags: [],
    };
  },
  watch: {
    tags: {
      handler (newTags) {
        localStorage.setItem('tags', JSON.stringify(newTags));
      },
      deep: true,
    },
    $route (to) {
      if (to.matched.some((record) => record.meta.requiresAuth)) {
        // 如果需要验证身份,则在异步组件加载完成后再添加标签
        const tag = { name: to.name, label: to.meta.title };
        About().then(() => {
          const isTagExist = this.tags.some((t) => t.name === tag.name);
          if (!isTagExist) {
            this.tags.push(tag);
          }
        });
      } else {
        // 否则直接添加标签
        const tag = { name: to.name, label: to.meta.title };
        const isTagExist = this.tags.some((t) => t.name === tag.name);
        if (!isTagExist) {
          this.tags.push(tag);
        }
      }
    },
  },
  mounted () {
    const tags = JSON.parse(localStorage.getItem('tags') || '[]');
    if (tags.length) {
      this.tags = tags;
    } else {
      this.tags.push({ path: '/users', name: 'users', label: '首页' });
    }
  },
  methods: {
    handleClose (tag, index) {
      // 处理关闭标签的逻辑
      if (tag.name !== 'users') {
        this.tags.splice(index, 1);
      }
      // 如果关闭的标签不是当前路由的话,就不跳转
      if (tag.name !== this.$route.name) {
        return;
      }
      const length = this.tags.length;
      // 关闭的标签是最右边的话,往左边跳转一个
      if (index === length) {
        this.$router.push({ name: this.tags[index - 1].name });
      } else {
        // 否则往右边跳转
        this.$router.push({ name: this.tags[index].name });
      }
    },
    changeMenu (tag) {
      // 跳转首页
      if (tag.name === 'users') {
        if (this.$route.path !== '/users') {
          this.$router.push({ path: '/users' });
        }
        return;
      }
      // 处理点击标签的逻辑
      if (tag.name !== 'users') {
        const toPath = this.$router.resolve({ name: tag.name }).href;
        if (this.$route.path !== toPath) {
          this.$router.push({ name: tag.name });
        }
      }
    },
    isActive (tag) {
      // 判断当前标签是否为当前路由
      return tag.name === this.$route.name;
    },
  },
};
</script>
<style lang="scss" scoped>
.el-tag--dark,
.el-tag--plain {
  cursor: pointer;
  margin-left: 10px;
}
.el-tag:nth-child(2n) {
  cursor: pointer;
  margin-left: 10px;
}
</style>