笔者使用的是vue3-seamless-scroll:GitHub - xfy520/vue3-seamless-scroll: Vue3.0 无缝滚动组件
全局注册笔者的出现红色波浪线,但单个.vue文件局部注册不会
我的代码:
<template>
<div class="tabBox">
<div class="tabBox-head">
<div class="row">
<span class="xh">序号</span>
<span v-for="item in tabHeadData" :key="item.id">{{ item.nickname }}</span>
</div>
</div>
<div class="tabBox-body" :style="{ height: TBH + 'px' }">
// limitScrollNum:tableData数据长度大于几条开始滚动
// step:步进速度(滚动行数)
// copyNum:拷贝列表次数
// delay:动画延时时间
<vue3-seamless-scroll :list="tableData" :limitScrollNum="1" :step="1" :copyNum="4" :delay="10">
<div class="row" v-for="(item,index) in tableData" :key="item.id">
<span class="xh">{{index + 1}}</span>
<span v-for="it in tabHeadData" :key="it.id">{{ item[it.filed] }}</span>
</div>
</vue3-seamless-scroll>
</div>
</div>
</template>
<script setup lang="ts">
import { Vue3SeamlessScroll } from "vue3-seamless-scroll";
const tabHeadData:any = [
{
id:1,
filed:'name',
nickname:'名字'
},
{
id:2,
filed:'age',
nickname:'年龄'
}
]
const tableData:any = [
{
id:1,
name:'张三',
age:18
},
{
id:2,
name:'李四',
age:25
},
{
id:3,
name:'王五',
age:20
},
{
id:4,
name:'丁六',
age:30
},
{
id:5,
name:'杨七',
age:19
}
]
const state:any = reactive({
lineHeight:30,
padding:10,
num:5 //展示的行数
})
// 表体高度计算
const TBH = computed(() => {
return (state.lineHeight + state.padding * 2 + 1) * state.num
})
</script>
<style lang="scss" scoped>
</style>
效果图:
以下展示的是笔者用js写的滚动:
<template>
<div class="listBox" :style="[listBoxStyle]">
<div class="screen">
<div class="listBox-body" :id="eleProp.id">
<div class="listBox-body-item">
<div class="col" v-for="(item,index) in tableData" :key="index">
<div class="text">
<div class="l">
<span class="order">{{ `No.${index+1}` }}</span>
<span class="data name">{{ item.name }}</span>
</div>
<div class="r data num">{{ item.age }}</div>
</div>
<div class="line">
<div class="bf" :style="{'width':getW(item.age,eleProp.max)}"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import {animation} from '@/utils/animation.ts'
const tableData:any = [
{
id:1,
name:'张三',
age:30
},
{
id:2,
name:'李四',
age:25
},
{
id:3,
name:'王五',
age:20
},
{
id:4,
name:'丁六',
age:30
},
{
id:5,
name:'杨七',
age:19
}
]
//样式
const listBoxStyle = computed(() => {
return {
'--col-h':'calc('+(300 - 20)+'px/'+ eleProp.scrollNum+')', //计算行高
'--main-c': '#1370FB',
'--data-c': '#000',
'--border-c': '#CDD2F8',
'--order-s': '20px',
'--tit-s': '16px',
'--num-s': '16px'
}
})
// 获取类名为bf的Dom的宽度
const getW = (num:number,total:number) => {
return (100 / total) * num + '%'
}
// 动画
const eleProp:any = reactive({
ele:null,
num:0,
flag:true,
count:0, //数据个数
timer:null,
id:'listBox-body'
max:30, //年龄最大值
scrollNum:4 //滚动个数
})
onMounted(() => {
eleProp.count = tableData.length
if(eleProp.count >= eleProp.scrollNum) {
eleProp.ele = document.querySelector('#' + eleProp.id)
// 克隆一个.listBox-body-item及其子元素
const sonDomCopy = eleProp.ele.children[0].cloneNode(true)
eleProp.ele.appendChild(sonDomCopy)
autoEvent()
}
})
const autoEvent = () => {
eleProp.timer = setInterval(function(){
listAnimation()
}, 1000)
}
const listAnimation = () => {
//为了预防上一次listAnimation未执行完又执行listAnimation导致滚动速度加快
if(!eleProp.flag){
return;
}
eleProp.flag=false
eleProp.num ++;
animation({
ele: eleProp.ele,
target : -eleProp.ele.children[0].children[0].offsetHeight*eleProp.num,
attr : 'top',
callback : function(){
if(eleProp.num == eleProp.count){
eleProp.num = 0;
eleProp.ele.style.top = 0;
}
eleProp.flag=true;
}
});
}
</script>
<style lang="scss" scoped>
@import '@/assets/styles/list.scss';
</style>
// utils/animation.ts
/**
* * 列表动画
* @param options
*/
export const animation = (options:any) => {
//先清除再开启
clearInterval(options.ele.timer);
//使用定时器
options.ele.timer = setInterval(function(){
//获取到现在的位置
var begin = parseInt(getStyle(options.ele, options.attr));
//步长 step = (target - begin)/10
var step = (options.target - begin)/10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
//位置+步长
var res = begin + step;
//赋值
options.ele.style[options.attr] = res + 'px';
if(res == options.target){
clearInterval(options.ele.timer);
//当有这个函数名称的时候,再调用函数
//两个条件必须都满足,才能执行
options.callback && options.callback();
}
}, 30)
}
/**
**获取元素样式
*/
const getStyle = (obj:any, attr:any) => {
if((window as any).getComputedStyle){
return getComputedStyle(obj, null)[attr];
}else{
return obj.currentStyle[attr];
}
}
// list.scss
.listBox {
width: 500px;
height: 300px;
padding: 10px;
box-sizing: border-box;
.screen {
height: 100%;
width: 100%;
overflow: hidden;
position: relative;
}
.listBox-body {
position: absolute;
width: 100%;
left: 0;
}
.col {
position: relative;
height: var(--col-h);
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
.text {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
div {
display: inline-flex;
align-items: center;
}
.data {color: var(--data-c);}
.order {font-size: var(--order-s);color: var(--main-c);margin-right: 10px;}
.name {font-size: var(--tit-s);}
.num {font-size: var(--num-s);}
}
.line {
border-bottom: 1px solid var(--border-c);
width: 100%;
.bf {
height: 4px;
background-color: var(--main-c);
overflow: hidden;
border-radius: 10px;
position: relative;
&::before {
content: '';
position: absolute;
width: 100%;
height: 100%;
opacity: .3;
background-color: white;
left: 0;
top: 0;
animation: widthAnimate 2s linear infinite;
}
}
}
&:nth-child(5n+2) .bf::before{
animation-delay: .5s;
}
&:nth-child(5n+3) .bf::before{
animation-delay: 1s;
}
&:nth-child(5n+4) .bf::before{
animation-delay: 1.5s;
}
&:nth-child(5n+5) .bf::before{
animation-delay: 2s;
}
}
}
@keyframes widthAnimate {
from {
width: 0%;
}
to{
width: 100%;
}
}
效果图