需求
实现一个横向滚动,一个页面同时只能显示5(可以根据需求自定义)个信息展示项,超出部分通过左按钮或者右按钮就行滑动,如果滑动到头,则按钮置灰,表示无法滑动
思路
使用相对定位,如果点击滑动的时候,让项相对原本位置进行偏移,然后加上简单的动画效果让偏移更加丝滑。
实现代码
/*html*/
<div class="center-content">
<div :class="['center-content-item', (index + 1 === frontIndex || index === frontIndex + 4) ? '' : 'split-line']"
v-for="(item, index) in businessData" :key="index" :style="getContentStyle()">
<div class="title">{{ item.deviceName }}</div>
<div v-for="(subItem, subIndex) in item.prodDtos" :key="index + '-' + subIndex" class="text">
{{ subItem.instId }}
</div>
</div>
</div>
<div class="center-bottom-item">
<div @click="changeItem('left')" :class="['left', frontIndex === 0 ? 'disabled-click' : '']">
<ArrowLeft :class="['center-bottom-btn', frontIndex === 0 ? 'disabled-click' : '']" />
</div>
<div @click="businessData.length > 5 && changeItem('right')"
:class="['right', businessData.length <= 5 ? 'disabled-click' : frontIndex === (businessData.length - 5) ? 'disabled-click' : '']">
<ArrowRight
:class="['center-bottom-btn', businessData.length <= 5 ? 'disabled-click' : frontIndex === (businessData.length - 5) ? 'disabled-click' : '']" />
</div>
</div>
/*js*/
// 需要偏移的位移
const offsetWidth = ref(0)
// 显示在第一个的index
const frontIndex = ref(0)
//点击向左或者向右的按钮时
const changeItem = (command) => {
const elements = document.getElementsByClassName('center-content-item'); // 替换为你要获取宽度的元素的类名
const width = elements[0].offsetWidth;
offsetWidth.value = width//获取单个item的宽度,用于偏移,为了能自适应屏幕
if (command === 'left') {
frontIndex.value === 0 ? '' : --frontIndex.value
offsetWidth.value = frontIndex.value * width
} else if (command === 'right') {
frontIndex.value === (businessData.value.length - 5) ? '' : ++frontIndex.value
offsetWidth.value = frontIndex.value * width
}
}
//获取样式
const getContentStyle = () => {
return {
position: 'relative',
right: offsetWidth.value + 'px',
}
}
/*css*/
.center-content {
height: 70%;
display: flex;
overflow-x: hidden;
max-width: 100%;
margin: 0;
white-space: nowrap;
position: relative;
}
.center-content-item {
flex: 0 0 calc(20% - 20px);
/* 每个子元素占据 20% 的宽度 */
min-width: calc(20% - 20px);
transition: transform 0.3s;
/* 最小宽度 20% */
height: 154px;
// border-right: 1px solid red;
margin: 0 10px;
padding: 20px 0px;
position: relative;
transition: right 0.5s;
}
.split-line::after {
content: '';
position: absolute;
top: 12%;
right: -2px;
height: 76%;
width: 1px;
background-color: #e8e8e8;
}
.center-bottom-item {
text-align: center;
display: flex;
justify-content: center;
.left {
width: 20px;
height: 20px;
background-color: #E8F2FF;
margin-right: 10px;
line-height: 20px;
}
.right {
width: 20px;
height: 20px;
background-color: #E8F2FF;
}
.center-bottom-btn {
width: 16px;
height: 16px;
position: relative;
top: 2px;
cursor: pointer;
color: #1D59F2;
}
.disabled-click {
background-color: #eaecf0;
color: #999999;
cursor: not-allowed;
}
}
改进
如果需要自动滑动(走马灯效果),那么在页面渲染的时候加个定时器,让其定时去调用changeItem函数即可,如果滑到最右边之后需要从头开始或者再从右往左滑动,根据条件动态改变frontIndex的值即可 例如:
let direation = 'upward'//滑动的方向
let timeInterval = null;
onMounted(() => {
timeInterval = setInterval(() => {
if (frontIndex.value === 0) {
changeItem('right')
direation = 'upward'
} else if (frontIndex.value === (businessData.value.length - 5)) {
changeItem('left')
direation = 'backward'
}else{
direation==='upward'?changeItem('right'):changeItem('left')//根据方向调用
}
}, 3000)
})
onDeactivated(() => {
clearInterval(timeInterval)
})
/*如果希望到头后从头开始,判断到头,然后重置frontIndex和offsetWidth 即可*/