有了动画效果属性,我们就可以在 JavaScript 中加入我们的定时器,让我们的图片在每三秒钟切换一次图片。我们使用 setInerval() 这个函数就可以解决这个问题了。
但是我们怎么才能让图片轮播,或者移动呢?想到 HTML 中的移动,大家有没有想到 CSS 当中有什么属性可以让我们移动元素的呢?
对没错,就是使用 transform,它就是在 CSS 当中专门用于挪动元素的。所以这里我们的逻辑就是,每 3 秒往左边挪动一次元素自身的长度,这样我们就可以挪动到下一张图的开始。
但是这样只能挪动一张图,所以如果我们需要挪动第二次,到达第三张图,我们就要让每一张图偏移 200%,以此类推。所以我们需要一个当前页数的值,叫做 current,默认值为 0。每次挪动的时候时就加一,这样偏移的值就是 − 100 × 页 数 -100\times页数 −100×页数。这样我们就完成了图片多次移动,一张一张图片展示了。
class Carousel extends Component { // 构造函数 // 创建 DOM 节点 constructor() { super(); this.attributes = Object.create(null); } setAttribute(name, value) { this.attributes[name] = value; } render() { this.root = document.createElement('div'); this.root.classList.add('carousel'); for (let picture of this.attributes.src) { let child = document.createElement('div'); child.style.backgroundImage = `url('${picture}')`; this.root.appendChild(child); } let current = 0; setInterval(() => { let children = this.root.children; ++current; for (let child of children) { child.style.transform = `translateX(-${100 * current}%)`; } }, 3000); return this.root; } mountTo(parent) { parent.appendChild(this.render()); } }
这里我们发现一个问题,这个轮播是不会停止的,一直往左偏移没有停止。而我们需要轮播到最后一张的时候是回到一张图的。
要解决这个问题,我们可以利用一个数学的技巧,如果我们想要一个数是在 1 到 N 之间不断循环,我们就让它对 n 取余就可以了。在我们元素中,children 的长度是 4,所以当我们 current 到达 4 的时候, 4 ÷ 4 4\div4 4÷4 的余数就是 0,所以每次把 current 设置成 current 除以 children 长度的余数就可以达到无限循环了。
这里 current 就不会超过 4, 到达 4 之后就会回到 0。
用这个逻辑来实现我们的轮播,确实能让我们的图片无限循环,但是如果我们运行一下看看的话,我们又会发现另外一个问题。当我们播放到最后一个图片之后,就会快速滑动到第一个张图片,我们会看到一个快速回退的效果。这个确实不是那么好,我们想要的效果是,到达最后一张图之后,第一张图就直接在后面接上。
那么我们就一起去尝试解决这个问题,经过观察其实在屏幕上一次最多就只能看到两张图片。那么其实我们就把这两张图片挪到正确的位置就可以了。
所以我们需要找到当前看到的图片,还有下一张图片,然后每次移动到下一张图片就找到再下一张图片,把下一张图片挪动到正确的位置。
讲到这里可能还是有点懵,但是不要紧,我们来整理一下逻辑。
获取当前图片 index 和 下一张图的 index
首先轮播肯定是从第一张图开始,而这张图在我们的节点中肯定是第 0 个
因为我们需要在看到一张图的时候就准备第二张图,所以我们就需要找到下一张图的位置
根据我们上面说的,下一张图的位置,我们可以使用数学里的技巧来获得: 下 一 张 图 的 位 置 = ( 当 前 位 置 + 1 ) ÷ 图 片 数 量 下一张图的位置 = (当前位置 + 1)\div 图片数量下一张图的位置=(当前位置+1)÷图片数量 的余数,根据这个公式,当我们达到图片最后一张的时候,就会返回 0,回到第一个图片的位置
计算图片移动的距离,保持当前图片后面有一张图片等着被挪动过来
当前显示的图片的位置肯定是对的,所以我们是不需要计算的
但是下一张图片的位置就需要我们去挪动它的位置,所以这里我们需要计算这个图片需要偏移的距离
每一个图片移动一格的距离就是等于它自身的长度,加上往左移动是负数,所以每往左边移动一个格就是 -100%
图片的 index 是从 0 到 n 的,如果我们用它们所在的 index 作为它们距离当前图片相差的图片数,我们就可以用 index * -100%,这样就可以把每一张图片移动到当前图片的位置。
但是我们需要的是先把图片移动到当前图片的下一位的位置,所以下一位的所在位置是 index - 1 的图片距离,也就是说我们要移动的距离是 (index - 1) * -100%
让第二张图就位的这个动作,我们不需要它出现任何动画效果,所以在这个过程中我们需要禁止图片的动画效果,那就要清楚 transition
第二张图就位,就可以开始执行轮播效果
因为上面我们需要至少一帧的图片移动时间,所以执行轮播效果之前需要一个 16 毫秒的延迟 (因为 16 毫秒刚好是浏览器一帧的时间)
首先把行内标签中的 transition 重新开启,这样我们 CSS 中的动效就会重新起效,因为接下来的轮播效果是需要有动画效果的