react+redux,实现 广告自动轮播效果

广告轮播效果是一个很常见的APP特效,多个图片广告自动翻滚展示,同时也支持用户的手势滑动。

我实现这个特效,一方面是想锻炼react/redux程序的设计思路,更重要的是会接触到css动画,这个前端技术我从未接触。

设计思路

轮播特效,最生动的一个感受就是播放电影胶片。电影放映机插入了一卷胶片,胶片的每一格是一帧图片,在播放的时候放映机通过一个小窗口打光到胶片的一格上,胶片缓慢的移动,从而播放出一帧一帧的画面,就形成了电影。

因此,在html结构上,我会放置1个固定长宽的<div>作为窗口,在其内部横向放置一个很长的图片列表<ul>,重要的是<ul>超过窗口大小的部分被遮盖,而我们只能看见当前处于窗口中的图片。

另外一个需要注意的点,就是我们最多在窗口中看到2个图片,这会发生在胶片移动的中途,很容易想象。

组件实现

使用方法

因为轮播特效很常用,所以我要将其实现成一个通用组件Slider。上层使用时,需要传入一些配置参数,例如:窗口的长宽,轮播的间隔,图片列表以及对应的跳转地址,最终我在MsgCreatePage组件中引入了Slider组件,看起来会是这样:

实现关键点

首先,为了实现电影放映机的类似效果,我会定义一个窗口容器div#SliderWrapper,内部的胶卷使用ul#SliderList并且相对于窗口绝对定位(position:absolute),这样才能基于css left进行胶卷的滑动。

render渲染方法

这里做了几个重要的事情:

  • 轮播和胶卷的一个重要差别就是胶卷播放结束无法从头播放,而轮播在遇到末尾时会继续从头滚动。为了实现这种轮回的感觉,如果图片大于1张(1张图片不用轮播)那么我将第一张图片放到图片列表的末尾,最后一张图片放到图片列表的头部,这样最后一张图片可以向右衔接到第一张图片(仅视觉上),同样第一张图片也可以向左衔接到最后一张图片(仅视觉上),配合一些代码逻辑可以在衔接阶段的背后进行真实的left偏移修正。
  • 为了支持手势,我们在胶卷(ul)上配置了onTouchXXX系列监听。

componentDidMount组件首次渲染完成

在render方法调用后,componentDidMount被紧接着调用,我们要做的就是初始化redux的state,并且启动轮播定时器。

tryStartAuto启动轮播

这里最重要的就是启动定时器,间隔interval毫秒后触发一次向右的滑动,这里this.props.slide是一个redux action。

slide 滑动action

看一下slide这个action,它传入一个step指示胶卷向哪个方向移动几格,经过reducer计算后生成新的下标,这里redux state中的curIndex和step被注入到Slider组件的Props供访问。

componentDidUpdate 重新渲染完成

当定时器通过slide action触发curIndex和step改变后,shouldComponentUpdate被首先调用,这里主要判断本次更新的触发原因是Slider组件的用户传入的props改变(例如imgs,options)还是slide引起的props改变,因此通过curIndex进行了简单判定。

render方法被调用重画dom,紧接着componentDidUpdate被调用。

如果是因为slide滚动引起的重画,并且step是1说明是普通的滚动事件,那么应该先停止轮播定时器,之后调用jquery的动画函数animate对ul进行滚动1格,同时在animate的complete回调中恢复轮播定时器。不过要注意的是,这里特殊判断了当前下标如果是位于头尾的衔接处,那么紧接着发起同步slide action,传入的step是2/-2,经过redux一系列流程后再次回到componentDidUpdate的step == 2/-2分支,直接进行css修正left,相当于将胶卷重新插入到放映机中。

手势

首先图片的滚动是一个动画,执行是异步的,花费若干时间。因为轮播,手势,动画三个事件同时存在,如果引入过多的并发组合会导致过渡复杂,无法避免bug。因此整个Slider实现时遵循2个思路:

  • 动画期间,手势和轮播定时器都应禁止。
  • 手势期间,轮播定时器应该禁止。

手势期间通过isTouching来标识,并且关闭了定时器。通过判断x轴偏移确认是往左滑还是往右滑,从而为slide action传入不同的step,而通过手势触发的slide操作最终会在其动画结束后恢复轮播定时器,这个可以在componentDidUpdate中看到。

体验

使用专业二维码软件扫描(不要用微信),或者手机浏览器输入网址:http://t.cn/RVIE4r0

1476506656

源码

点我下载源码

休息了2天,我又为组件的右下角添加了小圆点的进度效果,源代码和二维码都做了相应的更新,其中用到了css3的border-radix实现小圆点效果。

如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~