美文网首页
深入滚动事件

深入滚动事件

作者: skoll | 来源:发表于2022-04-01 15:26 被阅读0次

    简介

    1 .使用到滚动的场景

    1 .懒加载
    2 .loadmore
    3 .affix.固定位置
    4 .回到顶部
    

    2 .HTML5标准.scroll事件是每帧触发一次

    帧维度解析渲染过程

    1 .浏览器渲染页面的renderer进程里面,涉及到两个进程.两个进程之间通过commit的消息保持同步
    2 .Main进程:浏览器渲染的主要执行步骤.包含从js执行到Composite合成的一系列操作
    3 .Compositor线程:接收用户的一些交互操作,比如滚动->唤醒进程进行操作->接收Main线程的操作结果->commit给真正把页面draw到屏幕上的GPU进程


    正常的操作
    丢帧的操作

    主线程里的操作太多,耗时长,commit的时间被推迟.浏览器来不及间页面draw到屏幕上,就丢失了一帧
    4 .Main线程完成最后之后,与Compositor线程使用commit进行通信,Compositor调起Compositor来处理页面
    5 .页面Paint结束之后,这一帧就结束了.GPU进程里的GPU进程负责把Render进程操作好的页面,交由GPU内方法,由GPU把页面draw到屏幕上
    6 .屏幕刷新,我们就在浏览器上看到了新页面

    浏览器主要执行步骤

    1 .JavaScript:包含与视觉变化效果相关的js操作.包括不限于:Dom更新,元素样式动态改变
    2.Style:样式计算.浏览器根据css选择器计算哪些元素应该用哪些规则,然后间样式规则落实到每个元素上面,确定每个元素具体的样式
    3 .Layout:布局.在知道每一个元素应用哪些规则后,浏览器即可开始计算他占据的空间大小以及在屏幕中的位置

    1 .避免layout的操作,将DOM脱离文档流在对其进行操作,所有操作完毕之后再添加到文档流中,这样可以将重排以及重绘的次数降低到一次或两次
    2 .display:none
    3 .DocumentFragment
    4 .将原始元素拷贝到一个脱离文档的节点中,修改这个副本,完成后替换掉原始元素
    

    4 .Painting:绘制.绘制时填充像素的过程.涉及绘出文本,颜色,图像,边框和阴影.基本上包括元素的每个可视部分,绘制一般时在多个层上完成的.

    1 .painting和draw的区别:paint是把内容填充到页面,而draw是把页面反映到屏幕上
    

    5 .Composite:合成.由于页面的各部分可能被绘制到多层.因此他们还需要按照正确的顺序绘制到屏幕上,以便正确渲染页面.对于与另一个元素重叠的元素来说.这很重要,因为一个错误可能使另一个元素错误的出现在另一个元素上面
    6 .并不是每次都会走到全部的流程.
    7 .重排:会走完整的流程,改变了元素的几何属性(宽度,高度,左侧或者顶部位置等.必须检查所有的其他元素).任何受印象的部分都需要重新绘制.而且最终绘制的元素需要重新合成,重排进行了管道的每一步,性能受到很大的影响
    8 .重绘:和上面相比不需要layout:如果是背景图片,文字颜色或者阴影的话,不会影响页面布局的属性,浏览器会跳过布局
    9 .不重排和重绘的情况:仅仅使用transform和opacity来实现动画,会避免Layout和Paint操作
    10 .每个层中对这个层进行 Layout 或者 Paint 是不会影响其他层的,一般会根据整个页面的语义将页面分为几个层。
    11 .查询css属性变化导致的操作https://csstriggers.com/

    优化操作

    1 .避免在scroll事件中修改样式属性/将样式操作从scroll事件中剥离
    1 .变量的初始化,不依赖滚动位置变化的计算都应该在scroll事件外提前就绪

    2 .使用web worker分离和页面渲染无关的逻辑计算
    3 .触发监听事件时使用函数节流或者去抖
    4 .使用requestAnimationFrame提代定时器:浏览器每一次重回前触发这个钩子

    1 .不要在 rAF 的回调函数中先修改样式,再查询样式,这样就失去了 rAF 的作用。可以将对样式的查询提前到回调函数中或者 rAF 中尽量靠前的位置
    2 .动画是由浏览器按照一定的频率一帧一帧的绘制的,由css实现的动画的优势就是浏览器知道动画的开始及每一帧的循环间隔,能够在恰当的时间刷新UI,给用户一种流畅的体验,而setInterval或setTimeout实现的JavaScript动画就没有这么可靠了,因为浏览器压根就无法保证每一帧渲染的时间间隔,一般情况下,每秒平均刷新次数能够达到60帧,就能够给人流畅的体验,即每过 1000/60 毫秒渲染新一帧即可,但从上面的例子知,这一点单靠定时器是无法保证的。
    为此,requestAnimationFrame应运而生,其作用就是让浏览器流畅的执行动画效果。可以将其理解为专门用来实现动画效果的api,通过这个api,可以告诉浏览器某个JavaScript代码要执行动画,浏览器收到通知后,则会运行这些代码的时候进行优化,实现流畅的效果,而不再需要开发人员烦心刷新频率的问题了
    3 .requestAnimationFrame接受一个动画执行函数作为参数,这个函数的作用是仅执行一帧动画的渲染,并根据条件判断是否结束,如果动画没有结束,则继续调用requestAnimationFrame并将自身作为参数传入。从示例来看,得到了效果平滑流畅的动画,这样就巧妙地避开了每一帧动画渲染的时间间隔问题
    function animationWidth() {
      var div = document.getElementById('box');
      div.style.width = parseInt(div.style.width) + 1 + 'px';
    
      if(parseInt(div.style.width) < 200) {
        requestAnimationFrame(animationWidth)
      }
    }
    requestAnimationFrame(animationWidth);
    

    5 .requestIdleCallback():会在浏览器的每一帧末尾触发.而且是空闲的时候,如果不空闲,就推迟到下一帧.适合于执行在后台运行或者空闲时触发回调,否则推迟到下一帧.

    避免强制重排:当我们很频繁的执行下面这样的特殊操作.就会打断浏览器的节奏

    1 .当访问scrollWidth,clientWidth,offsetTop,computedStyle登属性时,会触发这个效果,导致style和layout前移到js代码执行过程中
    2 .
    elem.offsetLeft, elem.offsetTop, elem.offsetWidth, elem.offsetHeight, elem.offsetParent
    elem.clientLeft, elem.clientTop, elem.clientWidth, elem.clientHeight
    elem.getClientRects(), elem.getBoundingClientRect()
    elem.scrollWidth, elem.scrollHeight
    elem.scrollLeft, elem.scrollTop
    //这里不是求当前div的滚动距离的操作么,这个也会造成重排么?
    以上的特殊读操作,一定要使用requestAnimationFrame()包裹起来.避免单个裸奔

    提升合成层

    1 .一些属性会让元素们创建出不同的渲染层

    1 .relative,fixed,sticky,absolute
    2 .有透明度的属性
    3 .css滤镜
    4 .css transform属性
    

    2 .达成一些条件,渲染条件会提升为合成层

    1 .一键加速的iframe,iframe嵌入的页面中有合成层
    2 .3D或者硬件加速的2dCanvas
    3 .video元素
    4 .3d transform
    5 .will-change:设置为opacity,transoorm,top,left,bottom,
    6 .对opacity,tramsform,filter,backgroundFilter应用了animation或者transition
    

    3 .合成层之后,会交由GPU处理,比CPU处理快,但需要重绘的时候,只需要重绘自己的层,不会影响到其他的层

    相关文章

      网友评论

          本文标题:深入滚动事件

          本文链接:https://www.haomeiwen.com/subject/krcwjrtx.html