JavaScript 内容总结(JavaScript高级程序设计)
1.元素偏移量offset系列
-
动态的得到该元素的位置(偏移量)、大小等
- 获得元素距离带有定位父元素的位置
- 获得元素自身得大小(宽度高度)
- 返回数值不带单位
-
offset常见属性
<!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>Document</title> <style> * { margin: 0; padding: 0; } .father { position: relative; width: 200px; height: 200px; background-color: rgb(175, 81, 175); margin: 100px; } .son { width: 100px; height: 100px; background-color: rgb(187, 105, 105); margin: 25px; /* 存在父元素塌陷问题 */ } .sson { width: 50px; height: 50px; background-color: rgb(145, 187, 105); margin: 25px; padding: 5px; /* box-sizing: border-box; 不会撑大盒子*/ } </style> </head> <body> <div class="father"> <div class="son"> <div class="sson"></div> </div> </div> <script> var father = document.querySelector('.father'); var son = document.querySelector('.son'); var sson = document.querySelector('.sson'); console.log(father.offsetTop);//100 console.log(father.offsetLeft);//100 //它以带有定位的父亲为准 如果没有父亲则以body为主,或者父亲没有定位则一直想上找到有定位的父元素,以它为准 console.log(son.offsetTop);//0 console.log(son.offsetLeft);//25 console.log(sson.offsetTop);//0 console.log(sson.offsetLeft);//50 console.log(sson.offsetWidth);//60 </script> </body> </html>
offset和style区别:
-
案例:模态框拖拽
<!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>Document</title> <style> .father { position: absolute; width: 300px; height: 200px; left: 500px; top: 200px; background-color: rgb(255, 228, 196); display: none; } .close { position: absolute; top: -10px; right: -10px; background-color: rgb(255, 228, 196); width: 20px; height: 20px; font-size: 9px; border-radius: 10px; border: 1px solid silver; line-height: 20px; text-align: center; cursor: pointer; } </style> </head> <body> <button>点击</button> <div class="father"> <div class="close">关闭</div> </div> <script> var button = document.querySelector('button'); var father = document.querySelector('.father'); var close = document.querySelector('.close'); button.addEventListener('click', () => { document.body.style.backgroundColor = 'silver' father.style.display = 'block'; }); close.addEventListener('click', () => { father.style.display = 'none'; document.body.style.backgroundColor = '#fff' }); father.addEventListener('mousedown', (e) => { var x = e.pageX - father.offsetLeft; var y = e.pageY - father.offsetTop; function zz(e) { father.style.left = (e.pageX - x) + 'px'; father.style.top = (e.pageY - y) + 'px'; } document.body.addEventListener('mousemove', zz); document.body.addEventListener('mouseup', () => { document.body.removeEventListener('mousemove', zz); }); }); </script> </body> </html>
2.元素可视区client系列
- 获取元素可视区的相关信息,通过client系列的相关属性可以动态的得到该元素的边框大小、元素大小等
-
立即执行函数:不需要调用,立马能够自己执行的函数
好处:独立作用域,避免命名冲突,执行后销毁,常用于解决闭包
3.元素滚动scroll系列
- 可以动态的得到该元素的大小、滚动距离等
-
仿淘宝侧边栏案例:window.pageYOffset:动态获取页面滚动距离
<!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>Document</title> <style> * { padding: 0; margin: 0; } .header { width: 80%; height: 400px; background-color: red; } .center { width: 80%; height: 800px; background-color: purple; } .righttab { position: absolute; right: 220px; top: 481px; width: 50px; height: 200px; background-color: rgb(207, 111, 207); } .footer { width: 80%; height: 800px; background-color: green; } </style> </head> <body> <div class="header"></div> <div class="center"></div> <div class="righttab"></div> <div class="footer"></div> <script> var header = document.querySelector('.header'); var righttab = document.querySelector('.righttab'); var righttab_top = righttab.offsetTop; document.addEventListener('scroll', () => { //console.log(window.pageYOffset); if (window.pageYOffset > header.clientHeight) { righttab.style.position = 'fixed'; righttab.style.top = (righttab_top - header.clientHeight) + 'px'; } else { righttab.style.position = 'absolute'; righttab.style.top = righttab_top + 'px'; } }); </script> </body> </html>
4.动画函数封装
-
动画实现原理
核心原理:通过定时器setInterval()不断移动盒子位置
实现步骤:
- 获得盒子当前位置
- 让盒子在当前位置加上1个移动距离
- 利用定时器不断重复这个操作
- 加一个结束定时器的条件
- 此元素加定位
<!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>Document</title> <style> .box { position: absolute; width: 100px; height: 100px; background-color: red; } </style> </head> <body> <div class="box"></div> <script> var box = document.querySelector('.box'); var time = setInterval(() => { if (box.offsetLeft + 1 == 500) { clearInterval(time); } box.style.left = (box.offsetLeft + 1) + 'px'; }, 15); </script> </body> </html>
-
简单动画函数封装
参数:动画对象,最大移动距离,步长
<script> var box = document.querySelector('.box'); var box1 = document.querySelector('.box1'); function move(obj, mixlenght, step) { var time = setInterval(() => { if (obj.offsetLeft +step == mixlenght) { clearInterval(time); } obj.style.left = (obj.offsetLeft + step) + 'px'; }, 15); } move(box, 300, 2); move(box1, 400, 1); </script>
-
动画函数给不同元素记录不同定时器
<script> var box = document.querySelector('.box'); var box1 = document.querySelector('.box1'); function move(obj, mixlenght, step) { obj.time = setInterval(() => { clearInterval(obj.time); if (obj.offsetLeft + step == mixlenght) { clearInterval(obj.time); } obj.style.left = (obj.offsetLeft + step) + 'px'; }, 15); } move(box, 300, 2); move(box1, 400, 1); </script>
-
缓动动画:让元素运动速度有所变化,最常见的是让速度慢慢停下来
- 让盒子每次移动的距离慢慢变小,速度就会慢慢落下来
- 核心算法:(目标值-现在的位置)/10 作为每次移动的距离步长
- 停止的条件:让当前的盒子位置等于目标位置就停止定时器
- 注意步长值取整
<script> var box = document.querySelector('.box'); var box1 = document.querySelector('.box1'); function move(obj, mixlenght) { obj.timer = setInterval(() => { var step = Math.ceil((mixlenght - obj.offsetLeft) / 10);//核心算法 if (obj.offsetLeft == mixlenght) { clearInterval(obj.timer); } obj.style.left = (obj.offsetLeft + step) + 'px'; }, 15); } move(box, 300); move(box1, 400); </script>
-
缓动动画:多个值之间缓动
<script> var box = document.querySelector('.box'); var box1 = document.querySelector('.box1'); function move(obj, mixlenght, callback) { obj.timer = setInterval(() => { var step = (mixlenght - obj.offsetLeft) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step);//多个值之间缓动 if (obj.offsetLeft == mixlenght) { clearInterval(obj.timer); callback(); } obj.style.left = (obj.offsetLeft + step) + 'px'; }, 15); } move(box, 300, () => { console.log(11); }); move(box1, 400, () => { console.log(11); }); </script>
-
缓动动画加回调函数
原理:函数可以作为一个参数,将这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数,这个过程就叫做回调
<script> var box = document.querySelector('.box'); var box1 = document.querySelector('.box1'); function move(obj, mixlenght, callback) { obj.timer = setInterval(() => { var step = (mixlenght - obj.offsetLeft) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); if (obj.offsetLeft == mixlenght) { clearInterval(obj.timer); callback();//回调函数 } obj.style.left = (obj.offsetLeft + step) + 'px'; }, 15); } move(box, 300, () => { console.log(11); }); move(box1, 400, () => { console.log(11); }); </script>
-
动画函数封装到单独JS文件里面
- 单独新建一个JS文件
- 引入
animate.js
//缓动动画 function move(obj, mixlenght, callback) { obj.timer = setInterval(() => { var step = (mixlenght - obj.offsetLeft) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); if (obj.offsetLeft == mixlenght) { clearInterval(obj.timer); // if (callback) { callback(); } callback && callback(); } obj.style.left = (obj.offsetLeft + step) + 'px'; }, 15); }
5.常见的网页特效
轮播图案例:
html
<div class="focus">
<a href="javascript:;" class="left_btn"><</a>
<ul>
<li>
<img src="upload/focus1.jpg" alt="">
</li>
<li>
<img src="upload/focus2.jpg" alt="">
</li>
<li>
<img src="upload/focus3.jpg" alt="">
</li>
<li>
<img src="upload/focus4.jpg" alt="">
</li>
</ul>
<a href="javascript:;" class="right_btn">></a>
<div class="circle">
<ol>
<!-- <li class="check"></li> -->
</ol>
</div>
</div>
css
.main .focus{
position: relative;
width: 721px;
height: 455px;
float: left;
overflow: hidden;
}
.main .focus .left_btn,
.main .focus .right_btn{
position: absolute;
top: 50%;
margin-top: -20px;
width: 24px;
height: 40px;
background: rgba(0, 0, 0, .3);
text-align: center;
line-height: 40px;
font-size: 18px;
color: white;
}
.main .focus .right_btn{
right: 0;
border-radius: 50% 0 0 50%;
display: none;
z-index: 1;
}
.main .focus .left_btn{
border-radius: 0 50% 50% 0 ;
display: none;
z-index: 1;
}
.main .focus ul{
position: absolute;
width: 500%;
}
.main .focus ul li{
float: left;
}
.main .focus .circle {
position: absolute;
bottom: 2px;
left: 325px;
}
.main .focus .circle li {
float: left;
width: 10px;
height: 10px;
border: 2px solid rgba(255, 255, 255, 0.5);
margin: 0 3px;
border-radius: 50%;
cursor: pointer;
}
.main .focus .circle .check{
background-color: #fff;
}
js
// 轮播图
var focus = document.querySelector('.focus');
var right_btn = document.querySelector('.right_btn');
var left_btn = document.querySelector('.left_btn');
//解决左右按钮显隐问题
focus.addEventListener('mouseenter', function () {
right_btn.style.display = 'block';
left_btn.style.display = 'block';
//清除定时器
clearInterval(timer);
})
focus.addEventListener('mouseleave', function () {
right_btn.style.display = 'none';
left_btn.style.display = 'none';
//开启定时器
timer = setInterval(() => {
right_btn.click();//手动调用点击事件
}, 2000);
})
var circle = document.querySelector('.circle')
var focus_ol = circle.querySelector('ol')
var focus_ul = focus.querySelector('ul')
//根据图片生成小圆圈
for (let i = 0; i < focus_ul.children.length; i++) {
var img_width = focus_ul.children[i].clientWidth;
let li = document.createElement('li');
focus_ol.appendChild(li);
focus_ol.children[i].setAttribute('data_index', i);
}
//克隆图片 便于无缝连接
var img_first = focus_ul.children[0].cloneNode(true);
focus_ul.appendChild(img_first);
//圆圈底色及图跟着圆圈走
for (let i = 0; i < focus_ol.children.length; i++) {
focus_ol.children[0].className = 'check';
focus_ol.children[i].addEventListener('click', () => {
//干掉其他人
for (let i = 0; i < focus_ol.children.length; i++) {
focus_ol.children[i].className = '';
}
//留下我自己
focus_ol.children[i].className = 'check';
//图跟着圆圈走
move(focus_ul, -(i * img_width));
var index = focus_ol.children[i].getAttribute('data_index');
//圈圈跟着左右按钮走
num = index;
})
}
//有变量提升不怕
//按钮控制图片
var num = 0;
var flag = true;//节流阀
right_btn.addEventListener('click', () => {
if (flag) {
flag = false;
if (num >= focus_ul.children.length - 1) {
num = 0;
focus_ul.style.left = '0px';
}
num++;
move(focus_ul, -(num * img_width), () => { flag = true });
paita();
}
})
left_btn.addEventListener('click', () => {
if (flag) {
flag = false;
if (num == 0) {
num = focus_ul.children.length - 1;
focus_ul.style.left = (-num * img_width) + 'px';
}
num--;
move(focus_ul, -num * img_width, () => { flag = true });
paita();
}
})
//提取公共函数
function paita() {
for (let i = 0; i < focus_ol.children.length; i++) {
focus_ol.children[i].className = '';
}
//留下我自己
if (num == focus_ul.children.length - 1) {
focus_ol.children[0].className = 'check';
}
else {
focus_ol.children[num].className = 'check';
}
}
//自动轮播
var timer = setInterval(() => {
right_btn.click();//手动调用点击事件
}, 2000);
-
节流阀:防止轮播图按钮连续点击造成的播放过快
目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续播放
核心思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数。
if(flag){flag=false;do something};关闭水龙头
利用回调函数 动画执行完毕,flag=true;打开水龙头