参考哔哩哔哩pink老师课程
1. 元素偏移量 offset 系列
1.1 offset 概述
offset
翻译过来就是偏移量,我们使用 offset
系列相关属性可以动态的得到该元素的位置(偏移)、大小等。
- 获得元素距离带有定位父元素的位置
- 获得元素自身的大小(宽度高度)
- 注意:返回的数值都不带单位
offset
系列常用属性:
offset系列属性 | 作用 |
---|---|
element.offsetParent | 返回作为该元素带有定位的父级元素 如果父级都没有定位则返回body |
element.offsetTop | 返回元素相对带有定位父元素上方的偏移,返回的数值不带单位 |
element.offsetLeft | 返回元素带有定位父元素左边框的偏移,返回的数值不带单位 |
element.offsetWidth | 返回自身包括 padding 、边框border 、内容区的宽度width ,返回数值不带单位 |
element.offsetHeight | 返回自身包括 padding 、边框border 、内容区的宽度width ,返回数值不带单位 |
offsetParent
和parentNode
的区别:
offsetParent
返回的是 带有定位的父亲,否则返回 body
parentNode
返回的是 最近一级的父亲(亲爸爸) 不管父亲有没有定位
1.2 offset 与 style 区别
1.2.1 offset
offset
可以得到任意样式表中的样式值offset
系列获得的数值是没有单位的数字型offsetWidth
包含padding+border+width
offsetWidth
等属性是只读属性,只能获取不能赋值- 所以,我们想要获取元素大小位置,用
offset
更合适
1.2.2 style
style
只能得到行内样式表中的样式值style.width
获得的是带有单位的字符串style.width
获得不包含padding
和border
的值style.width
是可读写属性,可以获取也可以赋值- 所以,我们想要给元素更改值,则需要用
style
改变
案例:获取鼠标在盒子内的坐标
案例分析:
- 我们在盒子内点击,想要得到鼠标距离盒子左右的距离
- 首先得到鼠标在页面中的坐标(
e.pageX
,e.pageY
)或者(e.offsetX
,e.offsetY
) - 其次得到盒子在页面中的距离(
box.offsetLeft
,box.offsetTop
) - 用鼠标距离页面的坐标减去盒子在页面中的距离, 得到 鼠标在盒子内的坐标
- 如果想要移动一下鼠标,就要获取最新的坐标,使用鼠标移动事件
mousemove
方法一:
<body>
<div class="box"></div>
<script>
var box = document.querySelector('.box');
box.addEventListener('mousemove', function(e) {
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
this.innerHTML = 'x坐标是' + x + ' y坐标是' + y;
})
</script>
</body>
方法二:
<script>
var box = document.querySelector('.box');
box.addEventListener('mousemove',function(e){
var x = e.offsetX;
var y = e.offsetY;
this.innerHTML = 'x坐标是' + x + ' y坐标是' + y;
})
</script>
案例:模态框拖拽
弹出框,我们也称为模态框
- 点击弹出层,会弹出模态框,并且显示灰色半透明的遮挡层
- 点击关闭按钮,可以关闭模态框,并且同时关闭灰色半透明遮挡层
- 鼠标放到模态框最上面一行,可以按住鼠标拖拽模态框在页面中移动
- 鼠标松开,可以停止拖动模态框移动
案例分析:
- 点击弹出层,模态框和遮挡层就会显示出来
display: block;
- 点击关闭按钮,模态框和遮挡层就会隐藏起来
display: none;
- 在页面中拖拽的原理:鼠标按下并且移动,之后松开鼠标
- 触发事件是鼠标按下
mousedown
,鼠标移动mousemove
,鼠标松开mouseup
- 拖拽过程:鼠标移动过程中,获得最新的值赋值给模态框的
left
和top
值,这样模态框可以跟着鼠标走了 - 鼠标按下触发的事件源是 最上面一行,就是
id
为title
- 鼠标的坐标减去鼠标在盒子内的坐标,才是模态框真正的位置。
- 鼠标按下,我们要得到鼠标在盒子的坐标。
- 鼠标移动,就让模态框的坐标设置为:鼠标坐标减去盒子坐标即可,注意移动事件写到按下事件里面。
- 鼠标松开,就停止拖拽,就是可以让鼠标移动事件解除
2. 元素可视区 client 系列
2.1 定义
client
翻译过来就是客户端,我们使用 client
系列的相关属性来获取元素可视区的相关信息。通过client
系列的相关属性可以动态的得到该元素的边框大小、元素大小等。
client系列属性 | 作用 |
---|---|
element.clientTop | 返回元素上边框的大小 |
element.clientLeft | 返回元素左边框大大小 |
element.clientWidth | 返回自身包括 padding 、内容区的宽度,不含边框,返回数值不带单位 |
element.clientHeight | 返回自身包括 padding 、内容区的高度,不含边框,返回数值不带单位 |
2.2 案例:淘宝flexible.js源码分析
主要作用:创建一个独立的作用域。
2.2.1 立即执行函数
立即执行函数是指函数定义好后,不需要调用直接执行。即一引入 JS 文件,则该函数自动执行。
语法:
- 立即执行函数: 不需要调用,立马能够自己执行的函数
- 写法:也可以传递参数进来
(function() {})()
或者(function(){}())
,第二个小括号可以看做是调用函数 - 立即执行函数最大的作用就是 独立创建了一个作用域 ,里面所有的变量都是局部变量,不会有命名冲突的情况
2.2.2 pageShow 事件
下面三种情况都会刷新页面都会触发load 事件。
- a标签的超链接
- F5或者刷新按钮(强制刷新)
- 前进后退按钮
但是火狐中,有个特点,有个“往返缓存”,这个缓存中不仅保存着页面数据,还保存了 DOM 和 JavaScript 的状态;实际上是将整个页面都保存在了内存里。
所以此时后退按钮不能刷新页面。
此时可以使用 pageshow
事件来触发。这个事件在页面显示时触发,无论页面是否来自缓存。在重新加载页面中,pageshow
会在 load
事件触发后触发;根据事件对象中的 persisted
来判断是否是缓存中的页面触发的 pageshow
事件(返回 true
或者 false
),注意这个事件给 window
添加。
多个立即执行函数间要加分号
;
隔开。
(function flexible(window, document) {
// 获取的html 的根元素
var docEl = document.documentElement
// dpr (device pixel ratio) 物理像素比/设备像素比
var dpr = window.devicePixelRatio || 1
// adjust body font size 设置我们body 的字体大小
function setBodyFontSize() {
// 如果页面中有body 这个元素 就设置body的字体大小
if (document.body) {
document.body.style.fontSize = (12 * dpr) + 'px'
} else {
// 如果页面中没有body 这个元素,则等着 我们页面主要的DOM元素加载完毕再去设置body
// 的字体大小
document.addEventListener('DOMContentLoaded', setBodyFontSize)
}
}
setBodyFontSize();
// set 1rem = viewWidth / 10 设置我们html 元素的文字大小
// 把 rem 划分成十等份
function setRemUnit() {
var rem = docEl.clientWidth / 10
docEl.style.fontSize = rem + 'px'
}
setRemUnit()
// reset rem unit on page resize 当我们页面尺寸大小发生变化的时候,要重新设置下rem 的大小,调用上面的函数
window.addEventListener('resize', setRemUnit)
// pageshow 是我们重新加载页面触发的事件
window.addEventListener('pageshow', function(e) {
// e.persisted 返回的是true 就是说如果这个页面是从缓存取过来的页面,也需要重新计算一下rem 的大小
// 照顾各个浏览器
if (e.persisted) {
setRemUnit()
}
})
// detect 0.5px supports 有些移动端的浏览器不支持0.5像素的写法
if (dpr >= 2) {
var fakeBody = document.createElement('body')
var testElement = document.createElement('div')
testElement.style.border = '.5px solid transparent'
fakeBody.appendChild(testElement)
docEl.appendChild(fakeBody)
if (testElement.offsetHeight === 1) {
docEl.classList.add('hairlines')
}
docEl.removeChild(fakeBody)
}
}(window, document))
3. 元素滚动 scroll 系列
3.1 元素 scroll 系列属性
scroll
翻译过来就是滚动的,我们使用 scroll
系列的相关属性可以动态的得到该元素的大小、滚动距离等。
scroll系列属性 | 作用 |
---|---|
element.scrollTop | 返回被卷上去的上侧距离,(从边框下沿开始计算)返回数值不带单位 |
element.scrollLeft | 返回被卷上去的左侧距离,返回数值不带单位 |
element.scrollWidth | 返回自身实际宽度,不含边框,包括 padding ,返回数值不带单位 |
element.scrollHeight | 返回自身实际高度,不含边框,包括 padding ,返回数值不带单位 |
3.2 页面被卷去的头部
如果浏览器的高(或宽)度不足以显示整个页面时,会自动出现滚动条。当滚动条向下滚动时,页面上面被隐藏掉的高度,我们就称为页面被卷去的头部。滚动条在滚动时会触发 onscroll
事件。
获取页面被卷去的头部:
- 页面 被卷去的头部:可以通过
window.pageYOffset
获得,如果是被卷去的左侧window.pageXOffset
- 注意,元素被卷去的头部是
element.scrollTop
,左侧element.scrollLeft
3.3 案例:仿淘宝固定右侧侧边栏
需求:
- 原先侧边栏是绝对定位
- 当页面滚动到一定位置,侧边栏改为固定定位
- 页面继续滚动,会让返回顶部显示出来
案例分析:
- 需要用到页面滚动事件
scroll
因为是页面滚动,所以事件源是document
- 滚动到某个位置,就是判断页面被卷去的上部值。
- 页面被卷去的头部:可以通过
window.pageYOffset
获得,如果是被卷去的左侧window.pageXOffset
- 注意,元素被卷去的头部是
element.scrollTop
, 如果是页面被卷去的头部则是window.pageYOffset
- 其实这个值可以通过盒子的
offsetTop
可以得到,如果大于等于这个值,就可以让盒子固定定位了
3.4 页面被卷去的头部兼容性解决方案
需要注意的是,页面被卷去的头部,有兼容性问题,因此被卷去的头部通常有如下几种写法:
- 声明了 DTD,使用
document.documentElement.scrollTop
- 未声明 DTD,使用
document.body.scrollTop
- 新方法
window.pageYOffset
和window.pageXOffset
,IE9开始支持
function getScroll() {
return {
left: window.pageXOffset || document.documentElement.scrollLeft ||
document.body.scrollLeft || 0, top: window.pageYOffset ||
document.documentElement.scrollTop || document.body.scrollTop || 0
};
}
使用的时候 getScroll().left
4. 三大系列总结
4.1 对比
三大系列大小对比 | 作用 |
---|---|
element.offsetWidth | 返回自身包括 padding 、边框、内容区的宽度,返回数值不带单位 |
element.clientWidth | 返回自身包括 padding 、内容区的宽度,不含边框,返回数值不带单位 |
element.scrollWidth | 返回自身实际的宽度,不含边框,返回数值不带单位 |
4.2 主要用法
offset
系列经常用于获得元素位置offsetLeft
、offsetTop
client
经常用于获取元素大小clientWidth
、clientHeight
scroll
经常用于获取滚动距离scrollTop
、scrollLeft
- 注意页面滚动的距离通过
window.pageYOffset
获得
5. mouseenter 和 mouseover 的区别
- 当鼠标移动到元素上时就会触发
mouseenter
事件 - 类似
mouseover
,它们两者之间的差别是 mouseover
鼠标经过自身盒子会触发,经过子盒子还会触发。mouseenter
只会经过自身盒子触发- 之所以这样,就是因为
mouseenter
不会冒泡 - 跟
mouseenter
搭配鼠标离开mouseleave
同样不会冒泡