css
liukangdong
2024-05-22 d836f9914d8d838c5991157006682c3e39d22716
admin/src/components/common/tagsview.vue
@@ -1,50 +1,64 @@
<template>
  <div class="tags-view-style" style="display:flex; overflow-x: scroll;">
    <i class="el-icon-arrow-left btn" v-if="leftStatus" :class="leftStatus?'nor-btn':'ban-btn'" @click="scrollToStart()"></i>
  <div class="tags-view-style" style="display: flex; overflow-x: scroll">
    <i
      class="el-icon-arrow-left btn"
      v-if="leftStatus"
      :class="leftStatus ? 'nor-btn' : 'ban-btn'"
      @click="scrollToStart()"
    ></i>
    <div id="tags-box" ref="tags">
      <div
        v-for="(item, index) in tags"
        :key="index"
        :id="'tags-box-' + index"
        @contextmenu.prevent="openMenu(item,$event)"
        :class="isActive(item.url,index)?'active':''"
        @contextmenu.prevent="openMenu(item, $event)"
        :class="isActive(item.url, index) ? 'active' : ''"
        class="tagsview"
        @click="tagsmenu(item, index)"
      >
        {{ item.label }}
        <!-- 这个地方一定要click加个stop阻止,不然会因为事件冒泡一直触发父元素的点击事件,无法跳转另一个路由 -->
        <span v-if="tags.length > 1" class="el-icon-close tagsicon" @click.stop="handleClose(item,index)"></span>
        <span
          v-if="tags.length > 1"
          class="el-icon-close tagsicon"
          @click.stop="handleClose(item, index)"
        ></span>
        <!-- <ul v-show="visible" class="contextmenu" :style="{left:left+'px',top:top+'px'}">
          <li @click.stop="rightClose()">关闭</li>
          <li @click.stop="cleartags($route.path)">关闭其他</li>
        </ul> -->
      </div>
    </div>
    <i class="el-icon-arrow-right btn" v-if="rightStatus"  :class="rightStatus?'nor-btn':'ban-btn'" @click="scrollToEnd()"></i>
    <i
      class="el-icon-arrow-right btn"
      v-if="rightStatus"
      :class="rightStatus ? 'nor-btn' : 'ban-btn'"
      @click="scrollToEnd()"
    ></i>
  </div>
