1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務(wù)時(shí)間:8:30-17:00
      你可能遇到了下面的問(wèn)題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
      css怎么實(shí)現(xiàn)滾動(dòng)吸頂-創(chuàng)新互聯(lián)

      小編給大家分享一下css怎么實(shí)現(xiàn)滾動(dòng)吸頂,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

      站在用戶的角度思考問(wèn)題,與客戶深入溝通,找到遷西網(wǎng)站設(shè)計(jì)與遷西網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:網(wǎng)站制作、網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、申請(qǐng)域名、虛擬空間、企業(yè)郵箱。業(yè)務(wù)覆蓋遷西地區(qū)。

      修改版預(yù)覽

      這篇文章是三天前寫就的,有大佬給我提了一些修改意見,我覺(jué)得這個(gè)意見確實(shí)中肯。所以就有了這個(gè)升級(jí)的修改版本。代碼同步更新到 GitHub 了。

      修改內(nèi)容如下:

      1. 添加了圖文說(shuō)明,直觀的說(shuō)明 getBoundingClientRect()集合含義

      2. 頻繁 reflow 風(fēng)險(xiǎn)該如何規(guī)避(優(yōu)化滾動(dòng)監(jiān)聽)

      3. 監(jiān)聽滾動(dòng)帶來(lái)的性能問(wèn)題(使用 IntersectionObserver, 新方案)

      修改更新的內(nèi)容在第 4 點(diǎn)和第 5 點(diǎn),如果你看過(guò)本文,可以直接看修改更新的內(nèi)容。或者你可以再看一遍。

      前言

      我入職第二家公司接到的第一個(gè)需求就是修復(fù)之前外包做的滾動(dòng)吸頂效果。我當(dāng)時(shí)很納悶為何一個(gè)滾動(dòng)吸頂會(huì)有 bug,后來(lái)我查看代碼才發(fā)現(xiàn)直接用的是 offsetTop 這個(gè)屬性,而且并沒(méi)有做兼容性處理。

      offsetTop


      用于獲得當(dāng)前元素到定位父級(jí)( element.offsetParent )頂部的距離(偏移值)。

      定位父級(jí) offsetParent 的定義是:與當(dāng)前元素最近的 position != static 的父級(jí)元素。

      或許寫這個(gè)代碼的人沒(méi)有注意到“定位父級(jí)”這個(gè)這個(gè)附屬條件。

      后來(lái)在項(xiàng)目中總會(huì)遇到滾動(dòng)吸頂?shù)男Ч枰獙?shí)現(xiàn),現(xiàn)在我將我知道的 4 種滾動(dòng)吸頂實(shí)現(xiàn)方式做詳細(xì)介紹。

      以上這四種方式你都了解嗎?相關(guān)代碼已上傳到 GitHub ,感興趣的可以 clone 代碼到本地運(yùn)行。望給個(gè) star 支持一下。

      四種實(shí)現(xiàn)方式

      我們先看一下效果圖:

      css怎么實(shí)現(xiàn)滾動(dòng)吸頂

      一、使用 position:sticky 實(shí)現(xiàn)

      1、粘性定位是什么?

      粘性定位 sticky 相當(dāng)于相對(duì)定位 relative 和固定定位 fixed 的結(jié)合;在頁(yè)面元素滾動(dòng)過(guò)程中,某個(gè)元素距離其父元素的距離達(dá)到 sticky 粘性定位的要求時(shí);元素的相對(duì)定位 relative 效果變成固定定位 fixed 的效果。

      MDN 傳送門

      2、如何使用?

      使用條件:

      1. 父元素不能 overflow:hidden 或者 overflow:auto 屬性

      2. 必須指定 top、bottom、left、right 4 個(gè)值之一,否則只會(huì)處于相對(duì)定位

      3. 父元素的高度不能低于 sticky 元素的高度

      4. sticky 元素僅在其父元素內(nèi)生效

      在需要滾動(dòng)吸頂?shù)脑丶由弦韵聵邮奖憧梢詫?shí)現(xiàn)這個(gè)效果:

      .sticky {
          position: -webkit-sticky;
          position: sticky;
          top: 0;
      }

      3、這個(gè)屬性好用嗎?


      我們先看下在 Can I use 中看看這個(gè)屬性的兼容性:

      css怎么實(shí)現(xiàn)滾動(dòng)吸頂

      可以看出這個(gè)屬性的兼容性并不是很好,因?yàn)檫@個(gè) API 還只是實(shí)驗(yàn)性的屬性。不過(guò)這個(gè) API 在 IOS 系統(tǒng)的兼容性還是比較好的。

      所以我們?cè)谏a(chǎn)環(huán)境如果使用這個(gè) API 的時(shí)候一般會(huì)和下面的幾種方式結(jié)合使用。

      二、使用 JQuery 的 offset().top 實(shí)現(xiàn)

      我們知道 JQuery 中封裝了操作 DOM 和讀取 DOM 計(jì)算屬性的 API,基于 offset().top 這個(gè) API 和 scrollTop() 的結(jié)合,我們也可以實(shí)現(xiàn)滾動(dòng)吸頂效果。

      ...
      window.addEventListener('scroll', self.handleScrollOne);
      ...
      handleScrollOne: function() {
          let self = this;
          let scrollTop = $('html').scrollTop();
          let offsetTop = $('.title_box').offset().top;
          self.titleFixed = scrollTop > offsetTop;
      }
      ...

      這樣實(shí)現(xiàn)固然可以,不過(guò)由于 JQuery 慢慢的退出歷史的舞臺(tái),我們?cè)诖a中盡量不使用 JQuery 的 API。我們可以基于 offset().top 的源碼自己處理原生 offsetTop。于是乎就有了第三種方式。

      scrolloTop() 有兼容性問(wèn)題,在微信瀏覽器、IE、某些 firefox 版本中 $('html').scrollTop() 的值會(huì)為 0,于是乎也就有了第三種方案的兼容性寫法。

      三、使用原生的 offsetTop 實(shí)現(xiàn)

      我們知道 offsetTop 是相對(duì)定位父級(jí)的偏移量,倘若需要滾動(dòng)吸頂?shù)脑爻霈F(xiàn)定位父級(jí)元素,那么 offsetTop 獲取的就不是元素距離頁(yè)面頂部的距離。

      我們可以自己對(duì) offsetTop 做以下處理:

      getOffset: function(obj,direction){
          let offsetL = 0;
          let offsetT = 0;
          while( obj!== window.document.body && obj !== null ){
              offsetL += obj.offsetLeft;
              offsetT += obj.offsetTop;
              obj = obj.offsetParent;
          }
          if(direction === 'left'){
              return offsetL;
          }else {
              return offsetT;
          }
      }

      使用:

      ...
      window.addEventListener('scroll', self.handleScrollTwo);
      ...
      handleScrollTwo: function() {
          let self = this;
          let scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
          let offsetTop = self.getOffset(self.$refs.pride_tab_fixed);
          self.titleFixed = scrollTop > offsetTop;
      }
      ...

      你是不是看出了以上兩種方式的一些問(wèn)題?

      我們一定需要使用 scrollTop - offsetTop 的值來(lái)實(shí)現(xiàn)滾動(dòng)吸頂?shù)男Ч麊幔看鸢甘欠穸ǖ摹?/p>

      我們一同看看第四種方案。

      四、使用 obj.getBoundingClientRect().top 實(shí)現(xiàn)

      定義:這個(gè) API 可以告訴你頁(yè)面中某個(gè)元素相對(duì)瀏覽器視窗上下左右的距離。

      使用:tab 吸頂可以使用 obj.getBoundingClientRect().top 代替 scrollTop - offsetTop,代碼如下:

      // html
      
          
              // some code
          
        // vue export default {     data(){       return{         titleFixed: false       }     },     activated(){       this.titleFixed = false;       window.addEventListener('scroll', this.handleScroll);     },     methods: {       //滾動(dòng)監(jiān)聽,頭部固定       handleScroll: function () {         let offsetTop = this.$refs.pride_tab_fixed.getBoundingClientRect().top;         this.titleFixed = offsetTop < 0;         // some code       }     }   }

      offsetTop 和 getBoundingClientRect() 區(qū)別

      1. getBoundingClientRect():

      用于獲得頁(yè)面中某個(gè)元素的左,上,右和下分別相對(duì)瀏覽器視窗的位置。不包含文檔卷起來(lái)的部分。

      css怎么實(shí)現(xiàn)滾動(dòng)吸頂

      該函數(shù)返回一個(gè) object 對(duì)象,有8個(gè)屬性:top, right, buttom, left, width, height, x, y

      css怎么實(shí)現(xiàn)滾動(dòng)吸頂

      2. offsetTop:

      用于獲得當(dāng)前元素到定位父級(jí)( element.offsetParent )頂部的距離(偏移值)。

      定位父級(jí) offsetParent 的定義是:與當(dāng)前元素最近的 position != static 的父級(jí)元素。

      offsetTop 和 offsetParent 方法相結(jié)合可以獲得該元素到 body 上邊距的距離。代碼如下:

      getOffset: function(obj,direction){
          let offsetL = 0;
          let offsetT = 0;
          while( obj!== window.document.body && obj !== null ){
              offsetL += obj.offsetLeft;
              offsetT += obj.offsetTop;
              obj = obj.offsetParent;
          }
          if(direction === 'left'){
              return offsetL;
          }else {
              return offsetT;
          }
      }

      延伸知識(shí)點(diǎn)

      offsetWidth:

      元素在水平方向上占用的空間大小:

      offsetWidth =  border-left + padding-left + width + padding-right + border-right

      offsetHeight:

      元素在垂直方向上占用的空間大小:

      offsetHeight =  border-top + padding-top + height + padding-bottom + border-bottom

      注:如果存在垂直滾動(dòng)條,offsetWidth 也包括垂直滾動(dòng)條的寬度;如果存在水平滾動(dòng)條,offsetHeight 也包括水平滾動(dòng)條的高度;

      offsetTop:

      元素的上外邊框至 offsetParent 元素的上內(nèi)邊框之間的像素距離;

      offsetLeft:

      元素的左外邊框至 offsetParent 元素的左內(nèi)邊框之間的像素距離;

      注意事項(xiàng)

      1. 所有偏移量屬性都是只讀的;

      2. 如果給元素設(shè)置了 display:none,則它的偏移量屬性都為 0;

      3. 每次訪問(wèn)偏移量屬性都需要重新計(jì)算(保存變量);

      4. 在使用的時(shí)候可能出現(xiàn) DOM 沒(méi)有初始化,就讀取了該屬性,這個(gè)時(shí)候會(huì)返回 0;對(duì)于這個(gè)問(wèn)題我們需要等到 DOM 元素初始化完成后再執(zhí)行。

      遇到的兩個(gè)問(wèn)題

      一、吸頂?shù)哪且豢贪殡S抖動(dòng)

      出現(xiàn)抖動(dòng)的原因是因?yàn)椋涸谖斣?position 變?yōu)?fixed 的時(shí)候,該元素就脫離了文檔流,下一個(gè)元素就進(jìn)行了補(bǔ)位。就是這個(gè)補(bǔ)位操作造成了抖動(dòng)。

      解決方案

      為這個(gè)吸頂元素添加一個(gè)等高的父元素,我們監(jiān)聽這個(gè)父元素的 getBoundingClientRect().top 值來(lái)實(shí)現(xiàn)吸頂效果,即:

      
          
          使用 `obj.getBoundingClientRect().top` 實(shí)現(xiàn)
          

      這個(gè)方案就可以解決抖動(dòng)的 Bug 了。

      二、吸頂效果不能及時(shí)響應(yīng)

      這個(gè)問(wèn)題是我比較頭痛,之前我沒(méi)有在意過(guò)這個(gè)問(wèn)題。直到有一天我用美團(tuán)點(diǎn)外賣的時(shí)候,我才開始注意這個(gè)問(wèn)題。

      描述:

      1. 當(dāng)頁(yè)面往下滾動(dòng)時(shí),吸頂元素需要等頁(yè)面滾動(dòng)停止之后才會(huì)出現(xiàn)吸頂效果

      2. 當(dāng)頁(yè)面往上滾動(dòng)時(shí),滾動(dòng)到吸頂元素恢復(fù)文檔流位置時(shí)吸頂元素不恢復(fù)原樣,而等頁(yè)面停止?jié)L動(dòng)之后才會(huì)恢復(fù)原樣

      原因:

      在 ios 系統(tǒng)上不能實(shí)時(shí)監(jiān)聽 scroll 滾動(dòng)監(jiān)聽事件,在滾動(dòng)停止時(shí)才觸發(fā)其相關(guān)的事件。

      解決方案:

      還記得第一種方案中的 position:sticky 嗎?這個(gè)屬性在 IOS6 以上的系統(tǒng)中有良好的兼容性,所以我們可以區(qū)分 IOS 和 Android 設(shè)備做兩種處理。

      IOS 使用 position:sticky,Android 使用滾動(dòng)監(jiān)聽 getBoundingClientRect().top 的值。

      如果 IOS 版本過(guò)低呢?這里提供一種思路:window.requestAnimationFrame()。

      性能優(yōu)化篇(新增)


      到此 4 中滾動(dòng)吸頂?shù)姆绞浇榻B完了,可是這樣就真的結(jié)束了嗎?其實(shí)還是有優(yōu)化的空間的。
      我們從兩個(gè)方向做性能優(yōu)化(其實(shí)是一個(gè)方向):

      1. 避免過(guò)度的 reflow

      2. 優(yōu)化滾動(dòng)監(jiān)聽事件

      問(wèn)題定位過(guò)程

      我們知道過(guò)度的 reflow 會(huì)使頁(yè)面的性能下降。所以我們需要盡可能的降低 reflow 的次數(shù),給用戶更加流暢的感覺(jué)。

      有的朋友或許會(huì)說(shuō)這個(gè)我知道,可是這和滾動(dòng)吸頂有什么關(guān)系呢?

      不急,你是否還記得滾動(dòng)吸頂使用了 offsetTop 或者 getBoundingClientRect().top 來(lái)獲取響應(yīng)的偏移量呢?

      既然有讀取元素的屬性就自然會(huì)導(dǎo)致頁(yè)面 reflow。

      因此我們優(yōu)化的方向就是從減少讀取元素屬性次數(shù)下手,查看代碼發(fā)現(xiàn)一觸發(fā)屏幕滾動(dòng)事件就會(huì)調(diào)用相關(guān)方法讀取元素的偏移量。

      優(yōu)化方案

      解決這個(gè)問(wèn)題有以下兩個(gè)方案:

      1. 犧牲平滑度滿足性能,使用節(jié)流控制相關(guān)方法的調(diào)用

      2. 使用 IntersectionObserver 和節(jié)流結(jié)合,也犧牲了平滑度。

      第一種方案

      這個(gè)方案很常見,不過(guò)其帶來(lái)的副作用也很明顯,就是在吸頂效果會(huì)有些延遲,如果產(chǎn)品可以接受那就不失為一種好方法。

      這樣可以控制在一定時(shí)間內(nèi)只讀取

      這里節(jié)流函數(shù)就直接是用 lodash.js 封裝好的 throttle 方法。

      代碼如下:

      window.addEventListener('scroll', _.throttle(self.handleScrollThree, 50));

      第二種方案

      第二種方案相對(duì)來(lái)說(shuō)容易接受一點(diǎn),就是支持 IntersectionObserver 就用 IntersectionObserver,否則就用 throttle。

      我們先講講 IntersectionObserver

      IntersectionObserver 可以用來(lái)監(jiān)聽元素是否進(jìn)入了設(shè)備的可視區(qū)域之內(nèi),而不需要頻繁的計(jì)算來(lái)做這個(gè)判斷。

      通過(guò)這個(gè)屬性我們就可以在元素不在可視范圍內(nèi),不去讀取元素的相對(duì)位置,已達(dá)到性能優(yōu)化;當(dāng)瀏覽器不支持這個(gè)屬性的時(shí)候就使用 throttle 來(lái)處理。

      我們看看這個(gè)屬性的兼容性怎么樣:

      css怎么實(shí)現(xiàn)滾動(dòng)吸頂

      大概支持了 60% 以上,在項(xiàng)目中還是可以使用的(你需要做好兼容性處理)。

      關(guān)于 IntersectionObserver 如何使用,請(qǐng)看MDN 或者阮一峰教程。

      使用 IntersectionObserver 和 throttle 優(yōu)化的代碼如下:

      IntersectionObserverFun: function() {
          let self = this;
          let ele = self.$refs.pride_tab_fixed;
          if( !IntersectionObserver ){
              let observer = new IntersectionObserver(function(){
                  let offsetTop = ele.getBoundingClientRect().top;
                  self.titleFixed = offsetTop < 0;
              }, {
                  threshold: [1]
              });
              observer.observe(document.getElementsByClassName('title_box')[0]);
          } else {
              window.addEventListener('scroll', _.throttle(function(){
                  let offsetTop = ele.getBoundingClientRect().top;
                  self.titleFixed = offsetTop < 0;
              }, 50));
          }
      },

      注意

      IntersectionObserver API 是異步的,不隨著目標(biāo)元素的滾動(dòng)同步觸發(fā)。

      規(guī)格寫明,IntersectionObserver的實(shí)現(xiàn),應(yīng)該采用 requestIdleCallback()。它不會(huì)立即執(zhí)行回調(diào),它會(huì)調(diào)用 window.requestIdleCallback() 來(lái)異步的執(zhí)行我們指定的回調(diào)函數(shù),而且還規(guī)定了較大的延遲時(shí)間是 100 毫秒。

      以上是“css怎么實(shí)現(xiàn)滾動(dòng)吸頂”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!


      新聞名稱:css怎么實(shí)現(xiàn)滾動(dòng)吸頂-創(chuàng)新互聯(lián)
      網(wǎng)頁(yè)鏈接:http://ef60e0e.cn/article/dphcsh.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        嘉荫县| 舟曲县| 镇宁| 宜黄县| 崇文区| 九江县| 芜湖县| 祥云县| 陆良县| 盐池县| 汨罗市| 依兰县| 左权县| 阳曲县| 漠河县| 舒城县| 莱芜市| 临邑县| 黑龙江省| 澄江县| 左云县| 包头市| 凤山市| 柏乡县| 睢宁县| 财经| 民勤县| 清新县| 新沂市| 通州市| 霞浦县| 常宁市| 沁源县| 大同县| 马山县| 什邡市| 宜川县| 页游| 丰镇市| 察哈| 垣曲县|