BOM

文章目录

BOM

offset(只读,不可写)

ele.offsetParent获取元素第一个有定位的父级元素(如果一直找不到就会返回 元素)

ele.offsetWidth 获取元素宽度 (padding + width + border)

ele.offsetHeight 获取元素高度 (padding + height + border)

ele.offsetTop 获取元素顶部到有定位的父级元素的上内边距外侧(上外边距内侧)的距离(也就是到外边距就停)。当定位元素为 body 时,获取到页面顶端的距离(不管 body 是否有 border)

ele.offsetLeft 获取元素顶部到有定位的父级元素的左内边距外侧(左外边距内侧)的距离。当定位元素为 body 时,获取到页面最左侧的距离(不管 body 是否有 border)

以上获取的数值都是整数(一般会自动向上取整,遇 1 向下取整,遇 2 以上都向上取整),不带 ‘px’ 的。( ele.style.top/left 是带 px 的)

动画

缓速动画(速度越来越慢)

步长公式:(终点 - 起点) / 10 ,因为每经过一次步长的距离,起点的位置都会改变,导致差值变小,步长也变小, 10 是为了曲小数点后最多只有一位值。 到终点距离小于 10px 时,设定 步长为 1

事件对象

1
2
3
4
5
6
7
8
event.type // 事件类型
event.target // 触发事件的元素
event.currentTarget // 绑定事件的元素 ,因为上面那个可能会监听到冒泡事件的元素,所以可以用这个得到被委托的元素
event.pageX/Y // 触发事件时鼠标距离页面域左上角的距离(会计算滚动条) X Y
event.clientX/Y // 触发事件时鼠标距离页面可视区的距离(就是一页) X Y
event.screenX/Y // 触发事件时鼠标距离屏幕左上角的距离 X Y
event.offsetX/Y // 触发事件时鼠标距离触发事件的元素的上左边距 X Y
event.key/keycode // 返回触发事件时按下的键的 ASCII 码值 // keydown 事件不区分大小写,统一返回大写 ASCII 码值, keypress 不触发功能键(如Enter、CapsLock、Shift、Ctrl等),但能识别大小写的键

事件冒泡

1
2
3
4
5
6
7
8
9
10
11
event.stopPropagation() // 阻止事件冒泡 IE <= 10下 event.cancelBubble = true
// 兼容写法 即将废弃
event.stopPropagation ? event.stopPropagation : event.cancelBubble

event.preventDefault() // 阻止默认事件,有多种方法可以阻止默认事件,在 a 标签中默认事件是跳转, form 中是提交表单,如
ele.onclick = function() {
event.preventDefault() // 方法一
event.returnValue = false // 方法二 一般在 IE 低版本使用 即将废弃
return false // 方法三
}
<a herf="#" onclick="return false"> // 写在行内 方法四

事件委托

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<ul id="ulEle">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li><p>5</p></li>
</ul>
<script>
var lis = ulEle.children
// 利用冒泡机制实现事件委托,这样就不需要设置多个监听,只需要在父级元素上设置监听就行了,判断一下触发事件的是哪个元素就执行相应事件
ulEle.onclick = function() {
// event.target.tagName 返回的标签名是 大写的 !
if(event.target.tagName == "LI") {
console.log(event.target)
}
// 这样写第五个 li 中由于有 p 元素,占满了全部 li,点不到 li ,所以点击第五个 li,不会打印,写成这样,会返回自己或者一个最近的父级 li 元素或者 null
if(event.target.closest("li")) {
console.log(event.target.closeest("li"))
}

}
</script>

行为型事件委托

1
2
3
4
5
6
7
8
9
10
11
<p data-count>0</p>
<button data-count>0</button>
<span data-count>0</span>
<div>0</div>
<script>
// 为元素添加特殊类或者特殊属性(一般为自定义属性 data-xx )后,在文档范围级的处理器(下面的例子中是 body)追踪事件,如果事件发生在具有特定属性的元素上,就触发事件
document.body.addEventListener("click", function() {
if(event.target.dataset.count)
event.target.innerText = Number(event.target.innerText) + 1 // 每次点击有特殊属性的元素,它的内容数字加一 上面是除了 div 之外的元素内置本文都会加一
})
</script>

鼠标事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<style>
#box {
/* 要让元素保证在当前视口中,所以用 fixed 而不是 absolute */
position: fixed;
top: 0;
left: 0;
width: 100px;
height: 100px;
background-color: red;
}
</style>
<div id="box"></div>
<script>
// 效果是 鼠标移动到元素上之后元素就一直跟着鼠标走了
window.onmousemove = function () {

// + box.offsetHeight(Width)/ 2 是为了让鼠标出现在元素中间
box.style.top = event.clientY + box.offsetHeight/ 2+ "px"
box.style.left = event.clientX + box.offsetWidth/ 2 + "px"
}
</script>

