自己封装的Tagsview

Tagsview组件,具体要根据项目需改的地方 组件内都有备注

<template>
  <!-- calss添加了一个样式 -->
  <div class="tagsbox">
    <div
      v-for="(item, index) in tags"
      :key="index"
      :class="isActive(item.path) ? 'active' : ''"
      class="tagsview"
      @contextmenu.prevent="openMenu(item, $event)"
      @click="tagsmenu(item)"
    >
      {{ item.name }}
      <!-- 这个地方一定要click加个stop阻止,不然会因为事件冒泡一直触发父元素的点击事件,无法跳转另一个路由 -->
      <!-- 给首页去掉XX按钮 -->
      <span
        v-if="index != 0"
        class="el-icon-close tagsicon"
        @click.stop="handleClose(item, index)"
      />
      <ul
        v-show="visible"
        class="contextmenu"
        :style="{ left: left + 'px', top: top + 'px' }"
      >
        <li @click.stop="handleClose(item, index)">关闭</li>
        <!-- <li @click.stop="cleartags($route.path)">关闭所有</li> -->
      </ul>
    </div>
  </div>
</template>

<script>
// 这个就是导入vuex的数据,配合下面...map用
import { mapState, mapMutations } from 'vuex';
export default {
  data() {
    return {
      // 右键菜单隐藏对应布尔值
      visible: false,
      // 右键菜单对应位置
      top: 0,
      left: 0
    };
  },
  mounted() {
    // console.log(this.tags, 'tags111111');
  },
  computed: {
    // 引入vuex中state中的tags数据,一样this调用就行
    ...mapState('fhyctags', ['tags'])
    // ...mapState(['tags'])
  },
  watch: {
    // 监听右键菜单的值是否为true,如果是就创建全局监听点击事件,触发closeMenu事件隐藏菜单,如果是false就删除监听
    visible(value) {
      if (value) {
        document.body.addEventListener('click', this.closeMenu);
      } else {
        document.body.removeEventListener('click', this.closeMenu);
      }
    }
  },
  methods: {
    // 引入vuex中mutation方法,可以直接this.xxx调用他
    ...mapMutations('fhyctags', ['closeTab', 'cleartagsview']),
    // 点击叉叉删除的事件
    handleClose(item, index) {
      // console.log(item, index, 'XXXX');
      // 缓存状态传值
      this.$store.commit('fhyctags/isTabviewFalse');
      // 先把长度保存下来后面用来比较做判断条件
      const length = this.tags.length - 1;
      // vuex调方法,上面...map引入的vuex方法,不会这种方法的看vue官网文档
      this.closeTab(item);
      // console.log(item, 'itemitem');
      // 如果关闭的标签不是当前路由的话,就不跳转
      if (item.path !== this.$route.path) {
        return;
      }
      // 判断:如果index和length是一样的,那就代表都是一样的长度,就是最后一位,那就往左跳转一个
      if (index === length) {
        // console.log(index, length, 'changdu');
        // 再判断:如果length=0,也就是说你删完了所有标签
        if (length === 0) {
          // 那么再判断:如果当前路由不等于index,也就是我首页的路由
          // if (this.$route.path !== '/index') {
          if (this.$route.path !== '/loadForecasting/home/homeIndex') {
            // 缓存状态传值
            this.$store.commit('fhyctags/isTabviewFalse');
            // 那么就跳转首页。这一步的意思是:如果删除的最后一个标签不是首页就统一跳转首页,如果你删除的最后一个标签是首页标签,已经在这个首页路由上了,你还跳个什么呢。这不重复操作了吗。
            // this.$router.push({ path: '/index' })
            this.$router.push({ path: '/loadForecasting/home/homeIndex' });
            // this.reload();
          }
        } else {
          // 缓存状态传值
          this.$store.commit('fhyctags/isTabviewFalse');
          // 那么,如果上面的条件都不成立,没有length=0.也就是说你还有好几个标签,并且你删除的是最后一位标签,那么就往左边挪一位跳转路由
          this.$router.push({ path: this.tags[index - 1].path });
          // this.$router.push({ path: this.tags[index - 1].url });
        }
      } else {
        // 缓存状态传值
        this.$store.commit('fhyctags/isTabviewFalse');
        // 如果你点击不是最后一位标签,点的前面的,那就往右边跳转
        this.$router.push({ path: this.tags[index].path });
        // this.$router.push({ path: this.tags[index].url });
      }
    },
    // 点击跳转路由

    tagsmenu(item) {
      // 缓存状态传值
      this.$store.commit('fhyctags/isTabviewTrue');
      console.log(item, 'tags对象');
      // 判断:当前路由不等于当前选中项的url,也就代表你点击的不是现在选中的标签,是另一个标签就跳转过去,如果你点击的是现在已经选中的标签就不用跳转了,因为你已经在这个路由了还跳什么呢。
      if (this.$route.path !== item.path) {
        // 用path的跳转方法把当前项的url当作地址跳转。
        this.$router.push({ path: item.path });
      }
    },
    // 通过判断路由一致返回布尔值添加class,添加高亮效果
    isActive(route) {
      // console.log(route, '动态class');
      return route === this.$route.path;
    },
    // 右键事件,显示右键菜单,并固定好位置。
    openMenu(tag, e) {
      console.log(this.this.$route, 'llllllll');
      this.visible = true;
      // if(this.this.$route.path)
      this.selectedTag = tag;
      const offsetLeft = this.$el.getBoundingClientRect().left;
      this.left = e.clientX - offsetLeft + 10; // 右键菜单距离左边的距离
      this.top = e.clientY + 10; // 右键菜单距离上面的距离           这两个可以更改,看看自己的右键菜单在什么位置,自己调
    },
    // 隐藏右键菜单
    closeMenu() {
      this.visible = false;
    },
    // 右键菜单关闭所有选项,触发vuex中的方法,把当前路由当参数传过去用于判断
    cleartags(val) {
      this.cleartagsview(val);
    }
  }
};
</script>

