day-028-twenty-eight-20230315-动画-轮播图
动画
动画的处理
-
css3的动画
-
transform是变形属性,不是动画translate位移scale缩放rotate旋转skew倾斜matrix矩阵
-
transition过渡动画-
步骤: 设置过渡效果,当改变元素样式的时候,会按照过渡效果进行运动
transition-property: all;transition-duration: 0.3s;transition-timing-function: linear;transition-delay: 0s;
-
简写:
transition:property duration timing-function delay;
-
-
animation帧动画-
步骤
-
首先基于
@keyframes设置动画运动的轨迹(0%[from] ->100%[to]),即关键帧名称 -
最后基于
animation按照指定的轨迹进行播放即运动animation-name: 关键帧名称;要执行动画的关键帧名称animation-duration: 0s;动画持续时间animation-timing-function: linear;动画运动函数,即运动方式animation-delay: 0ms;动画延迟时间animation-iteration-count: 5;动画执行次数animation-direction: reverse;动画执行方向animation-fill-mode: both;动画填充模式,即动画运动终点与动画运动起点的关系animation-play-state: paused/running;动画播放状态- 简写:
animation: name duration timing-function delay iteration-count direction fill-mode;
-
-
-
css3动画方案选取规则简单动画优先使用transition,复杂动画使用animation- 如果
运动轨迹/运动样式是需要动态管理的,则使用transition
-
总原则:
- 能用
CSS3解决的动画,优先使用CSS3-性能体验最好 CSS3解决不了的,再基于js去实现- 如果
js解决不了,很早之前是基于flash处理。现在应该直接换需求,不行可能是产品经理问题
- 能用
-
-
设置动画
-
JavaScript与css3组合-
一般是
用css3先设置过渡或用css3先设置动画帧,之后用JavaScript改元素的样式。-
用
JavaScript配合css3先设置过渡-
也可以在
JS中设置元素的过渡效果 -
也可以使用
ontransitionend()在DOM元素对象上监听DOM元素对象运行结束后的事件- 有
几个样式发生过渡效果,则transitionend事件就会被触发几次
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>动画</title> <style> .box { position: absolute; top: 10px; left: 10px; box-sizing: border-box; width: 100px; height: 100px; background: lightcoral; transition: all 1s linear;/* 1. 设置过渡效果 */ } </style> </head> <body> <div class="box" id="box"></div> <!-- IMPORT JS --> <script> let box = document.querySelector('#box'); // 可以在JS中设置元素的过渡效果 // box.style.transition = 'all 1s linear'; box.style.transitionDuration = '2s'; box.onclick = function () { // 2. 直接改元素的样式,元素就会按照指定的过渡效果去运动 this.style.top = '210px'; this.style.left = '310px'; }; // 3. 我们还可以监听到元素运动结束/开始等阶段,从而做一些事情 box.ontransitionend = function () { // 有几个样式(方向)发生过渡效果,则transitionend事件就会被触发几次 console.log('哈哈哈,我终于运动完成了!'); }; </script> </body> </html> - 有
-
-
用
JavaScript配合css3先设置动画帧-
设置
动画关键帧名称和关键帧具体参数 -
设置
单独的动画类 -
用
JavaScript给DOM元素对象设置动画- 可以直接设置style的animation属性
- 也可以给元素设置样式类,来控制播放
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>动画</title> <style> .box { position: absolute; top: 10px; left: 10px; box-sizing: border-box; width: 100px; height: 100px; background: lightcoral; } /* 2. 设置单独的动画类.run */ .box.run { animation: run 2s linear 0s both; } /* 1. 设置动画关键帧名称和关键帧具体参数 */ @keyframes run { 0% { top: 10px; left: 10px; } 100% { top: 210px; left: 310px; } } </style> </head> <body> <div class="box" id="box"></div> <script> let box = document.querySelector("#box"); box.onclick = function () { // 3-1. 可以直接设置style的animation属性 // this.style.animation = 'run 2s linear 0s both'; // 3-2. 我们更喜欢给元素设置样式类,来控制播放 this.classList.add('run'); console.log("变量--->"); }; box.onanimationend = function () { // 帧动画结束后触发的事件 console.log("哇咔咔"); }; </script> </body> </html>
-
-
-
-
animate.css
-
直接用,用单个粘贴复制
-
直接用
-
引入
css文件<link rel="stylesheet" href="./css/animate.css">
-
给DOM元素对象设置类名
this.className='box animate__animated animate__infinite animate__bounce'- 基础类
animate__animated - 无限循环
animate__infinite - 效果类
animate__bounce
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>动画</title> <link rel="stylesheet" href="css/animate.min.css"> <style> .box { position: absolute; top: 10px; left: 10px; box-sizing: border-box; width: 100px; height: 100px; background: lightcoral; } </style> </head> <body> <div class="box" id="box"></div> <script> let box = document.querySelector('#box'); box.onclick = function () { // 基于animate.css管理运动效果 this.className = 'box animate__animated animate__infinite animate__bounce'; }; box.onanimationend = function () { // 帧动画结束后触发的事件 console.log('哇咔咔'); }; </script> </body> </html>
-
-
原生JavaScript动画
JavaScript的动画是基于定时器处理
-
定时器
-
setTimeout(callback,interval)-
到达时间后只执行一次,定时器就结束了,后续不再触发执行- 但是
结束不代表清除
- 但是
-
-
setInterval(callback,interval)轮询定时器,每间隔一段时间,都会把定时器触发执行,直至手动清除定时器。callback回调函数-定时器到时间后执行的回调函数interval时间因子-需要等待的时间
-
clearTimeout()/clearInterval()清除定时器 -
定时器的返回值:数字,代表当前设置的定时器是系统中的第几个定时器-
每一次
定时器结束后,最好手动从系统中移除该定时器-
clearTimeout()传递一个数字,就是把系统中编号为这个数字的定时器移除掉- 不论是
setTimeout()还是setInterval(),只要设置定时器,编号就会累积,所以基于任何一种清除定时器的方法(clearTimeout()/clearInterval()),只要把编号传递进来,都可以清除指定编号的定时器
- 不论是
-
-
-
把控
定时器是否已经设置//只有等上一次点击创建的定时器被清除后,都会创建新的定时器 //依据 timer是否为null,如果是null,就认为已经清除了。但是需要我们在每一次从系统中移除定时器后,手动把timer赋值为null才可以。 let timer = null; document.onclick = function () { console.log("console"); if (timer === null) { timer = setTimeout(function () { console.log("定时器"); clearTimeout(timer);//从系统中移除了编号为timer的定时器,但是此时timer的值还是数字。 timer = null//手动赋值timer为初始值 }, 1000);//定时器编号数字 } };- 用一个
初始值为null的变量来存储定时器返回的编号。 定时器执行后,手动清除定时器后把变量手动设置为null。- 之后
判断变量是否为null,来判断是否已经设置了定时器。
- 用一个
-
养成习惯:
定时器一旦设置了,就用变量存储定时器编号,定时器执行完就要清除定时器,并手动把变量设置为初始值null。-
每一个
定时器执行完毕,我们都最好把其从系统中移除掉// 需求:每隔1秒中,让数字累加1,但是累加到5后,则结束累加操作 let timer = null; let num = 0; timer = setInterval(() => { num++; console.log(num); // 累加到了5,则结束定时器 if (num === 5) { clearInterval(timer); timer = null; } }, 1000); /* // 思路:循环设置5个定时器,但是执行的时间需要间隔开 let num = 0; for (let i = 1; i <= 5; i++) { let timer = null; timer = setTimeout(() => { num++; console.log(num); // 每一个定时器处理完毕,我们都最好把其从系统中移除掉 clearTimeout(timer); timer = null; }, i * 1000); } */ /* // 基于递归操作,还是设置5个定时器 let num = 0, timer = null; const sum = function sum() { // 每一次执行sum,首先清除上一次设置的定时器 clearTimeout(timer); num++; console.log(num); if (num === 5) { timer = null; //当递归结束,不再设置新的定时器的时候,再把timer赋值为null即可 return; }; timer = setTimeout(sum, 1000); }; timer = setTimeout(sum, 1000); */
-
-
-
requestAnimationFrame(指定的回调函数)-
类似于
setTimeout()定时器,只不过不需要指定等待的时间-
电脑有一个
屏幕刷新率:1秒内,屏幕刷新了多少次-
一般都是
60次,但还有120次多- 以
60次(60HZ)计,大概16.666...毫秒刷新一次
- 以
-
-
-
它会
自动按照电脑屏幕刷新率的时间进行处理-
会等待到
每次屏幕刷新的时候,把指定的回调函数执行一次requestAnimationFrame(() => { console.log('哇咔咔'); });
-
-
DOM元素样式
-
设置
DOM元素的样式-
元素.style.xxx = xxx把样式设置在元素的行内上- 优势:
这样设置的样式,优先级高
- 优势:
-
样式类名
元素.className='xxx'元素.classList.add('xxx')/元素.classList.remove('xxx')- 在
样式表中先把样式写好,最后在JavaScript中,基于操作样式类名,来管理DOM元素的样式
-
-
获取
DOM元素的样式-
元素.style.xxx只能获取写在元素行内上的样式不常用,因为一般很少把样式写在行内上
-
window.getComputedStyle(元素,伪类)获取元素(或者其伪元素{::after/::before})所有经过浏览器计算过的样式- 只要
DOM元素被浏览器渲染了,那么其所有的样式都是经过计算的,不管我们以何种方式编写的样式,即不管是用JavaScript写的还是css样式表的 - 即便
不写样式,浏览器也会为被渲染的DOM元素设置默认样式
- 只要
-
…
-
JavaScript写动画步骤
-
方案一:
固定步长的匀速运动-
setTimeout()或setInterval()-
设置定时器,每间隔16ms走一步 -
首先获取
现在元素的样式 -
每一步都是在当前样式的基础上加步长即可 -
把
最新的样式赋值给现在元素 -
最后做一个
边界处理<div class="box" id="box"></div> <script> const run2 = function run2() { let box = document.querySelector("#box"); //初始位置10px 结束位置310px 总距离300px //方案一: 固定步长的匀速运行 let step = 2; let timer = null; timer = setInterval(() => { //1. 首先获取现在元素的样式 let obj = window.getComputedStyle(box); let currentLeft = parseFloat(obj.left); let currentTop = parseFloat(obj.top); //2. 在此基础上累加步长 currentLeft += step; currentTop += step; //4. 边界处理 if (currentLeft >= 310) { currentLeft = 310; } if (currentTop >= 210) { currentTop = 210; } if (currentLeft >= 310 && currentTop >= 210) { //所有方向都到达边界时 box.style.left = `310px`; box.style.top = `210px`; clearInterval(timer); timer = null; return; } //3. 再把最新的样式赋值给元素 box.style.left = currentLeft + `px`; box.style.top = currentTop + `px`; }, 16); //一般设置的时间就是16毫秒走一次,为了贴进于60HZ刷新率。 }; run2(); </script>
-
-
requestAnimationFrame()-
基于它实现动画,只能固定步长,不能固定时间<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>动画</title> <style> .box { position: absolute; top: 10px; left: 10px; box-sizing: border-box; width: 100px; height: 100px; background: lightcoral; } </style> </head> <body> <div class="box" id="box"></div> <script> // requestAnimationFrame:基于它实现动画,只能固定步长,不能固定时间 let box = document.querySelector('#box'), targetLeft = 310, stepLeft = 2; const move = function move() { // 获取当前最新的位置 let curLeft = parseFloat(getComputedStyle(box).left); // 累加步长 curLeft += stepLeft; // 边界判断 if (curLeft >= targetLeft) { box.style.left = targetLeft + 'px'; return; } // 运动到这个位置 box.style.left = curLeft + 'px'; // 轮询控制move的执行 requestAnimationFrame(move); }; move(); </script> </body> </html>
-
-
-
方案二:
固定时间的匀速运动-
真实项目中的动画,一般都是固定时间的动画<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>动画</title> <style> .box { position: absolute; top: 10px; left: 10px; box-sizing: border-box; width: 100px; height: 100px; background: lightcoral; } </style> </head> <body> <div class="box" id="box"></div> <script> /* 真实项目中的动画,一般都是固定时间的运动 */ // 计算元素当前位置的匀速运动公式 // t:time已经运动的时间 b:begin元素的起始位置 c:change运动的总距离 d:duration总时间 const Linear = (t, b, c, d) => { // t/d:已经运动的时间除以总时间 -> 已经运动的比例 // 已经运动的比例*总距离 -> 已经运动的距离 // 已经运动的距离+起始位置 -> 元素当前的位置 return t / d * c + b; }; let box = document.querySelector('#box'), objStyle = getComputedStyle(box), beginLeft = parseFloat(objStyle.left), beginTop = parseFloat(objStyle.top), changeLeft = 310 - beginLeft, changeTop = 210 - beginTop, duration = 2000, time = 0, timer = null; const move = function move() { // 运动的时间累计 time += 16; // 边界处理:已经运动的时间超过总时间 if (time >= duration) { box.style.left = '310px'; box.style.top = '210px'; clearInterval(timer); timer = null; return; } // 基于Liner公式获取到当前元素各方向的位置 let curLeft = Linear(time, beginLeft, changeLeft, duration), curTop = Linear(time, beginTop, changeTop, duration); // 按照计算的结果运动 box.style.left = curLeft + 'px'; box.style.top = curTop + 'px'; }; move(); timer = setInterval(move, 16); </script> </body> </html>
-
-
方案三:
jQuery动画
-
少用或者没人用了,但它的api好用。- 有蛮多
第三方库都参考了它的设计 代码少,简洁
- 有蛮多
-
jQuery中的动画都是基于JS/定时器实现的匀速运动动画- 不如
CSS3动画性能好
- 不如
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>动画</title>
<style>
.box {
position: absolute;
top: 10px;
left: 10px;
box-sizing: border-box;
width: 100px;
height: 100px;
background: lightcoral;
}
</style>
</head>
<body>
<div class="box" id="box"></div>
<!-- IMPORT JS -->
<script src="js/jquery.min.js"></script>
<script>
let $box = $('#box');
$box.animate({
left: 310,
top: 210,
width: 300
}, 2000, () => {
console.log('动画运动完毕后触发');
});
/* let $box = $('#box');
// JQ中的动画都是基于“JS/定时器”实现的匀速运动动画「都不如CSS3动画性能好」
$box.click(function () {
// 快捷动画:需要我们设定运动的时间「或者是'fast/slow'」
// + hide/show/toggle
// + fadeOut/fadeIn/fadeToggle
// + slideUp/slideDown/slideToggle
$box.slideUp(2000);
}); */
/* // 固定时间的匀速运动:就是把我们刚才写的那套代码做了封装
// + finish:结束正在运行的动画{让元素立即处于上一个动画最后一帧的位置}
// + stop:也是结束正在运行的动画,只不过在哪停止的,元素就在哪个位置
$box.finish().animate({
left: 310,
top: 210,
width: 300
}, 2000, () => {
console.log('动画运动完毕后触发');
}); */
</script>
</body>
</html>
轮播图
-
swiper
-
引入
css文件及js文件 -
建立
HTML骨架,使用swiper的类名来做 -
在
js中new Swiper()建立一个swiper实例,并配置好。- 最好用
一个变量来保存这个实例,以便后面进行操作
- 最好用
-
在
浏览器控制台查看swiper实例的html骨架,复制想要改的样式类名,在本地的css中改对应样式类名的样式。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>基于Swiper实现轮播图</title> <!-- IMPORT CSS --> <link rel="stylesheet" href="css/reset.min.css"> <link rel="stylesheet" href="css/swiper-bundle.min.css"> <style> .swiper, .swiper-slide, .swiper-slide img { width: 800px; height: 300px; } .swiper-pagination-bullet { width: 12px; height: 12px; } .swiper-pagination-bullet-active { width: 30px; border-radius: 6px; } </style> </head> <body> <div class="swiper" id="AAA"> <div class="swiper-wrapper"> <div class="swiper-slide"> <img src="images/1.jpg" alt=""> </div> <div class="swiper-slide"> <img src="images/2.webp" alt=""> </div> <div class="swiper-slide"> <img src="images/3.webp" alt=""> </div> <div class="swiper-slide"> <img src="images/4.webp" alt=""> </div> </div> <div class="swiper-pagination"></div> <div class="swiper-button-prev"></div> <div class="swiper-button-next"></div> </div> <!-- IMPORT JS --> <script src="js/swiper-bundle.min.js"></script> <script> let sw = new Swiper('#AAA', { /* 基于这些配置,告诉Swiper插件我想要的效果 https://www.swiper.com.cn/api/index.html */ // 开启无限循环切换「实现了无缝衔接」 loop: true, // 开启自动切换 autoplay: { delay: 3000, disableOnInteraction: false }, // 控制切换效果 // "slide"(普通位移切换)、"fade"(淡入)、"cube"(方块)、"coverflow"(3d流)、"flip"(3d翻转)、"cards"(卡片式) effect: 'slide', // 开启分页器 pagination: { el: '.swiper-pagination', clickable: true }, // 开启导航按钮 navigation: { nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev' }, // 事件监听 on: { slideChangeTransitionEnd(sw) { console.log(`当前切换到索引为 ${sw.activeIndex}/${sw.realIndex} 的这一张!`); } } }); /* setTimeout(() => { sw.slideNext(0); }, 1000); */ </script> </body> </html> -
进阶参考
- 牛X轰轰的帧动画库:animate.css - 帧动画库- css动画库,用类名控制动画效果
- 查询JavaScript函数的兼容性
- swiper - 轮播图
- animejs.com - JavaScript实际上真正常用的动画库
- animejs官方文档-英文的 - JavaScript实际上真正常用的动画库
- dynamicsjs.com - 物理效果的动画 - 引入方法,并对DOM元素设置JavaScript动画效果,用法类似于jQuery动画
- parallax.js - 偏向于视差的JavaScript动画效果
- CreateJS - 游戏引擎 - 用来做h5小游戏的-自然也可以做JavaScript动画效果