拖拽

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<style>
#box {
/* 要让元素保证在当前视口中,所以用 fixed 而不是 absolute */
position: fixed;
top: 0;
left: 0;
width: 100px;
height: 100px;
background-color: red;
}
</style>
<div id="box"></div>
<script>
// 拖拽逻辑一
// 元素起始距离页面的上左边距 + 元素移动的距离 = 元素移动后距离页面的上左边距
box.onmousedown = function () {
var mouseStartX = event.pageX,
mouseStartY = event.pageY,
eleStartX = this.offsetLeft,
eleStartY = this.offsetTop
// 让鼠标在 box 元素按下之后再触发页面的 move 事件
//获取鼠标距页面的上左边距、获取元素距页面的上左边距

window.onmousemove = function () {
// 鼠标移动上左距离 = 鼠标抬起时距离页面的上左边距 - 按下时距页面的上左边距
var distanceX = event.pageX - mouseStartX,
distanceY = event.pageY - mouseStartY
box.style.left = eleStartX + distanceX + 'px'
box.style.top = eleStartY + distanceY + 'px'
console.log(1)
}
// 鼠标抬起也在按下之后
box.onmouseup = function () {

}
}
</script>
<script>
// 拖拽逻辑二
// 不管元素拖拽前后,有一个等式, 元素与页面的距离 + 鼠标与元素的距离 = 鼠标与页面内的距离
// 1. 获取鼠标按下时鼠标在元素中的位置
// 2. 拖拽过程中鼠标与页面的距离 - 鼠标与元素的距离 = 元素与页面的距离
// 不能直接 鼠标与页面的距离 = 元素与页面的距离 (这样元素的左上角会变成鼠标点击的位置,但我们希望保留鼠标在元素内的位置,所以需要减去鼠标与元素的距离)
// 加边界,防止元素跑出范围
// 父元素无定位,相对于body
var minY = content.offsetTop,
minX = content.offsetLeft,
maxY = minY + content.offsetHeight - box.offsetHeight,
maxX = minX + content.offsetWidth - box.offsetWidth
// 父元素有定位
var minY = 0,
minX = 0,
maxY = minY + content.offsetHeight - box.offsetHeight,
maxX = minX + content.offsetWidth - box.offsetWidth
box.onmousedown = function () {
var mouseX = event.offsetX - this.offsetLeft
var mouseY = event.offsetY - this.offsetTop
window.onmousemove = function () {
var targetX = event.pageX - mouseX
var targetY = event.pageY - mouseY
if(targetX < minX) {
targetX = minX
}
if(targetX > maxX) {
targetX = maxX
}
if(targetY > maxY) {
targetY = maxY
}
if(targetY < minY) {
targetY = minY
}
box.style.top = targetY + 'px'
box.style.left = targetX + 'px'
}
box.onmouseup = function () {
// 在鼠标抬起后解绑移动事件,不然一直移
window.onmousemove = null
}
}
</script>
自定义属性
1
2
3
4
5
6
<p data-title="123abc"></p>
<script type="text/javascript">
var pE = document.querySelector("p")
var str = pE.dataset.title // 用 dataset [自定义属性名]获取自定义的属性值! 是 dataset 不是 data
str // "123abc"
</script>
获取最近的符合条件的元素
1
2
3
4
5
6
7
8
9
10
11
12
<!--ele..closest(这里写 CSS 选择器) 选择最近的符合条件的自己或者父级元素 -->
<div class="d1 d3">
<div class="d1 d2 insert">
</div>
</div>
<script>
var insert = document.querySelector(".insert")
var ele = insert.closest(".d2") // <div class="d1 d2 insert">
ele = insert.closest(".d1") // <div class="d1 d2 insert">
ele = insert.closest(".d3") // <div class="d1 d3">

</script>

scroll

scrollTopscrollLeft 可以被读写,获取元素滚动条当前的滚动高度(即卷入高度)、长度,没有滚动条时为 0

scrollHeightscrollWidth 获取上下(左右)内边距与内容区之和的高度(宽度)。元素内容超出元素宽高时:

  • 元素设置有 overflow 时(不一定是hidden!),scrollHeight 计算上下边距与内容区,scrollWidth 计算左边距与内容区。
  • 元素不设置 overflow 时,scrollHeight 计算上边距与内容区,scrollWidth 计算左边距与内容区。
获取页面当前滚动条卷入的高度、长度
1
2
3
4
5
6
7
8
document.body.scrollTop
document,body.scrollLeft
document.documentElement.scrollTop
document.documentElement.scrollLeft
// 一般用下面的 window
window.pageXOffset
window.pageYOffset
ele.getScroll() // 有很多位小数,记得取整
onscroll 事件

设置此事件的元素一定要有滚动条

window 滚动的方法

window.scroll(x, y) 让页面滚动到指定位置

window.scrollBy(x, y) 让页面滚动设定的值的长度,正值为向右/下滚动

window.scrollTo(x, y)window.scroll(),但这个低版本IE 不兼容。

实现页面顺滑滚动 (smooth scroll)
  1. html { scroll-behavior: smooth;}

  2. window.scroll(options) 传入一个对象作为参数,有 top( 默认 0 )、left( 默认 0 )、behavior( 默认 auto ),都是可选项

    window.scrollBy({top: 1000, left: 1000, behavior:"smooth"})

  3. ele.scrollIntoView(options) IE 不支持 options, 是个实验属性,浏览器支持不好

