在日常开发中,经常遇到需要支持列表循环滚动展示,特别是在数据化大屏开发中,无缝滚动使用频率更为频繁,在jquery时代,我们常用的无缝滚动组件为liMarquee,在vue中已经有vue-seamless-scroll组件(通过Vue2实现,不支持鼠标手动滚动),但是在使用过程中,发现滚动后会存在点击事件失效的问题,并且产品提了个需求,需要支持鼠标手动滚动,也要支持自动滚动,于是痛定思痛,决定通过Vue3来实现该功能,该组件已经实现上传npm,可以直接安装使用,链接在文尾。
首先写一个基础的list结构,通过插槽接收外部传入的list数据,因为需要实现无缝滚动,需要复制出同一份的Dom,在最外层监听鼠标hover和leave的状态,以实现鼠标hover暂停滚动,绑定鼠标滚动事件,在鼠标滚动时记住滚动的位置,在恢复自动滚动时能从当前滚动位置继续滚动。
<div class="custom-list" ref="scrollBody" @mouseenter="mouseenterFunc" @mouseleave="mouseleaveFunc"
@mousewheel="mousewheelFunc">
<div class="list-body" :class="{
'list-body2': isHorizontal
}" ref="listBody" :style="{ transform: getScrollDistance() }">
<slot>slot>
div>
<div class="list-body" :class="{
'list-body2': isHorizontal
}" ref="tBody" v-if="isCanScroll" :style="{ transform: getScrollDistance() }">
<slot>slot>
div>
div>
通过父级传入的isHorizontal判断是横向滚动,还是垂直滚动
const start = () => {
//判断是否可以滚动函数
let isScrollFunc = (bodySize:number, listSize:number) => {
if (bodySize > listSize) {
scrollDistance.value = 0;
isCanScroll.value = !1;
}
};
isStop.value = !1;
//判断是否可以滚动
if (!isHorizontal.value) {
isScrollFunc(bodyHeight.value, listHeight.value);
} else {
isScrollFunc(bodyWidth.value, listWidth.value);
}
if (isCanScroll.value) {
run();
}
}
计算目前滚动的距离,并判断需要滚动的方向,计算下一步滚动的距离。
const run = () => {
//清空动画
clearAnimation();
animationFrame.value = window.requestAnimationFrame(() => {
//滚动主逻辑函数
let main = (listSize:number, bodySize:number) => {
let tempScrollDistance = Math.abs(scrollDistance.value);
if (scrollDistance.value < 0) {
let cc = 2 * listSize - bodySize;
if (tempScrollDistance > cc) {
scrollDistance.value = -(listSize - bodySize);
}
} else {
scrollDistance.value = -listSize;
}
};
//根据滚动方向判断使用高度或宽度控制效果
if (!isHorizontal.value) {
main(listHeight.value, bodyHeight.value);
} else {
main(listWidth.value, bodyWidth.value);
}
//判断滚动值
if (!isStop.value) {
if (
props.scrollDirection === "top" ||
props.scrollDirection === "left"
) {
scrollDistance.value -= props.steep;
} else if (
props.scrollDirection === "bottom" ||
props.scrollDirection === "right"
) {
scrollDistance.value += props.steep;
}
run();
}
});
}
通过translate实现列表平移,已实现平滑滚动。
const getScrollDistance = () => {
let style;
if (!isHorizontal.value) {
style = "translate(0px, " + scrollDistance.value + "px)";
} else {
style = "translate(" + scrollDistance.value + "px,0px)";
}
return style;
}
const clearAnimation = () => {
if (animationFrame.value) {
cancelAnimationFrame(animationFrame.value);
animationFrame.value = null;
}
}
鼠标滚动时实时计算滚动的距离,可通过传入的鼠标滚动速率来计算每次滚动多少。
const mousewheelFunc = (e:any) => {
if (!isCanScroll.value || !props.isRoller) {
return false;
}
let dis = e.deltaY;
if (dis > 0) {
scrollDistance.value -= props.rollerScrollDistance;
} else {
scrollDistance.value += props.rollerScrollDistance;
}
run();
}
该组件已上传npm仓库,欢迎satrt使用
npm install @fcli/vue-auto-scroll --save-dev 来安装
在项目中使用
import VueAutoScroll from '@fcli/vue-auto-scroll';
const app=createApp(App)
app.use(VueAutoScroll);
使用示例:
<div class="content">
<vue-auto-scroll :data="list" :steep="0.5" scrollDirection="top" :isRoller="true" :rollerScrollDistance="50">
<div class="li" v-for="i in list" :key="i">
{{ i }}
div>
vue-auto-scroll>
div>
属性 | 属性名称 | 类型 | 可选值 |
---|---|---|---|
steep | 滚动的速率 | number | 为正数即可 |
scrollDirection | 滚动的方向 | string | top ,bottom,left,right |
isRoller | 是否可以使用滚轮滚动 | boolean | true,false |
rollerScrollDistance | 滚轮滚动的速率 | number | (isRoller 必须为 true)为正数即可 |
data | 接收异步数据 | array | 同步任务可不传 |
注: 当scrollDirection 为top或bottom时,一定要为 vue-auto-scroll 组件设置高度。 当scrollDirection 为left或right时,一定要为 vue-auto-scroll 组件设置宽度。并为嵌入vue-auto-scroll中的标签设置样式为display:inline-block; 示例样式名为list-item可以更改为其他类名。当scrollDirection 为left或right时,是基于行内元素的“white-space: nowrap;” 来控制强制不换行的。有可能会影响其内部的文字排列。可以在list-item 层添加 white-space: normal; 来处理给问题。并为其添加固定宽度,以保证文字可以正常换行及插件的正确计算与显示。如果没有为其添加固定宽度,会造成插件获取父容器层的宽度值错误,导致显示混乱
git地址:https://gitee.com/fcli/vue-auto-scroll.git