tab标签栏 类似于浏览器的tab栏 直接用

本文介绍了一个基于Vue的标签页组件实现,包括点击切换、关闭标签页、右侧关闭所有标签的功能,以及自动增加新页面标签页并跳转到已存在标签的逻辑。组件还实现了左右动画滚动,并能在窗口变化时自动重置。

效果
在这里插入图片描述
组件是直接封装好的

<template>
  <div class="tabPage flex" id="tabPage">
        <div class="leftTab cur" @click="leftClick"><i class="el-icon-arrow-left"></i></div>
        <div class="tabMain " id="tabItem" style="">
          <div class="tabItem"  v-for="item in $store.state.tabPageBox" :class="{isActive:item.isActive}" @click="chooseThis(item)">
            <span class="yuanTab"></span>
            <span class="name">{{item.meta.title}}</span>
            <i class="el-icon-close" @click="closeClick(item)" v-if="item.meta.title!='首页'"></i>
          </div>
        </div>

        <div class="rightTab cur" @click="rightClick"><i class="el-icon-arrow-right"></i></div>
        <el-dropdown class="closeTab cur" trigger="click"  @command="closeAll">
          <span class="el-dropdown-link">
            <i class="el-icon-circle-close"></i>
          </span>
          <el-dropdown-menu slot="dropdown">
            <el-dropdown-item command="关闭所有">关闭所有</el-dropdown-item>
          </el-dropdown-menu>
        </el-dropdown>
  </div>
</template>

<script>
  
  export default {
  
    components: {
      },
    data() {
          return {
            plusWidth:0,//记录实际宽度和本该有的宽度的差值 可以滚动的次数
            num:300,  //滑动距离
            ccRight:1,   //第几次右滑动
            ccLeft:1,   //第几次左滑动
          };
    },
    methods: {
      // 点击tab 选择
      chooseThis(val){
        if(val.isActive){
          return false;
        }
        let arr=JSON.parse(JSON.stringify(this.$store.state.tabPageBox));
        for(let i in arr){
          // 遍历
          if(arr[i].meta.title==val.meta.title){ //改变状态
            arr[i].isActive=true;
          } 
        }
        this.$store.commit("setTabPageBox",arr) ;
        this.$router.push(val.path)
      },
      // 关闭当前
      closeClick(val){
        let arr=JSON.parse(JSON.stringify(this.$store.state.tabPageBox));
        for(let i in arr){
          // 遍历
          if(arr[i].meta.title==val.meta.title){ //删除数组里的对应的
            arr.splice(i,1);
          } 
        }

        // 判断当前是否操作的是否是选中状态
        if(val.isActive){
          arr[0].isActive=true;
          this.$store.commit("setTabPageBox",arr) ;
          this.$router.push("/")
        }else{
          this.$store.commit("setTabPageBox",arr) ;
        }
        
      },
      // 关闭所有
      closeAll(val){
        if(val=='关闭所有'){
            let arr=[{
            path: '/index/homePage/homePage',
            name: '首页',
            isActive:true,
            meta: { title: "首页"},
          }]
          this.$store.commit("setTabPageBox",arr) ;
          this.$router.push("/");
          // 滑动重置
          this.ccRight=1;
          document.getElementById('tabItem').style.marginLeft=0;

        }
      },

      // 移动
      leftClick(){
        // 获取父级总宽度 offsetWidth
        let fatherWidth=document.getElementById('tabPage').offsetWidth;
        let sonWidth=fatherWidth-88;  //88是左右图标的 总宽度
        // 获取实际的子级宽度
        let curSonWidth=document.getElementById('tabItem').offsetWidth;
        // 比较子级的宽度和实际的区别
        if(curSonWidth-sonWidth>0){
          // 超过了宽度可以滚动
          this.plusWidth=Math.ceil((curSonWidth-sonWidth)/this.num); //+100是为了滑动之后右边流出距离  1此滑动300
          if(this.ccRight!=1){
            document.getElementById('tabItem').style.marginLeft='-'+this.num*(this.ccRight-2)+'px';
            this.ccRight--;
          }
        }
      },
      // 右边
      rightClick(){
        // 获取父级总宽度 offsetWidth
        let fatherWidth=document.getElementById('tabPage').offsetWidth;
        let sonWidth=fatherWidth-88;  //88是左右图标的 总宽度
        // 获取实际的子级宽度
        let curSonWidth=document.getElementById('tabItem').offsetWidth;
        // 比较子级的宽度和实际的区别
        if(curSonWidth-sonWidth>0){
          // 超过了宽度可以滚动
          this.plusWidth=Math.ceil((curSonWidth-sonWidth)/this.num); //+100是为了滑动之后右边流出距离  1此滑动300
          if(this.plusWidth>=this.ccRight){
            document.getElementById('tabItem').style.marginLeft='-'+this.num*this.ccRight+'px';
            this.ccRight++;
          }
        }
      }

    },
    mounted(){
      // 监听窗口变化
      const that = this
      window.onresize = () => {
          return (() => {
            // 滑动重置
             this.ccRight=1;
              document.getElementById('tabItem').style.marginLeft=0;
          })()
      }
    },
    created(){
      if(this.$store.state.tabPageBox.length==0){
        let arr=[{
          path: '/index/homePage/homePage',
          name: '首页',
          isActive:true,
          meta: { title: "首页"},
        }]
        this.$store.commit("setTabPageBox",arr)
      }
    },
    watch: {
      $route(toPage,from){
        let arr=JSON.parse(JSON.stringify(this.$store.state.tabPageBox))
        let newOpen=true; //控制是否新打开页面
        for(let i in arr){
          // 全部取消选中
          arr[i].isActive=false;
          // 遍历
          if(arr[i].meta.title==toPage.meta.title){ //说明此页面已打开过
            arr[i].isActive=true;
            newOpen=false;
          } 
        }
        if(newOpen){
          let obj={
            path: toPage.path,
            name: toPage.name,
            isActive:true,
            meta: { title: toPage.meta.title},
          }
          obj.isActive=true;
          arr.push(obj)
        }
        this.$store.commit("setTabPageBox",arr)
      },
    },
  
  }