防抖

触发事件在 n 秒内函数只执行一次,如果在 n 秒内又触发了事件,则重新计算函数执行时间,再持续 n 秒。

实际上是每次触发时,如果已经存在定时器,就清除上一次的定时器之后,再添加一个新的定时器。

可以用在搜索联想,当用户输入时,每隔一定时间间隔自动帮助拓展

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 执行后计时
function debounce(func, wait) {
var timer = null
return function () {
if (timer) {
clearTimeout(timer)
} else {
func()
}
timer = setTimeout(function () {
timer = null
}, wait)
}
}
// 计时后执行
function denounce(func, wait) {
var timer = null
return function () {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(function () {
func()
timer = null
}, wait)
}
}

节流

在一定时间内只执行一次函数,可以用在滚动事件与 move 事件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function throttle(func, wait) {
var timer = null
return function () {
if (!timer) {
func() // 执行后计时 (立即执行)
timer = setTimeout(function () {
// func() // 计时后执行 (非立即执行)
timer = null
}, wait)
}
}
}

// 时间戳版本
function throttle(func, wait) {
var startTime = 0
return function () {
// 用当前触发事件 - 起始时间 > wait
// 重置起始时间为当前触发函数的时间
if(Date.now() - startTime > wait) {
startTime = Date.now()
func()
}
}
}

client

clientWidth/Height 自身宽高 + padding ,不计算溢出内容,不计算滚动条宽度

clientTop 它的内边距外侧到父元素的宽度,感觉就是它的边框宽度

document.documentElement.clientWidth/Height

window.innerWidth/Height 获取表示 window 可视区域的大小,计入滚动条占的宽高。 不兼容 IE10 以下

window.

总结

  • clientWidth 计算自身宽、左右 padding,不计算滚动条宽度

  • offsetWidth 计算自身宽、左右 padding、左右 border

  • scrollWidth 计算自身宽与左右 padding,有 overflow 属性且内容超出时 计算自身宽与左 padding。

    scrollHeight 计算自身高与上下 padding,有overflow 属性且内容超出时 计算自身高与上下 padding,无 overflow 属性时,计算自身高与上 padding

  • window.innerWidth 可视区域高度

  • scrollWidth:对象的实际内容的宽度,不包边线宽度,会随对象中内容超过可视区后而变大。
    clientWidth:对象内容的可视区的宽度,不包滚动条等边线,会随对象显示大小的变化而改变。
    offsetWidth:对象整体的实际宽度,包滚动条等边线,会随对象显示大小的变化而改变。

    情况1:

    元素内无内容或者内容不超过可视区,滚动不出现或不可用的情况下。

    scrollWidth = clientWidth,两者皆为内容可视区的宽度。

    offsetWidth为元素的实际宽度。

    情况2:

    元素的内容超过可视区,滚动条出现和可用的情况下。

    scrollWidth > clientWidth

    scrollWidth为实际内容的宽度。

    clientWidth是内容可视区的宽度。

    offsetWidth是元素的实际宽度。

网页可见区域高:document.body.clientHeight
网页正文全文高:document.body.scrollHeight
网页可见区域高(包括边线的高):document.body.offsetHeight
网页被卷去的高:document.body.scrollTop
屏幕分辨率高:window.screen.height

通常情况下,你如果要获取一个元素的真正大小,是需要对它的clientHeight和scrollHeight进行判断的,哪一个大,哪一个就是它的真实高度

offsetWidth/Height = content + padding + border

scrollWidth/Height = content + padding 内容超出时显示 content + paddingLeft + paddingTop ,如果同时还有 overflow 属性 content + paddingLeft + paddingTop + paddingBottom

clientWidth/Height = content + padding 内容超出不计算、滚动条宽度不算

offsetTop/left = 盒子与它的 offsetParent 的border 之间的距离,如果 offsetParent 是 body 的话,border 也算在内

scrollTop/Left = 页面或元素被卷入高度 页面卷入高度: document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop

clientTop/Left = 元素的上左 border 的宽度,配合 offsetTop/Left 计算任意元素距离页面的上左边距

1
2
3
4
// 所以子元素 一直取  到有定位的父元素 margin 的距离 加上 父元素 margin 的距离 ,最后取到 父元素为 body 时,就是元素在页面中的高度
ele.offsetTop + ele.offsetParent.clientTop
+ ele.offsetParent.offsetTop + ele.offsetParent.offsetParent.clientTop + ... +
body.offsetTop

页面高度相关总结

1
2
3
4
5
6
7
document.body.scrollHeight // 好像是整个页面高度,下面的话作废
// 废:当前滚动条所在的视口高度及其之上的高度,如果没有滚动条,则为 html 的高度
document.documentElement.scrollTop // edge无 当前视口顶部距离页面顶部高度
document.body.scrollTop // gg无 edge无
window.pageYOffset edge无 // 当前视口顶部距离页面顶部高度
window.innerHeight // 当前视口高度 我的电脑正常是968
document.documentElement.clientHeight // 当前视口高度 我的电脑正常是 968

window

window.onload 页面完全加载完毕时调用 ( 中的 css、