摘要:讓網頁渲染如絲順滑本文轉載自眾成翻譯譯者文藺鏈接原文發布在即。另一部分是繪制與合成,這正是渲染器的工作。兩幀之間的時間被稱為幀預算。因此要確保在顯示器再次檢查前將所有像素放入幀緩沖區。將頁面分成圖層,拓展了最佳情形數量。
WebRender:讓網頁渲染如絲順滑
本文轉載自:眾成翻譯
譯者:文藺
鏈接:http://www.zcfy.cc/article/4386
原文:https://hacks.mozilla.org/2017/10/the-whole-web-at-maximum-fps-how-webrender-gets-rid-of-jank
Firefox Quantum 發布在即。它帶來了許多性能改進,包括從 Servo 引入的的極速 CSS 引擎。
但 Servo 中的很大一塊技術尚未被 Firefox Quantum 引入,雖然已經為期不遠。這就是WebRender,它是 Quantum Render 項目的一部分,正被添加到 Firefox 中。
WebRender 以極速著稱,但它所做的并非加速渲染,而是使渲染結果更加平滑。
依靠 WebRender,我們希望應用程序以每秒 60 幀(FPS)乃至更快的速度運行:無論顯示器有多大,頁面每幀發生多少變化。這是可以做到的。在 Chrome 和當前版本的 Firefox 中,某些頁面卡到只有 15 FPS,而使用 WebRender 則能達到 60 FPS。
WebRender 是如何做到這些的呢?它從根本上改變了渲染引擎的工作方式,使其更像 3D 游戲引擎。
一起來看看這話怎么說。
渲染器的工作在關于 Stylo 的文章中,我討論了瀏覽器如何將 HTML 和 CSS 轉換為屏幕上的像素,并提到大多數瀏覽器通過五個步驟完成此操作。
可以將這五個步驟分成兩部分來看。前一部分基本上是在構建計劃:渲染器將 HTML 和 CSS 以及視口大小等信息結合起來,確定每個元素應該長成什么樣(寬度,高度,顏色等)。最終得到的結果就是幀樹 (frame tree),又稱作渲染樹(render tree)。
另一部分是繪制與合成(painting and compositing),這正是渲染器的工作。渲染器將前一部分的結果轉換成顯示在屏幕上的像素。
對同一個網頁來說,這個工作不是只做一次就夠,而必須反復進行。一旦網頁發生變化(如某個 div 發生切換 ),瀏覽器需再次經歷這當中的很多步驟。
即便頁面并未發生變化(如頁面滾動,或某些文本高亮),瀏覽器仍需進行第二部分中的某些步驟,接著在屏幕上繪制新的內容。
想要滾動、動畫等操作看起來流暢,必須以 60 幀每秒的速度進行渲染。
每秒幀數(FPS)這個術語,也許你早有耳聞,但可能不確定其意義。想象你手上有一本手翻書(Flip Book)。一本畫滿靜態繪畫的書,用手指快速翻轉,畫面看起來就像動起來了。
為了使這本手翻書的動畫看起來平滑,每秒需要翻過 60 頁。
這本書的是由圖紙制成的。紙上有許許多多的小方格,每個方格只能填上一種顏色。
渲染器的工作就是給圖紙中的方格填色。填滿圖紙中的所有方格,一幀的渲染就完成了。
當然,計算機當中并不存在真實的圖紙。而是一段名為幀緩沖區(frame buffer)的內存。幀緩沖區中的每個內存地址就像圖紙中的一個方格...它對應著屏幕上的像素。瀏覽器將使用數字填充每個位置,這些數字代表 RGBA(紅、綠、藍以及 alpha 通道)形式的顏色值。
當顯示器需要刷新時,將會查詢這一段內存。
多數電腦顯示器每秒會刷新 60 次。這就是瀏覽器嘗試以每秒 60 幀的速度渲染頁面的原因。這意味著瀏覽器有16.67 ms 的時間來完成所有工作(CSS 樣式,布局,繪制),并使用像素顏色填充幀緩沖區內存。兩幀之間的時間(16.67ms)被稱為幀預算(frame budget)。
有時你可能聽到人們談論丟幀的問題。所謂丟幀,是系統未能在幀預算時間內未完成工作。緩沖區顏色填充工作尚未完成,顯示器就嘗試讀取新的幀。這種情況下,顯示器會再次顯示舊版的幀信息。
丟幀就像是從手翻書中撕掉一個頁面。這樣一來,動畫看上去就像消失或跳躍一樣,因為上一頁和下一頁之間的轉換頁面丟失了。
因此要確保在顯示器再次檢查前將所有像素放入幀緩沖區。來看看瀏覽器以前是如何做的,后來又發生了哪些變化。從中可以發現提速空間。
繪制、合成簡史注意:繪制與合成是不同渲染引擎之間最為不同的地方。_單一平臺瀏覽器(Edge 和 Safari)的工作方式與跨平臺瀏覽器(Firefox 和 Chrome)有所不同。_
即便是最早的瀏覽器也有一些優化措施,使頁面渲染速度更快。例如在滾動頁面的時候,瀏覽器會保留仍然可見的部分并將其移動。然后在空白處中繪制新的像素。
搞清楚發生變化的內容,只更新變動的元素或像素,這個過程稱為失效處理(invalidation)。
后來,瀏覽器開始應用更多的失效處理技術,如矩形失效處理(rectangle invalidation)。矩形失效處理技術可以找出屏幕中包圍每個發生改變的部分的最小矩形。然后只需重繪這些矩形中的內容。
頁面變化不大時,這確實能夠減少大量工作。比如說,光標閃動。
但如果頁面大部分內容發生變化,這就不夠用了。所以又出現了處理這些情況的新技術。
圖層與合成介紹當頁面的大部分發生變化時,使用圖層(layer)會方便很多...至少在某些情況下是如此。
瀏覽器中的圖層很像 Photoshop 中的圖層,或手繪動畫中使用的洋蔥皮層。大體說來就是在不同圖層上繪制不同元素。然后可以調整這些圖層的相對層級關系。
這些一直以來就是瀏覽器的一部分,但并不總是用于加速。起初,它們只是用來確保頁面正確呈現d。它們對應于堆疊上下文(stacking contexts)。
例如一個半透明元素將在自己的堆疊上下文中。這意味著它有自己的圖層,所以你可以將其顏色與下面的顏色混合。一幀完成后,這些圖層就被丟棄。在下一幀中,所有圖層將再次重繪。
但是,這些圖層中的東西在不同幀之間常常沒有變化。想一下那種傳統的動畫。背景不變,只有前景中的字符發生變化。保留并重用背景圖層,效率會更高。
這就是瀏覽器所做的。它保留了這些圖層。然后瀏覽器可以僅重繪已經改變的圖層。在某些情況下,圖層甚至沒有改變。它們只需要重新排列:例如動畫在屏幕上移動,或是某些內容發生滾動。
組織圖層的過程稱為合成。合成器(compositor)從這兩部分開始:
源位圖:背景(包括可滾動內容所占的空白框)和可滾動內容本身
目標位圖:屏幕所顯示的位圖
首先,合成器將背景復制到目標位圖中。
然后找到可滾動內容中應該展示的部分。將該部分復制到目標位圖。
這減少了主線程的繪制量。但這意味著主線程需要花費大量時間進行合成。而還有很多工作在主線程上爭奪時間。
以前我已經談過這個問題,主線程有些像一個全棧開發者。它負責 DOM,布局和 JavaScript。并且還負責繪制與合成。
主線程花費多少毫秒進行繪制、合成,就有多少毫秒無法用于 JavaScript 和布局。
而另一部分硬件正在閑置,沒有多少工作要做。這個硬件是專門用于圖形的。它就是 GPU。自 90 年代末以來,游戲一直在使用 GPU 加速渲染幀。自那以后,GPU 日益強大。
GPU 加速合成所以瀏覽器開發者開始把事情轉移給 GPU 來處理。
有兩項任務可以轉交給 GPU:
1. 圖層繪制
2. 圖層合成
將繪制工作交給 GPU 可能比較棘手。所以在多數情況下,跨平臺瀏覽器依然通過 CPU 進行繪制。
但 GPU 可以很快完成合成工作,轉移過來比較簡單。
一些瀏覽器在這種并行方法上走得更遠,直接在 CPU 上添加了一個合成器線程。由它管理 GPU 中發生的合成工作。這意味著如果主線程正在執行某些操作(如運行 JavaScript),則合成器線程仍然可以處理其他工作,如在用戶滾動時滾動內容。
這樣就將所有合成工作從主線程中移出。盡管如此,它仍然在主線程上留下了大量的工作。圖層需要重繪時,主線程需要執行繪制工作,然后將該圖層轉移給 GPU。
有些瀏覽器將繪制工作移動到另一個線程中(目前 Firefox 正致力于此)。但將繪制這點工作轉移到 GPU 上,速度會更快。
GPU 加速繪制因此,瀏覽器也開始將繪制工作轉移到 GPU。
這項轉變工作仍在進行中。一些瀏覽器一直通過 GPU 繪制,另一些瀏覽器只能在某些平臺上(如 Windows 或移動設備)這么做。
GPU 繪制能夠解決一些問題。CPU 得以解放,專心處理 JavaScript 和布局g"z。此外,GPU 繪制像素比 CPU 快得多,因此它可以加快繪制速度。這也意味著從 CPU 復制到 GPU 的數據要更少了。
但是,在繪制與合成工作之間保持這種區分仍然會產生一定的成本,即使它們都在 GPU 上進行。這么區分,還限制了能夠采用的優化的種類,它們可以使 GPU工作更快。
這就是WebRender 所要解決的問題。它從根本上改變了渲染方式,消除了繪制和合成之間的區別。這種解決渲染器性能的方法,能夠在當下網絡中提供最佳用戶體驗,并為未來網絡提供最好的支持。
這意味著,我們要做的不僅僅是想使幀渲染更快...我們希望使渲染更加一致,不會發生閃動。即便有大量需要繪制的像素,如 4k 顯示器或 WebVR 設備,我們仍希望體驗能夠平滑一些。
當前的瀏覽器何時會發生閃動 ?在某些情況下,上述優化能夠加速頁面渲染。當頁面上沒有太多變化時(如只有光標在閃爍),瀏覽器將進行盡量少的工作。
將頁面分成圖層,拓展了最佳情形數量。繪制數個圖層,并讓它們相對于彼此移動,則“繪畫+合成”架構效果非常好。
但圖層的使用也需要有所權衡。這將占用不少內存,實際可能會減慢工作。瀏覽器需要組合有意義的圖層。但是很難區分怎樣是有意義的。
這意味著,如果頁面中有很多不同的東西在移動,圖層可能會過多。這些圖層占滿內存,需要花費很長時間才能傳輸到合成器。
另一些時候,需要多個圖層時,卻可能只得到一個圖層。這個圖層將會不斷重繪并轉移到合成器,進行合成工作而不改變任何東西。
這意味著你已經將繪制量翻了一番,每個像素都處理了兩遍,毫無益處。跨過合成這一步,直接呈現頁面會更快。
還有很多情況下,圖層用處不大。如對背景色使用動畫效果,則整個圖層都必須重繪。這些圖層只能幫助少量的 CSS 屬性。
即使大部分幀都是最佳情形(也就是說,它們只占用了幀預算的一小部分), 動作仍可能不穩定。只要三兩幀落入最壞情況,就會產生可感知的閃動。
這些情況稱為性能懸崖(performance cliffs)。應用程序一直平穩運行,直到遇到這些最壞情況(如背景色動畫),幀率瞬間瀕臨邊緣。
不過,這些性能懸崖是可以規避的。
如何做到這一點呢?緊隨3D 游戲引擎的腳步。
像游戲引擎一樣使用 GPU如果停止嘗試猜測需要什么圖層呢?如果移除繪制與合成之間邊界,僅考慮每一幀繪制像素呢?
這聽起來似乎很荒謬,但實際有先例可循。現代視頻游戲重新繪制每個像素,并且比瀏覽器更可靠地保持每秒 60 幀。他們以一種意想不到的方式做到了這一點...他們只是重繪整個屏幕,無需創建那些用于最小化繪制內容的失效處理矩形和圖層。
這樣渲染網頁不會更慢嗎?
如果在 CPU 上繪制的話,的確會更慢。但 GPU 就是用來做這事的。
GPU 正是用于進行極端并行處理的。我在上一篇關于 Stylo 的文章中談到過并行的問題。通過并行,機器可以同時執行多種操作。它可以一次完成的任務數量,取決于內核數量。
CPU 通常有 2 到 8 個內核。GPU 往往至少有幾百個內核,通常有超過 1,000 個內核。
雖然這些內核的工作方式有所不同。它們不能像 CPU 內核那樣完全獨立地運行。相反,它們通常一起工作,在數據的不同部分執行相同指令。
填充像素時, 我們正需要這樣。每個像素可以由不同的內核填充。一次能夠操作數百個像素,GPU 在像素處理方面上比 CPU 要快很多...當所有內核都在工作時確實如此。
由于內核需要同時處理相同的事情,因此 GPU 具有非常嚴格的步驟,它們的 API 非常受限。我們來看看這是如何工作的。
首先,你需要告訴 GPU 需要繪制什么。這意味著給它傳遞形狀,并告知如何填充。
要達到目的,首先將繪圖分解成簡單形狀(通常是三角形)。這些形狀處于 3D 空間中,所以一些形狀可以在其他形狀背后。然后將三角形所有角頂點的 x、y、z 坐標組成一個數組。
然后發出一個繪圖調用 —— 告訴GPU來繪制這些形狀。
接下來由 GPU 接管。所有的內核將同時處理同一件事情。它們會:
找到形狀的所有角頂點位置。這被稱為頂點著色(vertex shading)。
找出連接這些角頂點的線條。由此可以得到哪些像素被形狀所覆蓋。這就是所謂的光柵化(rasterization)。
已經知道形狀所覆蓋的像素了,就可以遍歷每個像素,確定該像素的顏色。這稱為像素著色(pixel shading)。
最后一步可以通過不同的方式完成。要告訴 GPU 如何處理,可以傳給 GPU 一個稱為像素著色器的程序。像素著色是 GPU 中可編程的幾個部分之一。
一些像素著色器很簡單。例如形狀是單一顏色的,則著色器程序只需要為形狀中的每個像素返回同一個顏色。
另外一些情況更復雜,例如有背景圖像的時候,需要搞清楚圖像對應于每個像素的部分。可以像藝術家縮放圖像一樣…在圖像上放置一個網格,與每個像素相對應。這樣一來,只需知道某個像素所對應的區域,然后對該區域進行顏色取樣即可。這被稱為紋理映射(texture mapping),因為它將圖像(稱為紋理)映射到像素。
針對每個像素,GPU 會調用像素著色器程序。不同內核可以同時在不同的像素上并行工作,但是它們都需要使用相同的像素著色器程序。命令 GPU 繪制形狀時,你會告訴它使用哪個像素著色器。
對幾乎所有網頁來說,頁面的不同部分將需要使用不同的像素著色器。
在一次繪制中,著色器會作用域所有形狀,所以通常需要將繪制工作分為多個組。這些稱為批處理(batches)。為了盡可能利用所有內核,創建一定數量的批處理工作,每個批次包括大量形狀。
這就是 GPU 如何在數百或數千個內核上切分工作的。正是因為這種極端的并行性,我們才能想到在每一幀中渲染所有內容。即便有這樣極端的并行性,要做的工作還是很多。解決起來還需要費些腦筋。該 WebRender 出場了……
WebRender 如何利用 GPU回過頭再看下瀏覽器渲染網頁的步驟。這里將產生兩個變化。
1. 繪制與合成之間不再有區別。它們都是同一步驟的一部分。GPU 根據傳遞給它的圖形 API 命令同時執行它們。
2. 布局步驟將產生一種不同的數據結構。之前是幀樹(或 Chrome 中的渲染樹)。現在將產生一個顯示列表(display list)。
顯示列表是一組高級繪圖指令。它告訴我們需要繪制什么,并不指定任何圖形 API。
每當有新東西要繪制時,主線程將顯示列表提供給 RenderBackend,這是在 CPU 上運行的 WebRender 代碼。
RenderBackend 的工作是將這個高級繪圖指令列表轉換成 GPU 需要的繪圖調用,這些繪圖調用被分在同一批次,加快運行速度。
然后,RenderBackend 將把這些批次傳遞給合成器線程,合成器線程再將它們傳遞給 GPU。
RenderBackend 傳遞給 GPU 的繪圖調用需要盡可能快運行。它為此使用了幾種不同的技術。
從列表中刪除任何不必要的形狀(早期剔除)節省時間的最好辦法是什么都不做。
首先,RenderBackend 可以減少顯示列表項目。它會識別哪些項目將真正出現在屏幕上。為此,它將查看一些東西,如每個滾動盒的滾動距離。
如果形狀的某些部分在盒子內,則該形狀將被包括在需要繪制的列表中。否則將被刪除。這個過程叫做早期剔除。
最小化中間紋理數量(渲染任務樹)現在有了一個樹狀結構,其中只包含將要用到的形狀。這個樹被組織成此前提過的堆疊上下文。
鏈接文字
CSS filter 和堆疊上下文等這些效果,讓事情變得復雜了。假設有一個透明度為 0.5 的元素,該元素包含子元素。你可能覺得每個子元素都將是透明的……但實際上整個組才是透明的。
因此需要先將該組渲染為一個紋理,每個子元素都是不透明的。然后,將子元素加入到父元素中時,可以更改整個紋理的透明度。
這些堆疊上下文可以嵌套...該父元素可能是另一個堆疊上下文的一部分。這意味著它必須被渲染成另一個中間紋理……
為這些紋理創建空間代價不菲。我們想盡可能將事物分組到相同的中間紋理。
為了幫助 GPU 執行此操作,需要創建一個渲染任務樹。有了它,就能夠知道在其他紋理之前需要創建哪些紋理。任何不依賴于其他紋理的紋理都可以在首次創建,這意味著它們可以與那些中間紋理中組合在一起。
所以在上面的例子中,我們先輸出 box shadow 的一個角。(實際比這更復雜一點,但這是要點)。
第二遍的時候,可以將這個角通過鏡像放置到盒子的各個部分。然后就可以完全不透明地渲染該組。
接下來,我們需要做的就是改變這個紋理的不透明度,并將其放在需要輸入到屏幕的最終紋理中。
通過構建這個渲染任務樹,可以找出需要使用的離屏渲染目標的最小數量。這很好,前面已經提到過,為這些渲染目標紋理創建空間的代價不菲。
這也有利于分批處理。
繪制調用分組(批處理)前面已經提到過,需要創建一定量的批處理,每個批處理中包括大量形狀。
注意,創建批處理的方式真的能影響速度。同一批次中的形狀數量要盡可能多。這是由幾個原因決定的。
首先,當 CPU 告訴 GPU 進行繪圖調用時,CPU 必須做很多工作。它需要做很多工作,如啟動 GPU,上傳著色器程序和測試硬件 bug 等。并且當 CPU 進行這項工作時,GPU 可能是空閑的。
其次,改變狀態是會產生代價的。假設你需要在批處理之間更改著色器程序。在典型的 GPU 上,你需要等到所有內核都使用當前的著色器完成工作后。這被稱管道清空(draining the pipeline)。管道清空后,其他核心才會處于閑置狀態。
因此,批處理包含的東西要盡可能多。對于典型的 PC,每幀需要有100 次或更少的繪圖調用,每次調用中有數千個頂點。這樣就能充分利用并行性。
從渲染任務樹可以找出能夠批處理的內容。
目前,每種類型的圖元都需要一種著色器。例如邊框著色器,文本著色器,圖像著色器。
我們認為可以將很多著色器結合起來,這樣就能夠增加批處理容量。但目前這樣已經相當不錯了。
已經可以準備將它們發送給 GPU 了。但其實還可以做一些排除工作。
減少像素著色(Z-剔除)大多數網頁中都有大量相互重疊的形狀。例如,文本框位于某個帶有背景的 div 之中,而該 div 又在帶有另一個背景的 body 中。
GPU 在計算每個像素的顏色時,能夠計算出每個形狀中的像素顏色。但只有頂層才會顯示。這被稱為 overdraw,它浪費了 GPU 時間。
所以我們可以先渲染頂部的形狀。繪制下一個形狀時,遇到同一像素,先檢查是否已經有值。如果有值,則跳過。
不過這有一點點問題。當形狀是半透明的時候,需要混合兩種形狀的顏色。為了讓它看起來正確,需要從里向外繪制。
所以需要把工作分成兩道。首先做不透明的一道工作。由表及里,渲染所有不透明的形狀。跳過位于其他像素背后的像素。
然后處理半透明形狀。工作由內向外進行。如果半透明像素落在不透明像素的頂部,則會混合到不透明的像素中。如果它會落在不透明形狀之后,則忽略計算。
將工作分解為不透明和 alpha 通道兩部分,跳過不需要的像素計算,這個過程稱為 Z-剔除(Z-culling)。
這看起來只是一個簡單的優化,但對我們來說已經是很大的成功了。在典型的網頁上,該工作大大減少了我們需要處理的像素數量,目前我們正在研究如何將更多的工作轉移到不透明這一步。
到目前為止,我們已經準備好了一幀的內容。我們已經盡可能地減少了工作。
準備繪制我們準備好啟動 GPU 并渲染各個批次了。
警告:不是一切都靠 GPUCPU 仍然需要做一些繪制工作。例如,我們仍然使用 CPU 渲染文本塊中的字符(稱為字形,glyphs)。在 GPU 上也可以執行此操作,但是很難獲得與計算機在其他應用程序中呈現的字形相匹配的像素效果。所以 GPU 渲染的字體看起來會有一種錯亂感。我們正在嘗試通過 Pathfinder 項目將字形等工作轉移到 GPU 上。
這些內容目前是被 CPU 繪制成位圖的。然后把它們上傳到 GPU 的紋理緩存中。這個緩存在不同幀之間被保留,因為它們通常不會改變。
雖然這種繪制工作是由 CPU 完成的,但速度仍有提升空間。例如,使用某種字體繪制字符時,我們會將不不同的字符分割開,使用不同內核分別渲染。這和Stylo 用來并行計算樣式的技術是相同的……參見這里。
WebRender 接下來的工作在 Firefox Quantum 發布之后的若干版本后,WebRender 有望在 2018 年作為Quantum Render 項目的一部分,出現在 Firefox 中。這將使當今的網頁運行更順暢。隨著屏幕上的像素數量的增加,渲染性能變得越來越重要,因此 WebRender 還可以讓 Firefox 為新一波的高分辨率 4K 顯示器做好準備。
但 WebRender 不僅僅適用于 Firefox。它對于正在開展的 WebVR 的工作同樣至關重要,在 WebVR 中,需要為在 4K 顯示器上以 90 FPS 的速度為每只眼睛渲染不同的幀。
WebRender 的早期版本目前可以通過 Firefox 的 flag 來啟用。集成工作仍在進行中,所以性能目前還不如工作完成hou那么好。如果你想跟進 WebRender 開發,可以關注GitHub repo,或者關注Firefox Nightly 的Twitter,以獲得 Quantum Render 項目的更新周報。
關于作者Lin Clark
Lin 是 Mozilla 開發者關系團隊的工程師。她在鼓搗 JavaScript,WebAssembly,Rust 和 Servo,以及繪制代碼漫畫。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/115528.html
摘要:讓網頁渲染如絲順滑本文轉載自眾成翻譯譯者文藺鏈接原文發布在即。另一部分是繪制與合成,這正是渲染器的工作。兩幀之間的時間被稱為幀預算。因此要確保在顯示器再次檢查前將所有像素放入幀緩沖區。將頁面分成圖層,拓展了最佳情形數量。 WebRender:讓網頁渲染如絲順滑 本文轉載自:眾成翻譯譯者:文藺鏈接:http://www.zcfy.cc/article/4386原文:https://hac...
摘要:前端日報精選精讀殺雞用牛刀讓網頁渲染如絲順滑從上下文,到作用域彩蛋理解閉包網頁轉圖片技術分享中文第期反擊爬蟲,前端工程師的腦洞可以有多大浮點數陷阱及解法有用的代碼片段和免費的計算機編程類中文書籍,歡迎投稿核心特性理解 2017-10-15 前端日報 精選 精讀《css-in-js 殺雞用牛刀》WebRender:讓網頁渲染如絲順滑從上下文,到作用域(彩蛋:理解閉包)Vue 2.5 re...
摘要:由于是需要兼容的后臺系統,該項目并不能使用到等技術,因此我在上的經驗大都是使用原生的編寫的,可以看見一個組件分為兩部分視圖部分,和數據部分。 在公司里幫項目組里開發后臺系統的前端項目也有一段時間了。 vue這種數據驅動,組件化的框架和react很像,從一開始的快速上手基本的開發,到后來開始自定義組件,對element UI的組件二次封裝以滿足項目需求,期間也是踩了不少坑。由于將來很長一...
摘要:配置項配置項中的參數有以下三個所監聽對象的具體祖先元素,默認是計算交叉狀態時,將附加到祖先元素上,從而有效的擴大或者縮小祖先元素判定區域設置一系列的閾值,當交叉狀態達到閾值時,會觸發回調函數。 一、前言 ??通常情況下,HTML 中的圖片資源會自上而下依次加載,而部分圖片只有在用戶向下滾動頁面的場景下才能被看見,否則這部分圖片的流量就白白浪費了。 ??所以,對于那些含有大量圖片資源的網...
閱讀 2445·2021-10-13 09:40
閱讀 3334·2019-08-30 13:46
閱讀 1119·2019-08-29 14:05
閱讀 2952·2019-08-29 12:48
閱讀 3653·2019-08-26 13:28
閱讀 2141·2019-08-26 11:34
閱讀 2276·2019-08-23 18:11
閱讀 1155·2019-08-23 12:26