效果:
- 左右箭头是内容过多才会出来
- 滚动的距离:上一页/下一页的效果
缺点:不支持滚动条滚动
注意的点:
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>
结构图:
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";
}
}
点击左侧:
两种情况
点击右侧:
两种情况
自适应
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;
}
}