动态添加tag标签

前言

当页面路由变化时,然后生成一个tag标签,点击每个tag标签可以跳转到不同的页面

直接上代码

  • tag标签组件
// tagView.vue 
<template>
  <div class="tagwrap">
    <!-- 
      1. 在router-link中,to已经绑定了点击跳转的事件,
      2. 所以在router-link中绑定@click点击事件是没有作用的,
      3. 可以在router-link标签里面去定义一个标签去绑定@click点击事件
      4. 设置点击时的css样式绑定class,运用三目运算符
          :class="isActive(route) ? active : ''"
    -->
    <router-link
      :to="{ path: tagroute.path }"
      class="routerlink"
      v-for="tagroute in tagList"
      :key="tagroute.path"
      :class="isActive(tagroute) ? active : ''"
    >
      {{ tagroute.title }}
      <!-- 
        设置关闭字体图标,设置点击事件 
          设置点击事件的.prevent.stop修饰符,方式点击事件冒泡上去
      -->
      <span class="el-icon-close" @click.prevent.stop="delSelectTag(tagroute)"></span>
    </router-link>
  </div>
</template>

<script>
export default {
  data: function() {
    return {
      active: "active",
      tagViewBg: "tagViewBg"
    };
  },
  methods: {
    // 判断tag路由选中状态, route为当前点击的标签的路由
    isActive: function(tagroute) {
      /**
       *  1. route.path 遍历tagList中的我的标签route的path
       *  2. this.$route.path 点击当前路由对象的path
       *  3. 判断是否一致,一致的话表示当前为选中状态
       */
      return tagroute.path == this.$route.path;
    },
    delSelectTag: function(tagroute) {
      /**
       * 1. 调用vuex中删除标签的方法,将当前标签对象tagroute传进去,进行异步处理
       * 2. data为promise异步操作处理成功后返回的的数据
       */
      this.$store.dispatch("deleteTag", tagroute).then(data => {
        // 判断当前删除的标签的选中状态,选中的话,就跳到最后一个,未选中的话则不需要跳转
        if (this.isActive(tagroute)) {
          // slice(-1)选中data数组中最后一个元素并返回放在一个数组中
          const lastRoute = data.slice(-1)[0];
          // 判断数组中最后一个标签是否还存在,不存在的话就跳到首页index
          if (lastRoute) {
            // 路由跳转到最后一路由
            this.$router.push(lastRoute);
          } else {
            /**
             * 当页面跳转到首页时,watch侦听器会侦听到路由的变化;
             * 会再次执行储存路由状态到vuex中的操作,此时在首页会多出来一个标签;
             * 此时需要在侦听器中进行判断,当变化的路由是 index 时,不进行储存操作
             */
            this.$router.replace({ path: '/index' })
          }
        }
      });
    }
  },
  computed: {
    tagList: function() {
      let tagLists = this.$store.getters.tagList;
      return tagLists;
    }
  },
  watch: {
    // 直接监听路由的变化,当路由变化时,将当前路由对象保存到vuex当中去
    $route: function() {
      console.log("this.$route>>>>>>>>>>", this.$route);
      // 判断当前路由的path是index时,返回,不执行储存路由到vuex中去
      if (this.$route.path == '/index') return; 
      // 调用vuex中的添加方法
      this.$store.dispatch("addTag", this.$route);
    }
  }
};
</script>

<style lang="scss" scoped>
.tagwrap {
  margin-bottom: 20px;
  // padding: 10px 0;
  // background: red;
}
.routerlink {
  height: 30px;
  padding: 7px 15px;
  background-color: #f3f7f3;
  text-decoration: none;
  margin: 0 5px;
  font-size: 14px;
  color: black;
  &:hover {
    background-color: rgb(0, 180, 0);
    color: white;
  }
}
// 设置点击tag后的样式
.active {
  background-color: rgb(0, 180, 0);
  color: white;
  border-radius: 5px;
}
.tagViewBg {
  padding: 10px 0;
  background: red;
}
</style>>
  • 状态管理tagList
