vue-seamless-scroll滚动组件-复制可用
本篇文章列表可用于vue项目-大屏数据展示类-滚动表格模块,可配置slot插槽、单元格点击事件。
表格效果图如下:
一、安装vue-seamless-scroll
安装:
npm install vue-seamless-scroll --save
main.js文件全局引入注册:
// 滚动组件
import vueSeamlessScroll from 'vue-seamless-scroll'
Vue.component('vListScroll', vueSeamlessScroll)
二、公共组件:
创建一个listScroll.vue文件存放在components文件夹下:
完整代码:
- 表头与表格数据分为两个容器,表格数据部分使用vue-seamless-scroll组件,实现表头固定,表格滚动效果;
- noData部分暂无数据部分可按照自己项目需求,加入loading等待效果;
<template>
<div ref="listScroll" class="listScroll">
<ul class="title-ul">
<li ref="listTit">
<span :class="item.class || ''" :key="index" v-for="(item, index) in list.title"
:style="[item.width ? { width: item.width } : { flex: 1 },
{'text-align': item.align || 'left'}]">
{{ item.name }}
</span>
</li>
</ul>
<template v-if="list.data && list.data.length">
<v-list-scroll class="scroll_box"
style="overflow: hidden;"
:data="list.data"
:class-option="classOption"
@click.native="handleClick">
<ul>
<li class="row"
v-for="(item, index) in list.data"
:key="index"
:data-ind="index"
:item="JSON.stringify(item)">
<span v-for="(it, ind) in list.title" :key="ind" class="col"
:style="[it.width ? { width: it.width } : { flex: 1 },
{'text-align': it.align || 'left'}]">
<template v-if="it.slot">
<slot :name="it.slot" :item="JSON.stringify(item)"></slot>
</template>
<template v-else>
{{ item[it.key] }}
</template>
</span>
</li>
</ul>
</v-list-scroll>
</template>
<template v-else>
<div class="no_data">{{ option.noData || '暂无数据' }}</div>
</template>
</div>
</template>
- classOption 的属性可自由替换为可配置属性,如step属性,可取父组件传参:
- 因为vue-seamless-scroll组件的滚动效果是通过复制一组list元素实现的,所以直接在list上绑定click事件,会出现点击不起效果的情况,这里的点击事件用了事件委托,向父组件传递了类名和当前行的数据;
<script>
export default {
props: {
option: {}
},
data () {
return {
listLine: 0,
classOption: {},
list: {}
}
},
watch: {
listLine: {
immediate: true,
handler (val) {
this.classOption = {
step: this.$attrs.step, // 数值越大速度滚动越快,0时静止
limitMoveNum: this.listLine, // 开始无缝滚动的数据量 this.dataList.length
hoverStop: true, // 是否开启鼠标悬停stop
direction: 1, // 0向下 1向上 2向左 3向右
openWatch: true, // 开启数据实时监控刷新dom
singleHeight: 0, // 单步运动停止的高度(默认值0是无缝不停止的滚动) direction => 0/1
singleWidth: 0, // 单步运动停止的宽度(默认值0是无缝不停止的滚动) direction => 2/3
waitTime: 1000 // 单步运动停止的时间(默认值1000ms)
}
const obj = { ...this.option }
const data = this.option.data
obj.data = [...data, ...data]
this.list = this.option.data.length % 2 && this.option.data.length >= this.listLine ?
obj : this.option
}
}
},
mounted () {
const boxHeight = this.$refs.listScroll?.clientHeight || 0 // 容器高度
const lineHeight = this.$refs.listTit?.clientHeight || 1 // 行高
this.listLine = Math.floor(boxHeight / lineHeight) - 1 // 计算滚动数据长度
},
methods: {
handleClick (e) {
const path = e.path || (e.composedPath && e.composedPath())
let target = path.filter(r => /row/.test(r.className))
if (target.length) target = target[0]
else return
const obj = JSON.parse(target.getAttribute('item')) // 单项数据详情
const cls = path.map(item => {
return item.className
})
this.$emit('listClick', { cls, obj })
}
}
}
</script>
<style lang="scss" scoped>
.listScroll {
width: 100%;
height: 100%;
flex: 1;
overflow: hidden;
box-sizing: border-box;
position: relative;
display: flex;
flex-direction: column;
ul {
overflow: auto;
display: flex;
flex-direction: column;
padding: 0 15px;
margin: 0;
flex-shrink: 0;
li {
display: flex;
box-sizing: border-box;
height: 32px;
align-items: center;
overflow: hidden;
flex: unset;
span {
color: #fff;
font-size: 0.14px;
padding: 0 10px;
flex-shrink: 0;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
&:nth-child(even) {
background: rgba(70, 127, 224, 0.2);
}
&:nth-child(odd) {
background: transparent;
}
}
&.title-ul li {
background: rgba(70, 127, 224, 0.2);
}
}
.no_data {
color: #fff;
display: flex;
align-items: center;
justify-content: center;
flex: 1;
font-size: 0.14px;
}
}
</style>
三、引入使用:
可以在main.js中全局注册,方法如上面vueSeamlessScroll注册方式一致,不需要每个页面引入;
这里展示的为单个页面注册引入方法;
<template>
<div class="content">
<div class="list-box">
<list-scroll :option="opt" @listClick="listClick">
<template #sex="{ item }">
<div>{{item.sex === 0 ? '女' : '男'}}</div>
</template>
<template slot="btn">
<div class="check">查看</div>
</template>
</list-scroll>
</div>
</div>
</template>
用setTimeout模拟接口获取数据;
<script>
import listScroll from '@/components/listScroll'
export default {
components: {
listScroll
},
data () {
return {
opt: {
title: [
{ name: '姓名', key: 'name', width: '40px' },
{ name: '性别', slot: 'sex', width: '40px', align: 'center' },
{ name: '家庭地址', key: 'address' },
{ name: '照片', slot: 'btn', width: '40px', align: 'center' }
],
data: []
}
}
},
mounted () {
const that = this
window.setTimeout(function () {
that.getList()
}, 2000)
},
methods: {
getList () {
for (let i = 0; i < 10; i++) {
this.opt.data.push({
name: `姓名${i + 1}`,
sex: i % 2,
address: `山东省济南市高新区齐鲁软件园-${i + 1}`
})
}
},
// 点击事件
listClick ({ cls, obj }) {
cls.forEach(item => {
if (item === 'check') {
console.log(obj)
}
})
}
}
}
</script>
注意:必须配置容器宽高:
<style lang="scss" scoped>
.list-box {
width: 400px;
height: 300px;
background: #000;
margin: 0 auto;
}
</style>