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>
<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元素对象
设置动画
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>
引入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的动画
是基于定时器处理
定时器
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元素的样式
元素.style.xxx = xxx
把样式
设置在元素的行内
上
这样设置
的样式
,优先级
高元素.className='xxx'
元素.classList.add('xxx')
/元素.classList.remove('xxx')
样式表
中先把样式写好
,最后在JavaScript
中,基于操作样式类名
,来管理DOM元素的样式
DOM元素的样式
元素.style.xxx
只能获取写在元素行内上的样式
不常用
,因为一般很少把样式写在行内上
window.getComputedStyle(元素,伪类)
获取元素
(或者其伪元素
{::after
/::before
})所有经过浏览器计算过的样式
DOM元素
被浏览器渲染
了,那么其所有的样式
都是经过计算
的,不管我们以何种方式编写的样式
,即不管是用JavaScript写的
还是css样式表的
不写样式
,浏览器
也会为被渲染的DOM元素
设置默认样式
方案一: 固定步长
的匀速运动
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>
方案三:
少用
或者没人用
了,但它的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>
<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>
<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>
<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>