功能
- 默认情况无限循环向右移动
- 点击数字切换到对应图片
- 点击左右切换可切换图片
原理
首先说下原理。
- 在布局上所有的图片都是重叠的,即只要保证Y方向对齐即可,当前可见的图z-index层级最高。
- 每隔3s中更换一张图片,使用setTimeout定时。
- 使用gIndex记录当前可视区域的展示的是哪张图片下标,每次更换,计算下一张图片的下标。
- 通过requestAnimationFrame实现一次图片切换的动画。
这种方法也可以做到整个页面始终只有2个img标签,而不必把所有的img节点全部创建出来,要点是每次更换不可见img的src。
动画的实现
- 首先定义一个timestap,这个值记录每个帧移动多少距离。定义初始step=0,记录移动的步数。
- 每次移动的距离moveWidth是timestamp*step,图片1向右移动增加moveWidth,图片2从左侧进入moveWidth。因此,图片1的transform是translate(moveWidth), 而图片2的transform则是translate(moveWidth-图片宽度)。
3. step+1
4. 如果moveWidth>图片宽度,步骤5,否则requestAnimationFrame请求下一次执行,继续2-4.
5. 图片1和2都将位置放置在起始位置,图片2的z-index设置为最高。
这样就完成了一次移动的动画。
html代码
- <header>
- <div class="box">
- <img src="imgs/banner1.jpg">
- <img src="imgs/banner2.jpg">
- <img src="imgs/banner3.jpg">
- <img src="imgs/banner4.jpg">
- </div>
- <div class="buttons">
- <div class="active">1</div>
- <div>2</div>
- <div>3</div>
- <div>4</div>
- </div>
- <div class="left">
- <div class="arrow"></div>
- </div>
- <div class="right">
- <div class="arrow"></div>
- </div>
- </header>
JS代码
- var timeout = null;
- window.onload = function () {
- var oLeft = document.querySelector('.left');
- var oRight = document.querySelector('.right');
- var oButton = document.querySelector('.buttons');
- var oButtons = document.querySelectorAll('.buttons div');
- var oImgs = document.querySelectorAll('.box img');
- var imgWidth = oImgs[0].width;
- var gIndex = 0;
- begainAnimate();
- // 绑定左右点击事件
- oLeft.onclick = function () {
- clearTimeout(timeout);
- leftMove();
- begainAnimate();
- };
- oRight.onclick = function () {
- clearTimeout(timeout);
- rightMove();
- begainAnimate();
- };
- // 绑定数字序号事件
- oButton.onclick = function (event) {
- clearTimeout(timeout);
- var targetEl = event.target;
- var nextIndex = (+targetEl.innerText) - 1;
- console.log(nextIndex);
- rightMove(nextIndex);
- begainAnimate();
- }
- // 默认初始动画朝右边
- function begainAnimate() {
- clearTimeout(timeout);
- timeout = setTimeout(function () {
- rightMove();
- begainAnimate();
- }, 3000);
- }
- // 向左移动动画
- function leftMove() {
- var nextIndex = (gIndex - 1 < 0) ? oImgs.length - 1 : gIndex - 1;
- animateSteps(nextIndex, -50);
- }
- // 向右移动动画
- function rightMove(nextIndex) {
- if (nextIndex == undefined) {
- nextIndex = (gIndex + 1 >= oImgs.length) ? 0 : gIndex + 1;
- }
- animateSteps(nextIndex, 50);
- }
- // 一次动画
- function animateSteps(nextIndex, timestamp) {
- var currentImg = oImgs[gIndex];
- var nextImg = oImgs[nextIndex];
- nextImg.style.zIndex = 10;
- var step = 0;
- requestAnimationFrame(goStep);
- // 走一帧的动画,移动timestamp
- function goStep() {
- var moveWidth = timestamp * step++;
- if (Math.abs(moveWidth) < imgWidth) {
- currentImg.style.transform = `translate(${moveWidth}px)`;
- nextImg.style.transform = `translate(${moveWidth > 0 ? (moveWidth - imgWidth) : (imgWidth + moveWidth)}px)`;
- requestAnimationFrame(goStep);
- } else {
- currentImg.style.zIndex = 1;
- currentImg.style.transform = `translate(0px)`;
- nextImg.style.transform = `translate(0px)`;
- oButtons[gIndex].setAttribute('class', '');
- oButtons[nextIndex].setAttribute('class', 'active');
- gIndex = nextIndex;
- }
- }
- }
- }
- window.onclose = function () {
- clearTimeout(timeout);
- }
css布局样式
- <style>
- /* 首先设置图片box的区域,将图片重叠在一起 */
- header {
- width: 100%;
- position: relative;
- overflow: hidden;
- }
- .box {
- width: 100%;
- height: 300px;
- }
- .box img {
- width: 100%;
- height: 100%;
- position: absolute;
- transform: translateX(0);
- z-index: 1;
- }
- .box img:first-child {
- z-index: 10;
- }
- /* 数字序列按钮 */
- .buttons {
- position: absolute;
- right: 10%;
- bottom: 5%;
- display: flex;
- z-index: 100;
- }
- .buttons div {
- width: 30px;
- height: 30px;
- background-color: #aaa;
- border: 1px solid #aaa;
- text-align: center;
- margin: 10px;
- cursor: pointer;
- opacity: .7;
- border-radius: 15px;
- line-height: 30px;
- }
- .buttons div.active {
- background-color: white;
- }
- /* 左右切换按钮 */
- .left,
- .right {
- position: absolute;
- width: 80px;
- height: 80px;
- background-color: #ccc;
- z-index: 100;
- top: 110px;
- border-radius: 40px;
- opacity: .5;
- cursor: pointer;
- }
- .left {
- left: 2%;
- }
- .right {
- right: 2%;
- }
- .left .arrow {
- width: 30px;
- height: 30px;
- border-left: solid 5px #666;
- border-top: solid 5px #666;
- transform: translate(-5px, 25px) rotate(-45deg) translate(25px, 25px);
- }
- .right .arrow {
- width: 30px;
- height: 30px;
- border-left: solid 5px #666;
- border-top: solid 5px #666;
- transform: translate(50px, 25px) rotate(135deg) translate(25px, 25px);
- }
- </style>