<style lang="scss" scoped>
//标签导航样式
.tagsview {
  cursor: pointer;
  margin-left: 4px;
  height: 30px;
  line-height: 30px;
  padding: 0 10px;
  border: 1px solid #d8dce5;
  border-radius: 5px;
  color: #000;
  font-size: 14px;
  display: inline-block;
}
//叉号鼠标经过样式
.tagsicon:hover {
  color: #f56c6c;
}
//标签高亮
.active {
  background-color: #75b9e2;
  // background-color: #40ba84;
  color: #fff;
}
//右键菜单样式
.contextmenu {
  margin: 0;
  background: #fff;
  z-index: 100;
  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, 0.3);
  li {
    margin: 0;
    padding: 7px 16px;
    cursor: pointer;
    &:hover {
      background: #eee;
    }
  }
}
</style>

/store/modules内新建tagsView.js

const state = {
  tags: [],
  // tagsview标签显示隐藏
  isCollapse: false,
  // 判断缓存
  isTabview: true
}
const mutations = {
  // 更改缓存状态
  isTabviewFalse(state) {
    state.isTabview = false
  },
  // 更改缓存状态
  isTabviewTrue(state) {
    state.isTabview = true
  },
  // 全局方法
  pushtags(state, val) {
    // console.log(val)
    // 如果等于-1说明tabs不存在那么插入,否则什么都不做
    // findindex找角标,循环判断一下,如果等于那么就代表有相同的,就不必添加,如果找不到那就是-1.就添加
    const result = state.tags.findIndex(item => item.name === val.name)
    console.log(result, 1)
    result === -1 ? state.tags.push(val) : ''
    console.log(result, 2)
  },
  // 关闭标签
  closeTab(state, val) {
    // 同上,找角标,然后用角标的位置对应删除一位。splice:这是数组的删除方法
    const result = state.tags.findIndex(item => item.name === val.name)
    state.tags.splice(result, 1)
  },
  // 关闭所有tagsview标签
  cleartagsview(state, val) {
    // 清空数组  此处更改为项目内的首页路由保证清除全部时显示首页
    // state.tags = []
    state.tags = [{
      name: '首页',
      path: '/loadForecasting/home/homeIndex'
    }]
    // 跳转到首页,val接受传过来的当前路由  此处更改为项目内的首页路由
    if (val !== '/loadForecasting/home/homeIndex') {
      router.push({ path: '/loadForecasting/home/homeIndex' })
    }
  },
  // 改变tagsview显示隐藏
  changeisshow(state) {
    state.isCollapse = !state.isCollapse
  }
}

const actions = {

}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}

最后在/store/index文件内引入

import Vue from 'vue'
import Vuex from 'vuex'
import app from './modules/app'
import user from './modules/user'
import tagsView from './modules/tagsView'
import permission from './modules/permission'
import settings from './modules/settings'
import getters from './getters'

Vue.use(Vuex)

const store = new Vuex.Store({

  
  modules: {
    app,
    user,
    tagsView,//组件
    permission,
    settings,
  },
  getters
})

export default store
posted @ 2025-03-03 14:10  刘酸酸sour  阅读(49)  评论(0)    收藏  举报