飞道的博客

这3个高级前端常用的API,有你正在用的吗?

389人阅读  评论(0)

目录

前言

正文

一、getComputedStyle()

二、getBoundingClientRect()

三、requestAnimationFrame()

总结


前言

在平时的开发过程中,合理使用一些API,可以在一定程度上帮助我们提升开发效率。接下来我跟大家介绍一下3个前端开发中比较好用的API。

正文

一、getComputedStyle()

介绍

DOM2 Style 在 document.defaultView 上增加了 getComputedStyle() 方法,该方法返回一个 CSSStyleDeclaration 对象(与 style 属性的类型一样),包含元素的计算样式。

使用


  
  1. document. defaultView. getComputedStyle(element[,pseudo-element])
  2. // 或者是
  3. window. getComputedStyle(element[,pseudo-element])

这个方法接收两个参数:需要取得计算样式的元素、伪元素字符串(如":after")。如果不需要查询伪元素,则第二个参数可以传 null。


  
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <style type="text/css">
  5. #myDiv {
  6. background-color: blue;
  7. width: 100px;
  8. height: 200px;
  9. }
  10. </style>
  11. </head>
  12. <body>
  13. <div id="myDiv" style="background-color:red;border:1px solid black"> </div>
  14. </body>
  15. <script>
  16. function getStyleByAttr( obj, name) {
  17. return window. getComputedStyle ? window. getComputedStyle(obj, null)[name] : obj. currentStyle[name]
  18. }
  19. let node = document. getElementById( 'myDiv')
  20. console. log( "backgroundColor: ", getStyleByAttr(node, 'backgroundColor'))
  21. console. log( "width: ", getStyleByAttr(node, 'width'))
  22. console. log( "height :", getStyleByAttr(node, 'height'))
  23. console. log( "border :", getStyleByAttr(node, 'border'))
  24. </script>
  25. </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 以外的属性是相对于视图窗口的左上角来计算的。

如下,对例一的红色块位置信息进行打印


  
  1. let node = document. getElementById( 'myDiv')
  2. console. log( "positionMsg: ",node. getBoundingClientRect())

可轻松获得相关信息。 

场景一:获取 dom 元素相对于网页左上角定位的距离

以前的写法是通过 offsetParent 找到元素到定位父级元素,直至递归到顶级元素 body 或 html。


  
  1. // 获取dom元素相对于网页左上角定位的距离
  2. function offset( el) {
  3. let top = 0
  4. let left = 0
  5. do {
  6. top += el. offsetTop
  7. left += el. offsetLeft
  8. } while ((el = el. offsetParent)) // 存在兼容性问题
  9. return {
  10. top: top,
  11. left: left
  12. }
  13. }
  14. let odiv = document. getElementsByClassName( 'markdown-body')
  15. offset(a[ 0]) // {top: 271, left: 136}

使用 getBoundingClientRect() :


  
  1. let left = element. getBoundingClientRect(). left + document. documentElement. scrollLeft
  2. let top = element. getBoundingClientRect(). top + document. documentElement. scrollTop

场景二:判断元素是否在可视区域内


  
  1. function isElView( el) {
  2. let top = el. getBoundingClientRect(). top // 元素顶端到可见区域顶端的距离
  3. let bottom = el. getBoundingClientRect(). bottom // 元素底部端到可见区域顶端的距离
  4. let viewH = document. documentElement. clientHeight // 浏览器可见区域高度。
  5. if (top < viewH && bottom > 0) {
  6. return true
  7. } else if (top >= viewH || bottom <= 0) {
  8. // 不可见
  9. }
  10. return false
  11. }

三、requestAnimationFrame()

介绍

window.requestAnimationFrame() 告诉浏览器你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。

使用

window.requestAnimationFrame(callback)

兼容性处理


  
  1. window. _requestAnimationFrame = ( function ( ) {
  2. return (
  3. window. requestAnimationFrame ||
  4. window. webkitRequestAnimationFrame ||
  5. window. mozRequestAnimationFrame ||
  6. function ( callback) {
  7. window. setTimeout(callback, 1000 / 60)
  8. }
  9. )
  10. })()

结束动画


  
  1. let globalID
  2. function animate( ) {
  3. // 一直运行
  4. globalID = requestAnimationFrame(animate) // Do something animate
  5. }
  6. globalID = requestAnimationFrame(animate) //开始
  7. cancelAnimationFrame(globalID) //结束