</script>
<style lang="scss" scoped>
.tabPage{
  height: 40px;
  width: 100%;
  position: relative;
}
.leftTab{
  position: absolute;
  left: 0;
  top: 1px;
  height: 38px;
  width: 28px;
  text-align: center;
  line-height: 38px;
  font-size: 18px;
  background: #fff;
  i{
    color:#000
  }
  &:hover{
    i{
      color:$blue
    }
  }
}
.tabMain{
  white-space: nowrap;
  cursor: pointer;
  padding-left: 33px;
  margin:5px 0;
  transition: margin-left .5s;
  .tabItem{
    display: inline-block;
    margin-right:4px;
    padding:0 12px;
    height: 30px;
    line-height: 30px;
    background: #fff;
    border-radius: 4px;
  }
  .el-icon-close{
    margin-left:16px
  }
  .el-icon-close:hover{
    cursor: pointer;
    color:$blue;
  }
  .yuanTab{
    vertical-align: -1px;
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 100px;
    background: #E8EAEC;
    margin-right: 8px;
  }
}
.isActive .yuanTab{
  background: $blue;
}
.rightTab{
  position: absolute;
  right: 33px;
  top: 1px;
  height: 38px;
  width: 28px;
  text-align: center;
  line-height: 38px;
  font-size: 18px;
  background: #fff;
  i{
    color:#000
  }
  &:hover{
    i{
      color:$blue
    }
  }
}
.closeTab{
  position: absolute;
  right: 0px;
  top: 1px;
  height: 38px;
  width: 32px;
  text-align: center;
  line-height: 38px;
  font-size: 18px;
  background: #fff;
  i{
    color:#000
  }
  &:hover{
    i{
      color:$blue
    }
  }
}


</style>


store的代码


const state={
  
    tabPageBox:[]

}
const mutations={
 
  setTabPageBox(state,tabPageBox){
    console.log(tabPageBox)
    state.tabPageBox = tabPageBox;
  },
}


实现的效果
效果1

1)点击切换
2)关闭标签页
3)右边x关闭所有
4)点击新页面 标签页自动增加,已存在会自动跳转到存在的标签上
在这里插入图片描述

效果二

1)左右动画滚动
2)窗口变化 自动重置
在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值