// tagList.js
import { saveTagToCookie, deleteAllTagFromCookie } from "@/common/cookieTag.js";
// import { , getTagFromCookie } from "@/common/cookieTag.js";

export const Tag = {
    state: {
        tagList: []
    },
    mutations: {
        // 将传进来的tag添加到tagList中
        ADD_Tag(state, tag) {
            /**
             *  点击tag时,去重处理
             *    1. 用some函数去判断当前点击的tag是否在数组中存在,只要有一项满足条件,将返回true 
             */
            console.log("state.tagList", state.tagList);
            const isResult = state.tagList.some(item => {
                return item.path == tag.path;
            })
            // 2. 判断当isResult为真的时候返回,为假的时候执行下面push的代码
            if (isResult) return;

            /** 
             * 3. 在将传进来的标签json对象进行cookie持久化存储的时候,因为标签json对象里面有一些数组,就会遇到不能将json数据转换成字符串的错误
             *   取出tag标签json对象中我们需要的值存放到一个新json数组中,将新的json数组添加到state中的tagList
             * */
            const newTagArr = {
                name: tag.name,
                path: tag.path,
                title: tag.meta.title
            }

            state.tagList.push(newTagArr);

            // 4. 将tagList存放到cookie中进行持久化存储
            saveTagToCookie(state.tagList);
        },
        // 删除tag时,对传进来的tag值进行判断,若该值存在,就将其删除
        DELETE_Tag(state, tag) {
            // 在vuex中将一个tag数据从tag数组中删除
            for (let i = 0; i <= state.tagList.length; i++) {
                if (state.tagList[i] == tag) {
                    state.tagList.splice(i, 1);
                    break;
                }
            }
            // 将删除tag数据后的state.tagList在存储一遍
            saveTagToCookie(state.tagList);
        },
        DELETE_ALL_TAG(state) {
            state.tagList = [];
            deleteAllTagFromCookie();
        }
    },
    actions: {
        addTag({ commit, state }, tag) {
            console.log("state.tagList<<<<<<<<<<<<", state.tagList);
            commit('ADD_Tag', tag);
        },
        deleteTag({ commit, state }, tag) {
            /**
             * 1. 利用promise异步处理,避免取vuex中的数据时,会取到旧的数据
             * 2. 将vuex中state存储的数据传进来
             * 3. 当外部调用删除tag标签方法时,进行完删除操作后tagList数组的数据会更新
             * 4. 将更新的数据展开copy一份,避免直接操作state存储的数据  
             * 5. 将copy的数据数据交给resolve处理,并返回
             * 6. resolve处理成功的数据        
             */
            return new Promise((resolve, reject) => {
                commit('DELETE_Tag', tag);
                resolve([...state.tagList]);
            })
        },
        deleteAllTag({ commit }) {
            commit('DELETE_ALL_TAG');
        }
    }
}

1. 首先watch侦听器侦听路由的变化,当路由变化时,将当前路由对象保存到vuex当中去
2. 在vuex状态管理中有个tagList存放路由变化的tag,在vuex里面去处理去重问题,判断当前点击的路由不存在的时候,才将新的路由添加到tag数组中,并将tag数组进行持久化存储,解决一刷新tag标签就消失的问题
3. 用computed计算属性去监听从vuex状态管理中去获取到的值,在页面渲染出来

1)监听状态管理并返回一个tagList数组


2) 在页面渲染遍历出来

4. 判断tag标签的点击状态,设置不同的css样式

1)判断点击的tag标签的路由路径是否是当前路由this.$route.ptah的路径,返回truefalse

2) 三目运算符设置不同css样式


5. 点击关闭按钮关闭标签,

1)传入点击的tag标签的路由,从vuex状态管理中去删除一个点击的路由数组项,在vuex中有异步处理



2)关闭一个tag标签时,tag的选中状态转换到最后一个tag标签,页面跳转到最后一个tag标签的页面;若关闭的是最后一个tag标签,则跳转的index首页


©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。