前提条件:做一个商品列表,不换行,超出长度是横向滚动,但不是通过滚动条,是点击左右按钮滚动商品列表
过程:
先做一个测试商品列表和左右点击按钮
实现效果:
1、当商品列表为初始状态或商品列表滚动回第一个时,左按钮隐藏,右按钮展示
2、当商品列表展示滚动到中间部分时,左右按钮皆展示
3、当商品列表展示滚动到最后一个时,左按钮展示,右按钮隐藏
完整代码(仅滚动,不跟踪)
<template>
<div style="position: relative; margin: 20px">
<div class="product-container" id="product" ref="product">
<div>
<div style="text-align: center; height: 100%" v-if="isLeftShow">
<button class="leftBtn" @click="HorizontalScrolling('left')">
<i class="el-icon-arrow-left"></i>
</button>
</div>
<div class="productItem" v-for="n in 20" :key="n">商品 {{ n }}</div>
<div style="text-align: center; height: 100%" v-if="isRightShow">
<button class="rightBtn" @click="HorizontalScrolling('right')">
<i class="el-icon-arrow-right"></i>
</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
isLeftShow: false,
isRightShow: true,
};
},
methods: {
HorizontalScrolling(type) {
const allLength = document.getElementsByClassName(`productItem`)[0].clientWidth * 20 - this.$refs.product.getBoundingClientRect().width
if (type == "left") {
this.$refs.product.scrollLeft -= 200;
this.isRightShow = true;
if (this.$refs.product.scrollLeft <= 200) {
this.isLeftShow = false;
}
} else {
this.$refs.product.scrollLeft += 200;
this.isLeftShow = true;
if (this.$refs.product.scrollLeft >=allLength) {
this.isRightShow = false;
}
}
}
},
};
</script>
<style scoped>
.leftBtn {
position: absolute;
left: -10px;
top: -2px;
height: 105px;
border-radius: 10px;
background: white;
padding: 2px;
border: none;
}
.leftBtn:hover {
background: #eee;
}
.rightBtn {
position: absolute;
right: -10px;
top: -2px;
height: 105px;
border-radius: 10px;
background: white;
padding: 2px;
border: none;
}
.rightBtn:hover {
background: #eee;
}
.product-container {
width: 100%;
overflow-x: auto;
white-space: nowrap;
scroll-behavior: smooth;
}
.productItem {
display: inline-block;
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
margin-right: 10px;
background-color: rgb(235, 150, 135);
border-radius: 10px;
}
/* 隐藏下方的滚动条 */
.product-container::-webkit-scrollbar {
/* background-color: transparent; */
display: none;
}
</style>
以上是仅滚动不跟踪商品位置的示例,如果想要滚动条跟着商品列滚动, 就要换种写法
在这种需求下,实现效果的条件就要改变一下
1、当商品列表为初始状态时,左按钮不隐藏,右按钮展示,左右按钮表示商品的上一个或下一个
2、当高亮商品为第一个时,左按钮隐藏,否则展示
3、当高亮商品是最后一个时,右按钮隐藏,否则展示
4、高亮商品必须展示在可见区域内
实现逻辑
1、计算当前可见区域内可展示的商品个数,取中间值
2、找到滚动条滚动值和商品位置的关系
可知,滚动条是在可视容器中滚动,则滚动条的区域长度即为可视容器的宽度(clientWidth),而商品列的实际宽度(scrollWidth)为商品展示宽度(包括元素宽度+margin)*商品个数,则滚动条的可滚动距离为商品列实际宽度-可视容器的宽度,滚动条移动的距离与内容滚动的距离之间的比率是恒定的
则可得出对应商品的滚动值 = 最大滚动值/商品总数*当前商品所在下标
3、当高亮商品的下标小于中间值时,滚动值为0
4、当高亮商品下标大于中间值,且小于总数-中间值+1时,滚动值为计算的滚动值
5、当高亮商品下标大于总数-中间值+1时,滚动值为最大滚动值
6、当点击左按钮直到下标为0时,左按钮隐藏
7、当点击右按钮直到下位为商品总数时,右按钮隐藏
以本次示例数据计算
商品总数:20
可视区域宽度(685):this.$refs.product.clientWidth 或 this.$refs.product.getBoundingClientRect().width
实际内容宽度(2200):this.$refs.product.scrollWidth 或(document.getElementsByClassName(`productItem`)[0].clientWidth +10)* 20
最大滚动值:实际内容宽度 - 可视区域宽度 = 1515
单个商品元素宽度:document.getElementsByClassName(`productItem`)[0].clientWidth
可见区域内可展示的商品个数:可视区域宽度/单个商品元素宽度=6.85,向上取整为7
具体代码如下:
//滚动,跟踪商品位置
HorizontalScrolling(type) {
//可见区域内可展示的商品个数,向上取整,取中间值
let center =
Math.ceil(
this.$refs.product.getBoundingClientRect().width /
document.getElementsByClassName(`productItem`)[0].clientWidth
) / 2;
//点击上一个
if (type == "left") {
this.currentIndex--; //下标-1
this.isRightShow = true;
if (this.currentIndex == 1) {
this.isLeftShow = false;
}
} else {
//点击下一个
this.currentIndex++; //下标+1
this.isLeftShow = true;
if (this.currentIndex == 20) {
this.isRightShow = false;
}
}
//计算滚动值:最大滚动值/商品总数*当前商品所在下标
// let scrollLeft =
// (document.getElementsByClassName(`productItem`)[0].clientWidth -
// this.$refs.product.getBoundingClientRect().width / 20 +
// 10) *
// this.currentIndex;
let scrollLeft =
((this.$refs.product.scrollWidth -
this.$refs.product.getBoundingClientRect().width) /
20) * this.currentIndex;
if (this.currentIndex <= 20 - center + 1 && this.currentIndex > center) {
this.$refs.product.scrollLeft = scrollLeft;
} else if (this.currentIndex > 20 - center + 1) {
// this.$refs.product.scrollLeft =
// (document.getElementsByClassName(`productItem`)[0].clientWidth -
// this.$refs.product.getBoundingClientRect().width / 20 +
// 10) *
// 20;
this.$refs.product.scrollLeft =
this.$refs.product.scrollWidth -
this.$refs.product.getBoundingClientRect().width;
} else {
this.$refs.product.scrollLeft = 0;
}
}
效果如图:
坚持就是胜利!