↖  JavaScript网页前端常用的API-2..


-loading- -loading- -loading-

2021-11-16 , 3389 , 104 , 123

听音频 🔊 . 看视频 🎦


getComputedStyle()

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


API

document.defaultView.getComputedStyle(element[,pseudo-element])// orwindow.getComputedStyle(element[,pseudo-element])

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

<!DOCTYPE html>
 
   <style type="text/css">
     #myDiv {        background-color: blue;        width: 100px;        height: 200px;
     }    </style>
 
 
   <div id="myDiv" style="background-color: red; border: 1px solid black"></div>
 
 <script>
   function getStyleByAttr(obj, name) {      return window.getComputedStyle ? window.getComputedStyle(obj, null)[name] : obj.currentStyle[name]
   }    let node = document.getElementById('myDiv')    console.log(getStyleByAttr(node, 'backgroundColor'))    console.log(getStyleByAttr(node, 'width'))    console.log(getStyleByAttr(node, 'height'))    console.log(getStyleByAttr(node, 'border'))  </script>

和 style 的异同

getComputedStyle 和 element.style 的相同点就是二者返回的都是 CSSStyleDeclaration 对象。而不同点就是:

element.style 读取的只是元素的内联样式,即写在元素的 style 属性上的样式;而 getComputedStyle 读取的样式是最终样式,包括了内联样式、嵌入样式和外部样式。

element.style 既支持读也支持写,我们通过 element.style 即可改写元素的样式。而 getComputedStyle 仅支持读并不支持写入。我们可以通过使用 getComputedStyle 读取样式,通过 element.style 修改样式

getBoundingClientRect

getBoundingClientRect() 方法返回元素的大小及其相对于视口的位置。

API

let DOMRect = object.getBoundingClientRect()

它的返回值是一个 DOMRect 对象,这个对象是由该元素的 getClientRects() 方法返回的一组矩形的集合,就是该元素的 CSS 边框大小。返回的结果是包含完整元素的最小矩形,并且拥有 left, top, right, bottom, x, y, width, 和 height 这几个以像素为单位的只读属性用于描述整个边框。除了 width 和 height 以外的属性是相对于视图窗口的左上角来计算的。



应用场景

1、获取 dom 元素相对于网页左上角定位的距离

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

// 获取dom元素相对于网页左上角定位的距离function offset(el) {  var top = 0
 var left = 0
 do {
   top += el.offsetTop
   left += el.offsetLeft
 } while ((el = el.offsetParent)) // 存在兼容性问题,需要兼容
 return {    top: top,    left: left
 }
}var odiv = document.getElementsByClassName('markdown-body')offset(a[0]) // {top: 271, left: 136}

-loading- -loading--loading-


现在根据 getBoundingClientRect 这个 api,可以写成这样:

UfqiLong

var positionX = this.getBoundingClientRect().left + document.documentElement.scrollLeftvar positionY = this.getBoundingClientRect().top + document.documentElement.scrollTop


2、判断元素是否在可视区域内

function isElView(el) {  var top = el.getBoundingClientRect().top // 元素顶端到可见区域顶端的距离
 var bottom = el.getBoundingClientRect().bottom // 元素底部端到可见区域顶端的距离
 var se = document.documentElement.clientHeight // 浏览器可见区域高度。
 if (top < se && bottom > 0) {    return true
 } else if (top >= se || bottom <= 0) {    // 不可见
 }  return false}



----


requestAnimationFrame

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

API

该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。

window.requestAnimationFrame(callback)

兼容性处理

window._requestAnimationFrame = (function () {  return (    window.requestAnimationFrame ||    window.webkitRequestAnimationFrame ||    window.mozRequestAnimationFrame ||    function (callback) {      window.setTimeout(callback, 1000 / 60)
   }
 )
})()

结束动画

var globalIDfunction animate() {  // done(); 一直运行
 globalID = requestAnimationFrame(animate) // Do something animate}
globalID = requestAnimationFrame(animate) //开始cancelAnimationFrame(globalID) //结束

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

var 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 刷新一次,多次绘制并不会在屏幕上体现出来。


-loading- -loading--loading-


UfqiLong

应用场景

1、监听 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)
 }
}scrollToTop()


2、大量数据渲染

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

(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)


监控卡顿方法

每秒中计算一次网页的 FPS,获得一列数据,然后分析。通俗地解释就是,通过 requestAnimationFrame API 来定时执行一些 JS 代码,如果浏览器卡顿,无法很好地保证渲染的频率,1s 中 frame 无法达到 60 帧,即可间接地反映浏览器的渲染帧率。

var lastTime = performance.now()var frame = 0var lastFameTime = performance.now()var loop = function (time) {  var now = performance.now()  var fs = now - lastFameTime
 lastFameTime = now  var fps = Math.round(1000 / fs)
 frame++  if (now > 1000 + lastTime) {    var fps = Math.round((frame * 1000) / (now - lastTime))
   frame = 0
   lastTime = now
 }  window.requestAnimationFrame(loop)
}

我们可以定义一些边界值,比如连续出现 3 个低于 20 的 FPS 即可认为网页存在卡顿。


朋友圈的风景:美妙时光美景风光:山河湖水人文城市-24

+网页 +元素 +样式 +函数 +动画

本页Url

↖回首页 +当前续 +尾续 +修订 +评论✍️


👍11 仁智互见 👎0
  • 还没有评论. → +评论
  • -loading- -loading- -loading-


    🔗 连载目录

    🤖 智能推荐

    + 底蕴 底蕴
    AddToFav   
    新闻 经典 官宣