- 说明:该文属于 大前端全栈架构白宝书专栏,目前阶段免费,如需要项目实战或者是体系化资源,文末名片加V!
- 作者:不渴望力量的哈士奇(哈哥),十余年工作经验, 从事过全栈研发、产品经理等工作,目前在公司担任研发部门CTO。
- 荣誉:2022年度博客之星Top4、2023年度超级个体得主、谷歌与亚马逊开发者大会特约speaker、全栈领域优质创作者。
- 白宝书系列
- 启示录 - 攻城狮的自我修养
- Python全栈白宝书
- ChatGPT实践指南白宝书
- 产品思维训练白宝书
- 全域运营实战白宝书
- 大前端全栈架构白宝书
我们已经知道CSS3的transition过渡属性可以实现动画,而JavaScript可以利用这一属性轻松的实现元素的动画,并且JSS和CSS3结合可以规避利用定时器实现动画的缺点。
示例代码:
DOCTYPE html>
<html lang="en">
<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>Documenttitle>
<style>
#box {
width: 100px;
height: 100px;
background-color: orange;
position: absolute;
top: 100px;
left: 100px;
}
style>
head>
<body>
<button id="btn">开始运动button>
<div id="box">div>
<script>
var oBtn = document.getElementById('btn');
var oBox = document.getElementById('box');
var pos = 1; //1左边,2右边
oBtn.onclick = function () {
//加上过渡属性,即可实现缓动效果
oBox.style.transition = 'all 2s linear 0s';
if (pos == 1) {
//如果盒子在左边,让它的移动到右边
oBox.style.left = 500 + 'px';
pos = 2;
}else {
//如果盒子在右边,让它移动到左边
oBox.style.left = 100 + 'px';
pos = 1;
};
};
script>
body>
html>
上述案例可以看到,每次点击“开始运动”按钮,不管盒子有没有移动到重点,盒子的运动方向都会改变。在很多情况下,我们需要控制当某个“动作”结束后,才能进行下一次的点击。这就需要用到函数节流
**函数节流:**一个函数执行一次后,只有大于设定的执行周期才允许执行第二次。
函数节流需要借助延时器:setTimeout()
函数节流的公式:
var lock = true;
function 需要节流的函数() {
//如果锁是关闭状态,则不执行
if (!lock) return;
//函数核心语句
//关锁
lock = false;
//指定毫秒数后将锁打开
setTimeout(function () {
lock = true;
}, 2000);
}
利用函数节流优化一下上面案例中的代码:
<body>
<button id="btn">开始运动button>
<div id="box">div>
<script>
var oBtn = document.getElementById('btn');
var oBox = document.getElementById('box');
var pos = 1; //1左边,2右边
var lock = true; //函数节流锁
oBtn.onclick = function () {
//判断如果锁是关闭的,则直接return,不执行下面的程序
if (!lock) return;
oBox.style.transition = 'all 2s linear 0s';
if (pos == 1) {
//如果盒子在左边,让它的移动到右边
oBox.style.left = 500 + 'px';
pos = 2;
}else {
//如果盒子在右边,让它移动到左边
oBox.style.left = 100 + 'px';
pos = 1;
};
//关锁
lock = false;
//2s后将锁打开,因为过渡的时间是2s,所以2s后盒子会到到达终点
setTimeout(function name(params) {
lock = true;
}, 2000);
};
script>
使用函数节流优化了代码之后,在盒子还没有运动到终点时,再次点击按钮不会改变盒子的运动方向,只有盒子运动到终点,再次点击盒子才能返回。
比如下面这个网站上就有一个“无缝连续滚动特效”,“最新播报”栏目中的新闻点连续不断的持续从右向左循环滚动。下面就来动手实现一个这样的案例。
案例: 实现下面的无缝连续滚动特效,
题目分析:
滚动其实就是元素在盒子内向左移动,盒子设置overflow:hidden使盒子外侧的部分隐藏。要达到无缝连续滚动的效果,不可能设置无限多的元素,这里用到一个视觉欺骗的小技巧,用js复制一组元素,当第一组元素完全移出盒子时,把第一组的元素的位置再调整回来继续向左移动,这样就实现了“连续滚动”的效果。用定时器就可以实现。
DOCTYPE html>
<html lang="en">
<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>Documenttitle>
<style>
* {
margin: 0;
padding: 0;
}
.box {
width: 1000px;
height: 200px;
border: 1px solid #000;
margin: 50px auto;
overflow: hidden;
}
.box ul {
width: 3000px;
list-style: none;
position: relative;
}
.box ul li {
float: left;
margin-right: 10px;
}
style>
head>
<body>
<div id="box" class="box">
<ul id="list">
<li><img src="/images/husky1_little.png" alt="">li>
<li><img src="/images/husky2_little.jpg" alt="">li>
<li><img src="/images/husky3_little.jpg" alt="">li>
<li><img src="/images/husky4_little.jpg" alt="">li>
ul>
div>
<script>
var oBox = document.getElementById('box');
var oList = document.getElementById('list');
oList.innerHTML += oList.innerHTML; //复制一份图片插入ul里面
//定义全局变量
var left = 0;
var timer;
move(); //一开始先进行滚动
//将滚动封装成函数,方便调用
function move() {
//设表先关(设置一个定时器,先关掉它)
clearInterval(timer);
//设置定时器
timer = setInterval(function () {
left -= 2;
//当到达最左侧时,返回到原点继续移动,制造滚动的视觉效果
if (left <= -857) {
left = 0;
};
oList.style.left = left + 'px';
}, 20);
};
//鼠标移动到上面,停止滚动
oBox.onmouseover = function () {
clearInterval(timer);
};
//鼠标移开,继续滚动
oBox.onmouseleave = function () {
move();
};
script>
body>
html>
记住一个口诀:设表先关,即设置定时器前,先调用clearInterval()
方法关闭定时器,防止用户频繁的触发定时器 ,导致定时器出现叠加现象。
实现下面效果的轮播图,点击左右两边的按钮,实现图片左右滚动循环切换
题目分析:
给左右两个按钮添加事件监听,类似上篇中的无缝连续滚动特效,点击按钮时更改ul的left属性,实现图片向左/向右移动。
难点:
示例代码:
DOCTYPE html>
<html lang="en">
<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>Documenttitle>
<style>
* {
margin: 0;
padding: 0;
}
.carousel {
width: 1202px;
height: 800px;
border: 1px solid #000;
margin: 100px auto;
position: relative;
overflow: hidden;
}
.carousel ul {
position: absolute;
left: 0;
width: 8000px;
}
.carousel ul li {
float: left;
}
.carousel a {
width: 100px;
height: 100px;
background-color: orange;
border-radius: 50%;
position: absolute;
top: 50%;
margin-top: -50px;
}
.carousel #leftbtn {
left: 50px;
}
.carousel #rightbtn {
right: 50px;
}
style>
head>
<body>
<div class="carousel">
<ul id="list">
<li><img src="/images/spring.jpg" alt="">li>
<li><img src="/images/summer.jpg" alt="">li>
<li><img src="/images/autumn.jpg" alt="">li>
<li><img src="/images/winter.jpg" alt="">li>
ul>
<a href="javascript:;" id="leftbtn">a>
<a href="javascript:;" id="rightbtn">a>
div>
<script>
//得到ul 左右按钮
var leftbtn = document.getElementById('leftbtn');
var rightbtn = document.getElementById('rightbtn');
var oList = document.getElementById('list');
//克隆第一个li放到ul的最后
var cloneli = oList.firstElementChild.cloneNode(true);
oList.appendChild(cloneli);
//设置全局变量
var idx = 0; //代表第几张图片
var lock = true; //函数节流锁
//右边按钮事件监听
rightbtn.onclick = function () {
if (!lock) return;
lock = false;
idx++;
oList.style.left = idx * -1200 + 'px';
oList.style.transition = 'left .5s ease 0s';
setTimeout(function () {
if (idx >= 4) {
oList.style.left = 0 + 'px';
idx = 0;
oList.style.transition = 'none';
}
}, 500);
setTimeout(function () {
lock = true;
}, 500);
};
//左边按钮事件监听
leftbtn.onclick = function () {
if (!lock) return;
lock = false;
if (idx <= 0) {
//让图片瞬间移动到最后一张克隆的图片上
idx = 4;
oList.style.left = idx * -1200 + 'px';
oList.style.transition = 'none';
}
//小技巧:设置一个延时时间为0的延时器,虽然延时时间是0s,但可以让当过渡先瞬间取消,然后再加上
setTimeout(function name(params) {
idx--;
oList.style.left = idx * -1200 + 'px';
oList.style.transition = 'left .5s ease 0s'
}, 0);
setTimeout(function () {
lock = true;
}, 500);
}
script>
body>
html>
实现下面效果的轮播图,点击左右两边的按钮,实现图片淡出、淡入切换:
**题目分析:**重点是点击按钮时,老图淡出、新图淡入,更改opacity属性就可以实现。
示例代码:
DOCTYPE html>
<html lang="en">
<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>Documenttitle>
<style>
* {
margin: 0;
padding: 0;
}
.carousel {
width: 1202px;
height: 800px;
border: 1px solid #000;
margin: 100px auto;
position: relative;
}
.carousel ul {
list-style: none;
}
.carousel ul li {
/*图片透明度是0*/
opacity: 0;
position: absolute;
top: 0;
left: 0;
transition: opacity 1s ease 0s;
}
.carousel ul li:first-child {
/*第一张图片的透明度是1*/
opacity: 1;
}
.carousel a {
width: 100px;
height: 100px;
background-color: orange;
border-radius: 50%;
position: absolute;
top: 50%;
margin-top: -50px;
}
.carousel #leftbtn {
left: 50px;
}
.carousel #rightbtn {
right: 50px;
}
style>
head>
<body>
<div class="carousel">
<ul id="list">
<li><img src="/images/spring.jpg" alt="">li>
<li><img src="/images/summer.jpg" alt="">li>
<li><img src="/images/autumn.jpg" alt="">li>
<li><img src="/images/winter.jpg" alt="">li>
ul>
<a href="javascript:;" id="leftbtn">a>
<a href="javascript:;" id="rightbtn">a>
div>
<script>
var leftbtn = document.getElementById('leftbtn');
var rightbtn = document.getElementById('rightbtn');
var oList = document.getElementById('list');
var lis = oList.getElementsByTagName('li');
var idx = 0; //代表第几张图片
var lock = true; //函数节流锁
//右边按钮事件监听
rightbtn.onclick = function () {
if (!lock) return;
lock = false;
//老图淡出
lis[idx].style.opacity = 0;
idx++;
if (idx > 3) idx = 0; //如果是最后一张图片了,则第一张图片是新图
//新图淡入
lis[idx].style.opacity = 1;
setTimeout(function () {
lock = true;
}, 1000);
};
//左边按钮事件监听
leftbtn.onclick = function () {
if (!lock) return;
lock = false;
//老图淡出
lis[idx].style.opacity = 0;
idx--;
if (idx < 0) idx = 3; //如果是第一张图片,则最后最后一张是新图
//新图淡入
lis[idx].style.opacity = 1;
setTimeout(function () {
lock = true;
}, 1000);
};
script>
body>
html>