与 setTimeout 相比,requestAnimationFrame 最大的优势是由系统来决定回调函数的执行时机。具体一点讲,如果屏幕刷新率是 60Hz,那么回调函数就每 16.7ms 被执行一次,如果刷新率是 75Hz,那么这个时间间隔就变成了 1000/75=13.3ms,换句话说就是,requestAnimationFrame 的步伐跟着系统的刷新步伐走。它能保证回调函数在屏幕每一次的刷新间隔中只被执行一次,这样就不会引起丢帧现象,也不会导致动画出现卡顿的问题。这个 API 的调用很简单,如下所示:


  
  1. let progress = 0
  2. // 回调函数
  3. function render( ) {
  4. progress += 1 // 修改进度条的位置
  5. if (progress < 100) {
  6. // 在进度条没有结束前,递归渲染
  7. window. requestAnimationFrame(render)
  8. }
  9. }
  10. // 第一帧渲染
  11. window. requestAnimationFrame(render)

优点

  • CPU 节能:使用 setTimeout 实现的动画,当页面被隐藏或最小化时,setTimeout 仍然在后台执行动画任务,由于此时页面处于不可见或不可用状态,刷新动画是没有意义的,完全是浪费 CPU 资源。而 requestAnimationFrame 则完全不同,当页面处理未激活的状态下,该页面的屏幕刷新任务也会被系统暂停,因此跟着系统步伐走的 requestAnimationFrame 也会停止渲染,当页面被激活时,动画就从上次停留的地方继续执行,有效节省了 CPU 开销。

  • 函数节流:在高频率事件(resize,scroll 等)中,为了防止在一个刷新间隔内发生多次函数执行,使用 requestAnimationFrame 可保证每个刷新间隔内,函数只被执行一次,这样既能保证流畅性,也能更好的节省函数执行的开销。一个刷新间隔内函数执行多次时没有意义的,因为显示器每 16.7ms 刷新一次,多次绘制并不会在屏幕上体现出来。

场景一:监听 scroll 函数

页面滚动事件(scroll)的监听函数,就很适合用这个 api,推迟到下一次重新渲染。 


  
  1. $( window). on( 'scroll', function ( ) {
  2. window. requestAnimationFrame(scrollHandler)
  3. })

平滑滚动到页面顶部


  
  1. const scrollToTop = ( ) => {
  2. const c = document. documentElement. scrollTop || document. body. scrollTop
  3. if (c > 0) {
  4. window. requestAnimationFrame(scrollToTop)
  5. window. scrollTo( 0, c - c / 8) // 每次网上滚动 1/8,每一帧平滑
  6. }
  7. }
  8. scrollToTop()

场景二、大量数据渲染

比如对十万条数据进行渲染,主要由以下几种方法:

(1)使用定时器


  
  1. // 需要插入的容器
  2. let ul = document. getElementById( 'container')
  3. // 插入十万条数据
  4. let total = 100000
  5. // 一次插入 20 条
  6. let once = 20
  7. // 总页数
  8. let page = total / once
  9. // 每条记录的索引
  10. let index = 0
  11. // 循环加载数据
  12. function loop( curTotal, curIndex) {
  13. if (curTotal <= 0) {
  14. return false
  15. }
  16. // 每页多少条
  17. let pageCount = Math. min(curTotal, once)
  18. setTimeout( () => {
  19. for ( let i = 0; i < pageCount; i++) {
  20. let li = document. createElement( 'li')
  21. li. innerText = curIndex + i + ' : ' + ~~( Math. random() * total)
  22. ul. appendChild(li)
  23. }
  24. loop(curTotal - pageCount, curIndex + pageCount)
  25. }, 0)
  26. }
  27. loop(total, index)

(2)使用 requestAnimationFrame


  
  1. // 需要插入的容器
  2. let ul = document. getElementById( 'container')
  3. // 插入十万条数据
  4. let total = 100000
  5. // 一次插入 20 条
  6. let once = 20
  7. // 总页数
  8. let page = total / once
  9. // 每条记录的索引
  10. let index = 0
  11. // 循环加载数据
  12. function loop( curTotal, curIndex) {
  13. if (curTotal <= 0) {
  14. return false
  15. }
  16. // 每页多少条
  17. let pageCount = Math. min(curTotal, once)
  18. window. requestAnimationFrame( function ( ) {
  19. for ( let i = 0; i < pageCount; i++) {
  20. let li = document. createElement( 'li')
  21. li. innerText = curIndex + i + ' : ' + ~~( Math. random() * total)
  22. ul. appendChild(li)
  23. }
  24. loop(curTotal - pageCount, curIndex + pageCount)
  25. })
  26. }
  27. loop(total, index)

总结

以上就是几个不错的API,在某些场景下使用能大大提高我们的开发效率,赶紧用起来吧。 


转载:https://blog.csdn.net/qq_41809113/article/details/125626444
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场