▊ 元素偏移量offset
使用offset可动态的得到元素的位置(偏移)、大小等
注:偏移是指相对于带有定位的父元素;大小是指自身整个盒子的宽高;返回值都不带单位
box.offsetTop // 上偏移位置
box.offsetLeft // 左偏移位置
box.offsetWidth // 宽
box.offsetHeight // 高
box.offsetParent // 返回带有定位的父亲
offsetWidth
和style.width
的区别(height同理)
▊ 元素可视区client
使用client可动态的得到元素的边框大小、元素大小
box.clientTop // 上边框的大小(很不常用)
box.clientLeft // 左边框的大小
box.clientWidth // 返回宽度(包括padding和自身width,不包括边框border)
box.clientHeight // 返回宽度(包括padding和自身heigth,不包括边框border)
▊ 元素滚动scroll
使用scroll可以动态的得到元素的大小、滚动距离
box.scrollTop // 被卷去的上方距离
box.scrollLeft // 被卷去的左侧距离
box.scrollWidth // 返回宽度(包括padding,不包括border)
box.scrollHeight // 返回高度(包括padding,不包括border)
// 与clientWidth和clientHeigth的区别是,返回的内容实际的宽高,包括超出的部分
// 注意区分———页面被卷去的头部是pageYOffset;盒子中被卷去的头部是scrollTop(同理宽度)
▊ 三个系列的总结
在获取元素大小方面:offset
获取的是包含border的;client
和scroll
不包含border的;都包含padding;scroll
还包含超出的内容
主要用法:offsetTop、offsetLeft
用来获取位置偏移;offsetWidth、offsetHeight(clientWidth、clientHeight)
用来获取元素大小;scrollTop、scrollLeft
用来获取滚动距离;页面滚动距离用window.pageXOffset、window.pageYOffset
;其他的几乎不用
上面的主要用法是重点 ! ! !
▊ 补充内容——立即执行函数
// 不需要调用,立即执行
// 写法:
(function() {})() // 其实这样最容易理解(其实就是声明后立即传入了参数>_<)
(function() {}()) // 当然这样也可以
(function(a, b) {
console.log(a + b);
})(2, 3); // 输出5
(function(a, b) {
console.log(a + b);
}(2, 3)); // 输出5
// ☀ 主要作用:每个立即执行函数都创建了一个独立的作用域,这避免了命名冲突的问题
▊ 补充内容——mouseover和mouseenter的区别
mouseover
经过自身盒子会触发,经过子盒子也会触发;mouseenter
只有经过自身盒子会触发
mouseover经过自身盒子的触发,实际上子盒子冒泡的结果;
也就是说,mouseover冒泡,mouseenter不冒泡(mouseleave也不冒泡)
▊ 动画函数封装
动画实现的核心原理是:通过定时器 setInterval() 不断移动盒子的位置
// 简单动画函数的封装:参数有 目标对象obj,目标位置target
function anime(obj, target) {
clearInterval(obj.timer); // 清除以前的定时器,防止元素有多个定时器(timer越来越多,元素无限加速...)
obj.timer = setInterval(function() { // 给不同的对象指向了不同的定时器(节约了资源,避免了命名歧义)
if (obj.offsetLeft >= target) {
clearInterval(obj.timer);
} else {
obj.style.left = obj.offsetLeft + 1 + 'px';
}
}, 30);
}
// 优化:渐慢(通过修改步长实现) + 可返回(通过步长的负值实现反向)
function anime(obj, target) {
clearInterval(obj.timer);
obj.timer = setInterval(function() {
var step = (target - obj.offsetLeft) / 10; // 通过设置可变步长,巧妙实现了渐慢的效果
step = step > 0 ? Math.ceil(step) : Math.floor(step); // 避免了取到0后无法到达指定位置的bug(重难点)
if (obj.offsetLeft == target) {
clearInterval(obj.timer);
} else {
obj.style.left = obj.offsetLeft + step + 'px';
}
}, 30);
}
// 再添加功能:添加回调函数
// 其实很简单,这样声明动画函数,然后传入一个函数实参(匿名函数or函数名)就行了:
function anime(obj, target, callback){
if(callback){ // 别忘啦,JS允许传入任意数量的实参,也就是说它自带重载(我们可以使用回调函数)
callback(); // 通常这句话写在clearInteval(timer)的后面———在动画结束时调用这个效果
}
// 一种更优雅的写法
callback && callback();
}
上面封装的那个动画函数虽说没有css丝滑,但绝对比你想象中的经典且强大
在后面的PC端网页特效案例会经常用到且效果极佳
----------------------------------------------------------分割线----------------------------------------------------------------
▊ PC端网页特效案例
var box = document.querySelector('.box');
box.addEventListener('click', function(e) {
// 巧妙使用了一个减法(本身不难,但需要想到 ! ! !)
var dx = e.pageX - this.offsetLeft;
var dy = e.pageY - this.offsetTop;
})
// 核心思路:分为三步:鼠标按下--鼠标移动--鼠标弹起
// 除了鼠标按下绑定在box上,其他两个事件都绑定在document上 !
var box = document.querySelector('.box');
box.addEventListener('mousedown', function(e) {
var dx = e.pageX - box.offsetLeft; // 鼠标按下,获得鼠标相对于盒子的位置(这个位置在拖动时是不变量)
var dy = e.pageY - box.offsetTop;
// 鼠标移动和鼠标弹起的事件,一定要位于鼠标按下内!!!
document.addEventListener('mousemove', move); // 鼠标移动,通过计算(鼠标咋页面的位置-鼠标相对盒子的位置)给盒子的left和top赋值
document.addEventListener('mouseup', function() { // 鼠标弹起,移除鼠标移动事件
document.removeEventListener('mousemove', move);
})
function move(e) { // 鼠标移动时,对盒子位置的计算
box.style.left = e.pageX - dx + 'px';
box.style.top = e.pageY - dy + 'px';
}
})
❸ 淘宝侧边栏案例
// 需求是:本来侧边栏是随主体而滚动的,到了某处时固定
// 关键点是获得页面上方被卷曲的值,当该值达到某个数值是,将绝对定位(absolute)改为固定定位(fixed)
// 再复习一下什么是绝对定位:不是说一直固定在页面某处(那是固定定位),也会随着页面滚动而滚动,不要曲解“绝对”二字
var bar = document.querySelector('.bar');
document.addEventListener('scroll', function() { // 滚动事件时document的滚动,事件源是document
if (window.pageYOffset >= 300) { // 页面被卷去的头部是pageYOffset;盒子中被卷去的头部是scrollTop;注意区分
bar.style.position = 'fixed';
} else {
bar.style.position = 'absolute';
}
})
// 其实还有点小bug,改为固定定位的同时还要给固定定位设置fixed,这可以利用offsetTop经过简单的计算实现
// html和css很简单,ul>li*6并且有一个绝对定位的.cloud;它们属于.box大盒子
// 核心思路:
// .box相对定位后,使用offsetLeft作为cloud移动的目标位置
// 上面封装的anime位移动画函数派上了大用场
window.addEventListener('load', function() {
var box = document.querySelector('.box');
var cloud = document.querySelector('.cloud');
var lists = document.querySelectorAll('li');
var current = 0; // current作为起始位置
for (var i = 0; i < lists.length; i++) {
lists[i].addEventListener('mouseenter', function() {
anime(cloud, this.offsetLeft); // 鼠标经过就移动cloud
})
lists[i].addEventListener('mouseleave', function() {
anime(cloud, current); // 鼠标离开,cloud回到起始位置
})
lists[i].addEventListener('click', function() {
current = this.offsetLeft; // 鼠标点击,cloud起始位置更新为此处
})
}
})
☀ Loli & JS
♫ Suki