太长了,巧妙地优化了跑马灯

开发 前端
用animation虽然好,但是不能控制跑马灯的长度,即我不想让50个item一起滚动,最好是让只需要出现在屏幕中的item滚动就好了。于是就将滚动改成了item为绝对定位,然后利用transform来改变位置,然后利用transition来实现动画的过渡。

前言

上周优化了个跑马灯,原因是跑马灯的长度太长了,每个item的节点比较多,所以即使限制最多只有50个item,也还是很长很长,有多长可以看看下面

图片图片

怎么优化呢?看看之前的跑马灯。

优化前的写法

图片图片图片

之前的写法很简单,其实就是让很长很长的class="animate"的div在lottery-person-wrapper中滚动。用的是css 中的animation属性。

用animation虽然好,但是不能控制跑马灯的长度,即我不想让50个item一起滚动,最好是让只需要出现在屏幕中的item滚动就好了。于是就将滚动改成了item为绝对定位,然后利用transform来改变位置,然后利用transition来实现动画的过渡。

优化后的写法

图片

可以看到没有那么多的item节点了,这是怎么办到的呢?

  1. 首先获取lottery-person-wrapper的宽度。
this.animationWrapperWidth = this.$refs.animateWrapper.clientWidth;
  1. 然后再让一个item出现在跑马灯中。
mounted() {
this.$nextTick(() => {
this.animationWrapperWidth = this.$refs.animateWrapper.clientWidth;
this.emitItem();
});
}
  1. 看看emit是怎么写的。

首先需要知道:

  • swiperUserList是从接口获取到的列表。
  • swiperUserListShow是在template中遍历的列表。

图片图片

我们先拿出swiperUserList中的第一个item,然后再把item放入swiperUserList的尾部,让swiperUserList始终保持50个item。

然后,再把这个item深拷贝放入到swiperUserListShow中,为什么要深拷贝是因为,不希望swiperUserListShow的item与swiperUserList中的item出现引用的关系,否则会十分混乱。

给每一个item添加了一个id是为了作为遍历时独一无二的key。

图片图片

接下来则是要获取该item的宽度clientWidth,然后计算出该item的尾部出现的时间endShowTime,以及该item完全走完消失的时间disappearTime。

在该item尾部出现的时候,就让下一个item push到swiperUserListShow中,使其出现在跑马灯中,在该item完全跑完消失的时候就让这个item从swiperUserListShow中剔除。

emitItem() {
if (!this.isShow) {
return;
}
let swiperUser = this.swiperUserList.shift();
this.swiperUserList.push(swiperUser);
this.swiperUserListShow.push(
Object.assign({}, { ...swiperUser, id: this.swiperId })
);
this.swiperId += 1;
this.$nextTick(() => {
let elm = this.$refs.swiperUserList[this.swiperUserListShow.length - 1];

let elmWidth = elm.clientWidth || 0;

let disappearTime = (elmWidth + this.animationWrapperWidth) / 60;
let endShowTime = elmWidth / 60;

let moveItem =
this.swiperUserListShow[this.swiperUserListShow.length - 1];
elm.style.transition = `transform ${disappearTime}s linear`;
elm.style.transform = 'translate(-100%,-50%)';
// this.clearTimer(moveItem)
moveItem.endShowTimer = window.setTimeout(() => {
clearTimeout(moveItem.endShowTimer);
moveItem.endShowTimer = null;
this.emitItem();
}, endShowTime * 1000);

moveItem.disappearTimer = window.setTimeout(() => {
clearTimeout(moveItem.disappearTimer);
moveItem.disappearTimer = null;
this.swiperUserListShow.shift();
}, disappearTime * 1000);
});
},

基本上就已经实现了。

为什么说是基本?

因为有两个坑。

看看坑

第一个是我们用了setTimeout,在我们将页面切到后台的时候,setTimeout里的代码是挂起的,不会执行,但是页面上的动画还是会继续执行的。

elm.style.transition = `transform ${disappearTime}s linear`;
elm.style.transform = 'translate(-100%,-50%)';

所以,为了解决这个bug,需要监听是否切出切入后台,切到后台则清除所有setTimeout和清空swiperUserListShow列表,切回页面,再重新执行emitItem。

mounted() {
this.$nextTick(() => {
this.animationWrapperWidth = this.$refs.animateWrapper.clientWidth;
this.emitItem();
});

// 处理退出前台,跑马灯还在跑的问题,隐藏就是直接清空展示列表
document.addEventListener('visibilitychange', () => {
const isShow = document.visibilityState === 'visible'
this.handleSwiperListShow(isShow);
});
}
methods: {

// 处理跑马灯展示列表和清除计时器
handleSwiperListShow(isShow) {
if (isShow) {
this.emitItem();
} else {
this.swiperUserListShow.forEach((item) => {
clearTimeout(item.endShowTimer);
clearTimeout(item.disappearTimer);
});
this.swiperUserListShow = [];
}
},
}

第二个坑是我们使用了clientWidth来获取item的宽度,当我们页面中有tab的时候,并且跑马灯在某个tab下,然后当前v-show是激活的是其他tab,则会导致跑马灯被隐藏,则获取不到item的宽度,这时的clientWidth的值为0.导致计算出来的endShowTime的值为0,则会导致疯狂执行settimeout里面的内容。

为了解决这个bug则需要在父组件中传入isShow来判断跑马灯这个页面是否被隐藏。

props: {
isShow: {
type: Boolean,
default: false
},
}

然后监听isShow。

watch: {

// 处理tab选项卡隐藏抽奖模块,获取不到item clientWith的问题,隐藏就是直接清空展示列表
isShow(newVal, oldVal) {
this.handleSwiperListShow(newVal)
}
},

至此,优化过程就到此完美结束了。

其实还有个比较简单的优化方法,但是不适用于我这个场景,但是也分享一下。

就是依然使用css的animation动画属性,然后使用animationEnd的监听事件。

图片

其他优化方案

当监听到结束的时候,利用v-if把当前跑马灯销毁,然后就往swiperUserListShow中push两个item,再生成展示跑马灯,又实现animation动画,这样是一个实现起来十分方便的方案,但是由于同一时刻只有我们push的item数,而且需要跑完才继续展示下两个,会留下一片空白,就有的不连贯的感觉,所以不使用这种方案。

图片

责任编辑:姜华 来源: 前端阳光
相关推荐

2015-08-07 15:45:02

swift跑马灯源码

2011-07-29 10:01:21

IOS 跑马灯

2013-01-14 17:18:43

Android开发TextView跑马灯效果

2023-11-01 08:33:45

CSS动画效果

2017-11-10 11:04:29

NVIDIA TITA处理器典藏版

2021-01-28 14:34:35

鸿蒙HarmonyOS应用开发

2021-01-29 09:48:17

鸿蒙HarmonyOS应用开发

2022-10-26 11:00:06

VisualC++函数

2021-04-16 05:54:05

CSS 文字动画技巧

2020-08-12 09:53:18

代码开发工具

2021-02-14 14:06:24

SQL数据库面试

2020-05-28 09:06:23

大数据平台优化

2014-12-31 15:42:21

Android多线程软件下载

2023-09-06 10:44:09

Nitrux 3.0工具

2011-01-13 16:11:13

silverlightwebasp.net

2020-10-22 10:15:33

优化Windows电脑

2021-07-28 14:35:09

代码进度条前端

2021-02-18 11:56:43

恶意软件勒索软件网络攻击

2013-10-22 09:28:39

广域网优化 路由器WAN

2023-03-30 07:34:10

Linux性能数据结构
点赞
收藏

51CTO技术栈公众号