在大屏开发过程中,无限滚动列表是一个常用的需求,效果如下:
在vue2和vue3的开发过程中会有一些区别:
- 如果是是在用vue3进行开发,那么则需要安装 vue3-seamless-scroll,比如当前的node版本是16.20.2, vue版本是3.2.47, vue3-seamless-scroll版本是2.0.1,直接上代码:
import { Vue3SeamlessScroll } from 'vue3-seamless-scroll'
<div class="handle-ontime-list">
<div class="handle-ontime-list-header">
<div class="handle-ontime-list-header-item" style="width: 7.2917vw">处理时间</div>
<div class="handle-ontime-list-header-item" style="width: 27.9167vw">内容</div>
<div class="handle-ontime-list-header-item" style="width: 5.5208vw">操作</div>
</div>
<vue3-seamless-scroll
:step="0.6"
:wheel="true"
:hover="true"
direction="up"
count="infinite"
:list="handledList"
:limitScrollNum="6"
class="handle-ontime-list-body"
>
<div
v-for="(li, i) in handledList"
:key="i"
:class="'handle-ontime-list-row ' + (i >= 0 ? 'with-border' : '')"
@click="openDetail(li)"
>
<div class="handle-ontime-list-item" style="width: 7.2917vw">
{{ li.timeStr }}
</div>
<div class="handle-ontime-list-item" style="width: 27.9167vw">
{{ li.detail }}
</div>
<div class="handle-ontime-list-item" style="width: 5.5208vw">
{{ '查看详情' }}
</div>
</div>
</vue3-seamless-scroll>
</div>
<style scoped lang="scss">
.handle-ontime-list{
width: 40.4688vw;
height: 20.3vw;
margin-left: 1.25vw;
border-radius: 0.4167vw;
background: rgba(0, 157, 255, 0.1);
backdrop-filter: blur(2.6vw);
box-shadow: inset 0px 0px 0.52vw 0px #009dff;
}
.handle-ontime-list-header{
width: 100%;
height: 2.0833vw;
display: flex;
justify-content: space-between;
background: rgba(0, 157, 255, 0.5);
border-top-left-radius: 0.4167vw;
border-top-right-radius: 0.4167vw;
}
.handle-ontime-list-header-item{
height: 1.9688vw;
line-height: 1.9688vw;
overflow: hidden;
font-family: Source Han Sans CN;
font-size: 0.9375vw;
font-weight: bold;
color: #ffffff;
}
.handle-ontime-list-body{
width: 100%;
height: 17.7083vw;
overflow: hidden;
}
.handle-ontime-list-row{
height: 1.9688vw;
display: flex;
justify-content: space-between;
color: rgba(255, 255, 255, 1);
cursor: pointer;
}
.handle-ontime-list-row:hover {
background: linear-gradient(
270deg,
rgba(0, 255, 221, 0) 0%,
rgba(0, 255, 221, 0.5) 47%,
rgba(0, 255, 221, 0) 100%
);
}
.with-border {
border-top: 1px solid rgba(67, 152, 255, 0.2);
}
.handle-ontime-list-item {
height: 1.9688vw;
line-height: 1.9688vw;
overflow: hidden;
font-family: Source Han Sans CN;
font-size: 0.8333vw;
font-weight: 500;
letter-spacing: 0;
}
</style>
这个组件可以实现列表的自动无限循环滚动,鼠标悬浮停止滚动,手动滑动滚轮时可滚动。
- 如果是用vue2进行开发,对应的vue-seamless-scroll组件会有一个缺陷,就是无法手动滚动,这个问题在vue3版本的vue3-seamless-scroll组件中得到了解决,所以如果是在vue2开发无限滚动时需要手动滚动的功能时,就不能用vue-seamless-scroll了,此处推荐 "@david-j/vue-j-scroll": "^1.2.7",这个组件,使用时需要全局引入:
// main.js
import VueJScroll from '@david-j/vue-j-scroll'
Vue.use(VueJScroll)
// 组件直接用
<div class="schedule_list">
<div class="schedule_list_title">
<div style="flex: 0 0 20%">姓名</div>
<div style="flex: 0 0 20%">排</div>
<div style="flex: 0 0 20%">班</div>
<div style="flex: 0 0 20%">床位号</div>
<div style="flex: 0 0 20%">时间段</div>
</div>
<vue-j-scroll
v-show="!noData"
class="list-style"
:data="scheduleList"
:steep="0.5"
scroll-direction="top"
:is-roller="true"
:roller-scroll-distance="50"
>
<div
v-for="(item, index) in scheduleList"
:key="'t' + index"
class="list-item"
>
<div style="flex: 0 0 20%">{{ item.name }}</div>
<div style="flex: 0 0 20%">{{ item.gradeName }}</div>
<div style="flex: 0 0 20%">{{ item.className }}</div>
<div style="flex: 0 0 20%" class="bigscreen_num">{{ item.bedName }}</div>
<div style="flex: 0 0 20%" class="bigscreen_num">{{ item.time }}</div>
</div>
</vue-j-scroll>
</div>
<style lang="scss">
.schedule_list{
width: 95%;
height: 9.8958vw;
background: url('../../assets/screenimages/bold/bottombox.png') no-repeat;
background-size: 100% 100%;
font-size: 0.6771vw;
.schedule_list_title {
width: 100%;
height: 2.2917vw;
background: url('../../assets/screenimages/duletitleback.png') no-repeat;
background-size: 100% 100%;
display: flex;
line-height: 2.2917vw;
font-size: 0.8333vw;
font-weight: 700;
div{
text-align: center;
}
}
}
.list-style{
width: 100%;
height: calc(100% - 2.5vw);
overflow: hidden;
}
.list-item{
display: flex;
padding: 0.625vw 0.9375vw;
font-size: 0.7292vw;
div{
text-align: center;
}
&:hover{
background: radial-gradient(rgba(57, 127, 130, 1), rgba(57, 127, 130, 0));
}
}
</style>
- 自己写一个原生的无限滚动列表:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<title>滚动列表</title>
</head>
<body>
<div id="app">
<p>{{message}}</p>
<div class="schedule">
<div class="schedule_list">
<div class="schedule_list_title">
<div style="flex: 0 0 20%">姓名</div>
<div style="flex: 0 0 20%">排</div>
<div style="flex: 0 0 20%">班</div>
<div style="flex: 0 0 20%">床位号</div>
<div style="flex: 0 0 20%">时间段</div>
</div>
<div
ref="scheduleScroll"
class="schedule_list_data"
@mouseout="setScrollState(true)"
@mouseover="setScrollState(false)"
>
<div v-for="(item, index) in scheduleList" :key="index" class="schedule_list_item">
<div style="flex: 0 0 20%">{{ item.name }}</div>
<div style="flex: 0 0 20%">{{ item.gradeName }}</div>
<div style="flex: 0 0 20%">{{ item.className }}</div>
<div style="flex: 0 0 20%" class="bigscreen_num">{{ item.bedName }}</div>
<div style="flex: 0 0 20%" class="bigscreen_num">{{ item.time }}</div>
</div>
</div>
</div>
</div>
</div>
</body>
<script>
var app = new Vue({
el: "#app",
data: {
message: "滚动列表",
scheduleList: [
{
name: "张三",
gradeName: "一年级",
className: "一班",
bedName: "101",
time: "10:00-12:00"
},
{
name: "李四",
gradeName: "一年级",
className: "一班",
bedName: "102",
time: "10:00-12:00"
},
{
name: "王五",
gradeName: "一年级",
className: "一班",
bedName: "103",
time: "10:00-12:00"
},
{
name: "赵六",
gradeName: "一年级",
className: "一班",
bedName: "104",
time: "10:00-12:00"
},
{
name: "孙七",
gradeName: "一年级",
className: "一班",
bedName: "105",
time: "10:00-12:00"
},
{
name: "周八",
gradeName: "一年级",
className: "一班",
bedName: "106",
time: "10:00-12:00"
},
{
name: "吴九",
gradeName: "一年级",
className: "一班",
bedName: "107",
time: "10:00-12:00"
},
{
name: "郑十",
gradeName: "一年级",
className: "一班",
bedName: "108",
time: "10:00-12:00"
},
{
name: "王十一",
gradeName: "一年级",
className: "一班",
bedName: "109",
time: "10:00-12:00"
},
{
name: "赵十二",
gradeName: "一年级",
className: "一班",
bedName: "110",
time: "10:00-12:00"
},
{
name: "孙十三",
gradeName: "一年级",
className: "一班",
bedName: "111",
time: "10:00-12:00"
},
{
name: "周十四",
gradeName: "一年级",
className: "一班",
bedName: "112",
time: "10:00-12:00"
},
{
name: "吴十五",
gradeName: "一年级",
className: "一班",
bedName: "113",
time: "10:00-12:00"
},
],
scrollSetInterval: null, // 滚动定时器
scrollSetIntervalCurTop: 0, // 记录当前滚动的位置
},
methods: {
setScrollState(val) {
const node = this.$refs.scheduleScroll
if (val) {
if (!this.scrollSetInterval) {
this.scrollSetInterval = setInterval(() => {
this.scrollSetIntervalCurTop += 2
node.scroll(0, this.scrollSetIntervalCurTop)
// 滑动到底部时自动滚回头部
if ((this.scrollSetIntervalCurTop + node.clientHeight) >= node.scrollHeight) {
this.scrollSetIntervalCurTop = 0
}
}, 120)
}
} else {
clearInterval(this.scrollSetInterval)
this.scrollSetInterval = null
this.scrollSetIntervalCurTop = node.scrollTop
}
}
},
mounted() {
this.setScrollState(true)
}
})
</script>
<style>
.schedule {
width: 600px;
height: 200px;
background: #043e40;
color: #fff;
}
.schedule_list {
width: 100%;
height: 100%;
/* background: url('http://troop.isuke.com.cn/static/img/bottombox.a9501974.png') no-repeat;
background-size: 100% 100%; */
font-size: 14px;
}
.schedule_list_title {
width: 100%;
height: 44px;
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAiEAAAAyCAYAAACKygubAAAAAXNSR0IArs4c6QAABABJREFUeF7t3UFrlFcUBuBzqiKWSmkpLaWpUirVtmgtQyYZRQyW0lLyO7Jz4cakZibeTJKF/8o/4K9wK7gpFBdCuQ3TGeh2cmaRZzYf3+olD/e8uXyXbybDhwABAgQIECCwAoGM1j5YQa5IAgQIECBA4JwLZGy1i7EVES8jXDlYB+ZAD+gBPaAHqnogBzs7lyIGC3uxV+Gex3xBWA/mwTyYh5mAPtAHy+2DvPH48eVz/jTIn0+AAAECBAisQCDXnjy58vVC8OuIcD8H4WE9mAfzMBPQB/pAHyy3D3LQ2ocr2PyIJECAAAECBM65QP7Q2kfn3MCfT4AAAQIECKxAIG8+fXH1s4h4ExGuHKwDc6AH9IAe0ANVPZCD3d2PIz6JiLfhysE6MAd6QA/oAT1Q1QN5e2+vT5wPAQIECBAgQKBUIEetfVqaKIwAAQIECBAgEBH97Zh+9ONDgAABAgQIECgVyDutfT5L7K/J/LUQ756H9TAfCPNgHsyDefD/8lRgWX2YG89Ovijd9ggjQIAAAQIECPx7HPPs5EsSBAgQIECAAIFqgfxpf/+r6lB5BAgQIECAAIHcaG0NAwECBAgQIECgWiAHz59fqw6VR4AAAQIECBDIe/vH1/9juBIRfy+guOdhPcwHwjyYB/NgHmYC+mApfZDD8fibiMsLO4934Z7HfEFYD+bBPJiHmYA+0AfL7YMcjMffnqLOFpcrD+vBPOgBPaAH9MDZ90D/2vYbTqUIECBAgAABAtUCOWztu+pQeQQIECBAgACBHPzZbmEgQIAAAQIECFQL5Ob46PvqUHkECBAgQIAAgVyfTH/EQIAAAQIECBCoFsjRZHq7OlQeAQIECBAgQKB/bfsdDAQIECBAgACBaoFcb+1udag8AgQIECBAgEA/jvkZAwECBAgQIECgWiA3JtNBdag8AgQIECBAgEB/O2YdAwECBAgQIECgWiBH7XhYHSqPAAECBAgQINDfjtnEQIAAAQIECBCoFug/YHevOlQeAQIECBAgQCA3J9P7GAgQIECAAAEC1QI5nEwfVIfKI0CAAAECBAj07wl5iIEAAQIECBAgUC2Qm61tRVxYyH0f7nnMF4T1YB7Mg3mYCegDfbDcPsjhuD2q3vnII0CAAAECBAjk6ODwFwwECBAgQIAAgWqB3Dg4/LU6VB4BAgQIECBAIIcHh7/1E57ZSZ/r6YkfBw7WgTnQA3pAD5xtD+SoHf1uL0aAAAECBAgQqBboX9v+h72uve7Z7nX58vVMQc/qAT3w/x7ob8dsV+985BEgQIAAAQIE+nGMTYh1QIAAAQIECJQL9B+w2/aY0GNCjwkdF+gBPaAH9EB1D3gSUr7vE0iAAAECBAh0gX8Auw/iROkL+g4AAAAASUVORK5CYII=') no-repeat;
background-size: 100% 100%;
display: flex;
line-height: 44.0006px;
font-size: 15.9994px;
font-weight: 700;
}
.schedule_list_title > div{
text-align: center;
}
.schedule_list_data{
position: relative;
height: calc(100% - 48px);
overflow: auto;
}
.schedule_list_item{
display: flex;
padding: 12px 6px;
}
.schedule_list_item > div{
text-align: center;
}
.schedule_list_data::-webkit-scrollbar {
display: none;
}
</style>
</html>