目录
前言
在平时的开发过程中,合理使用一些API,可以在一定程度上帮助我们提升开发效率。接下来我跟大家介绍一下3个前端开发中比较好用的API。
正文
一、getComputedStyle()
介绍
DOM2 Style 在 document.defaultView
上增加了 getComputedStyle() 方法,该方法返回一个 CSSStyleDeclaration
对象(与 style 属性的类型一样),包含元素的计算样式。
使用
-
document.
defaultView.
getComputedStyle(element[,pseudo-element])
-
// 或者是
-
window.
getComputedStyle(element[,pseudo-element])
这个方法接收两个参数:需要取得计算样式的元素、伪元素字符串(如":after")。如果不需要查询伪元素,则第二个参数可以传 null。
-
<!DOCTYPE html>
-
<html>
-
<head>
-
<style type="text/css">
-
#myDiv {
-
background-color: blue;
-
width:
100px;
-
height:
200px;
-
}
-
</style>
-
</head>
-
<body>
-
<div id="myDiv" style="background-color:red;border:1px solid black">
</div>
-
</body>
-
<script>
-
function
getStyleByAttr(
obj, name) {
-
return
window.
getComputedStyle ?
window.
getComputedStyle(obj,
null)[name] : obj.
currentStyle[name]
-
}
-
let node =
document.
getElementById(
'myDiv')
-
console.
log(
"backgroundColor: ",
getStyleByAttr(node,
'backgroundColor'))
-
console.
log(
"width: ",
getStyleByAttr(node,
'width'))
-
console.
log(
"height :",
getStyleByAttr(node,
'height'))
-
console.
log(
"border :",
getStyleByAttr(node,
'border'))
-
</script>
-
</html>
控制台打印
与 element.style 的异同
相同点
二者返回的都是 CSSStyleDeclaration 对象;
不同点
(1)element.style 读取的只是元素的内联样式,即写在元素的 style 属性上的样式;而 getComputedStyle 读取的样式是最终样式,包括了内联样式、嵌入样式和外部样式。
如上,由于 background-color 既在行内样式,也在嵌入样式设置,且行内样式优先级高,最终样式为 red,则 getComputedStyle 得出的也是 red。
(2)element.style 既支持读也支持写,我们通过 element.style 即可改写元素的样式。而 getComputedStyle 仅支持读并不支持写入。我们可以通过使用 getComputedStyle 读取样式,通过 element.style 修改样式。
二、getBoundingClientRect()
介绍
getBoundingClientRect() 方法返回元素的大小及其相对于视口的位置。
使用
let DOMRect = element.getBoundingClientRect()
它的返回值是一个 DOMRect 对象,这个对象是由该元素的 getClientRects() 方法返回的一组矩形的集合,就是该元素的 CSS 边框大小。返回的结果是包含完整元素的最小矩形,并且拥有 left,top,right,bottom,x,y,width 和 height 这几个以像素为单位的只读属性用于描述整个边框。除了 width 和 height 以外的属性是相对于视图窗口的左上角来计算的。
如下,对例一的红色块位置信息进行打印
-
let node =
document.
getElementById(
'myDiv')
-
console.
log(
"positionMsg: ",node.
getBoundingClientRect())
可轻松获得相关信息。
场景一:获取 dom 元素相对于网页左上角定位的距离
以前的写法是通过 offsetParent 找到元素到定位父级元素,直至递归到顶级元素 body 或 html。
-
// 获取dom元素相对于网页左上角定位的距离
-
function
offset(
el) {
-
let top =
0
-
let left =
0
-
do {
-
top += el.
offsetTop
-
left += el.
offsetLeft
-
}
while ((el = el.
offsetParent))
// 存在兼容性问题
-
return {
-
top: top,
-
left: left
-
}
-
}
-
-
let odiv =
document.
getElementsByClassName(
'markdown-body')
-
offset(a[
0])
// {top: 271, left: 136}
使用 getBoundingClientRect() :
-
let left = element.
getBoundingClientRect().
left +
document.
documentElement.
scrollLeft
-
let top = element.
getBoundingClientRect().
top +
document.
documentElement.
scrollTop
场景二:判断元素是否在可视区域内
-
function
isElView(
el) {
-
let top = el.
getBoundingClientRect().
top
// 元素顶端到可见区域顶端的距离
-
let bottom = el.
getBoundingClientRect().
bottom
// 元素底部端到可见区域顶端的距离
-
let viewH =
document.
documentElement.
clientHeight
// 浏览器可见区域高度。
-
if (top < viewH && bottom >
0) {
-
return
true
-
}
else
if (top >= viewH || bottom <=
0) {
-
// 不可见
-
}
-
return
false
-
}
三、requestAnimationFrame()
介绍
window.requestAnimationFrame() 告诉浏览器你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。
使用
window.requestAnimationFrame(callback)
兼容性处理
-
window.
_requestAnimationFrame = (
function (
) {
-
return (
-
window.
requestAnimationFrame ||
-
window.
webkitRequestAnimationFrame ||
-
window.
mozRequestAnimationFrame ||
-
function (
callback) {
-
window.
setTimeout(callback,
1000 /
60)
-
}
-
)
-
})()
结束动画
-
let globalID
-
function
animate(
) {
-
// 一直运行
-
globalID =
requestAnimationFrame(animate)
// Do something animate
-
}
-
globalID =
requestAnimationFrame(animate)
//开始
-
cancelAnimationFrame(globalID)
//结束
与 setTimeout 相比,requestAnimationFrame 最大的优势是由系统来决定回调函数的执行时机。具体一点讲,如果屏幕刷新率是 60Hz,那么回调函数就每 16.7ms 被执行一次,如果刷新率是 75Hz,那么这个时间间隔就变成了 1000/75=13.3ms,换句话说就是,requestAnimationFrame 的步伐跟着系统的刷新步伐走。它能保证回调函数在屏幕每一次的刷新间隔中只被执行一次,这样就不会引起丢帧现象,也不会导致动画出现卡顿的问题。这个 API 的调用很简单,如下所示:
-
let progress =
0
-
// 回调函数
-
function
render(
) {
-
progress +=
1
// 修改进度条的位置
-
if (progress <
100) {
-
// 在进度条没有结束前,递归渲染
-
window.
requestAnimationFrame(render)
-
}
-
}
-
// 第一帧渲染
-
window.
requestAnimationFrame(render)
优点
-
CPU 节能:使用 setTimeout 实现的动画,当页面被隐藏或最小化时,setTimeout 仍然在后台执行动画任务,由于此时页面处于不可见或不可用状态,刷新动画是没有意义的,完全是浪费 CPU 资源。而 requestAnimationFrame 则完全不同,当页面处理未激活的状态下,该页面的屏幕刷新任务也会被系统暂停,因此跟着系统步伐走的 requestAnimationFrame 也会停止渲染,当页面被激活时,动画就从上次停留的地方继续执行,有效节省了 CPU 开销。
-
函数节流:在高频率事件(resize,scroll 等)中,为了防止在一个刷新间隔内发生多次函数执行,使用 requestAnimationFrame 可保证每个刷新间隔内,函数只被执行一次,这样既能保证流畅性,也能更好的节省函数执行的开销。一个刷新间隔内函数执行多次时没有意义的,因为显示器每 16.7ms 刷新一次,多次绘制并不会在屏幕上体现出来。
场景一:监听 scroll 函数
页面滚动事件(scroll)的监听函数,就很适合用这个 api,推迟到下一次重新渲染。
-
$(
window).
on(
'scroll',
function (
) {
-
window.
requestAnimationFrame(scrollHandler)
-
})
平滑滚动到页面顶部
-
const
scrollToTop = (
) => {
-
const c =
document.
documentElement.
scrollTop ||
document.
body.
scrollTop
-
if (c >
0) {
-
window.
requestAnimationFrame(scrollToTop)
-
window.
scrollTo(
0, c - c /
8)
// 每次网上滚动 1/8,每一帧平滑
-
}
-
}
-
-
scrollToTop()
场景二、大量数据渲染
比如对十万条数据进行渲染,主要由以下几种方法:
(1)使用定时器
-
// 需要插入的容器
-
let ul =
document.
getElementById(
'container')
-
// 插入十万条数据
-
let total =
100000
-
// 一次插入 20 条
-
let once =
20
-
// 总页数
-
let page = total / once
-
// 每条记录的索引
-
let index =
0
-
// 循环加载数据
-
function
loop(
curTotal, curIndex) {
-
if (curTotal <=
0) {
-
return
false
-
}
-
// 每页多少条
-
let pageCount =
Math.
min(curTotal, once)
-
setTimeout(
() => {
-
for (
let i =
0; i < pageCount; i++) {
-
let li =
document.
createElement(
'li')
-
li.
innerText = curIndex + i +
' : ' + ~~(
Math.
random() * total)
-
ul.
appendChild(li)
-
}
-
loop(curTotal - pageCount, curIndex + pageCount)
-
},
0)
-
}
-
loop(total, index)
(2)使用 requestAnimationFrame
-
// 需要插入的容器
-
let ul =
document.
getElementById(
'container')
-
// 插入十万条数据
-
let total =
100000
-
// 一次插入 20 条
-
let once =
20
-
// 总页数
-
let page = total / once
-
// 每条记录的索引
-
let index =
0
-
// 循环加载数据
-
function
loop(
curTotal, curIndex) {
-
if (curTotal <=
0) {
-
return
false
-
}
-
// 每页多少条
-
let pageCount =
Math.
min(curTotal, once)
-
window.
requestAnimationFrame(
function (
) {
-
for (
let i =
0; i < pageCount; i++) {
-
let li =
document.
createElement(
'li')
-
li.
innerText = curIndex + i +
' : ' + ~~(
Math.
random() * total)
-
ul.
appendChild(li)
-
}
-
loop(curTotal - pageCount, curIndex + pageCount)
-
})
-
}
-
loop(total, index)
总结
以上就是几个不错的API,在某些场景下使用能大大提高我们的开发效率,赶紧用起来吧。
转载:https://blog.csdn.net/qq_41809113/article/details/125626444