Tags标签内容过长 添加左右按钮进行滑动

27 阅读3分钟

效果:

Tags箭头.gif

  1. 左右箭头是内容过多才会出来
  2. 滚动的距离:上一页/下一页的效果

缺点:不支持滚动条滚动

注意的点:

scrollWrapper 需要加上 white-space: nowrap; 子元素不换行 tag-style 必须添加该定位,offsetLeft 获取元素相对带有定位父元素左边框的偏移

template 中的代码

 <div class="tags-view-container" :style="{ padding: (!showButton ? '0 15px' : '0') }">


   <el-icon class="arrow-icon" @click="arrowLeft"><i-ep-arrowLeft /></el-icon>

   <div class="tag-style" ref="tagBox"> 
     <div class="scrollWrapper" ref="scrollWrapper" id="nav" :style="{ marginLeft: tabScroll }">
       <router-link v-for="tag in visitedViews" ref="refTag" :class="isActive(tag) ? 'active' : ''"
         class="tags-view-item" :to="tag.path" :key="tag.path" @contextmenu.prevent="openMenu(tag, $event)"
         @click.middle="!isAffix(tag) ? closeSelectedTag(tag) : ''">
         <span class="tags-title">{{ tag.meta.title }}</span>
         <el-icon @click.prevent.stop="closeSelectedTag(tag)" class="tags-icon" v-if="!isAffix(tag)">
           <i-ep-close />
         </el-icon>
       </router-link>
       <ul v-show="visible" :style="{ left: left + 'px', top: top + 'px' }" class="contextmenu">
         <li @click="refreshSelectedTag(selectedTag)">刷新</li>
         <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">
           关闭
         </li>
         <li @click="closeOthersTags">关闭其他</li>
         <li @click="closeAllTags(selectedTag)">关闭全部</li>
       </ul>
     </div>
   </div>

   <el-icon class="arrow-icon" @click="arrowRight"><i-ep-arrowRight /></el-icon>
 </div>

结构图:

image.png

css:

.tags-view-container {
  width: 100%;
  height: 40px;
  background: #fff;
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.12), 0 0 3px 0 rgba(0, 0, 0, 0.04);
  box-sizing: border-box;

  display: flex;
  align-items: center;

  .tag-style {
    // width: 100%;
    flex: 1;
    display: flex;
    align-items: center;
    overflow: hidden;
    pointer-events: all;
    cursor: pointer;
    position: relative; // 必须添加该定位,offsetLeft 获取元素相对带有定位父元素左边框的偏移

    .scrollWrapper {
      // display: flex;
      // align-items: center;
      white-space: nowrap;
      overflow-x: auto;
      overflow-y: hidden;
      transition: all 500ms linear
    }

    .scrollWrapper::-webkit-scrollbar {
      height: 0;
    }
  }

  .arrow-icon {
    width: 32px;
    height: 32px;
    pointer-events: all;
    cursor: pointer;
    font-size: 16px;
    display: flex;
    align-content: center;
    justify-content: center;
  }
}

.tags-view-wrapper {
  display: flex;
  align-items: center;
  height: 40px;
}

.tags-view-item {
  display: inline-block;
  position: relative;
  height: 26px;
  line-height: 26px;
  border: 1px solid #d8dce5;
  padding: 0 10px;
  color: #495060;
  font-size: 12px;
  margin-right: 10px;
}

.tags-title {}

.tags-icon {
  margin-top: -2px;
  vertical-align: middle;
  margin-left: 4px;
  border-radius: 50%;
  color: #4a4a4b;
}

.tags-icon:hover {
  background-color: #b4bccc;
  color: #fff;
}

.active {

  color: #000c;
  margin-right: 10px;
}

.active .tags-title:before {
  content: "";
  background: #16baaa;
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  position: relative;
  margin-right: 5px;
}

.contextmenu {
  margin: 0;
  background: #fff;
  z-index: 3000;
  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);
}

.contextmenu li {
  margin: 0;
  padding: 7px 16px;
  cursor: pointer;
}

.contextmenu li:hover {
  background: #eee;
}

js

const tabScroll = ref('0px')// 移动的距离
const showButton = ref(false)  // 标签左右两侧箭头是否显示


// 点击左箭头 标签向右滚动
const arrowLeft = () => {
  let tabBoxWidth = tagBox.value.clientWidth; //盒子宽度
  let offsetLeft = Math.abs(scrollWrapper.value.offsetLeft); //移动距离
  console.log('左 盒子宽度', tabBoxWidth)
  console.log('左 移动距离', offsetLeft)
  console.log('offsetLeft > tabBoxWidth', offsetLeft > tabBoxWidth)
  if (offsetLeft > tabBoxWidth) {
    //移动距离大于父盒子宽度,向前移动一整个父盒子宽度
    tabScroll.value = -(offsetLeft - tabBoxWidth) + "px";
    console.log('tabScroll.value', tabScroll.value)
  } else {
    tabScroll.value = "0px";// 否则移动到开始位置
  }
}
// 点击右箭头 标签向左滚动
const arrowRight = () => {
  let tabBoxWidth = tagBox.value.clientWidth; //盒子宽度
  let scrollWidth = scrollWrapper.value.scrollWidth; //内容宽度
  console.log('右tabBoxWidth', tabBoxWidth)
  console.log('右scrollWidth', scrollWidth)
  console.log('scrollWrapper.value.offsetLeft', scrollWrapper.value.offsetLeft)
  // 必须要在循环的父级添加 定位样式, offsetLeft 获取元素相对带有定位父元素左边框的偏移
  let offsetLeft = Math.abs(scrollWrapper.value.offsetLeft); //移动距离
  let diffWidth = scrollWidth - tabBoxWidth; //计算内容宽度与盒子宽度的差值
  console.log('diffWidth差值', diffWidth)//
  if (diffWidth > 0) {
    if (diffWidth - offsetLeft > tabBoxWidth) {
      //判断差值减去移动距离是否大于盒子宽度 大于则滚动已移动距离+盒子宽度
      tabScroll.value = -(offsetLeft + tabBoxWidth) + "px";
    } else {
      tabScroll.value = -diffWidth + "px"; //小于则移动差值距离
    }
  } else {
    tabScroll.value = "0px";
  }
}

点击左侧:

两种情况 微信图片_20240130141529.jpg 点击右侧:

两种情况 微信图片_20240130141539.jpg

自适应

onMounted(() => {
  window.addEventListener("resize", checkButtonStatus);
})

const checkButtonStatus = () => {
  if (!scrollWrapper.value) return;
  // 盒子的宽度
  let containerSize = tagBox.value.clientWidth;
  // 内容的宽度
  let navSize = scrollWrapper.value.scrollWidth;

  console.log('盒子的宽度', containerSize)
  console.log('内容的宽度', navSize)
  if (containerSize > navSize || containerSize == navSize) {
    showButton.value = false;
  } else {
    showButton.value = true;
  }
}