前面一篇文章:「高頻面試題」瀏覽器從輸入url到頁面展示中間發生了什么 中,我們有對瀏覽器的渲染流程做了一個概括性的介紹,今天這篇文章我們將深入學習這部分內容。
對于很多前端開發來說,平常做工主要專注于業務開發,對瀏覽器的渲染階段可能不是很了解。實際上這個階段很重要,了解瀏覽器的渲染過程,能讓我們知道我們寫的HTML、CSS、JS代碼是如何被解析,并最終渲染成一個頁面的,在頁面性能優化的時候有相應的解決思路。
我們先來看一個問題:
HTML、CSS、JS文件在瀏覽器中是如何轉化成頁面的?
如果你回答不上來,那就往下看吧。
按照渲染的時間順序,渲染過程可以分為下面幾個子階段:構建DOM樹、樣式計算、布局階段、分層、柵格化和合成顯示。
下面詳細看下每個階段都做了哪些事情。
HTML文檔描述一個頁面的結構,但是瀏覽器無法直接理解和使用HTML,所以需要通過HTML解析器將HTML轉換成瀏覽器能夠理解的結構——DOM樹。
HTML文檔中所有內容皆為節點,各節點之間有層級關系,彼此相連,構成DOM樹。
構建過程:讀取HTML文檔的字節(Bytes),將字節轉換成字符(Chars),依據字符確定標簽(Tokens),將標簽轉換成節點(Nodes),以節點為基準構建DOM樹。參考下圖:
打開Chrome的開發者工具,在控制臺輸入 document 后回車,就能看到一個完整的DOM樹結構,如下圖所示:
在控制臺打印出來的DOM結構和HTML內容幾乎一樣,但和HTML不同的是,DOM是保存在內存中的樹狀結構,可以通過JavaScript來查詢或修改其內容。
樣式計算這個階段,是為了計算出DOM節點中每個元素的表現樣式。
CSS樣式可以通過下面三種方式引入:
和HTML一樣,瀏覽器無法直接理解純文本的CSS樣式,需要通過CSS解析器將CSS解析成 styleSheets 結構,也就是我們常說的 CSSOM樹。
styleSheets結構同樣具備查詢和修改功能:
document.styleSheets
屬性值標準化看字面意思有點不好理解,我們通過下面一個例子來看看什么是屬性值標準化:
在寫CSS樣式的時候,我們在設置color屬性值的時候,經常會用white、red等,但是這種值瀏覽器的渲染引擎不容易理解,所以需要將所有值轉換成渲染引擎容易理解的、標準化的計算值,這個過程就是屬性值標準化。
white標準化后的值為 rgb(255, 255, 255)
完成樣式的屬性值標準化后,就需要計算每個節點的樣式屬性,這個階段CSS有兩個規則我們需要清楚:
樣式計算階段是為了計算出DOM節點中每個元素的具體樣式,在計算過程中需要遵守CSS的繼承和層疊兩個規則。
該階段最終輸出的內容是每個DOM節點的樣式,并被保存在 ComputedStyle 的結構中。
經過上面的兩個步驟,我們已經拿到了DOM樹和DOM樹中元素的樣式,接下來需要計算DOM樹中可見元素的幾何位置,這個計算過程就是布局。
在DOM樹中包含了一些不可見的元素,例如 head 標簽,設置了 display:none 屬性的元素,所以我們需要額外構建一棵只包含可見元素的布局樹。
構建過程:從DOM樹的根節點開始遍歷,將所有可見的節點加到布局樹中,忽略不可見的節點。
到這里我們就有了一棵構建好的布局樹,就可以開始計算布局樹節點的坐標位置了。從根節點開始遍歷,結合上面計算得到的樣式,確定每個節點對象在頁面上的具體大小和位置,將這些信息保存在布局樹中。
布局階段的輸出是一個盒子模型,它會精確地捕獲每個元素在屏幕內的確切位置與大小。
現在我們已經有了布局樹,也知道了每個元素的具體位置信息,但是還不能開始繪制頁面,因為頁面中會有像3D變換、頁面滾動、或者用 z-index 進行z軸排序等復雜效果,為了更方便實現這些效果,渲染引擎還需要為特定的節點生成專用的圖層,并生成一棵對應的圖層樹(LayerTree)。
在Chrome瀏覽器中,我們可以打開開發者工具,選擇 Elements-Layers 標簽,就可以看到頁面的分層情況,如下圖所示:
瀏覽器的頁面實際上被分成了很多圖層,這些圖層疊加后合成了最終的頁面。
到這里,我們構建了兩棵樹:布局樹和圖層樹。下面我們來看下這兩棵樹之間的關系:
正常情況下,并不是布局樹的每個節點都包含一個圖層,如果一個節點沒有對應的圖層,那么這個節點就從屬于父節點的圖層。
那節點要滿足什么條件才會被提升為一個單獨的圖層?只要滿足下面其中一個條件即可:
構建好圖層樹之后,渲染引擎就會對圖層樹中的每個圖層進行繪制。
渲染引擎實現圖層繪制,會把一個圖層的繪制拆分成很多小的繪制指令,然后將這些指令按照順序組成一個繪制列表。
繪制一個圖層時會生成一個繪制列表,這只是用來記錄繪制順序和繪制指令的列表,實際上繪制操作是由渲染引擎中的合成線程來完成的。
通過下圖來看下渲染主線程和合成線程之間的關系:
當圖層的繪制列表準備好后,主線程會把該繪制列表提交給合成線程,合成線程開始工作。
首先合成線程會將圖層劃分為圖塊(tile),圖塊大小通常是 256256 或者 512512。
然后合成線程會按照視口附近的圖塊來優先生成位圖,實際生成位圖的操作是由柵格化來執行的。所謂柵格化,是指將圖塊轉換為位圖。而圖塊是柵格化執行的最小單位。渲染進程維護了一個柵格化的線程池,所有的圖塊柵格化都是在線程池內執行的,運行方式如下圖所示:
一旦所有圖塊都被光柵化,合成線程就會生成一個繪制圖塊的命令——“DrawQuad”,然后將該命令提交給瀏覽器進程。
瀏覽器進程里面有一個名字叫做 viz 的組件,用來接收合成線程發過來的 DrawQuad 命令,然后根據命令執行。 DrawQuad 命令,將其頁面內容繪制到內存中,最后再將內存顯示在屏幕上。
多年開發老碼農福利贈送:網頁制作,網站開發,web前端開發,從最零基礎開始的的HTML+CSS+JavaScript。jQuery,Vue、React、Ajax,node,angular框架等到移動端小程序項目實戰【視頻+工具+電子書+系統路線圖】都有整理,需要的伙伴可以私信我,發送“前端”等3秒后就可以獲取領取地址,送給每一位對編程感興趣的小伙伴
一個完整的渲染流程可以總結如下:
渲染過程中還有兩個我們經常聽到的概念:重排和重繪。在這篇文章中就不細說了,下一篇文章再詳細介紹。
家好,我是 Echa。
今天來分享 50 個超實用的 Chrome 瀏覽器擴展!
JSON Viewer Pro 用于可視化JSON文件。其核心功能包括:
輸入界面如下:
格式化之后:
JSONVue 是一個JSON數據查看器,主要用來格式化JSON數據:
Library Sniffer 是一款給開發者使用的工具,能夠探測當前網頁所使用的類庫、框架和服務器環境,為開發者提供了方便。
Wappalyzer 擴展可以用來識別網站背后的底層技術。通過此擴展,可以了解特定應用程序是否是用 React、Vue、Angular、PHP等編寫的。還可以訪問有關 Web 服務器、編程語言、框架、內容管理系統、分析的信息工具、數據庫等。
WhatRuns 擴展程序只需單擊一下即可找到任何網站上使用的技術。
使用PerfectPixel插件可以將設計圖加載至網頁中,與已成型的網頁進行重疊對比,以幫助開發和設計人員規范網頁像素精度。這是一款可以優化前端頁面顯示的Chrome插件。
可以使用此擴展程序快速清除緩存,無需任何確認對話框、彈出窗口等。可以在選項頁面上自定義要清除的數據和數量,包括:應用程序緩存、緩存、Cookie、下載、文件系統、表單數據、歷史記錄、索引數據庫、本地存儲、插件數據、密碼和 WebSQL。
VisBug 是一個使用 JavaScript 構建的開源網頁設計調試工具,它可以讓用戶使用點擊式和拖放式界面來查看網站的元素。
Debug CSS 是一個幫助調試CSS的插件。他可以顯示出頁面元素的輪播,按住Ctrl,并將鼠標懸浮在元素上,即可查看其信息:
CSS Viewer 是一款適用于 Web 開發人員的高效 Chrome 擴展。顧名思義,CSS 查看器可以顯示將鼠標懸停在任何網頁上的元素的 CSS 屬性。
EditThisCookie 是一個 cookie 管理器。可以添加,刪除,編輯,搜索,鎖定和屏蔽cookies。
React Developer Tools 是開源 JavaScript 庫 React 的 Chrome DevTools 擴展。它允許我們在 Chrome 開發者工具中檢查 React 組件層次結構。安裝此插件之后,將在 Chrome DevTools 中獲得兩個新選項卡:"?? Components" 和 "?? Profiler":
Vue.js devtools 是一款基于chrome瀏覽器的用于調試Vue.js應用程序的插件,可以使得開發人員大大提高調試效率。支持用戶對DOM結構數據結構進行解析和調試功能。
Augury 可以幫助開發人員在 Google Chrome 瀏覽器中調試和分析 Angular 應用程序。
Firebug Lite是火狐瀏覽器中著名的開發者工具firebug插件移植到Chrome中的插件,在Chrome中安裝了Firebug Lite插件以后,開發人員可以像在火狐瀏覽器中使用firebug一樣熟悉的方式來調試網頁內容,其包含了基本的HTML、CSS以及Javascript的調試功能,用于幫助網頁前端開發工程師快速地調試網頁,以便及時地找到網頁中的BUG并及時修復。
HTML Validator 在 Chrome 的開發者工具中添加了 HTML Validator。HTML 頁面的錯誤數通過瀏覽器狀態欄中的圖標顯示,詳細信息可以在瀏覽器的開發者工具中查看。
Web Developer 擴展為帶有各種 Web 開發工具的瀏覽器添加了一個工具欄按鈕。該擴展適用于 Chrome 和 Firefox,并且可以在這些瀏覽器支持的任何平臺上運行,包括 Windows、macOS 和 Linux。
Requestly 是一款Chrome和Firefox瀏覽器插件,提供URL轉發、修改HTTP請求和結果、插入腳本等功能。
Window Resizer 主要用來調整瀏覽器窗口的大小以模擬各種屏幕分辨率。
Responsive Viewer 是在一個視圖中顯示多個屏幕的 Chrome 擴展程序。該擴展將幫助前端開發人員在開發響應式網站/應用程序時測試多個屏幕。
此插件允許直接從瀏覽器發送跨域請求,而不會收到跨域錯誤。可以使用此插件覆蓋 Request Origin 標頭,并將 Access-Control-Allow-Origin 設置為 *.
ColorPick Eyedropper 是一個放大的吸管和顏色選擇器工具,可讓從網頁等中選擇顏色值。
CSS Peeper 用于檢查和復制元素樣式的優秀工具,使用 CSSPeeper 可以將鼠標懸停在網頁中的任何元素上,然后單擊鼠標即可復制元素的樣式。
24. Dimensions
Dimensions是一款能幫助使用者對網頁上各種元素屬性之間的距離進行測量的Chrome頁面元素測量插件,該插件在點擊啟動插件圖標后,可以對頁面中圖像、輸入字段、按鈕以及視頻等頁面元素之間上下左右的方位尺寸進行測量,同時還可以通過使用快捷鍵來快速啟用或關閉該插件的功能,簡單實用。
Site Palette 用于生成調色板。設計師和前端開發人員必備的工具。可以通過這款插件輕松獲取網站的配色方案。
ColorZilla 是一款功能強大地提取網頁色彩的工具;也是個快速的對顏色進行調節的Chrome插件,許多的用戶將這款軟件稱呼為顏色吸取插件,它提取的顏色是非常的多樣化,還可生產css顏色的代碼等。
當我們想查看網頁中文字的字體時,最常用的方法就是在控制臺查看文字的字體樣式。那還有沒有更簡單的方法呢?WhatFont 就是一個查看網頁字體的Chrome擴展。只需要的點擊擴展圖標,再點需要查看為文字即可:
Fonts Ninja 可以從任何網站識別字體、添加書簽、試用并購買它們。
使用 BrowserStack 快速啟動擴展在任何瀏覽器中啟動一個新的測試會話。最多可設置 12 個瀏覽器以實現快速訪問并最大限度地減少切換瀏覽器所花費的時間。
Toby 是一款 Chrome 新標簽頁工具,能夠將未讀的標簽頁分組顯示在新標簽頁中,這樣就能把所有未看完的標簽頁都關閉了。分組相當于多個 Chrome 窗口,將你的標簽頁都拖進 Toby 中,就不需要實時開著占地方了。
該擴展提供了每日熱門開發者新聞,不需要再浪費時間搜索高質量的文章了。
Momentum 擁有漂亮的新標簽頁面,每日更新精彩背景壁紙圖片,可設置每日新鮮事焦點以及跟蹤待辦事項,無廣告,無彈窗。
The Great Suspender 是一個輕量級的擴展用來減少 Chrome 的內存占用。如果同時打開許多選項卡,在可配置的時間之后未查看的選項卡將在后臺自動掛起,從而釋放該選項卡消耗的內存和 CPU。
Session Buddy是一個可以幫助用戶查看、新增、編輯當前網站Session狀態的Chrome插件。用戶可以利用該插件保存網站當前的狀態以便在關閉Chrome或關閉計算機后恢復,從而達到節省內存的作用。
Octotree 旨在讓 GitHub 體驗更好。通常,為了檢查 Github 中的子文件夾,需要手動單擊文件夾并導航。Octotree 擴展解決了這個問題。此擴展在項目的左側顯示存儲庫的目錄結構,這有助于更好地理解文件夾結構。
1_EKF88oqIyX6FzgueCKdtXg.gif
File Icons for GitHub and GitLab 可以將 GitHub 和 GitLab 上的原始文件圖標替換為特定文件類型的圖標。
ax DevTools 是一個快速、輕量級但功能強大的測試工具,由 Deque 開發的世界上最值得信賴的可訪問性測試引擎 axe-core 驅動。使用 ax DevTools 在網站開發過程中查找并修復更多可訪問性問題。
OctoLinker 可以將特定語言的語句(如 include、require 或 import)轉換為鏈接。當打開一個包含多個導入語句的文件并且想要快速打開它時,只需將鼠標懸停在鏈接的文件上并單擊即可打開。
此擴展可幫助 Web 開發人員分析網頁是否違反最佳實踐。
Check My Links 是一個鏈接檢查器,它可以抓取網頁并查找損壞的鏈接。
Checkbot 是用于驗證一組HTML頁面上的鏈接的工具。Checkbot可以檢查一個或多個服務器上的單個文檔或一組文檔。它會創建一個報告,該報告匯總了引起某種警告或錯誤的所有鏈接。
Google Page Speed Insighs 是一款旨在優化所有設備上的網頁、提高網頁加載速度的工具。
META SEO inspector是一款可以幫助用戶分析網頁的meta信息并得到SEO評估的谷歌瀏覽器插件。
Ghostery 是強大的隱私保護擴展程序。其主要有以下功能:
AdBlock 用來在YouTube、Facebook、Twitch和其他你喜愛的網站上攔截廣告和彈窗。
番茄工作法(Pomodoro?)時間管理助理。? 長短兩種休息時間 ? 帶有倒計時顯示的工具欄圖標 ? 追蹤Pomodoro歷史和統計訊息 ? 可配置的長休間隔 ? 可配置的定時器時長 ? 桌面與新標簽頁通知 ? 超過20種音效可選的聲音通知 ? 計時器秒針走動音效
Loom 可以用來快速錄制視頻,并且能夠將錄制的視頻上傳到指定的網頁中,Loom還支持在用戶點擊啟動插件時,立即捕捉屏幕圖像,同時開始視頻錄制操作,還可以將錄制好的視頻復制到粘貼板中存儲。
GoFullPage 是一款全屏截圖插件(整個網頁截圖),完整捕獲您當前頁面的屏幕,進行滾動截圖,而無需任何額外的權限。單擊擴展程序圖標,然后將其傳輸到屏幕快照的新標簽頁中,可以在其中將其下載為圖像或PDF,甚至只需拖動即可,保存到桌面。
BetterViewer 可以提供更好的圖像查看體驗,旨在替代基于 Chrome 瀏覽器中內置的圖像查看模式。使用時,只需在頁面右鍵點擊圖片,選擇“在新標簽頁中打開圖片”即可。
svg-grabber 是一個快速預覽并從網站獲取所有 svg 的工具。可以用來預覽、下載和復制網站中所有 SVG 圖標和插圖的代碼。
現在我們已經確定了 D3 的角色及其工具生態系統,是時候開始工作了!在本章中,我們將為第一個可視化奠定基礎,同時學習如何使用 D3 操作 DOM(文檔對象模型)。
DOM 操作是任何 D3 項目的根源,并且您將在本章中學習的技術可能是您作為 D3 開發人員最常使用的技術。首先,我們將介紹選擇,它允許我們從 DOM 中獲取單個或多個元素。您會發現 D3 使選擇變得非常簡單和直觀。然后,一旦我們做出選擇,我們就會想用它做一些事情。我們在 D3 項目中經常執行的一項操作是將 HTML 或 SVG 元素添加到選擇中。例如,為了創建可視化效果,我們經常將 SVG 形狀附加到 SVG 容器內。最后,我們調整這些 SVG 形狀的位置、大小和顏色。我們通過設置它們的屬性和樣式來做到這一點。
由于本書重點關注在本地開發環境中構建項目,因此在我們深入研究 D3 技術之前,您需要擁有一個。在 2.2 節中,我們將解釋如何使用 VS Code 及其 Live Server 擴展在幾分鐘內準備好本地環境。
在本章和下一章中,您將開發第一個 D3 可視化:如圖 2.1 所示的條形圖。盡管我們在第 1 章中提到 D3 不一定是制作簡單、經典圖表的最有效工具,但條形圖非常適合介紹 D3 的基本概念。堅持使用我們,很快您就會擁有堅實的基礎,使您能夠輕松構建復雜的可視化。
我們的條形圖背后的數據來自數據可視化協會 ( datavisualizationsociety.org )主辦的2021 年數據可視化 - 行業狀況調查。
圖2.1 數據可視化從業者最流行的技術。我們將在本章中開始構建這個條形圖。
2,181 名數據可視化從業者(從專業人士到學生再到業余愛好者)回答了 2021 年行業狀況調查。我們將可視化調查中一個問題的答案:“您經常使用哪些技術來可視化數據?”,受訪者可以從預定義列表中選擇所有適用的工具。在圖 2.1 中,您可以看到生成的條形圖,其中工具垂直列出,每個條形的長度代表選擇該工具的受訪者數量。根據這項調查,D3 躋身數據可視化工具前 10 名。讓我們開始吧!
在開始使用 D3 之前,我們需要決定在哪里構建和運行我們的項目。我們可以使用在線代碼編輯器,例如 Observable ( observablehq.com ) 或 Codepen ( codepen.io ),這些選項非常適合快速測試和共享代碼。但由于本書的目標是幫助您準備好將 D3 項目發送到網站和 Web 應用程序中,因此我們將選擇本地開發環境。
現在,如果設置開發環境的想法讓您感到畏縮,請不要擔心。那種需要花半天的時間流汗、哭泣的日子已經一去不復返了。借助現代工具,您的整個設置第一次不會超過幾分鐘,之后只需單擊按鈕即可啟動并運行。
此時,您可能想知道為什么我們不能簡單地使用瀏覽器打開 HTML 文件,就像我們在第 1 章中的 SVG 形狀庫練習中所做的那樣。雖然這種方法有時可以很好地工作,但最終會導致瀏覽器拒絕執行具體任務和拋出錯誤。出于安全原因,某些瀏覽器阻止使用 JavaScript 加載本地文件,而是需要通過 Web 服務器加載它們。由于在 D3 項目中,我們通常需要加載數據文件,因此我們確實需要一個 Web 服務器。
在本書中,我們將使用代碼編輯器Visual Studio Code(也稱為 VS Code),通常與其 Live Server 擴展結合使用,后者提供本地 Web 服務器。但如果您已經有了首選設置,請隨意使用它并跳至第 2.2.1 節。
我們將在本書第一部分中使用的項目結構非常簡單,而且有點老式。我們的目標是讓環境盡可能簡單,以便您可以專注于學習 D3。但是,如果您是一名更高級的開發人員并且希望使用基于模塊的項目,那么您完全可以這樣做。有關通過 npm 安裝 D3 并將庫導入文件的說明,請參閱第 8 章的開頭(第 8.2 節)。
VS Code 在開發人員中廣受歡迎。它是免費、開源、易于使用且功能強大的。它具有內置的 Git 命令(無需在側面打開終端窗口!)并且高度可定制。如果您的計算機上尚未安裝 VS Code,可以從 Visual Studio Code 官方網站(https://code.visualstudio.com/Download)下載。擁有 VS Code 后,您將需要安裝其Live Server 擴展。
如果您需要安裝幫助,請參閱附錄 A。本附錄還包含有關如何使用 Live Server 擴展啟動和停止本地 Web 服務器的說明。
如果您還沒有下載代碼文件,請在本書的 Github 存儲庫 ( https://github.com/d3js-in-action-third-edition/code-files ) 上下載。從現在到本章結束,我們將使用該chapter_02/start文件夾。如果您在任何時候遇到困難并需要查看解決方案,您可以在該chapter_02/end文件夾中找到它。使用本章的代碼文件時,僅打開一個開頭或一個結尾代碼編輯器中的文件夾。如果您一次打開所有章節的文件并使用 Live Server 擴展來為項目提供服務,則某些路徑將無法按預期工作,尤其是當我們將數據集加載到項目中時。代碼文件分為多個部分。當我們轉到本書中的新部分時,您可以繼續處理初始代碼文件或從專用于該部分的文件夾重新開始。兩種選擇都應該導致相同的結果。
我們將在下一章中處理的 D3 項目都將具有類似的結構,如圖 2.2 所示。
圖2.2 我們的第一個D3項目的文件夾結構
在項目的根目錄下,我們有一個index.html文件,其中包含項目的初始標記。在本書的第一部分中,我們也將在此處將 D3 庫、JavaScript 文件和 CSS 文件加載到項目中。
然后我們有三個文件夾:
在開始之前,請通過查看 VS Code 窗口的左下角來檢查您的 Web 服務器是否正在運行。它應該顯示“端口 5500”,表明服務器正在運行。如果顯示“上線”,請單擊以啟動實時服務器。現在我們已經啟動并運行了 Web 服務器,在開始使用 D3 編碼之前我們還需要做一件事:將 D3 庫加載到我們的項目中。在本書中,我們將使用兩種主要方法。第一個是添加一個腳本標簽來index.html鏈接到最新版本的 D3。我們可以使用這種方法加載整個 D3 庫或僅加載特定模塊。第二種方法是將 D3 作為 NPM 模塊加載,主要適合使用 React 或其他 JavaScript 框架構建的站點。
在本章中,我們將選擇第一種方法,因為它是最簡單的。隨著本書的進展,我們將開始使用第二種方法,它更能代表當今專業 D3 項目的構建方式。
在 VS Code 或您選擇的代碼編輯器中,打開index.html位于文件夾根目錄的文件。在結束正文標記 ( </body>) 之前,使用標記加載 D3 庫的版本 7,這是撰寫本書時的最新版本script。main.js添加另一個腳本標簽以加載位于文件夾中的文件/js并保存您的項目。您可以在清單 2.1.a 中了解如何繼續。
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="js/main.js"></script>
d3js.org的主頁始終包含如何將最新版本的 D3 庫加載到項目中的說明和代碼片段。
瀏覽器按照與 中列出的腳本標簽相同的順序讀取 JavaScript 文件index.html。我們必須先加載D3庫main.js。否則,瀏覽器將無法訪問main.js. 它會拋出錯誤并且代碼不會執行。
我們還希望腳本成為網頁上最后加載的內容,因此我們將腳本標簽放置在結束正文標簽 ( ) 之前</body>。通過這種方法,我們可以減少頁面的加載時間,而不必在顯示 DOM 之前等待腳本加載。在嘗試從腳本文件中操作 DOM 之前,我們還要確保 DOM 可用。
清單 2.1.a 在腳本標簽中加載整個 D3 庫 - index.html
<!DOCTYPE html>
<html>
<head> ... </head>
<body>
<div class="container">
<h1>You are about to start working with D3!</h1>
</div>
<script src="https://d3js.org/d3.v7.min.js"></script> #A
<script src="js/main.js"></script> #B
</body> #C
</html>
現在,讓我們測試 D3 庫和main.js文件是否已正確加載到我們的項目中。在代碼編輯器中,轉到/js文件夾并打開main.js. 將以下代碼片段復制粘貼到 中main.js,然后保存文件。
d3.select("h1").style("color", "plum");
在下一節中,我們將詳細解釋此代碼片段中的 D3 方法的用途,但現在,我們假設我們已選擇標題 h1 并將其顏色更改為 CSS 顏色名稱“plum”。如果你在瀏覽器中查看你的項目,標題的顏色應該已經改變,如圖 2.3 所示。
圖2.3 D3修改的標題顏色
現在我們已經確認 D3 已加載到我們的項目中,您可以從 中刪除片段main.js和 h1 標題index.html。在下一節中,我們將介紹 D3 選擇。
在構建 D3 項目時,我們不斷地操作 DOM,任何 DOM 操作都是從選擇開始的。選擇就像從 DOM 中抓取一個元素并準備好進行進一步操作。D3 有兩種選擇方法:d3.select()和d3.selectAll()。
該方法d3.select()采用選擇器作為參數,并返回與該選擇器匹配的第一個元素。此方法鏈接到d3對象并用于選擇一個元素。如圖2.4所示,選擇器參數可以是類屬性、id、標簽名稱或上述的任意組合,就像我們在CSS中使用的選擇器一樣。
圖2.4 select()方法
讓我們以圖 2.5 所示的虛構 DOM 示例為例。它由一個包含 h1 標題的 div 元素、一個帶有 class 的段落元素intro和另一個帶有 id 的 div組成viz-container。該 div 將另一個段落和一個 SVG 容器包裝在一起。最后,SVG 容器包含三個圓形元素。這些圓圈中的第一個和最后一個有類faded。
圖 2.5 一個虛構的 DOM 示例
如果我們想要選擇 h1 標題,我們可以使用它的標簽名稱作為傳遞給該d3.select()方法的選擇器,如下所示:
d3.select("h1");
同樣,如果我們想選擇帶有 class 的段落intro或帶有 id 的 div viz-container,我們可以使用它們各自的 class 或 id 屬性作為選擇器。與 CSS 選擇器一樣,類名前面有一個點 ( .), ID 前面有一個主題標簽 ( #)。
d3.select(".intro");
d3.select("#viz-container");
我們還可以使用選擇器的組合。例如,如果我們想選擇 div 內 id 為 的段落元素viz-container,我們在兩個選擇器之間留一個空格。
d3.select("#viz-container p");
需要記住的一件重要事情是,該方法d3.select()僅返回 DOM 中與其選擇器匹配的第一個元素。例如,我們的 DOM 示例中有三個圓形元素,如圖 2.6 所示。但選擇d3.select("circle")只返回第一個,而忽略其他。
圖2.6 d3.select()方法返回的DOM元素
那么,如果我們需要在選擇中包含多個元素,我們該怎么辦呢?這就是我們使用該d3.selectAll()方法的時候。d3.selectAll()工作原理與 類似d3.select(),只不過它返回與其選擇器匹配的所有 DOM 元素。例如,如果我們回到虛構的 DOM 示例,d3.selectAll("circle")則返回 DOM 中包含的所有圓形元素。
圖2.7 d3.selectAll()方法返回的DOM元素
有時了解這一點也很有幫助,就像在 CSS 中一樣,我們可以將多個選擇器字符串分組,并用逗號分隔。例如,在下面的代碼片段中,我們選擇h1類為 的標題和段落intro。
d3.selectAll("h1, .intro");
圖 2.8 用逗號對選擇器進行分組
大多數時候,您需要將您的選擇存儲到 JavaScript 常量中,以便以后可以重用和操作它們。您可以像使用任何 JavaScript 常量 ( const) 或變量 ( let) 一樣存儲 D3 選擇。
const myCircles = d3.selectAll("circle");
選擇固然很好,但如果我們不對它們做任何事情,它們就沒有多大用處。D3 中的典型模式是執行選擇以將另一個元素附加到其中。盡管普通 JavaScript 已經允許我們附加元素,但 D3 使其變得更加容易。
用于將元素添加到選擇的主要 D3 方法是selection.append()。該append()方法添加一個新元素作為選擇的最后一個子元素,并采用元素的類型或標簽的名稱作為參數。
圖2.9append()方法
讓我們回到我們虛構的 DOM 示例。如果我們想添加一個矩形元素作為 SVG 容器的最后一個子元素,我們首先選擇 SVG 容器,然后將追加方法鏈接到選擇。要附加的節點類型(元素)作為參數rect傳遞給該方法。append()
d3.select("svg").append("rect");
圖2.10 使用selection.append()方法添加一個元素作為選擇的最后一個子元素
我們還可以d3.selectAll("div")選擇 DOM 中的每個 div 節點,并向每個節點添加一個段落元素,如圖 2.11 所示。
d3.selectAll("div").append("p");
圖 2.11 當與 d3.selectAll() 結合使用時,append 方法將節點添加到選擇的每個元素中。
為了將我們所學到的知識付諸實踐,讓我們開始構建本章簡介中描述的條形圖。
確保start第 2 章代碼文件的文件夾在代碼編輯器中仍然打開,并且本地 Web 服務器正在運行。如果您需要回顧如何使用 VS Code 的 Live Server 擴展啟動 Web 服務器,請參閱附錄 A。打開該文件index.html并注意它包含一個帶有 class 的 div 元素responsive-svg-container。
正如第 1 章中所討論的,大多數 D3 可視化都是使用 SVG 元素構建的,我們的條形圖也不例外。為此,我們需要一個 SVG 容器,用于制作圖表的 SVG 形狀將放入其中。我們現在將添加這個 SVG 元素。
main.js打開文件夾中包含的文件/js。使用方法d3.select(),選擇類為 的 divresponsive-svg-container并在該 div 中添加一個 SVG 元素。由于 div 是空的,因此可以使用append()或insert()方法。它們將具有完全相同的效果。以下代碼片段顯示了該append()方法如何鏈接到選擇。
d3.select(".responsive-svg-container")
.append("svg");
保存文件main.js并在瀏覽器中查看項目。視口中看不到任何變化,但如果打開檢查器,您將看到 SVG 元素已添加到 DOM,這正是我們想要的!
圖2.12 添加到DOM樹的SVG元素
在下一節中,我們將通過給 SVG 一個viewBox屬性來使其具有響應能力。
在第一章中,我們廣泛討論了主要的 SVG 元素以及決定其位置和大小的屬性。我們還解釋說,作為 D3 開發人員,您將需要在代碼中設置和修改這些屬性。現在是學習如何做的時候了!
可以使用D3方法設置和修改屬性selection.attr(),其中“attr”代表“屬性”。如圖2.13所示,該attr()方法有兩個參數,第一個是屬性的名稱,第二個是屬性的值。該值可以直接設置,也可以通過訪問器函數設置,我們將在第 3 章中討論。
圖 2.13 attr() 方法
在我們的條形圖練習中,圍繞 SVG 容器的 div 元素具有類responsive-svg-container。main.css如果您打開文件夾中的文件/css,您將看到此類應用了響應式 SVG 元素容器所需的所有樣式,如第 1.2.2 節中所述。這里,容器的max-width屬性為 1200px,這也是條形圖的最大寬度。
為了讓我們的 SVG 容器在適應其容器的同時保持其寬高比,我們只需要設置其 viewBox 屬性。我們將使用attr()該方法。正如您在下一個代碼片段中看到的,傳遞給該方法的第一個參數attr()是屬性的名稱,在本例中為viewBox。請注意該屬性名稱的“B”字母是大寫字母。表示屬性區分大小寫,必須遵守viewBox屬性的駝峰式大小寫表示法,以便瀏覽器識別它。
第二個參數是屬性的值viewBox,它是四個數字的列表。前兩個數字是viewBox坐標系的原點,位于(0,0)。最后兩個數字是 viewBox 的寬度和高度。寬度對應于max-width容器 div 的屬性,因此為 1200px,讓我們估計高度為 1600px。如果需要的話,我們可以稍后調整。我們的 viewBox 屬性的值為"0 0 1200 1600"。
d3.select(".responsive-svg-container")
.append("svg")
.attr("viewBox", "0 0 1200 1600");
設置 SVG 元素的 viewBox 屬性,保存main.js并在檢查器中查看您的項目。您將看到該viewBox屬性已添加到 SVG 元素中,如圖 2.14 所示。此外,如果您縮小瀏覽器的視口,SVG 元素將進行調整,同時保持其縱橫比為 1200:1600。
圖 2.14 具有 viewBox 屬性的 SVG 元素
讓我們將最新的代碼保存到一個名為svg我們很快就會使用的 JavaScript 常量中。
const svg = d3.select(".responsive-svg-container")
.append("svg")
.attr("viewBox", "0 0 1200 1600");
每次我們使用.append()或.insert()方法向選擇添加新元素時,我們都會更改選擇返回的元素。例如,當我們重用constant時svg,它不會返回帶有類的div responsive-svg-container,而是返回我們添加到其中的SVG容器。
在進一步討論之前,我們先討論一下 D3 縮進約定。在我們最后的代碼片段中,您可能已經注意到每個鏈接的方法都寫在一個新行上。這樣做有助于提高可讀性,尤其是當超過 2 或 3 個方法鏈接在一起時。您可能還注意到該append()方法縮進了兩個空格,而 attr() 方法使用了四個縮進空格,因此遵循縮進約定。
在 D3 中,每次我們將新元素附加到選擇時,我們都會更新選擇所針對的 DOM 元素。當我們設置新添加元素的屬性和樣式時,適當的縮進可以幫助我們了解屬性和樣式應用于哪個選擇。
D3 縮進約定
當多個元素一個接一個地附加時,縮進約定特別方便。想象一下,添加 SVG 元素并設置 viewBox 屬性后,我們將一個 group 元素附加到 SVG 容器中,其類為my-group. 然后,我們將一個矩形元素附加到組中并設置其所需的屬性。正如您在上圖中看到的,我們需要鏈接多個方法才能實現這一點。但是,由于縮進約定,鏈很容易閱讀,我們一目了然地看到每個屬性應用于哪個選擇或元素。
條形圖,就像我們正在構建的那樣,由矩形組成,而 SVG 矩形是使用元素創建的rect。為了練習選擇和attr()方法,我們將在條形圖中添加一個矩形,該矩形將代表在調查中選擇 D3.js 工具的數據可視化從業者的數量。data.csv如果你打開文件夾中的文件/data,你會發現有414名練習者表示他們經常使用D3。
在 中main.js,首先調用常量svg,它返回 SVG 容器。rect在 SVG 容器內添加一個元素。在下面的代碼片段中,我們使用了append()方法來添加 rect 元素,但我們也可以使用方法insert()。保存您的項目并確認該rect元素已添加到 SVG 中。
const svg = d3.select(".responsive-svg-container")
.append("svg")
.attr("viewBox", "0 0 1200 1600");
svg
.append("rect");
該rect元素存在于 DOM 中,但在屏幕上尚不可見,因為尚未設置其所需的屬性。我們知道 SVG 矩形需要四個屬性才能出現在屏幕上。您可以參考 1.2.2 節來回顧這些概念。和x屬性y控制矩形左上角的位置。我們(10, 10)暫時將其放置在。矩形的寬度對應于有多少練習者選擇 D3 作為工具,即 414,其高度可以是任意數字,我們將使用 16。通過分別給出 414 和 16 的 和 屬性值,我們的矩形width將height寬度為 414 像素,高度為 16 像素。這四個屬性的值以數字形式傳遞。
svg
.append("rect")
.attr("x", 10)
.attr("y", 10)
.attr("width", 414)
.attr("height", 16);
最后,矩形的 fill 屬性設置為 CSS 顏色名稱"turquoise"并作為字符串傳遞。
svg
.append("rect")
.attr("x", 10)
.attr("y", 10)
.attr("width", 414)
.attr("height", 16)
.attr("fill", "turquoise");
請注意我們在這里如何使用縮進約定:當我們追加矩形時創建的新選擇使用兩個縮進空格,而方法attr()使用四個空格。這樣,我們就可以清楚地看出屬性已應用于元素rect。
保存項目后,該矩形將在瀏覽器的視口中可見。
圖 2.15 附加到 SVG 容器中的矩形元素
為了使我們的可視化元素具有我們想要的外觀和感覺,我們需要能夠對其應用樣式。傳統的 CSS 樣式表方法是一種很好的方法,而且通常是出于可維護性目的的更好選擇。但有時,直接使用 D3 設置和修改樣式屬性很方便,特別是當樣式旨在表示數據時。
D3允許我們用方法設置和修改元素的樣式屬性selection.style()。該方法有兩個參數。第一個是樣式屬性的名稱,第二個是其值。
圖2.16 style()方法
回到我們的條形圖練習,在 中main.js,將一個style()方法鏈接到 SVG 容器選擇,該方法存儲在名為 的常量中svg。就像下面的代碼片段一樣,使用該style()方法將邊框應用到 SVG 容器。您可以給它任何您想要的值。這里我們使用簡寫屬性來應用寬度為 1px 的黑色邊框。
const svg = d3.select(".responsive-svg-container")
.append("svg")
.attr("viewBox", "0 0 1200 1600")
.style("border", "1px solid black");
SVG 容器周圍的邊框將幫助我們可視化我們正在工作的空間。它還將幫助我們理解該style()方法是如何工作的。
保存您的項目并在瀏覽器中查看它。在 DOM 檢查器中找到 SVG 容器。您應該看到在 style 屬性中添加了 border 屬性,如圖 2.17 所示。這意味著該style()方法注入內聯樣式。
圖 2.17 使用 style() 方法應用邊框
使用 SVG 元素時,某些樣式可以作為屬性或使用內聯樣式應用,例如 和fill屬性stroke。沒有嚴格的規則表明我們應該使用 theattr()或 thestyle()方法來應用此類屬性,但一些開發人員更喜歡保持一致,并且始終將表示屬性應用為 CSS 或內聯樣式,而不是使用屬性。這可能是一個好主意,特別是當我們希望通過將生成形狀的代碼與指示形狀的代碼分開來使級聯樣式易于管理時。在本書中,我們將使用 attr() 和 style() 方法以及外部 CSS 文件來設置 SVG 元素的表示屬性。
讓我們用一個例子來說明這一點。在 中main.js,將一個style()方法鏈接到矩形選擇,并使用此方法對矩形應用不同顏色的第二個填充。在下面的代碼片段中,我們使用 CSS color "plum"。
svg
.append("rect")
.attr("x", 10)
.attr("y", 10)
.attr("width", 414)
.attr("height", 16)
.attr("fill", "turquoise")
.style("fill", "plum");
現在,打開main.css文件并向矩形添加第三個填充屬性。這里我們使用了CSS顏色"orange"。
rect {
fill: orange;
}
圖 2.18 填充作為屬性、來自永恒樣式表和內聯樣式應用
我們的矩形現在具有三個填充屬性,應用方式不同。它有一個 color 填充"turquoise",作為屬性應用,另一個 color 填充"plum",作為內聯樣式,最后一個 color 填充"orange",從外部 CSS 樣式表應用。這當然不是我們在現實生活中會做的事情,僅用于演示目的。
保存您的項目并注意使用樣式屬性應用的填充如何覆蓋其他兩個。在圖 2.19 中,您可以看到如何應用級聯樣式。內聯樣式會覆蓋任何其他樣式,后跟從外部 CSS 樣式表應用的樣式。填充屬性排在最后。牢記這條規則將幫助您制定適合您的習慣、團隊和項目的策略,同時避免困惑為什么一種風格在屏幕上可見而另一種風格不可見。
我們現在知道如何執行選擇、向 DOM 添加元素以及如何定位它們并設置它們的樣式。但是像我們在這里所做的那樣將矩形一一添加到我們的條形圖中根本沒有效率。在下一章中,我們將學習數據綁定如何幫助我們一次添加所有矩形。main.js在我們到達那里之前,請從和 中刪除與矩形相關的代碼main.css。文件 main.js 現在僅包含清單 2.1.b 中的代碼。
清單 2.1.b 第 2 章末尾的 main.js 內容
const svg = d3.select(".responsive-svg-container")
.append("svg")
.attr("viewBox", "0 0 1200 1600")
.style("border", "1px solid black");
D3 包含一系列模塊,我們可以獨立使用這些模塊,也可以根據項目的需要進行組合。每個模塊包含多個執行相關任務的方法。
我們在本章中討論的所有方法都是模塊d3-selection ( https://github.com/d3/d3-selection ) 的一部分。該模塊托管在 github 上,是值得信賴且始終最新的資源。
如果您是 Web 開發新手,此類 API 文檔一開始可能會令人生畏,但您參考它的次數越多,您就會開始更好地理解其技術語言。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。