</template>
<script>
//这个就是导入vuex的数据,配合下面...map用
import { mapState, mapMutations } from "vuex";
// 这个就是导入vuex的数据,配合下面...map用
import { mapState, mapMutations } from 'vuex'
export default {
  data() {
    return {
      //右键菜单隐藏对应布尔值
      // 右键菜单隐藏对应布尔值
      visible: false,
      //右键菜单对应位置
      // 右键菜单对应位置
      top: 0,
      left: 0,
      leftStatus: false,
      rightStatus: false,
      rightStatus: false
    }
  },
  computed: {
    //引入vuex中state中的tags数据,一样this调用就行
    ...mapState(["tags"]),
    // 引入vuex中state中的tags数据,一样this调用就行
    ...mapState(['tags'])
  },
  watch:{
    //监听右键菜单的值是否为true,如果是就创建全局监听点击事件,触发closeMenu事件隐藏菜单,如果是false就删除监听
  watch: {
    // 监听右键菜单的值是否为true,如果是就创建全局监听点击事件,触发closeMenu事件隐藏菜单,如果是false就删除监听
    visible(value) {
      if (value) {
        document.body.addEventListener('click', this.closeMenu)
@@ -52,10 +66,10 @@
        document.body.removeEventListener('click', this.closeMenu)
      }
    },
    $route(to,from){
    $route(to, from) {
      this.tags.forEach((item, index) => {
        if (item.url === to.path) {
          let tagsDiv = document.getElementById('tags-box')
          const tagsDiv = document.getElementById('tags-box')
          if (index) {
            tagsDiv.scrollTo(index * 110, 0)
          } else {
@@ -68,109 +82,106 @@
  },
  mounted() {
    this.$refs.tags.addEventListener('scroll', e => {
      if (this.$refs.tags.scrollLeft > 0) {
        this.leftStatus = true
      } else {
        this.leftStatus = false
      }
      if (this.$refs.tags.scrollLeft + this.$refs.tags.clientWidth < this.$refs.tags.scrollWidth) {
       this.rightStatus = true
        this.rightStatus = true
      } else {
        this.rightStatus = false
      }
    }, false)
  },
  methods: {
    //引入vuex中mutation方法,可以直接this.xxx调用他
    ...mapMutations(["closeTab", "cleartagsview"]),
    //点击叉叉删除的事件
    // 引入vuex中mutation方法,可以直接this.xxx调用他
    ...mapMutations(['closeTab', 'cleartagsview']),
    // 点击叉叉删除的事件
    rightClose() {
      this.visible = false
      if (this.tags.length == 1) {
        return
      }
      let index = this.tags.indexOf(this.selectedTag)
      const index = this.tags.indexOf(this.selectedTag)
      this.handleClose(this.selectedTag, index)
    },
    handleClose(item, index) {
      if (this.tags.length == 1) {
        return
      }
      //先把长度保存下来后面用来比较做判断条件
      let length = this.tags.length - 1;
      //vuex调方法,上面...map引入的vuex方法,不会这种方法的看vue官网文档
      this.closeTab(item);
      // 先把长度保存下来后面用来比较做判断条件
      const length = this.tags.length - 1
      // vuex调方法,上面...map引入的vuex方法,不会这种方法的看vue官网文档
      this.closeTab(item)
      // 如果关闭的标签不是当前路由的话,就不跳转
      if (item.url !== this.$route.path) {
        return;
        return
      }
      // 判断:如果index和length是一样的,那就代表都是一样的长度,就是最后一位,那就往左跳转一个
      if (index === length) {
        //再判断:如果length=0,也就是说你删完了所有标签
        // 再判断:如果length=0,也就是说你删完了所有标签
        if (length === 0) {
          //那么再判断:如果当前路由不等于index,也就是我首页的路由
          if (this.$route.path !== "/index") {
            //那么就跳转首页。这一步的意思是:如果删除的最后一个标签不是首页就统一跳转首页,如果你删除的最后一个标签是首页标签,已经在这个首页路由上了,你还跳个什么呢。这不重复操作了吗。
            this.$router.push({ path: "/index" });
          // 那么再判断:如果当前路由不等于index,也就是我首页的路由
          if (this.$route.path !== '/index') {
            // 那么就跳转首页。这一步的意思是:如果删除的最后一个标签不是首页就统一跳转首页,如果你删除的最后一个标签是首页标签,已经在这个首页路由上了,你还跳个什么呢。这不重复操作了吗。
            this.$router.push({ path: '/index' })
          }
        } else {
          //那么,如果上面的条件都不成立,没有length=0.也就是说你还有好几个标签,并且你删除的是最后一位标签,那么就往左边挪一位跳转路由
          this.$router.push({ path: this.tags[index - 1].url });
          // 那么,如果上面的条件都不成立,没有length=0.也就是说你还有好几个标签,并且你删除的是最后一位标签,那么就往左边挪一位跳转路由
          this.$router.push({ path: this.tags[index - 1].url })
        }
      } else {
        // 如果你点击不是最后一位标签,点的前面的,那就往右边跳转
        this.$router.push({ path: this.tags[index].url });
        this.$router.push({ path: this.tags[index].url })
      }
    },
    //点击跳转路由
    // 点击跳转路由
    tagsmenu(item, index) {
      console.log('tagsmenu');
      //判断:当前路由不等于当前选中项的url,也就代表你点击的不是现在选中的标签,是另一个标签就跳转过去,如果你点击的是现在已经选中的标签就不用跳转了,因为你已经在这个路由了还跳什么呢。
      console.log('tagsmenu')
      // 判断:当前路由不等于当前选中项的url,也就代表你点击的不是现在选中的标签,是另一个标签就跳转过去,如果你点击的是现在已经选中的标签就不用跳转了,因为你已经在这个路由了还跳什么呢。
      if (this.$route.path !== item.url) {
        //用path的跳转方法把当前项的url当作地址跳转。
        this.$router.push({ path: item.url });
        let tagsDiv = document.getElementById('tags-box')
        // 用path的跳转方法把当前项的url当作地址跳转。
        this.$router.push({ path: item.url })
        const tagsDiv = document.getElementById('tags-box')
        if (index) {
          tagsDiv.scrollTo(index * 110, 0)
        }
      }
    },
    //通过判断路由一致返回布尔值添加class,添加高亮效果
    // 通过判断路由一致返回布尔值添加class,添加高亮效果
    isActive(route, index) {
      let res = route === this.$route.path
      const res = route === this.$route.path
      return res
    },
    scrollToStart() {
      let tagsDiv = document.getElementById('tags-box')
      const tagsDiv = document.getElementById('tags-box')
      tagsDiv.scrollTo(0, 0)
    },
    },
    scrollToEnd() {
      let tagsDiv = document.getElementById('tags-box')
      const tagsDiv = document.getElementById('tags-box')
      tagsDiv.scrollTo(tagsDiv.scrollWidth, 0)
    },
    //右键事件,显示右键菜单,并固定好位置。
    // 右键事件,显示右键菜单,并固定好位置。
    openMenu(tag, e) {
      this.visible = true
      this.selectedTag = tag
      const offsetLeft = this.$el.getBoundingClientRect().left
      console.log(tag, e);
      this.left = e.clientX - offsetLeft + 60  //右键菜单距离左边的距离
      this.top = e.clientY +20  //右键菜单距离上面的距离           这两个可以更改,看看自己的右键菜单在什么位置,自己调
      console.log(tag, e)
      this.left = e.clientX - offsetLeft + 60 // 右键菜单距离左边的距离
      this.top = e.clientY + 20 // 右键菜单距离上面的距离           这两个可以更改,看看自己的右键菜单在什么位置,自己调
    },
    //隐藏右键菜单
    // 隐藏右键菜单
    closeMenu() {
      this.visible = false
    },
    //右键菜单关闭所有选项,触发vuex中的方法,把当前路由当参数传过去用于判断
    cleartags(val){
    // 右键菜单关闭所有选项,触发vuex中的方法,把当前路由当参数传过去用于判断
    cleartags(val) {
      this.visible = false
      this.cleartagsview(val)
    }
  },
};
  }
}
</script>
<style lang="scss" scoped>
@@ -183,13 +194,13 @@
  color: #666;
  cursor: pointer;
  &:hover {
    color: #2E68EC;
    color: #4d99a8;
  }
}
.ban-btn {
  color: #999;
  cursor:not-allowed
  cursor: not-allowed;
}
#tags-box {
@@ -200,11 +211,11 @@
  scrollbar-width: none; /* firefox */
  -ms-overflow-style: none; /* IE 10+ */
  &::-webkit-scrollbar {
      display: none; /* Chrome Safari */
    }
    display: none; /* Chrome Safari */
  }
}
#tags-box::-webkit-scrollbar {
    display: none; /* Chrome Safari */
  display: none; /* Chrome Safari */
}
//标签导航样式
.tagsview {
@@ -218,16 +229,15 @@
  color: #000;
  font-size: 14px;
  display: inline-block;
}
//叉号鼠标经过样式
.tagsicon:hover{
.tagsicon:hover {
  color: #f56c6c;
}
//标签高亮
.active{
  color: #2E68EC;
  border-bottom: 2px solid #2E68EC;
.active {
  color: #4d99a8;
  border-bottom: 2px solid #4d99a8;
}
//右键菜单样式
.contextmenu {
@@ -241,7 +251,7 @@
  font-size: 12px;
  font-weight: 400;
  color: #333;
  box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
  box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, 0.3);
  li {
    margin: 0;
    padding: 7px 16px;