整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          D3.js實(shí)戰(zhàn)教程:1 D3.js簡(jiǎn)介


          章涵蓋

          • 了解 D3.js 的作用及其背后的理念
          • 認(rèn)識(shí)與 D3 結(jié)合使用來(lái)創(chuàng)建數(shù)據(jù)可視化的工具
          • 使用代碼創(chuàng)建可縮放矢量圖形 (SVG) 并為其設(shè)計(jì)樣式
          • 了解數(shù)據(jù)可視化最佳實(shí)踐如何支持您作為 D3 開(kāi)發(fā)人員的旅程

          D3.js 是網(wǎng)絡(luò)上幾乎所有最具創(chuàng)新性和令人興奮的信息可視化的幕后黑手。D3 代表數(shù)據(jù)驅(qū)動(dòng)文檔,它是一個(gè)品牌名稱,也是多年來(lái)以某種形式提供的一類應(yīng)用程序。我們可以使用這個(gè)庫(kù)來(lái)構(gòu)建各種數(shù)據(jù)驅(qū)動(dòng)的項(xiàng)目,從簡(jiǎn)單的條形圖到動(dòng)態(tài)地圖,再到復(fù)雜的空間和時(shí)間探索。當(dāng)您希望在數(shù)據(jù)可視化方面獲得完全的創(chuàng)意和技術(shù)自由時(shí),無(wú)論您是構(gòu)建用于研究的交互式原型、頂級(jí)科技公司廣泛且完全響應(yīng)的數(shù)據(jù)儀表板,還是揭示數(shù)據(jù)故事的長(zhǎng)篇文章,D3 都是您的首選工具當(dāng)用戶滾動(dòng)時(shí)。

          1.1 什么是D3.js

          D3 是一個(gè)開(kāi)源 JavaScript 庫(kù),由 Mike Bostock 于 2011 年創(chuàng)建,用于為 Web 生成動(dòng)態(tài)和交互式數(shù)據(jù)可視化。盡管過(guò)去幾年推出了許多新的數(shù)據(jù)可視化庫(kù),但它們通常在底層使用 D3。這是因?yàn)?D3 與 JavaScript 一樣,非常靈活且強(qiáng)大。




          圖 1.1 漢密爾頓中每條線的交互式可視化,這是Shirley Wu創(chuàng)建的 D3 項(xiàng)目


          1.1.1 對(duì)可通過(guò)網(wǎng)絡(luò)訪問(wèn)的數(shù)據(jù)可視化的需求

          D3.js 的創(chuàng)建是為了滿足對(duì)可通過(guò)網(wǎng)絡(luò)訪問(wèn)的復(fù)雜數(shù)據(jù)可視化的迫切需求。假設(shè)您的公司正在使用商業(yè)智能工具,但它沒(méi)有顯示您的團(tuán)隊(duì)所需的數(shù)據(jù)模式。您必須構(gòu)建一個(gè)自定義儀表板,根據(jù)您的特定領(lǐng)域量身定制,準(zhǔn)確顯示客戶的行為方式。該儀表板需要快速、交互式且可在整個(gè)組織內(nèi)共享。D3 將是此類項(xiàng)目的自然選擇。

          或者想象一下,您被雇用來(lái)實(shí)現(xiàn)一個(gè)網(wǎng)頁(yè),該網(wǎng)頁(yè)以可視化方式展示 LGBTQ+ 群體(女同性戀、男同性戀、雙性戀、跨性別者、酷兒等)的權(quán)利在過(guò)去幾十年和全世界的演變情況。此頁(yè)面包含許多隨著用戶滾動(dòng)而變化的創(chuàng)意可視化效果。它們通過(guò)鼠標(biāo)事件顯示更多信息并適應(yīng)屏幕大小。D3 將是構(gòu)建此類項(xiàng)目的首選工具。

          Mike Bostock 最初創(chuàng)建 D3 是為了利用新興的 Web 標(biāo)準(zhǔn),正如他所說(shuō),“避免了專有表示并提供了非凡的靈活性,暴露了 CSS3、HTML5 和 SVG 等 Web 標(biāo)準(zhǔn)的全部功能”(http: // d3js.org)。D3.js 版本 7 是這個(gè)流行庫(kù)的最新版本,它通過(guò)模塊化 D3 的各個(gè)部分來(lái)延續(xù)這一趨勢(shì),使其與 ECMAScript 模塊(一種基于 JavaScript 的腳本語(yǔ)言)和現(xiàn)代應(yīng)用程序開(kāi)發(fā)完全兼容。

          D3.js 使開(kāi)發(fā)人員不僅能夠制作豐富的交互式應(yīng)用程序,而且能夠制作樣式和服務(wù)類似于傳統(tǒng) Web 內(nèi)容的應(yīng)用程序。這使得它們更可移植,更適合增長(zhǎng),并且更容易由其他團(tuán)隊(duì)成員可能不知道 D3 的具體語(yǔ)法的大型團(tuán)體維護(hù)。

          圖 1.2 D3 開(kāi)發(fā)人員可以訪問(wèn)各種數(shù)據(jù)表示形式,地圖就是一個(gè)例子。這是由Christophe Viau創(chuàng)建的數(shù)字高程模型 (DEM) 地圖。


          Bostock 決定廣泛處理數(shù)據(jù)并創(chuàng)建一個(gè)能夠像圖表一樣簡(jiǎn)單、像網(wǎng)絡(luò)一樣簡(jiǎn)單、像列表一樣簡(jiǎn)單地呈現(xiàn)地圖的庫(kù),這也意味著開(kāi)發(fā)人員不需要了解以下內(nèi)容的抽象和語(yǔ)法:一個(gè)用于地圖的庫(kù),另一個(gè)用于動(dòng)態(tài)文本內(nèi)容的庫(kù),還有另一個(gè)用于傳統(tǒng)圖形的庫(kù)。相反,用于運(yùn)行交互式網(wǎng)絡(luò)可視化的代碼接近于純 JavaScript,并且也類似于表示 D3 地圖上的動(dòng)態(tài)點(diǎn)的代碼。方法是相同的,但數(shù)據(jù)也可以是相同的,以一種方式制定用于網(wǎng)絡(luò)的節(jié)點(diǎn)和鏈路,而以另一種方式制定用于地圖上的地理空間表示。

          D3 不僅可以創(chuàng)建復(fù)雜多樣的圖形,還可以嵌入用戶期望的高水平交互性,這對(duì)于現(xiàn)代 Web 開(kāi)發(fā)至關(guān)重要。使用 D3,每個(gè)圖表的每個(gè)元素(從旋轉(zhuǎn)的地球儀到餅圖的切片)都以相同的方式進(jìn)行交互。由于 D3 是由精通數(shù)據(jù)可視化實(shí)踐的人編寫的,因此它包含數(shù)據(jù)可視化和 Web 開(kāi)發(fā)中標(biāo)準(zhǔn)的交互式組件和行為。

          圖 1.3 交互性是 D3 的核心。在此網(wǎng)絡(luò)可視化中,鼠標(biāo)交互揭示了不同組織之間的關(guān)系以及特定于所選節(jié)點(diǎn)的信息(https://amdufour.github.io/organizations-against-polization)。



          1.1.2 什么時(shí)候使用D3.js?

          數(shù)據(jù)可視化領(lǐng)域正在蓬勃發(fā)展,可用于生成數(shù)據(jù)綁定圖形的工具數(shù)量在過(guò)去十年中呈爆炸式增長(zhǎng)。我們擁有 Excel(數(shù)據(jù)可視化的常用入口)和 Power BI(用于構(gòu)建儀表板的 Microsoft 解決方案)等商業(yè)智能工具。另一方面,更有經(jīng)驗(yàn)的數(shù)據(jù)科學(xué)家通常會(huì)轉(zhuǎn)向 R 的 ggplot2 或 Python 的 matplotlib。

          基于瀏覽器的點(diǎn)擊式工具(例如 Tableau、Flourish、DataWrapper、RAWGraphs 和 Google 圖表)也占據(jù)了主導(dǎo)地位,允許用最少的技術(shù)知識(shí)創(chuàng)建令人驚嘆的作品。

          最后,HighCharts、Chart.js 和 D3.js 等 JavaScript 庫(kù)專門用于開(kāi)發(fā)基于 Web 的交互式可視化。

          而且這個(gè)列表遠(yuǎn)非詳盡無(wú)遺......

          那么,D3 在數(shù)據(jù)可視化工具的海洋中處于什么位置呢?我們何時(shí)以及如何使用它?我們可以說(shuō),雖然 D3 完全可以構(gòu)建此處列出的數(shù)據(jù)可視化庫(kù)提供的任何圖表,但它通常不是構(gòu)建簡(jiǎn)單的傳統(tǒng)圖表或探索階段(我們調(diào)查哪種類型的可視化是)的首選選項(xiàng)。最適合代表我們的數(shù)據(jù)。構(gòu)建 D3 項(xiàng)目需要時(shí)間,而 D3 在復(fù)雜、交互式和定制的項(xiàng)目中真正表現(xiàn)出色。數(shù)據(jù)可視化不僅僅是折線圖和散點(diǎn)圖!雖然上面提到的工具通常專注于預(yù)定義的圖表,但 D3 允許我們將數(shù)據(jù)綁定到任何圖形元素,并通過(guò)以獨(dú)特的方式組合這些視覺(jué)元素來(lái)打破常規(guī)。

          圖 1.4 D3 具有 SVG 和畫(huà)布繪圖功能,允許開(kāi)發(fā)人員構(gòu)建自定義可視化效果,例如Elijah Meeks的樂(lè)譜表示形式。


          以下是我們?nèi)绾卧跀?shù)據(jù)可視化項(xiàng)目范圍內(nèi)使用 D3 的示例。首先,我們從預(yù)先存在的數(shù)據(jù)集或手動(dòng)收集的數(shù)據(jù)開(kāi)始。在開(kāi)始數(shù)據(jù)分析過(guò)程之前,我們通常會(huì)花費(fèi)大量時(shí)間清理、格式化和準(zhǔn)備數(shù)據(jù)。Python 和 R 等數(shù)據(jù)科學(xué)工具在這方面功能強(qiáng)大,可以幫助我們識(shí)別隱藏在數(shù)據(jù)中的故事。Excel 還可以完成簡(jiǎn)單的數(shù)據(jù)整理和數(shù)據(jù)分析工作,并且需要較少的技術(shù)背景。我們甚至可以使用 JavaScript 和 D3 進(jìn)行基本數(shù)據(jù)探索,因?yàn)樗鼈兲峁┝宋覀儗⒃诒緯?shū)后面討論的統(tǒng)計(jì)方法。

          一旦數(shù)據(jù)分析開(kāi)始,通常會(huì)創(chuàng)建一些原型來(lái)幫助完善我們的故事。Tableau 和 RawGraphs 等工具使我們能夠快速生成此類圖表。這是非常重要的一步,在此階段創(chuàng)建的可視化通常并不花哨或精致。我們不想在原型設(shè)計(jì)階段過(guò)于執(zhí)著于我們的想法,花費(fèi)大量時(shí)間。我們可能會(huì)發(fā)現(xiàn)自己必須“殺死我們的寶貝”并重新開(kāi)始幾次,直到我們找到最適合我們想要講述的故事的可視化效果。網(wǎng)絡(luò)圖可能是一個(gè)例外,直接跳到 D3 對(duì)于這些項(xiàng)目通常是有意義的。

          最后,一旦我們知道要?jiǎng)?chuàng)建的可視化類型,就該卷起袖子,對(duì)其進(jìn)行編碼,并使用 D3 對(duì)其進(jìn)行完善。如今,編碼步驟通常發(fā)生在單頁(yè)應(yīng)用程序 (SPA) 中,使用 React 或 Svelte 等框架。

          圖 1.5 使用 D3 構(gòu)建的自定義可視化的另一個(gè)示例,其中形狀與每首歌曲的不同屬性(例如持續(xù)時(shí)間、流派和節(jié)奏)成比例(https://amdufour.github.io/spotify-hits)。



          1.1.3 D3.js 的工作原理

          您可能已經(jīng)嘗試過(guò) D3,并發(fā)現(xiàn)它并不容易上手。也許那是因?yàn)槟M且粋€(gè)簡(jiǎn)單的圖表庫(kù)。一個(gè)恰當(dāng)?shù)睦邮莿?chuàng)建條形圖,我們將在第 2 章和第 3 章中進(jìn)行此操作。D3 沒(méi)有一個(gè)函數(shù)來(lái)創(chuàng)建條形圖。相反,它有一個(gè)將<svg>容器附加到文檔對(duì)象模型 (DOM) 的函數(shù),以及另一組附加容器的函數(shù)。<rect>每個(gè)數(shù)據(jù)點(diǎn)的元素。然后,我們使用比例來(lái)計(jì)算構(gòu)成直方圖的矩形的長(zhǎng)度并設(shè)置它們的屬性。最后,我們調(diào)用另一組函數(shù),將 x 軸和 y 軸添加到條形圖中。如圖 1.6 所示,這個(gè)過(guò)程比使用 Highcharts 等專用圖表庫(kù)要長(zhǎng)得多。但 D3 處理數(shù)據(jù)和圖形的明確方式也是它的優(yōu)勢(shì)。盡管其他圖表庫(kù)允許您方便地制作折線圖和餅圖,但當(dāng)您想要?jiǎng)?chuàng)建不屬于傳統(tǒng)圖表范圍的可視化效果或?qū)崿F(xiàn)自定義交互時(shí),它們很快就會(huì)崩潰。不是D3。D3 允許您構(gòu)建您可以想象的任何數(shù)據(jù)驅(qū)動(dòng)圖形和交互性。

          圖 1.6 使用 Highcharts 與 D3.js 生成的條形圖。Highcharts 的代碼更簡(jiǎn)單、更短,但 D3.js 更通用。



          在圖 1.7 中,您可以看到我們通常如何使用 D3 進(jìn)行數(shù)據(jù)可視化編碼的地圖。我們從一個(gè)數(shù)據(jù)集(通常是 CSV 或 JSON 文件)開(kāi)始,然后使用 d3-fetch 模塊將此數(shù)據(jù)集加載到我們的項(xiàng)目中。我們通常需要執(zhí)行一些操作來(lái)格式化數(shù)據(jù)。例如,我們確保數(shù)字和日期的格式正確。如果我們之前沒(méi)有這樣做,我們可能還想詢問(wèn)我們的數(shù)據(jù)集以找到其主要特征。例如,提前知道其最大值和最小值通常很有幫助。然后我們準(zhǔn)備開(kāi)始構(gòu)建可視化,為此我們將結(jié)合我們將在本書(shū)中學(xué)習(xí)的不同 D3 函數(shù)。最后,我們通過(guò)監(jiān)聽(tīng)鼠標(biāo)事件來(lái)添加交互性,允許用戶過(guò)濾數(shù)據(jù)或放大可視化。

          圖 1.7 如何使用 D3.js 實(shí)現(xiàn)數(shù)據(jù)可視化



          1.2 D3 生態(tài)系統(tǒng) - 入門所需了解的內(nèi)容

          D3.js 從來(lái)不會(huì)單獨(dú)使用,而是我們結(jié)合起來(lái)創(chuàng)建豐富的 Web 界面的技術(shù)和工具生態(tài)系統(tǒng)的一部分。與任何網(wǎng)頁(yè)一樣,D3 項(xiàng)目是在 DOM(文檔對(duì)象模型)內(nèi)構(gòu)建的,并利用 HTML5 的強(qiáng)大功能。盡管 D3 可以創(chuàng)建和操作傳統(tǒng)的 HTML 元素,例如分區(qū) ( <div>) 和列表 ( <ul>, <ol>),但我們主要使用 SVG 圖形或在畫(huà)布(從腳本渲染位圖圖像的 HTML 元素)內(nèi)生成可視化效果。然后,我們還可以使用舊的 CSS 樣式表,它可以增強(qiáng) D3 項(xiàng)目并使其設(shè)計(jì)更易于維護(hù),尤其是在廣泛的團(tuán)隊(duì)中。

          鑒于 D3 是一個(gè) JavaScript 庫(kù),我們自然傾向于將 D3 方法與本機(jī) JavaScript 函數(shù)結(jié)合起來(lái)來(lái)訪問(wèn)和操作數(shù)據(jù)。D3 現(xiàn)在完全支持 JavaScript 的 ECMAScript 2015 或 ES6 修訂版以及大多數(shù)最新更新。D3 還作為模塊提供,可以集成到我們構(gòu)建 Web 項(xiàng)目所用的最新框架和庫(kù)中。使用這些模塊通常是首選方法,因?yàn)樗粫?huì)污染我們應(yīng)用程序的全局范圍。

          在本節(jié)中,我們將簡(jiǎn)要討論這些技術(shù)及其在 D3 生態(tài)系統(tǒng)中的作用。由于 SVG 知識(shí)是理解 D3 的基礎(chǔ),因此我們將花時(shí)間更詳細(xì)地解釋您開(kāi)始構(gòu)建可視化所需理解的基礎(chǔ)知識(shí)。如果您已經(jīng)熟悉 HTML、SVG 元素、CSS、JavaScript 和 JavaScript 模塊,請(qǐng)隨意瀏覽或跳至第 1.3 節(jié)。

          1.2.1 HTML 和 DOM

          與 GIF 動(dòng)畫(huà)和框架成為網(wǎng)絡(luò)動(dòng)態(tài)內(nèi)容頂峰的時(shí)代相比,我們已經(jīng)走過(guò)了很長(zhǎng)一段路。在圖 1.8 中,您可以看到為什么 GIF 從未在強(qiáng)大的基于 Web 的數(shù)據(jù)可視化中流行起來(lái)。GIF 與設(shè)計(jì)用于使用 VML(矢量標(biāo)記語(yǔ)言)的 infoviz 庫(kù)一樣,對(duì)于早期瀏覽器來(lái)說(shuō)是必需的,但 D3 是為不再需要向后兼容性的現(xiàn)代瀏覽器而設(shè)計(jì)的。

          圖 1.8 20 世紀(jì) 90 年代的一些例子,比如dpgraph.com,仍然存在,讓我們想起動(dòng)畫(huà) GIF 無(wú)處不在的時(shí)代。



          當(dāng)您登陸網(wǎng)頁(yè)時(shí),要加載的第一個(gè)文件是超文本標(biāo)記語(yǔ)言或 HTML 文件,如下例所示。瀏覽器解析 HTML 文件以構(gòu)建文檔對(duì)象模型或 DOM,這是用于 Web 文檔的編程接口。我們經(jīng)常將其稱為 DOM 樹(shù),因?yàn)樗梢唤M嵌套元素(也稱為節(jié)點(diǎn)或標(biāo)簽)組成。在我們的示例中,<head>和 the<body>元素是<html>父元素的子元素。同樣,標(biāo)簽是、the和標(biāo)簽<body>的父標(biāo)簽。標(biāo)題也是該元素的同級(jí)元素。當(dāng)您加載網(wǎng)頁(yè)時(shí),您在屏幕上看到的是標(biāo)記中包含的元素。

          <!DOCTYPE#nbsp;html>
          <html>
            <head>
              <meta charset="UTF-8">  
              <title>A simple HTML file | D3.js in Action</title>
            </head>
            <body>
              <h1>I am a title</h1>
              <div>
                <p>I am a paragraph.</p>
                <p>I am another paragraph.</p>
              </div>
            </body>
          </html>

          在 DOM 中,每個(gè)元素的三類信息定義了其行為和外觀:樣式、屬性和特性。樣式?jīng)Q定顏色、大小、邊框、不透明度等。屬性包括類、id 和交互行為,盡管某些屬性也可以確定外觀,具體取決于您正在處理的元素類型。對(duì)于 SVG 元素,屬性用于設(shè)置不同形狀的位置、大小和比例。屬性通常指的是狀態(tài),例如復(fù)選框的“checked”屬性,如果該框被選中,則該屬性為 true;如果該框未被選中,則該屬性為 false。盡管術(shù)語(yǔ)“屬性”和“屬性”經(jīng)常互換使用,但它們是兩個(gè)不同的東西。呈現(xiàn) DOM 時(shí),屬性顯示為初始狀態(tài)。屬性是元素的當(dāng)前狀態(tài),并且可以隨著用戶與界面交互而改變。在第2章中,我們將討論用于生成或修改HTML和SVG元素的樣式和屬性的D3方法。

          DOM 還決定元素在屏幕上的繪制順序,子元素在父元素之后和內(nèi)部繪制。盡管 CSS 屬性z-index使我們能夠部分控制傳統(tǒng) HTML 元素繪制到屏幕上的順序,但 SVG 元素嚴(yán)格遵循它們?cè)?DOM 中出現(xiàn)的順序。根據(jù)畫(huà)家的模型,之后繪制的內(nèi)容出現(xiàn)在之前繪制的內(nèi)容之上。

          1.2.2 SVG——可縮放矢量圖形

          可擴(kuò)展矢量圖形 (SVG) 的引入確實(shí)改變了網(wǎng)絡(luò)的面貌。幾年之內(nèi),SVG 圖形成為主要的 Web 開(kāi)發(fā)工具。光柵圖形(PNG 和 JPG)由微小的像素組成,當(dāng)我們放大得太近時(shí),這些像素就會(huì)變得可見(jiàn),而矢量圖形則是通過(guò)數(shù)學(xué)和幾何圖形構(gòu)建的。它們?cè)谌魏纬叽绾腿魏纹聊环直媛氏露寄鼙3智逦耐庥^。SVG 圖形的另一個(gè)顯著優(yōu)勢(shì)是它們可以直接注入 DOM,允許開(kāi)發(fā)人員操縱其元素并為其設(shè)置動(dòng)畫(huà),并使屏幕閱讀器可以訪問(wèn)它們。如果構(gòu)建正確,SVG 也具有高性能,其文件大小僅為等效光柵圖像的一小部分。

          當(dāng)使用 D3 創(chuàng)建數(shù)據(jù)可視化時(shí),我們通常將 SVG 形狀注入 DOM 并修改其屬性以生成組成可視化的視覺(jué)元素。了解 SVG 的工作原理、主要 SVG 形狀及其表示屬性對(duì)于大多數(shù) D3 項(xiàng)目至關(guān)重要。

          如何訪問(wèn)代碼文件

          本書(shū)的每一章都包含旨在支持您的學(xué)習(xí)體驗(yàn)的代碼練習(xí)。我們強(qiáng)烈建議您“做”這本書(shū),而不僅僅是“讀”這本書(shū),這意味著在閱讀章節(jié)時(shí)完成練習(xí)。通過(guò)這種方式,您將保留更多信息,并很快就能構(gòu)建自己的 D3 項(xiàng)目!

          對(duì)于每個(gè)練習(xí)和項(xiàng)目,您都可以訪問(wèn)現(xiàn)成的代碼文件。您可以在本書(shū)的 Github 存儲(chǔ)庫(kù)(https://github.com/d3js-in-action-third-edition/code-files)上找到它們。如果您熟悉 Git,則可以將存儲(chǔ)庫(kù)克隆到您的計(jì)算機(jī)上。您還可以下載壓縮文件。

          從 Github 存儲(chǔ)庫(kù)下載代碼文件


          每一章都有自己的文件夾,其中包含一個(gè)或多個(gè)練習(xí),按照每章中的部分編號(hào)。練習(xí)包括一個(gè)start文件夾,其中包含入門所需的所有文件。您將在文件夾中找到練習(xí)的完整解決方案end。當(dāng)您完成一章的各個(gè)部分時(shí),您可以繼續(xù)在上一部分使用的文件中進(jìn)行編碼,或者使用專用于該部分的文件夾重新開(kāi)始。兩種選擇都會(huì)導(dǎo)致相同的結(jié)果。

          讓我們開(kāi)始探索矢量圖形。轉(zhuǎn)到本書(shū)提供的代碼文件。找到end中的文件夾chapter_01/SVG_Shapes_Gallery并右鍵單擊該文件index.html。在菜單中,轉(zhuǎn)到打開(kāi)方式并選擇瀏覽器。我們建議使用 Chrome 或 Firefox,因?yàn)樗鼈兙哂谐錾臋z查器工具。該文件將在新的瀏覽器選項(xiàng)卡中打開(kāi),并且將出現(xiàn)您在圖 1.9 中看到的矢量圖形。您還可以在 Github 托管項(xiàng)目 ( https://d3js-in-action-third-edition.github.io/svg-shapes-gallery ) 上查看這些 SVG 形狀。

          圖 1.9 我們將在本節(jié)中構(gòu)建的基本 SVG 形狀圖庫(kù)。


          您正在查看的 SVG 圖形包含創(chuàng)建 D3 可視化時(shí)最常使用的形狀:線條、矩形、圓形、橢圓形、路徑和文本。

          使用 D3 時(shí),您通常會(huì)告訴庫(kù)應(yīng)將哪些形狀附加到 DOM。您還負(fù)責(zé)了解需要計(jì)算哪些表示屬性才能使形狀具有您正在尋找的尺寸、顏色和位置。在下面的練習(xí)中,您將編寫創(chuàng)建圖 1.9 中每個(gè) SVG 元素的代碼。我們將此練習(xí)稱為SVG 形狀圖庫(kù)。之后,您將了解入門所需的所有 SVG 基礎(chǔ)知識(shí)。

          在您選擇的代碼編輯器中打開(kāi)練習(xí)文件夾index.html中的文件。我們推薦VS Code,這是一個(gè)免費(fèi)、易于使用的代碼編輯器,并且具有多種功能,對(duì)前端開(kāi)發(fā)很有幫助。startSVG_Shapes_Gallery

          正如您所看到的,index.html是一個(gè)簡(jiǎn)單的 HTML 文件。如果您在瀏覽器中打開(kāi)此文件(右鍵單擊該文件并在“打開(kāi)方式”菜單中選擇瀏覽器),您將只會(huì)看到一個(gè)空白頁(yè)面。這是因?yàn)樵?lt;body>元素為空。在接下來(lái)的小節(jié)中,我們將向此<body>元素添加 SVG 形狀。

          清單 1.1.a SVG 形狀庫(kù)練習(xí)的起始 HTML 文件

          <!DOCTYPE html>
          <html>
          <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">  
            <title>SVG Shapes Gallery | D3.js in Action</title>
          </head>
          <body>
            
          </body>
          </html>

          哪里可以找到更多信息

          以下部分將介紹多個(gè) SVG 元素及其屬性。作為開(kāi)發(fā)人員,我們?cè)跇?gòu)建項(xiàng)目、使用我們不熟悉的 SVG 元素或?qū)ふ?JavaScript 函數(shù)來(lái)執(zhí)行特定操作時(shí)嚴(yán)重依賴在線資源。在前端開(kāi)發(fā)中,MDN Web Docs ( https://developer.mozilla.org/ ) 始終是可靠且全面的資源。它包含 HTML 元素及其屬性、CSS 屬性和 JavaScript 函數(shù)的易于理解且通常可編輯的示例。

          響應(yīng)式 svg 容器

          在 SVG 圖形的世界中,<svg></svg>容器是在其上繪制所有內(nèi)容的白板。每個(gè) SVG 形狀都嵌套在<svg>父級(jí)中。要查看其實(shí)際效果,請(qǐng)?jiān)谠豬ndex.html內(nèi)編輯并添加 SVG 容器<body>。在瀏覽器中重新加載頁(yè)面。目前還看不到任何東西。

          <body>
            <svg></svg>
          </body>

          打開(kāi)瀏覽器的檢查器工具(在瀏覽器窗口中右鍵單擊并選擇“檢查”)。在檢查器窗口中,您將看到組成頁(yè)面的 DOM。找到<svg></svg>容器,也稱為 SVG 節(jié)點(diǎn)。當(dāng)您在檢查器中將鼠標(biāo)移到它上面時(shí),SVG 元素會(huì)在頁(yè)面上突出顯示。您可以在圖 1.5 中看到此效果。

          圖 1.10 在 DOM 樹(shù)中選擇并在視口中突出顯示的 SVG 節(jié)點(diǎn)


          默認(rèn)情況下,瀏覽器為 SVG 容器提供寬度300px和高度。150px但我們也可以使用屬性來(lái)分配這些值。屬性用于提供有關(guān) HTML 元素的附加信息。對(duì)于內(nèi)聯(lián) SVG,我們主要使用屬性來(lái)設(shè)置組成 SVG 圖形的元素和形狀的大小和位置。

          例如,我們可以設(shè)置SVG 容器的寬度和高度屬性。返回到文本編輯器,并將 awidth和 aheight屬性添加到 SVG 容器。將它們的值設(shè)置為900和300并保存文件。

          <svg width="900" height="300"></svg>

          在瀏覽器中重新加載項(xiàng)目并在檢查工具中找到 SVG 節(jié)點(diǎn)。請(qǐng)注意,寬度和高度屬性現(xiàn)在顯示在 SVG 容器的括號(hào)內(nèi)。如果將鼠標(biāo)移到檢查工具 DOM 樹(shù)中的 SVG 節(jié)點(diǎn)上,您還會(huì)看到視口中的 SVG 容器現(xiàn)在的大小為 900 像素 x 300 像素。

          圖1.11 SVG節(jié)點(diǎn)采用其屬性指定的大小


          為了幫助我們查看 SVG 容器,而不必從檢查器中突出顯示它,讓我們給它一個(gè)邊框。向 SVG 容器添加樣式屬性并插入 CSS 邊框?qū)傩浴T谙乱粋€(gè)代碼片段中,我們使用 border 速記屬性創(chuàng)建一個(gè)寬度為 1px 的黑色實(shí)心邊框。

          <svg width="900" height="300" style="border:1px solid black;"></svg>

          保存文件,重新加載頁(yè)面并確認(rèn) SVG 容器周圍有邊框。現(xiàn)在,調(diào)整瀏覽器窗口的大小,直到它小于 SVG 容器。您將觀察到 SVG 容器保持固定的寬度和高度,并且不適應(yīng)瀏覽器窗口的大小。讓我們嘗試使 SVG 容器具有響應(yīng)能力。

          之前,我們將 SVG 屬性設(shè)置為絕對(duì)值 (900和300),瀏覽器將它們解釋為以像素為單位的測(cè)量值 (900px和300px)。但我們也可以使用百分比。在文本編輯器中,將寬度屬性更改為相對(duì)值“ 100%”,保存文件并重新加載頁(yè)面。

          <svg width="100%" height="300" style="border:1px solid black;"></svg>

          再次調(diào)整瀏覽器大小,并注意 SVG 如何獲取可用的完整寬度并保持 300 像素的固定高度。這更好,但我們失去了原來(lái)的縱橫比。

          為了使內(nèi)聯(lián) SVG 具有響應(yīng)能力,我們可以使用viewBox 屬性。在代碼編輯器中,從 SVG 容器中刪除width和屬性,并將它們替換為屬性。給它一個(gè)值。heightviewBox"0 0 900 300"

          <svg viewBox="0 0 900 300" style="border:1px solid black;"></svg>

          再次調(diào)整瀏覽器窗口的大小。你注意到了什么?SVG 容器現(xiàn)在可以適應(yīng)任何屏幕尺寸,同時(shí)保持其縱橫比為 900:300。我們有一個(gè)響應(yīng)式 SVG!

          正如您所注意到的,viewBox 屬性由四個(gè)值的列表組成。前兩個(gè)數(shù)字指定 viewBox 坐標(biāo)系的原點(diǎn)(x 和 y)。在本書(shū)中,我們將始終使用0 0,但很高興知道這些值可用于更改 SVG 容器的哪一部分在屏幕上可見(jiàn)。viewBox 屬性的最后兩個(gè)數(shù)字是其寬度和高度。它們定義 SVG 的縱橫比,并確保其完美縮放以適合任何容器而不變形。

          安裝在容器內(nèi)是這里的關(guān)鍵。到目前為止,我們的內(nèi)聯(lián) SVG 的容器是 HTML<body>元素,它通常會(huì)擴(kuò)展以適應(yīng)瀏覽器的視口。如果視口變得非常大,SVG 也會(huì)變得非常大。通常,我們希望 SVG 具有最大寬度,以便它不會(huì)大于頁(yè)面上的其余內(nèi)容。為此,請(qǐng)將 SVG 容器包裝在寬度為 100%、最大寬度為 1200px 的 div 內(nèi)。為簡(jiǎn)單起見(jiàn),我們將這些屬性設(shè)置為內(nèi)聯(lián)樣式,但在實(shí)際項(xiàng)目中,這些屬性將來(lái)自 CSS 文件。請(qǐng)注意,我們還添加了值邊距“ 0 auto”,以使 SVG 在頁(yè)面上水平居中。

          <div style="width:100%; max-width:1200px; margin:0 auto;">
            <svg viewBox="0 0 900 300" style="border:1px solid black;"> ... </svg>
          </div>

          嘗試再次調(diào)整瀏覽器的大小,看看我們的 SVG 如何優(yōu)雅地適應(yīng)任何屏幕尺寸,同時(shí)尊重其容器的最大寬度。該策略有助于將 D3 可視化注入響應(yīng)式網(wǎng)頁(yè),我們將在本書(shū)中使用它。

          svg坐標(biāo)系

          既然我們知道了如何使內(nèi)聯(lián) SVG 具有響應(yīng)性,那么解決 SVG 形狀在 SVG 容器內(nèi)的定位方式就很重要了。SVG 容器就像一張白紙,我們可以在上面繪制矢量形狀。矢量形狀是根據(jù)基本幾何原理定義的,并參考 SVG 容器的坐標(biāo)系進(jìn)行定位。

          SVG 坐標(biāo)系與笛卡爾坐標(biāo)系類似。其 2D 平面使用兩個(gè)垂直軸來(lái)確定元素的位置,稱為 x 和 y。這兩個(gè)軸源自SVG 容器的左上角,如圖 1.12 所示。意思是y軸的正方向是從上到下。記住這一點(diǎn)可以讓你避免一些頭痛!

          圖1.12 SVG容器的坐標(biāo)系和元素的位置


          為了在 SVG 容器內(nèi)定位元素,我們從左上角的原點(diǎn)開(kāi)始向右移動(dòng)。這將為我們提供元素的水平 (x) 位置。對(duì)于垂直 (y) 位置,我們從頂部開(kāi)始向下移動(dòng)。這些位置由每個(gè) SVG 形狀的表示屬性定義。

          現(xiàn)在,我們將了解您在構(gòu)建 D3 項(xiàng)目時(shí)經(jīng)常遇到的 SVG 形狀。我們還將討論它們的主要表現(xiàn)屬性。這里的目標(biāo)絕不是編寫 SVG 提供的所有形狀和功能的綜合指南,而是涵蓋支持您的 D3 之旅的基礎(chǔ)知識(shí)。

          數(shù)據(jù)可視化技巧:幾何基元

          出色的藝術(shù)家可以用矢量圖形繪制任何東西,但您可能不會(huì)因?yàn)槟且幻囆g(shù)家而關(guān)注 D3。相反,您正在處理圖形并考慮更務(wù)實(shí)的目標(biāo)。從這個(gè)角度來(lái)看,理解幾何基元(也稱為圖形基元)的概念至關(guān)重要。幾何基元是簡(jiǎn)單的形狀,例如點(diǎn)、線、圓和矩形。這些形狀可以組合成更復(fù)雜的圖形,特別方便直觀地顯示信息。

          基元對(duì)于理解您在現(xiàn)實(shí)世界中看到的復(fù)雜信息可視化也很有用。樹(shù)形布局,就像我們將在第 10 章中構(gòu)建的那樣,當(dāng)您意識(shí)到它們只是圓形和直線時(shí),它們就不那么令人生畏了。當(dāng)您將交互式時(shí)間線視為矩形和點(diǎn)的集合時(shí),它們更容易理解和創(chuàng)建。即使是主要以多邊形、點(diǎn)和線形式出現(xiàn)的地理數(shù)據(jù),當(dāng)您將其分解為最基本的圖形結(jié)構(gòu)時(shí),也不會(huì)那么混亂。

          線條元素可能是所有 SVG 形狀中最簡(jiǎn)單的。它獲取兩個(gè)點(diǎn)的位置,設(shè)置為屬性,并在它們之間繪制一條直線。返回到該index.html文件,并在 SVG 容器內(nèi)添加一個(gè)<line />元素。聲明其屬性x1和y1并分別賦予它們值 50 和 45。這意味著我們的線的起點(diǎn)位于(50, 45)SVG 容器的坐標(biāo)系中。如果從 SVG 容器的左上角開(kāi)始,向右移動(dòng) 50 像素,向下移動(dòng) 45 像素,您將遇到線條的起點(diǎn)。(140, 225)同樣,使用屬性x2和y2將線的端點(diǎn)設(shè)置為。

          <svg>
            <line x1="50" y1="45" x2="140" y2="225" />
          </svg>

          圖1.13 在SVG容器的坐標(biāo)系中定位線元素


          如果您保存并重新加載項(xiàng)目,您的線條將不可見(jiàn),您可能想知道發(fā)生了什么。為了使 SVG 線條在屏幕上可見(jiàn),我們還需要設(shè)置其描邊屬性,該屬性控制線條的顏色。border 屬性的值與 CSS color 屬性類似。它可以是顏色名稱 ( black, blue, ...)、RGB 顏色 ( rgb(255,0,0)) 或十六進(jìn)制值 ( #808080)。向您的線條添加筆劃屬性,并為其指定您選擇的顏色(我們使用黑色)。現(xiàn)在它應(yīng)該在屏幕上可見(jiàn)。

          <line x1="50" y1="45" x2="140" y2="225" stroke="black" />

          如果我們想設(shè)置線條的寬度,我們可以使用描邊寬度屬性。此屬性接受絕對(duì)數(shù)字(轉(zhuǎn)換為像素)或相對(duì)值 (%)。例如,以下行的 a 為stroke-width3px。如果stroke-width未聲明該屬性,瀏覽器將應(yīng)用默認(rèn)值 1px。

          <line x1="50" y1="45" x2="140" y2="225" stroke="black" stroke-width="3" />

          打開(kāi)瀏覽器的檢查器工具并找到 SVG 節(jié)點(diǎn)及其包含的行。雙擊其中一個(gè)屬性,更改其值并觀察新值如何修改線的起點(diǎn)或終點(diǎn)。花時(shí)間嘗試不同的值,以確認(rèn)您了解屬性x1、y1、x2和如何y2影響線條的位置和長(zhǎng)度。

          -20現(xiàn)在,為屬性賦予 值x1。你看到線的起點(diǎn)是如何消失的嗎?落在 SVG viewBox 之外的任何形狀或形狀部分在屏幕上都不可見(jiàn)。不過(guò),該元素仍然存在于 DOM 中。我們可以訪問(wèn)和操縱它。如果 SVG 中的某個(gè)元素不可見(jiàn),并且您不知道為什么首先要檢查它是否在 SVG viewBox 之外!請(qǐng)記住,您始終可以通過(guò)使用開(kāi)發(fā)人員工具檢查 DOM 來(lái)找到它。正如我們之前所做的那樣,如果將鼠標(biāo)移到檢查器工具中的元素上,即使它位于 SVG viewBox 之外,它也會(huì)在視口中突出顯示。

          圖 1.14 SVG 線在 SVG 容器外部時(shí)部分隱藏



          筆記

          為了提高效率,大多數(shù) SVG 元素只需要一個(gè)自閉合標(biāo)簽(我們使用 <line /> 而不是 <line></line>)。與其他一些 HTML 標(biāo)簽一樣,SVG 元素的固有結(jié)構(gòu)在自閉合標(biāo)簽中提供了所有必需的信息。這對(duì)于 SVG 文本元素有所不同,其中文本放置在開(kāi)始標(biāo)簽和結(jié)束標(biāo)簽之間。

          長(zhǎng)方形

          顧名思義,矩形元素<rect />在屏幕上繪制一個(gè)矩形形狀。該<rect />元素需要四個(gè)屬性才能可見(jiàn)。屬性x和y聲明矩形左上角的位置,而屬性width和height分別控制其寬度和高度。<rect />在 SVG 容器中添加以下元素及其屬性。

          <rect x="260" y="25" width="120" height="60" />

          在我們的示例中,矩形的左上角位于SVG 容器原點(diǎn)的260px右側(cè)和下方。25px它的寬度為120px,高度為60px。與其他位置屬性一樣,我們可以使用百分比而不是絕對(duì)數(shù)字來(lái)設(shè)置它們的值。例如,如果我們將該width屬性設(shè)置為50%,則矩形將擴(kuò)展到 SVG 容器寬度的一半。

          圖 1.15 在 SVG 容器的坐標(biāo)系中定位矩形并調(diào)整其大小


          您可能已經(jīng)注意到我們的矩形充滿了黑色。默認(rèn)情況下,瀏覽器對(duì)大多數(shù) SVG 形狀應(yīng)用黑色填充。我們可以通過(guò)設(shè)置fill屬性并為其指定任何 CSS 顏色來(lái)更改該顏色。如果我們想給矩形添加邊框,我們添加一個(gè)描邊屬性。圖 1.16 顯示了一些示例。請(qǐng)注意,如果不聲明屬性,則矩形周圍不會(huì)繪制邊框stroke。另外,在最后一個(gè)矩形中,屬性fill-opacity和border-opacity用于使fill和stroke半透明。與 CSS 中一樣,不透明度可以設(shè)置為絕對(duì)值 ( 0.3) 或百分比 (30%)。與填充和描邊相關(guān)的所有屬性也可以從 CSS 文件設(shè)置或修改。

          圖 1.16 應(yīng)用于矩形 SVG 形狀的不同樣式屬性


          如果您希望矩形具有圓角,則只需添加rxry屬性,分別是水平和垂直角半徑。這些屬性接受絕對(duì)值(以像素為單位)和相對(duì)值(百分比)。例如,下面矩形的每個(gè)角的半徑都是 20px。將此矩形添加到您的形狀庫(kù)中。

          <rect x="260" y="100" width="120" height="60" rx="20" ry="20" />

          此時(shí),您可能想知道 SVG 中是否有一個(gè)可以繪制正方形的元素。我們不需要一個(gè)!在 SVG 中,我們<rect />通過(guò)賦予元素相等width和height屬性來(lái)繪制帶有元素的正方形。例如,以下<rect />元素將繪制一個(gè) 60px x 60px 的正方形。也將它添加到您的形狀庫(kù)中。

          <rect x="260" y="175" width="60" height="60" />

          作為參考,我們的形狀庫(kù)中現(xiàn)在有三種類型的 SVG 矩形:經(jīng)典矩形、圓角矩形和正方形。為了好玩,我們給了它們顏色#6ba5d7并玩弄它們stroke和fill屬性。請(qǐng)注意,只有筆劃在正方形上可見(jiàn),因?yàn)槠鋐ill屬性值為transparent或none。您的矩形應(yīng)該類似于圖 1.17 中的矩形,除非您更改了它們的屬性(我們鼓勵(lì)您這樣做)!

          <rect x="260" y="25" width="120" height="60" fill="#6ba5d7" />
          <rect x="260" y="100" width="120" height="60" rx="20" ry="20"
          ?  fill="#6ba5d7" />
          <rect x="260" y="175" width="60" height="60" fill="transparent"
          ?  stroke="#6ba5d7" />

          圖1.17 三種SVG矩形


          SVG筆畫(huà)的位置

          當(dāng)您嘗試在可視化中對(duì)齊形狀時(shí)需要記住的一點(diǎn)是,筆劃是均勻地繪制在 SVG 形狀的內(nèi)部和外部邊界上的。如下圖所示,如果矩形的width屬性為 40px,則應(yīng)用 ofstroke-width會(huì)1在視覺(jué)上向矩形的左側(cè)添加 0.5px,向右側(cè)添加 0.5px(而不是像我們本能地認(rèn)為的那樣,向每邊添加 1px) ),實(shí)際總寬度為 41px。如果stroke-width是2,它會(huì)在每邊添加 1px,依此類推。

          筆劃寬度對(duì) SVG 形狀實(shí)際寬度的影響


          圓和橢圓

          圓形形狀經(jīng)常用于數(shù)據(jù)可視化。它們自然地吸引眼球,并使可視化感覺(jué)更加友好和有趣。我們使用<circle />元素繪制 SVG 圓圈。其所需屬性是圓心的位置 ( cx , cy ) 及其半徑 ( r )。圓的半徑是從圓心到其邊界上任意點(diǎn)所繪制的直線的長(zhǎng)度。將以下圓圈添加到您的形狀庫(kù)中。將其中心定位于(530, 80)并為其指定 50px 的半徑。

          <circle cx="530" cy="80" r="50" />

          圖 1.18 在 SVG 容器的坐標(biāo)系中定位圓和橢圓并調(diào)整其大小


          您還可以使用圓形的填充和描邊屬性。為了生成圖 1.18 中的效果,我們使用了透明填充和 3px 的描邊,顏色為#81c21c。

          類似地,<ellipse />元素需要形狀中心位置的屬性 ( cx, cy)。圓形具有恒定的半徑,而橢圓形的半徑則不同,從而使其具有扁平形狀。我們通過(guò)聲明水平半徑 ( rx ) 和垂直半徑 ( ry ) 來(lái)創(chuàng)建這種扁平化效果。將下一個(gè)片段添加到您的圖庫(kù)中。它將在圓下方繪制一個(gè)橢圓,水平半徑為 50px,垂直半徑為 30px。

          <ellipse cx="530" cy="205" rx="50" ry="30" />

          路徑

          SVG路徑是迄今為止所有 SVG 元素中最靈活的。它們?cè)?D3 中廣泛用于繪制幾乎所有無(wú)法用迄今為止討論的形狀基元之一(直線、矩形、圓形和橢圓形)表示的復(fù)雜形狀和曲線。

          d我們通過(guò)聲明其屬性(代表“draw”)來(lái)指示瀏覽器如何繪制路徑。該d屬性包含一個(gè)命令列表,從開(kāi)始繪制路徑的位置到要使用的曲線類型,直到指定我們是否希望路徑成為閉合形狀。例如,將以下路徑元素添加到您的庫(kù)中。在此示例中,d屬性以M680 150開(kāi)頭,表示“移動(dòng)到坐標(biāo)(680, 150)”。然后我們從當(dāng)前點(diǎn) (680, 150) 到字母 C 后面的第三個(gè)坐標(biāo) (755 150) 指定的端點(diǎn)繪制一條三次貝塞爾曲線。三次貝塞爾曲線需要控制點(diǎn),即字母 C 后面、起點(diǎn)和終點(diǎn)之間的坐標(biāo)((710, 80) 和 (725, 80))。這些控制點(diǎn)定義了曲線的陡峭程度。然后我們有字母 S,它代表“停止”。它的工作原理與字母 C 類似,只不過(guò)它通向曲線的端點(diǎn)。這里最后一條曲線的起點(diǎn)是(755 150),終點(diǎn)是(840, 150),控制點(diǎn)是(810, 220)。曲線可以由一個(gè)或兩個(gè)控制點(diǎn)定義。

          <path d="M680 150 C 710 80, 725 80, 755 150 S 810 220, 840 150" fill="none" 
          ?  stroke="#773b9a" stroke-width="3" />

          圖 1.19 一個(gè)簡(jiǎn)單的 SVG 路徑及其控制點(diǎn)


          要深入了解 SVG 路徑,請(qǐng)參閱 MDN 的教程:https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths。

          手動(dòng)編寫d屬性對(duì)于簡(jiǎn)單的形狀是可行的,但隨著形狀變得復(fù)雜而變得乏味。幸運(yùn)的是,D3 具有強(qiáng)大的形狀生成器,我們將在第 4 章中討論。

          關(guān)于路徑要記住的另一件重要的事情是瀏覽器將以黑色填充它們,除非我們將它們的fill屬性設(shè)置為noneor transparent。即使路徑未閉合(如我們的示例中所示),情況也是如此。

          文本

          <div>內(nèi)聯(lián) SVG 圖形的最大優(yōu)點(diǎn)之一是它們可以包含可導(dǎo)航的文本,就像插入一個(gè)或一個(gè)元素中的任何其他 HTML 文本一樣<p>。這對(duì)于可訪問(wèn)性來(lái)說(shuō)是一個(gè)很大的優(yōu)勢(shì)。

          由于數(shù)據(jù)可視化通常包含多個(gè)標(biāo)簽,因此有必要了解如何使用<text></text>元素操作 SVG 文本。讓我們向形狀庫(kù)添加標(biāo)簽,以了解 SVG 文本的基本原理。

          到目前為止討論的 SVG 形狀使用自閉合標(biāo)簽 ( <line />, <rect />, <path />, ...)。使用 SVGtext元素時(shí),我們需要使用開(kāi)始標(biāo)簽和結(jié)束標(biāo)簽。我們將要顯示的文本放置在這兩個(gè)標(biāo)簽之間。例如,讓我們?cè)?SVG 中添加一個(gè)表示“l(fā)ine”的文本元素。

          <text>line</text>

          保存文件并重新加載頁(yè)面。您可能希望文本出現(xiàn)在 SVG 容器的左上角,但實(shí)際上卻看不到......這是為什么?默認(rèn)情況下,SVG 文本的位置是參考其基線計(jì)算的,由屬性控制dominant-baseline。如果文本基線的坐標(biāo)是(0, 0),您可以在圖 1.20 中看到實(shí)際文本如何最終出現(xiàn)在 SVG 容器之外。由于位于 SVG 容器外部的任何元素都是不可見(jiàn)的,因此我們看不到文本。

          圖 1.20 位于 SVG 容器外部的文本



          使用 SVG 文本時(shí)要考慮的另一點(diǎn)是文本的流動(dòng)方式。常規(guī) HTML 元素按照控制內(nèi)容流的特定規(guī)則放置在頁(yè)面上。如果您將一堆<div></div>元素插入頁(yè)面中,它們會(huì)自然地堆疊在一起,并且它們的內(nèi)容將重排,以便它永遠(yuǎn)不會(huì)超出其容器。SVG 文本根本不流動(dòng),每個(gè) SVG 元素必須單獨(dú)定位。一種方法是設(shè)置它們的x和y屬性。如果我們使用這些屬性將文本放置在 處(60, 260),標(biāo)簽“l(fā)ine”將出現(xiàn)在形狀庫(kù)中 SVG 線的下方。

          <text x="60" y="260">line</text>

          為了練習(xí),創(chuàng)建一個(gè)新的文本元素,將標(biāo)簽“矩形”放置在矩形和正方形下方。

          到目前為止,我們已經(jīng)使用x和y屬性來(lái)聲明文本元素的左下角。但是如果我們想設(shè)置文本中點(diǎn)的位置怎么辦?我們可以通過(guò)使用屬性text-anchor并為其指定值來(lái)做到這一點(diǎn)middle。例如,我們可以使用此屬性將圓形的文本標(biāo)簽居中。

          <text x="530" y="155" text-anchor="middle">circle</text>

          圖1.21 text-anchor屬性影響SVG文本的對(duì)齊方式。它的默認(rèn)值是“開(kāi)始”。為了根據(jù)中間對(duì)齊文本元素,我們應(yīng)用“middle”的 text-andchor 屬性。類似地,為了根據(jù)文本的結(jié)尾對(duì)齊文本,我們應(yīng)用“end”的 text-andchor 屬性。


          最后為橢圓添加一個(gè)標(biāo)簽,為路徑元素添加另一個(gè)標(biāo)簽。默認(rèn)情況下,SVG 文本為黑色。您可以使用屬性更改其顏色fill。

          分組元素

          我們將在本節(jié)中討論的最后一個(gè) SVG 元素是組元素。group 或<g></g>元素與我們迄今為止討論的 SVG 元素不同,因?yàn)樗鼪](méi)有圖形表示,也不作為有界空間存在。相反,它是元素的邏輯分組。在創(chuàng)建由多個(gè)形狀和文本元素組成的可視化效果時(shí),您需要廣泛使用組。

          如果我們希望正方形和“rect”標(biāo)簽一起顯示并在 SVG 容器中作為一個(gè)整體移動(dòng),我們可以將它們放置在一個(gè)<g>元素內(nèi),如下例所示。請(qǐng)注意元素的左上角如何<rect>更改為(0, 0)。位于<text>處以(0, 85)保持其低于<rect>。

          <g>
            <rect x="0" y="0" width="60" height="60" />
            <text x="0" y="85">rect</text>
          </g>

          包含正方形及其標(biāo)簽的組現(xiàn)在顯示在 SVG 容器的左上角。我們可以將這個(gè)組及其包含的所有元素移動(dòng)到 SVG 容器中任何我們想要的位置,同時(shí)保持正方形與其標(biāo)簽之間的對(duì)齊。

          在 SVG 容器中移動(dòng)組是通過(guò)轉(zhuǎn)換屬性完成的。變換屬性比目前討論的屬性有點(diǎn)嚇人,但與 CSS 變換屬性相同。它采用一個(gè)變換(平移、旋轉(zhuǎn)、縮放等)或一堆變換作為值。為了移動(dòng)一個(gè)組,我們使用translate(x, y)變換。如果我們想要將<rect>和<text>元素移回其原始位置,我們需要對(duì)元素應(yīng)用向右 260 像素和向下 175 像素的平移。<g>為此,我們將其 Transform 屬性設(shè)置為transform="translate(260,175)"。

          <g transform="translate(260,175)">
            <rect x="0" y="0" width="60" height="60" />
            <text x="0" y="85">rect</text>
          </g>

          <g> 元素的另一個(gè)有用的方面是它的子元素繼承它的屬性。為了說(shuō)明這一點(diǎn),讓我們將<g>元素中所有剩余的文本元素分組,除了標(biāo)簽“矩形”,我們已經(jīng)將其與正方形分組。

          <g>
            <text x="60" y="260">line</text>
            <text x="530" y="155" style="text-anchor:middle">circle</text>
            <text x="530" y="260" style="text-anchor:middle">ellipse</text>
            <text x="730" y="260">path</text>
          </g>

          #636466如果我們對(duì)組應(yīng)用填充屬性,<text>則該組內(nèi)的每個(gè)元素將繼承相同的顏色。同樣,如果我們向組添加樣式屬性,例如使用font-family和font-size屬性,則組內(nèi)的文本將繼承這些屬性。

          <g fill="#636466" style="font-size:16px; font-family:monospace">
            <text x="60" y="260">line</text>
            <text x="530" y="155" style="text-anchor:middle">circle</text>
            <text x="530" y="260" style="text-anchor:middle">ellipse</text>
            <text x="730" y="260">path</text>
          </g>

          最后重新加載頁(yè)面并觀察組內(nèi)的標(biāo)簽如何繼承組的顏色和字體,而保留在該組之外的標(biāo)簽則保持其原始外觀。這種將共享屬性應(yīng)用于組元素的技術(shù)非常方便,可以幫助您將 DRY(不要重復(fù)自己)編碼原則應(yīng)用到您的工作中。當(dāng)您需要更新這些屬性時(shí),它也會(huì)讓您的生活更輕松。

          恭喜您完成了本書(shū)的第一個(gè)練習(xí)!您可以在清單 1.1.b 和編碼文件的末尾文件夾中找到形狀庫(kù)的完整代碼。當(dāng)您構(gòu)建第一個(gè) D3 項(xiàng)目時(shí),請(qǐng)使用此練習(xí)作為參考。

          清單 1.1.b 用于 SVG 形狀圖庫(kù)練習(xí)的完整 HTML 文件

          <!DOCTYPE html>
          <html>
          <head> [...] </head>
          <body>
            <div style="width:100%; max-width:1200px; margin:0 auto;">
              <svg viewBox="0 0 900 300" style="border:1px solid black;">
           
                <line x1="50" y1="45" x2="140" y2="225" stroke="black" />
           
                <rect x="260" y="25" width="120" height="60" fill="#6ba5d7" />
                <rect x="260" y="100" width="120" height="60" rx="20" ry="20"  
                ?  fill="#6ba5d7" /> 
                <g transform="translate(260, 175)">
                  <rect x="0" y="0" width="60" height="60" fill="transparent"
                  ?  stroke="#6ba5d7" />
                  <text x="0" y="85">rect</text>
                </g>
           
                <circle cx="530" cy="80" r="50" fill="none" stroke="#81c21c" stroke-
                ?  width="3" />
                <ellipse cx="530" cy="205" rx="50" ry="30" fill="#81c21c" />
           
                <path d="M680 150 C 710 80, 725 80, 755 150 S 810 220, 840 150" 
                ?  fill="none" stroke="#773b9a" stroke-width="3" />
           
                <g fill="#636466" style="font-size:16px; font-family:monospace">
                  <text x="60" y="260">line</text>
                  <text x="530" y="155" style="text-anchor:middle">circle</text>
                  <text x="530" y="260" style="text-anchor:middle">ellipse</text>
                  <text x="730" y="260">path</text>
                </g>
           
              </svg>
            </div>
          </body>
          </html>

          練習(xí):創(chuàng)建 SVG 圖形

          現(xiàn)在輪到你了!創(chuàng)建如下圖所示的 SVG 圖形。您可以在本章代碼文件start內(nèi)的文件夾中工作。02_SVG_exercise以下是一些指導(dǎo)原則:

          · 創(chuàng)建一個(gè)寬度和高度均為 400 像素的響應(yīng)式 SVG 容器(當(dāng)屏幕上有足夠的空間時(shí))。

          · 繪制一個(gè)寬度和高度均為 200 像素的正方形。將其置于 SVG 容器的中心,并為其提供透明填充和 5px 黑色描邊。

          · 在 SVG 容器的中心添加一個(gè)半徑為 100px 的圓。將其填充屬性設(shè)置為 CSS 顏色名稱“plum”。

          · 繪制兩條對(duì)角黑線,筆劃為 5 像素。一個(gè)從正方形的左上角到右下角。另一個(gè)從正方形的右上角到左下角。

          · 添加文本“SVG 太棒了!” 位于正方形上方并將其置于 SVG 容器的中心。為文本指定以下樣式屬性:字體大小為 18px,字體系列為 sans-serif。

          我們鼓勵(lì)您構(gòu)建此 SVG 圖形來(lái)強(qiáng)化本節(jié)中討論的概念。


          02_SVG_exercise / end您可以在附錄 D 的 D.1.1 節(jié)和本章代碼文件的文件夾中找到解決方案。我們鼓勵(lì)您嘗試自己完成它。

          1.2.3 畫(huà)布和webGL

          我們已經(jīng)提到過(guò),我們通常使用 SVG 元素構(gòu)建 D3 項(xiàng)目。有時(shí),我們可能需要從大型數(shù)據(jù)集創(chuàng)建復(fù)雜的可視化效果,而傳統(tǒng)的 SVG 方法可能會(huì)產(chǎn)生性能問(wèn)題。請(qǐng)務(wù)必記住,對(duì)于數(shù)據(jù)可視化中的每個(gè)圖形細(xì)節(jié),D3 都會(huì)將一個(gè)或多個(gè) SVG 元素附加到 DOM。一個(gè)典型的例子是由數(shù)千個(gè)節(jié)點(diǎn)和鏈接組成的大型網(wǎng)絡(luò)可視化。這些可能會(huì)讓你的瀏覽器喘不過(guò)氣來(lái)……盡管瀏覽器可以輕松處理的對(duì)象數(shù)量隨著性能的提高而不斷增加,但普遍接受的經(jīng)驗(yàn)法則是,如果滿足以下條件,我們應(yīng)該考慮使用畫(huà)布而不是 SVG:可視化包含 1000 多個(gè)元素。

          Canvas 是一種客戶端繪圖 API,它使用腳本(通常是 JavaScript)來(lái)創(chuàng)建視覺(jué)效果和動(dòng)畫(huà)。它不會(huì)將 XML 元素添加到 DOM,這在從大型數(shù)據(jù)集構(gòu)建可視化時(shí)可以顯著提高性能。

          Canvas 還允許您使用 WebGL API 來(lái)創(chuàng)建 3D 對(duì)象。盡管學(xué)習(xí) WebGL 超出了本書(shū)的范圍,但為 Web 創(chuàng)建 3D 數(shù)據(jù)可視化是可能的。目前主要用于實(shí)驗(yàn)項(xiàng)目。在第 15 章中,我們將介紹如何使用畫(huà)布構(gòu)建可視化并討論其優(yōu)點(diǎn)和缺點(diǎn)。

          1.2.4 CSS

          CSS 代表層疊樣式表,是一種描述 DOM 元素如何在屏幕上顯示及其外觀的語(yǔ)言。從頁(yè)面的整體網(wǎng)格布局到文本使用的字體系列,再到散點(diǎn)圖中圓圈的顏色,CSS 可以將普通的 HTML 文件變成令人驚嘆的網(wǎng)頁(yè)。在 D3 項(xiàng)目中,我們通常使用內(nèi)聯(lián)樣式或通過(guò)外部樣式表應(yīng)用 CSS 樣式。

          內(nèi)聯(lián)樣式應(yīng)用于具有該style屬性的元素,如以下示例所示。該style屬性可以在傳統(tǒng)的 HTML 或 SVG 元素上使用,D3 有一個(gè)方便的方法來(lái)設(shè)置或修改該屬性,我們將在第 2 章中討論。

          <div style="padding:10px; background:#00ced1;"> ... </div>
          <text style="font-size:16px; font-family:serif;"> ... </text>

          內(nèi)聯(lián)樣式僅影響應(yīng)用它們的元素。如果我們想要將相同的設(shè)計(jì)傳播到多個(gè)元素,我們需要將相同的style屬性應(yīng)用于每個(gè)元素(或?qū)⑺性匕b在一起的 SVG 組)。它當(dāng)然有效,但不是最有效的方法。

          另一方面,外部 CSS 樣式表非常適合全局應(yīng)用樣式。一種策略是要求 D3 將相同的類名添加到多個(gè)元素。然后,我們使用此類名稱作為外部樣式表中的選擇器,并將相同的樣式屬性應(yīng)用于目標(biāo)元素組,如以下示例所示。這種方法效率更高,尤其是在維護(hù)大型項(xiàng)目時(shí)。它還遵循關(guān)注點(diǎn)分離原則,即我們將由 JavaScript 控制的行為與由 CSS 監(jiān)管的樣式分開(kāi)。請(qǐng)注意,CSS 預(yù)處理器(例如 SASS 和 LESS)是此處描述的外部樣式表方法的一部分。

          在 CSS 樣式表中:

          .my-class {
            font-size: 16px;
            font-family: serif;
          }
           
          In the DOM:
          <text class="my-class"> ... </text>

          請(qǐng)記住,內(nèi)聯(lián)樣式優(yōu)先于從外部樣式表應(yīng)用的樣式。在任何前端開(kāi)發(fā)項(xiàng)目中,規(guī)劃 CSS 樣式的架構(gòu)并考慮級(jí)聯(lián)順序非常重要。

          1.2.5 JavaScript

          D3 是一個(gè) JavaScript 庫(kù)。它在 JavaScript 現(xiàn)有核心功能的基礎(chǔ)上添加了新方法。這意味著在使用 D3 時(shí),具有一點(diǎn) JavaScript 經(jīng)驗(yàn)會(huì)很有幫助。這也意味著,在構(gòu)建 D3 項(xiàng)目時(shí),您可以訪問(wèn)所有現(xiàn)有的 JavaScript 功能。

          在本節(jié)中,我們將解釋 D3 項(xiàng)目中廣泛使用的兩個(gè) JavaScript 主題:方法鏈和對(duì)象操作。

          方法鏈接

          如果您在網(wǎng)絡(luò)上搜索 D3 項(xiàng)目的示例,您會(huì)發(fā)現(xiàn)在同一選擇上會(huì)依次調(diào)用方法。這種技術(shù)就是我們所說(shuō)的方法鏈,有助于保持代碼簡(jiǎn)潔和可讀。

          我們可以將方法鏈視為汽車裝配線。假設(shè)我們編寫了運(yùn)行這樣一條裝配線的腳本。正如您在下面的示例中看到的,我們首先聲明一個(gè)car創(chuàng)建新Car()對(duì)象的變量。然后我們調(diào)用函數(shù)putOnHood(),將引擎蓋放在汽車頂部,然后我們繼續(xù)調(diào)用將放置車輪、輪胎和燈的函數(shù)。每個(gè)連續(xù)的調(diào)用都會(huì)添加一個(gè)元素到Car()對(duì)象,并且,一旦執(zhí)行了所有方法,汽車就有了引擎蓋、車輪、輪胎和車燈。每個(gè)方法都會(huì)將更新后的汽車對(duì)象傳遞給下一個(gè)方法,從而“鏈接”。請(qǐng)注意,每個(gè)調(diào)用都用點(diǎn)分隔,并且調(diào)用方法的順序很重要。在我們的汽車裝配線示例中,我們需要先安裝車輪,然后才能將輪胎安裝到車輪上。

          let car = new Car().putOnHood().putOnWheels().putOnTires().putOnLights();

          現(xiàn)在讓我們看看如何在 D3 中使用方法鏈接。想象一下,我們想要從 DOM 中獲取所有 div 并在每個(gè) div 中添加一個(gè)段落元素。段落元素應(yīng)具有類屬性my-class并包含文本“Wow”。然后,我們要在每個(gè)段落中插入一個(gè) span 元素,并將文本“Even More Wow”以粗體顯示。如果沒(méi)有方法鏈接,我們需要將每個(gè)操作存儲(chǔ)到一個(gè)常量中,然后在執(zhí)行下一個(gè)操作時(shí)調(diào)用該常量,如下所示。光是看著就已經(jīng)很累了……

          const mySelection = d3.selectAll("div");
          const myParagraphs = mySelection.append("p");
          const myParagraphsWithAClass = myParagraphs.attr("class", "my-class");
          const myParagraphsWithText = myParagraphsWithAClass.text("Wow");
          const mySpans = myParagraphsWithText.append("span");
          const mySpansWithText = mySpans.text("Even More Wow")
          const myBoldSpans = mySpansWithText.style("font-weight", "900");

          由于方法鏈接,相同的示例變得更加簡(jiǎn)潔。

          d3.selectAll("div").append("p").attr("class", "my-class").text("Wow")
             ? .append("span").text("Even More Wow").style("font-weight", "900");

          在 D3 中,斷行(JavaScript 會(huì)忽略這一點(diǎn))以及縮進(jìn)鏈接方法是很常見(jiàn)的。這使得代碼更容易閱讀,并且縮進(jìn)可以幫助我們看到我們正在處理哪個(gè)元素。

          d3.selectAll("div")
            .append("p")
              .attr("class", "my-class")
              .text("Wow")
            .append("span")
              .text("Even More Wow")
              .style("font-weight", "900");

          不要擔(dān)心理解前面的代碼示例的作用,盡管您完全可以從不同方法的名稱中猜出它!目前,我們只希望您熟悉如何在 JavaScript 中鏈接方法。我們將在第 2 章中介紹 D3 特定的術(shù)語(yǔ)。

          數(shù)組和對(duì)象操作

          D3 都是關(guān)于數(shù)據(jù)的,而數(shù)據(jù)通常被構(gòu)造為 JavaScript 對(duì)象。了解這些對(duì)象的構(gòu)造以及如何訪問(wèn)和操作它們包含的數(shù)據(jù)將為您構(gòu)建可視化提供巨大幫助。

          我們首先討論簡(jiǎn)單數(shù)組,它是元素列表。在與數(shù)據(jù)相關(guān)的項(xiàng)目中,數(shù)組通常是數(shù)字或字符串的有序列表。

          const arrayOfNumbers = [17, 82, 9, 500, 40];
          const arrayOfStrings = ["blue", "red", "yellow", "orange"];

          數(shù)組中的每個(gè)元素都有一個(gè)數(shù)字位置,稱為索引,數(shù)組中第一個(gè)元素的索引為 0。

          arrayOfNumbers[0]   // => 17
          arrayOfStrings[2]   // => "yellow"

          數(shù)組具有長(zhǎng)度屬性,對(duì)于非稀疏數(shù)組,該屬性指定它們包含的元素?cái)?shù)量。由于數(shù)組是零索引的,因此數(shù)組中最后一個(gè)元素的索引對(duì)應(yīng)于數(shù)組長(zhǎng)度減一。

          arrayOfNumbers.length;                      // => 5
          arrayOfStrings[arrayOfStrings.length - 1]   // => "orange"

          我們還可以使用方法來(lái)確定數(shù)組是否包含特定值includes()。true如果數(shù)組中的元素之一與作為參數(shù)傳遞的值完全對(duì)應(yīng),則此方法返回。否則,它返回false。

          arrayOfNumbers.includes(9)         // => true
          arrayOfStrings.includes("pink")    // => false
          arrayOfStrings.includes("ellow")   // => false

          然而,大多數(shù)數(shù)據(jù)集并不是簡(jiǎn)單的數(shù)字或字符串列表,它們的每個(gè)數(shù)據(jù)點(diǎn)通常由多個(gè)屬性組成。讓我們想象一個(gè)虛構(gòu)機(jī)構(gòu)的員工數(shù)據(jù)庫(kù),如表 1.1 所示。該表包含四列:每個(gè)員工的 ID、姓名和職位,以及該員工是否在 D3 工作。

          表 1.1 包含員工及其職位的小型數(shù)據(jù)集

          ID

          姓名

          位置

          與_d3一起工作

          1

          佐伊

          數(shù)據(jù)分析師

          錯(cuò)誤的

          2

          詹姆士

          前端開(kāi)發(fā)人員

          真的

          3

          愛(ài)麗絲

          全棧開(kāi)發(fā)人員

          真的

          4

          休伯特

          設(shè)計(jì)師

          錯(cuò)誤的

          數(shù)據(jù)集中的每一行或數(shù)據(jù)點(diǎn)都可以由 JavaScript 對(duì)象表示,如下所示row1。

          const row1 = {
                         id:"1",
                         name:"Zoe",
                         position:"Data analyst",
                         works_with_d3:false
                       };

          我們可以使用點(diǎn)符號(hào)輕松訪問(wèn)對(duì)象中每個(gè)屬性的值。

          row1.name            // => "Zoe"
          row1.works_with_d3   // => false

          我們還可以使用括號(hào)表示法訪問(wèn)這些值。如果屬性名稱包含空格等特殊字符,或者如果我們之前將屬性名稱保存在常量或變量中,那么括號(hào)表示法會(huì)很方便。

          row1["position"]                      // => "Data analyst"
           
          const myProperty = "works_with_d3";
          row1[myProperty]                      // => false

          在現(xiàn)實(shí)生活中,數(shù)據(jù)集通常被格式化為對(duì)象數(shù)組。例如,如果我們使用 D3 加載表 1.2 中包含的數(shù)據(jù)集(正如我們將在第 3 章中學(xué)習(xí)的那樣),我們將獲得以下對(duì)象數(shù)組,可以將其保存在名為 的常量中data。

          const data = [
           {id:"1", name:"Zoe", position:"Data analyst", works_with_d3:false},
           {id:"2", name:"James", position:"Frontend developer", works_with_d3:true},
           {id:"3", name:"Alice", position:"Fullstack developer", works_with_d3:true},
           {id:"4", name:"Hubert", position:"Designer", works_with_d3:false}
          ];

          data我們可以使用循環(huán)遍歷數(shù)組中的每個(gè)元素或數(shù)據(jù)點(diǎn)。更具體地說(shuō),JavaScript forEach循環(huán)非常方便且易于編寫和閱讀。迭代數(shù)據(jù)集的一個(gè)常見(jiàn)用例是數(shù)據(jù)整理。當(dāng)我們加載外部 CSV 文件時(shí),數(shù)字通常被格式化為字符串。讓我們以data數(shù)組為例,將屬性的值id從字符串轉(zhuǎn)換為數(shù)字。

          在下面的示例中,數(shù)組迭代器使d我們能夠訪問(wèn)每個(gè)對(duì)象。使用點(diǎn)符號(hào),我們id使用運(yùn)算符將?每個(gè)值轉(zhuǎn)換為數(shù)字+。

          data.forEach(d => {
            d.id = +d.id;
          });

          JavaScript 提供了許多數(shù)組迭代器方法,可以幫助我們與數(shù)據(jù)交互,甚至在需要時(shí)重塑數(shù)據(jù)。假設(shè)我們想要將數(shù)據(jù)集中的每個(gè)員工定位到可視化上。創(chuàng)建一個(gè)僅包含員工姓名的簡(jiǎn)單數(shù)組可能會(huì)派上用場(chǎng),為此我們將使用map()方法。

          data.map(d => d.name);   // => ["Zoe", "James", "Alice", "Hubert"]

          同樣,如果我們只想隔離使用 D3 的員工,我們可以使用這些filter()方法。

          data.filter(d => d.works_with_d3);
           
          // => [
             {id:2, name:"James", position:"Frontend developer", works_with_d3:true},
             {id:4, name:"Hubert", position:"Designer", works_with_d3:true}
            ];

          最后,我們可以通過(guò)該方法找到id為3的員工find()。請(qǐng)注意,該find()方法在找到它要查找的值后停止迭代。我們只能在搜索單個(gè)數(shù)據(jù)點(diǎn)時(shí)使用此方法。

          data.find(d => d.id === 3);
           
          // => {id:"3", name:"Alice", position:"Fullstack developer", works_with_d3:true}

          本節(jié)討論的方法遠(yuǎn)未涵蓋 JavaScript 提供的所有數(shù)組和對(duì)象操作技術(shù)。但在處理數(shù)據(jù)時(shí),您可能會(huì)不斷回想起它們。每當(dāng)您需要找到另一種方法來(lái)訪問(wèn)或操作數(shù)據(jù)時(shí),MDN Web 文檔 ( https://developer.mozilla.org/ ) 始終是包含大量示例的可靠參考。

          1.2.6 Node 和 JavaScript 框架

          JavaScript 在過(guò)去十年中發(fā)生了重大變化。現(xiàn)代 JavaScript 的兩個(gè)最重要的趨勢(shì)是 Node.js 的興起和 JavaScript 框架作為大多數(shù)項(xiàng)目標(biāo)準(zhǔn)的建立。

          對(duì)于 D3 項(xiàng)目,我們想了解的主要 Node 技術(shù)是 NPM,即 Node Package Manager。NPM 允許您安裝“模塊”或小型 JavaScript 代碼庫(kù)以在應(yīng)用程序中使用。您不必包含<script>對(duì)單個(gè)文件的一堆標(biāo)記引用,并且如果模塊已構(gòu)建為不是一個(gè)整體結(jié)構(gòu),則可以減少應(yīng)用程序中包含的代碼量。

          D3.js 版本 7 于 2021 年中期發(fā)布,利用了模塊導(dǎo)入的優(yōu)勢(shì)。在本書(shū)中,您將看到以兩種方式之一使用 D3 的示例。我們要么加載整個(gè) D3 庫(kù),就像我們?cè)诘?2 章中所做的那樣,要么只包含我們需要的 D3 的各個(gè)部分,正如您將在后面的示例中看到的那樣。我們可以使用腳本標(biāo)簽來(lái)做到這一點(diǎn),但從第 2 部分開(kāi)始,我們將使用 NPM 導(dǎo)入 D3 模塊,因?yàn)檫@被認(rèn)為是當(dāng)今的標(biāo)準(zhǔn)做法。如果您交付專業(yè)的 D3 項(xiàng)目,您可能需要熟悉它。

          如果您已經(jīng)參與了專業(yè)的 Web 項(xiàng)目,那么您也很有可能正在使用 JavaScript 框架,例如 React、Angular、Vue 或 Svelte。框架為開(kāi)發(fā)人員提供了使用模塊化、可重用且可測(cè)試的代碼構(gòu)建 Web 項(xiàng)目的基礎(chǔ)。這些框架負(fù)責(zé)構(gòu)建和更新 DOM,這也是 D3 庫(kù)所做的事情。在第 8 章中,我們將討論在 JavaScript 框架內(nèi)構(gòu)建 D3 可視化時(shí)避免沖突的策略。

          最后,在專業(yè)的工作環(huán)境中,您可能會(huì)將 D3 與 TypeScript 結(jié)合使用。TypeScript 是 JavaScript 的語(yǔ)法超集,為代碼添加了類型安全性。盡管我們不會(huì)在本書(shū)中詳細(xì)討論它,但 D3 方法的類型可以使用 NPM 包 @type/d3 ( https://www.npmjs.com/package/@types/d3 ) 進(jìn)行安裝。在第 8 章中,我們將在 Angular 項(xiàng)目中使用此類類型。

          1.2.7 可觀察的筆記本

          如果您在網(wǎng)絡(luò)上搜索 D3 項(xiàng)目的示例,您無(wú)疑會(huì)遇到 Observable 筆記本 ( observablehq.com )。Observable 是數(shù)據(jù)科學(xué)和可視化的協(xié)作平臺(tái),類似于 Python 項(xiàng)目的 Jupyter 環(huán)境。Observable 平臺(tái)由 Mike Bostock 創(chuàng)建,取代了之前的在線 D3 沙箱bl.ocks.org 。所有官方的 D3 示例現(xiàn)在都位于 Observable 上,并且 D3 社區(qū)在那里非常活躍。

          重要的是要知道 Observable 要求您學(xué)習(xí)一種處理特定于該平臺(tái)的 D3 項(xiàng)目的方法。此外,您不能直接將 Observable Notebook 復(fù)制粘貼到前端開(kāi)發(fā)環(huán)境中(但有多種方法可以導(dǎo)出和重用它們)。由于本書(shū)的重點(diǎn)是在類似于我們?nèi)绾谓桓?D3 項(xiàng)目進(jìn)行生產(chǎn)的環(huán)境中構(gòu)建 D3 可視化,因此我們不會(huì)討論 Observable 筆記本。如果您有興趣學(xué)習(xí) Observable,您可以在observablehq.com/tutorials找到一系列優(yōu)秀的教程。您將在本書(shū)中學(xué)到的大部分技術(shù)和概念都可以轉(zhuǎn)化為 Observable 筆記本。

          1.3 D3.js 表達(dá)的數(shù)據(jù)可視化標(biāo)準(zhǔn)

          數(shù)據(jù)可視化從未像今天這樣流行。豐富的地圖、圖表以及系統(tǒng)和數(shù)據(jù)集的復(fù)雜表示不僅存在于工作場(chǎng)所,而且還存在于我們的娛樂(lè)和日常生活中。隨著這種流行,使用視覺(jué)手段以及美學(xué)規(guī)則來(lái)表示數(shù)據(jù)和信息的類和子類庫(kù)不斷增長(zhǎng),以促進(jìn)易讀性和理解性。您的受眾,無(wú)論是公眾、學(xué)者還是決策者,已經(jīng)習(xí)慣了我們?cè)?jīng)認(rèn)為極其抽象和復(fù)雜的數(shù)據(jù)趨勢(shì)表示。這使得 D3 這樣的庫(kù)不僅受到數(shù)據(jù)科學(xué)家的歡迎,而且還受到記者、藝術(shù)家、學(xué)者、IT 專業(yè)人士,甚至數(shù)據(jù)可視化愛(ài)好者的歡迎。

          如此豐富的選項(xiàng)似乎讓人不知所措,而且修改數(shù)據(jù)集以顯示在流圖、樹(shù)狀圖或直方圖中相對(duì)容易,這往往會(huì)促進(jìn)這樣一種觀念:信息可視化更多地是關(guān)于風(fēng)格而不是實(shí)質(zhì)內(nèi)容。幸運(yùn)的是,完善的規(guī)則規(guī)定了針對(duì)不同系統(tǒng)的不同數(shù)據(jù)類型使用哪些圖表和方法。本書(shū)并不旨在涵蓋數(shù)據(jù)可視化中的所有最佳實(shí)踐,但我們將介紹其中的一些。盡管開(kāi)發(fā)人員使用 D3 徹底改變了顏色和布局的使用,但大多數(shù)人希望創(chuàng)建支持實(shí)際問(wèn)題的數(shù)據(jù)的可視化表示。

          當(dāng)您構(gòu)建第一個(gè)可視化項(xiàng)目時(shí),如果有疑問(wèn),請(qǐng)簡(jiǎn)化 - 通常,呈現(xiàn)直方圖比小提琴圖更好,或者分層網(wǎng)絡(luò)布局(如樹(shù)狀圖)比力導(dǎo)向的網(wǎng)絡(luò)布局更好。視覺(jué)上更復(fù)雜的數(shù)據(jù)顯示方法往往會(huì)激發(fā)更多的興奮,但也會(huì)導(dǎo)致觀眾關(guān)注圖形的美觀而不是數(shù)據(jù)。創(chuàng)建酷炫且令人瞠目結(jié)舌的可視化并沒(méi)有什么錯(cuò),但我們永遠(yuǎn)不應(yīng)該忘記任何數(shù)據(jù)可視化的主要目標(biāo)都是講述一個(gè)故事。詢問(wèn)周圍的人是否理解你的可視化以及他們?nèi)绾谓忉屗侵陵P(guān)重要的一步。他們需要解釋嗎?他們可以從與您的項(xiàng)目的互動(dòng)中得出哪些結(jié)論?故事被講述了嗎?

          盡管如此,為了正確部署信息可視化,您應(yīng)該知道該做什么和不該做什么。您需要對(duì)您的數(shù)據(jù)和受眾有深入的了解。D3 賦予我們巨大的靈活性,但正如俗話所說(shuō),“能力越大,責(zé)任越大”。雖然知道某些圖表更適合表示特定類型的數(shù)據(jù)固然很好,但更重要的是要記住,如果不謹(jǐn)慎地從知情的角度構(gòu)建數(shù)據(jù)可視化,則可能會(huì)攜帶錯(cuò)誤信息。如果您打算設(shè)計(jì)自己的可視化,那么了解數(shù)據(jù)可視化最佳實(shí)踐是至關(guān)重要的。了解這一點(diǎn)的最佳方法是回顧知名設(shè)計(jì)師和信息可視化從業(yè)者的工作。盡管整個(gè)圖書(shū)館的作品都在處理這些問(wèn)題,以下是我們發(fā)現(xiàn)的一些有用的內(nèi)容,可以幫助您了解基礎(chǔ)知識(shí)。這些絕不是學(xué)習(xí)數(shù)據(jù)可視化的唯一文本,但它們是一個(gè)很好的起點(diǎn)。

          • 更好的數(shù)據(jù)可視化,喬納森施瓦比什
          • 功能藝術(shù)真實(shí)藝術(shù)圖表如何謊言,阿爾貝托·開(kāi)羅
          • 數(shù)據(jù)可視化數(shù)據(jù)驅(qū)動(dòng)設(shè)計(jì)手冊(cè),安迪·柯克
          • 定量信息的視覺(jué)顯示設(shè)想信息,愛(ài)德華·塔夫特
          • 信息設(shè)計(jì),伊莎貝爾·梅雷萊斯
          • 模式識(shí)別,克里斯蒂安·斯溫哈特
          • 可視化分析與設(shè)計(jì),Tamara Munzner

          在閱讀有關(guān)數(shù)據(jù)可視化的內(nèi)容時(shí)要記住的一件事是,文獻(xiàn)通常關(guān)注靜態(tài)圖表。使用 D3,您將進(jìn)行交互式動(dòng)態(tài)可視化。一些交互可以使可視化不僅更具可讀性,而且更有吸引力。感覺(jué)自己是在探索而不是閱讀的用戶,即使只是將鼠標(biāo)懸停在事件上幾次或簡(jiǎn)單地單擊進(jìn)行縮放,也可能會(huì)發(fā)現(xiàn)可視化的內(nèi)容比閱讀靜態(tài)等效內(nèi)容更引人注目和更令人難忘。但這種增加的復(fù)雜性需要了解用戶體驗(yàn)。我們將在第 7 章中更詳細(xì)地討論這一點(diǎn)。

          我們的第一章到此結(jié)束!盡管我們還沒(méi)有使用過(guò) D3,但您現(xiàn)在已經(jīng)掌握了入門所需的所有知識(shí)。當(dāng)您不確定應(yīng)該在可視化中使用哪個(gè) SVG 元素或者需要提醒如何使用 JavaScript 操作數(shù)據(jù)時(shí),請(qǐng)繼續(xù)返回本章。從下一章開(kāi)始,我們將卷起袖子,創(chuàng)建 D3 可視化。

          1.4 總結(jié)

          • 當(dāng)您希望在數(shù)據(jù)可視化方面擁有完全的創(chuàng)意和技術(shù)自由時(shí),D3 是您的首選工具。
          • D3 應(yīng)用程序的樣式和服務(wù)與傳統(tǒng) Web 內(nèi)容類似。
          • D3 從來(lái)不會(huì)單獨(dú)使用,而是技術(shù)和工具生態(tài)系統(tǒng)的一部分,我們將這些技術(shù)和工具結(jié)合起來(lái)創(chuàng)建豐富的 Web 界面:HTML、CSS、JavaScript、SVG、Canvas 和 React 或 Svelte 等框架。
          • 我們?cè)跇?gòu)建數(shù)據(jù)可視化時(shí)最常使用的 SVG 形狀是直線、矩形、圓形、橢圓形、路徑和文本。
          • 您需要對(duì)這些形狀及其主要屬性有基本的了解才能使用 D3。使用 D3 編寫 JavaScript 時(shí),您應(yīng)該熟悉兩個(gè)主題:方法鏈和對(duì)象操作。方法鏈接是一種模式,其中在同一對(duì)象上依次調(diào)用多個(gè)方法。在 D3 中,數(shù)據(jù)集通常被構(gòu)造為對(duì)象數(shù)組。JavaScript 提供了多種方法來(lái)訪問(wèn)和操作這些結(jié)構(gòu)中的數(shù)據(jù)。
          • 作為 D3 開(kāi)發(fā)人員,深入了解數(shù)據(jù)可視化最佳實(shí)踐非常重要。多種資源可以幫助您開(kāi)始學(xué)習(xí)之旅。

          眾號(hào):

          CSS

          1. 請(qǐng)解釋CSS的盒模型是什么,并描述其組成部分。

          答案:CSS的盒模型是用于布局和定位元素的概念。它由內(nèi)容區(qū)域、內(nèi)邊距、邊框和外邊距組成,這些部分依次包裹在元素周圍。

          2. 解釋CSS中的選擇器及其優(yōu)先級(jí)。

          答案:CSS選擇器用于選擇要應(yīng)用樣式的HTML元素。選擇器的優(yōu)先級(jí)規(guī)則是:內(nèi)聯(lián)樣式 > ID選擇器 > 類選擇器、屬性選擇器、偽類選擇器 > 元素選擇器 > 通用選擇器。同時(shí),使用!important可以提升樣式的優(yōu)先級(jí)。

          3. 解釋CSS中的浮動(dòng)(float)是如何工作的,并提供一個(gè)示例。

          答案:浮動(dòng)(float)是CSS中用于實(shí)現(xiàn)元素的左浮動(dòng)或右浮動(dòng),使其脫離文檔流并環(huán)繞在其周圍的元素。例如:

          .float-example {
          float: left;
          width: 200px;
          height: 200px;
          }

          4. 解釋CSS中的定位(position)屬性及其不同的取值。

          答案:定位(position)屬性用于控制元素的定位方式。常見(jiàn)的取值有:static(默認(rèn),按照文檔流定位)、relative(相對(duì)定位)、absolute(絕對(duì)定位)、fixed(固定定位)和sticky(粘性定位)。

          5. 解釋CSS中的層疊順序(z-index)是如何工作的。

          答案:層疊順序(z-index)用于控制元素在垂直方向上的堆疊順序。具有較高層疊順序值的元素將顯示在較低層疊順序值的元素之上。默認(rèn)情況下,層疊順序值為auto。

          6. 解釋CSS中的偽類和偽元素的區(qū)別,并給出一個(gè)示例。

          答案:偽類用于向選擇器添加特殊的狀態(tài),如:hover、:active等。偽元素用于向選擇器添加特殊的元素,如::before、::after等。例如:

          /* 偽類示例 */
          a:hover {
          color: red;
          }
          /* 偽元素示例 */
          p::before {
          content: "前綴";
          }

          7. 解釋CSS中的盒子模型的兩種模式:標(biāo)準(zhǔn)模式和怪異模式。

          答案:標(biāo)準(zhǔn)模式是按照W3C標(biāo)準(zhǔn)解析渲染頁(yè)面的模式。怪異模式是兼容舊版本瀏覽器的解析渲染頁(yè)面的模式。可以通過(guò)聲明來(lái)指定使用哪種模式。

          8. 解釋CSS中的BFC是什么,它的作用是什么?

          答案:BFC(塊級(jí)格式化上下文)是CSS中的一種渲染模式,它創(chuàng)建了一個(gè)獨(dú)立的渲染環(huán)境,其中的元素按照一定的規(guī)則進(jìn)行布局和定位。BFC的作用包括:清除浮動(dòng)、防止外邊距重疊等。

          9. 解釋CSS中的flexbox布局是什么,它的優(yōu)勢(shì)是什么?

          答案:flexbox布局是一種用于創(chuàng)建靈活的、響應(yīng)式的布局的CSS模塊。它通過(guò)flex容器和flex項(xiàng)目的組合來(lái)實(shí)現(xiàn)強(qiáng)大的布局能力。其優(yōu)勢(shì)包括簡(jiǎn)單易用、自適應(yīng)性強(qiáng)、對(duì)齊和分布控制靈活等。

          10.解釋CSS中的媒體查詢是什么,它的作用是什么?

          答案:媒體查詢是CSS中的一種技術(shù),用于根據(jù)設(shè)備的特性和屬性來(lái)應(yīng)用不同的樣式。通過(guò)媒體查詢,可以根據(jù)屏幕尺寸、設(shè)備類型、分辨率等條件來(lái)優(yōu)化頁(yè)面的布局和樣式。

          JavaScript

          1. 解釋JavaScript的數(shù)據(jù)類型,并舉例說(shuō)明每種類型。

          答案:JavaScript有七種數(shù)據(jù)類型:字符串(String)、數(shù)字(Number)、布爾值(Boolean)、對(duì)象(Object。Array/數(shù)組 和 function/函數(shù) 也屬于對(duì)象的一種)、空值(Null)、未定義(Undefined)、Symbol(獨(dú)一無(wú)二的值,ES6 新增)、BigInt (大整數(shù),能夠表示超過(guò) Number 類型大小限制的整數(shù),ES 2020新增)

          例如:

          let str = "Hello";
          let num = 10;
          let bool = true;
          let obj = { name: "John" };
          let arr = [1, 2, 3];
          let n = null;
          let undef;

          2. 解釋JavaScript中的變量提升(Hoisting)是什么。

          答案:變量提升是指在JavaScript中,變量和函數(shù)聲明會(huì)在代碼執(zhí)行之前被提升到作用域的頂部。這意味著可以在聲明之前使用變量和函數(shù)。例如:

          console.log(x); // 輸出 undefined
          var x = 5;

          3. 解釋JavaScript中的閉包(Closure)是什么,并舉例說(shuō)明。

          答案:閉包是指函數(shù)可以訪問(wèn)并操作其詞法作用域之外的變量。它通過(guò)在函數(shù)內(nèi)部創(chuàng)建一個(gè)內(nèi)部函數(shù),并返回該內(nèi)部函數(shù)來(lái)實(shí)現(xiàn)。例如:

          function outer() {
          let x = 10;
          function inner() {
          console.log(x);
          }
          return inner;
          }
          let closure = outer();
          closure(); // 輸出 10

          4. 解釋JavaScript中的事件冒泡(Event Bubbling)和事件捕獲(Event Capturing)。

          答案:事件冒泡是指事件從最具體的元素開(kāi)始向父元素逐級(jí)觸發(fā),直到觸發(fā)到根元素。事件捕獲是指事件從根元素開(kāi)始,逐級(jí)向最具體的元素觸發(fā)。可以使用addEventListener方法的第三個(gè)參數(shù)來(lái)控制是使用事件冒泡還是事件捕獲。

          5. 解釋JavaScript中的原型繼承(Prototype Inheritance)是什么。

          答案:原型繼承是JavaScript中實(shí)現(xiàn)對(duì)象之間繼承關(guān)系的一種機(jī)制。每個(gè)對(duì)象都有一個(gè)原型對(duì)象,它包含了共享的屬性和方法。當(dāng)訪問(wèn)對(duì)象的屬性或方法時(shí),如果對(duì)象本身沒(méi)有,則會(huì)沿著原型鏈向上查找。可以使用Object.create()方法或設(shè)置對(duì)象的__proto__屬性來(lái)實(shí)現(xiàn)原型繼承。

          6. 解釋JavaScript中的異步編程,并提供一個(gè)異步操作的示例。

          答案:異步編程是指在代碼執(zhí)行過(guò)程中,不會(huì)阻塞后續(xù)代碼執(zhí)行的一種編程方式。常見(jiàn)的異步操作包括網(wǎng)絡(luò)請(qǐng)求、定時(shí)器等。例如:

          console.log("開(kāi)始");
          setTimeout(function() {
          console.log("異步操作");
          }, 1000);
          console.log("結(jié)束");

          7. 解釋JavaScript中的this關(guān)鍵字的作用和使用場(chǎng)景。

          答案:this關(guān)鍵字在JavaScript中表示當(dāng)前執(zhí)行上下文的對(duì)象。它的具體取值根據(jù)函數(shù)的調(diào)用方式而定。在全局作用域中,this指向全局對(duì)象(瀏覽器環(huán)境中為window對(duì)象)。在函數(shù)中,this的指向取決于函數(shù)的調(diào)用方式,可以通過(guò)call、apply、bind等方法來(lái)顯式地指定this的值。

          8. 解釋JavaScript中的事件委托(Event Delegation)是什么,并提供一個(gè)使用事件委托的示例。

          答案:事件委托是指將事件處理程序綁定到父元素上,而不是直接綁定到每個(gè)子元素上。當(dāng)事件觸發(fā)時(shí),事件會(huì)冒泡到父元素,然后通過(guò)判斷事件的目標(biāo)來(lái)執(zhí)行相應(yīng)的處理邏輯。這樣可以減少事件處理程序的數(shù)量,提高性能。例如:

          <ul id="list">
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
          </ul>
          <script>
          document.getElementById("list").addEventListener("click", function(event) {
          if (event.target.tagName === "LI") {
          console.log(event.target.textContent);
          }
          });
          </script>

          9. 解釋JavaScript中的模塊化編程,并提供一個(gè)使用模塊的示例。

          答案:模塊化編程是指將代碼劃分為獨(dú)立的模塊,每個(gè)模塊負(fù)責(zé)特定的功能,并通過(guò)導(dǎo)入和導(dǎo)出來(lái)實(shí)現(xiàn)模塊之間的依賴關(guān)系。ES6引入了模塊化的語(yǔ)法,可以使用import和export關(guān)鍵字來(lái)導(dǎo)入和導(dǎo)出模塊。例如:

          // module.js
          export function sayHello() {
          console.log("Hello!");
          }
          // main.js
          import { sayHello } from "./module.js";
          sayHello(); // 輸出 "Hello!"

          10. 解釋JavaScript中的嚴(yán)格模式(Strict Mode)。

          答案:嚴(yán)格模式是一種JavaScript的執(zhí)行模式,它提供了更嚴(yán)格的語(yǔ)法和錯(cuò)誤檢查。在嚴(yán)格模式下,一些不安全或不推薦的語(yǔ)法會(huì)被禁用,同時(shí)會(huì)引入一些新的特性,如變量必須先聲明才能使用、禁止使用this指向全局對(duì)象等。

          11. 解釋JavaScript中的事件冒泡(Event Bubbling)和事件捕獲(Event Capturing)。

          答案:事件冒泡是指當(dāng)一個(gè)事件在DOM樹(shù)中觸發(fā)時(shí),它會(huì)從最內(nèi)層的元素開(kāi)始向外傳播至最外層的元素。事件捕獲是指當(dāng)一個(gè)事件在DOM樹(shù)中觸發(fā)時(shí),它會(huì)從最外層的元素開(kāi)始向內(nèi)傳播至最內(nèi)層的元素。

          12. 什么是原型鏈(Prototype Chain)?如何利用原型鏈實(shí)現(xiàn)繼承?

          答案:原型鏈?zhǔn)荍avaScript中對(duì)象之間的連接關(guān)系,每個(gè)對(duì)象都有一個(gè)指向其原型(prototype)的引用。通過(guò)原型鏈,對(duì)象可以繼承其原型對(duì)象的屬性和方法。可以使用原型鏈實(shí)現(xiàn)繼承,通過(guò)將一個(gè)對(duì)象的原型指向另一個(gè)對(duì)象,從而使得該對(duì)象可以訪問(wèn)另一個(gè)對(duì)象的屬性和方法。

          13. 解釋JavaScript中的防抖(Debounce)和節(jié)流(Throttle)。

          答案:防抖和節(jié)流都是用于控制函數(shù)執(zhí)行頻率的技術(shù)。防抖指的是在某個(gè)時(shí)間段內(nèi),只執(zhí)行最后一次觸發(fā)的函數(shù)調(diào)用。節(jié)流指的是在某個(gè)時(shí)間段內(nèi),按照固定的時(shí)間間隔執(zhí)行函數(shù)調(diào)用。

          14. 什么是事件循環(huán)(Event Loop)?請(qǐng)解釋JavaScript中的事件循環(huán)機(jī)制。

          答案:事件循環(huán)是JavaScript中處理異步操作的機(jī)制。事件循環(huán)不斷地從任務(wù)隊(duì)列中取出任務(wù)并執(zhí)行,直到任務(wù)隊(duì)列為空。事件循環(huán)由主線程和任務(wù)隊(duì)列組成,主線程負(fù)責(zé)執(zhí)行同步任務(wù),異步任務(wù)會(huì)被放入任務(wù)隊(duì)列中,等待主線程空閑時(shí)被執(zhí)行。

          15. 解釋JavaScript中的深拷貝和淺拷貝。

          答案:深拷貝是指創(chuàng)建一個(gè)新對(duì)象,將原始對(duì)象的所有屬性和嵌套對(duì)象的屬性都復(fù)制到新對(duì)象中。淺拷貝是指創(chuàng)建一個(gè)新對(duì)象,將原始對(duì)象的屬性復(fù)制到新對(duì)象中,但嵌套對(duì)象的引用仍然是共享的。

          16. 什么是異步編程?請(qǐng)列舉幾種處理異步操作的方法。

          答案:異步編程是一種處理可能耗時(shí)的操作而不阻塞主線程的編程方式。常見(jiàn)的處理異步操作的方法有回調(diào)函數(shù)、Promise、async/await和事件監(jiān)聽(tīng)等。

          17. 解釋JavaScript中的Hoisting(變量提升)。

          答案:變量提升是指在JavaScript中,變量和函數(shù)的聲明會(huì)被提升到當(dāng)前作用域的頂部。這意味著可以在聲明之前使用變量和函數(shù),但它們的賦值或定義仍然在原來(lái)的位置。

          18. 什么是柯里化(Currying)?請(qǐng)給出一個(gè)柯里化的示例。

          答案:柯里化是一種將接受多個(gè)參數(shù)的函數(shù)轉(zhuǎn)換為接受一個(gè)參數(shù)并返回一個(gè)新函數(shù)的過(guò)程。示例:

          function add(a) {
          return function(b) {
          return a + b;
          }
          }
          var add5 = add(5);
          console.log(add5(3)); // 輸出:8

          TypeScript

          1. 解釋TypeScript和JavaScript之間的關(guān)系。

          答案:TypeScript是JavaScript的超集,它添加了靜態(tài)類型和其他一些特性。TypeScript代碼可以編譯成JavaScript代碼,因此可以在任何支持JavaScript的環(huán)境中運(yùn)行。

          2. TypeScript中的類型注解是什么?如何使用類型注解?

          答案:類型注解是指在變量、函數(shù)參數(shù)、函數(shù)返回值等地方顯式地聲明類型信息。可以使用冒號(hào)(:)后跟類型來(lái)添加類型注解。例如:

          let num: number = 10;
          function add(a: number, b: number): number {
          return a + b;
          }

          3. TypeScript中的接口是什么?如何定義和使用接口?

          答案:接口是一種用于定義對(duì)象的結(jié)構(gòu)和類型的語(yǔ)法。可以使用interface關(guān)鍵字來(lái)定義接口。例如:

          interface Person {
          name: string;
          age: number;
          }
          function greet(person: Person) {
          console.log(`Hello, ${person.name}!`);
          }
          let john: Person = { name: "John", age: 25 };
          greet(john); // 輸出 "Hello, John!"

          4. TypeScript中的類是什么?如何定義和使用類?

          答案:類是一種用于創(chuàng)建對(duì)象的藍(lán)圖,它包含屬性和方法。可以使用class關(guān)鍵字來(lái)定義類。例如:

          class Person {
          name: string;
          age: number;
          constructor(name: string, age: number) {
          this.name = name;
          this.age = age;
          }
          greet() {
          console.log(`Hello, ${this.name}!`);
          }
          }
          let john = new Person("John", 25);
          john.greet(); // 輸出 "Hello, John!"

          5. TypeScript中的泛型是什么?如何使用泛型?

          答案:泛型是一種用于創(chuàng)建可重用代碼的工具,它允許在定義函數(shù)、類或接口時(shí)使用占位符類型。可以使用尖括號(hào)(<>)來(lái)指定泛型類型。例如:

          function identity<T>(value: T): T {
          return value;
          }
          let result = identity<string>("Hello");
          console.log(result); // 輸出 "Hello"

          6. TypeScript中的枚舉是什么?如何定義和使用枚舉?

          答案:枚舉是一種用于定義命名常量集合的語(yǔ)法。可以使用enum關(guān)鍵字來(lái)定義枚舉。例如:

          enum Color {
          Red,
          Green,
          Blue,
          }
          let color: Color = Color.Green;
          console.log(color); // 輸出 1

          7. TypeScript中的模塊是什么?如何導(dǎo)出和導(dǎo)入模塊?

          答案:模塊是用于組織和封裝代碼的單元。可以使用export關(guān)鍵字將模塊中的變量、函數(shù)、類等導(dǎo)出,以便其他模塊可以使用。可以使用import關(guān)鍵字來(lái)導(dǎo)入其他模塊的導(dǎo)出。例如:

          // module.ts
          export function greet(name: string) {
          console.log(`Hello, ${name}!`);
          }
          // main.ts
          import { greet } from "./module";
          greet("John"); // 輸出 "Hello, John!"

          8. TypeScript中的類型推斷是什么?如何使用類型推斷?

          答案:類型推斷是指TypeScript根據(jù)上下文自動(dòng)推斷變量的類型,而無(wú)需顯式地添加類型注解。例如:

          let num = 10; // 推斷為 number 類型
          let str = "Hello"; // 推斷為 string 類型

          9. TypeScript中的命名空間是什么?如何定義和使用命名空間?

          答案:命名空間是一種用于組織和封裝代碼的機(jī)制,它避免了全局命名沖突。可以使用namespace關(guān)鍵字來(lái)定義命名空間。例如:

          namespace MyNamespace {
          export function greet(name: string) {
          console.log(`Hello, ${name}!`);
          }
          }
          MyNamespace.greet("John"); // 輸出 "Hello, John!"

          10. TypeScript中的類型別名是什么?如何定義和使用類型別名?

          答案:類型別名是給類型起一個(gè)別名,以便在代碼中更方便地引用。可以使用type關(guān)鍵字來(lái)定義類型別名。例如:

          type Point = { x: number; y: number };
          function printPoint(point: Point) {
          console.log(`(${point.x}, ${point.y})`);
          }
          let p: Point = { x: 1, y: 2 };
          printPoint(p); // 輸出 "(1, 2)"

          VUE2

          1. Vue.js是什么?它有哪些特點(diǎn)?

          答案:Vue.js是一個(gè)用于構(gòu)建用戶界面的JavaScript框架。它具有以下特點(diǎn):

          響應(yīng)式數(shù)據(jù)綁定:通過(guò)使用Vue的數(shù)據(jù)綁定語(yǔ)法,可以實(shí)現(xiàn)數(shù)據(jù)的自動(dòng)更新。 組件化開(kāi)發(fā):Vue允許將頁(yè)面劃分為獨(dú)立的組件,提高了代碼的可維護(hù)性和復(fù)用性。 虛擬DOM:Vue使用虛擬DOM來(lái)跟蹤頁(yè)面上的變化,并高效地更新實(shí)際的DOM。 指令系統(tǒng):Vue提供了豐富的內(nèi)置指令,用于處理常見(jiàn)的DOM操作和邏輯控制。 生態(tài)系統(tǒng):Vue擁有龐大的生態(tài)系統(tǒng),包括插件、工具和第三方庫(kù),可以滿足各種開(kāi)發(fā)需求。

          2. Vue中的雙向數(shù)據(jù)綁定是如何實(shí)現(xiàn)的?

          答案:Vue中的雙向數(shù)據(jù)綁定是通過(guò)v-model指令實(shí)現(xiàn)的。v-model可以在表單元素(如、、)上創(chuàng)建雙向數(shù)據(jù)綁定。當(dāng)用戶輸入改變表單元素的值時(shí),數(shù)據(jù)模型會(huì)自動(dòng)更新;反之,當(dāng)數(shù)據(jù)模型的值改變時(shí),表單元素也會(huì)自動(dòng)更新。

          3. Vue中的生命周期鉤子有哪些?它們的執(zhí)行順序是怎樣的?

          答案:Vue中的生命周期鉤子包括beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy和destroyed。它們的執(zhí)行順序如下:

          beforeCreate created beforeMount mounted beforeUpdate updated beforeDestroy destroyed

          4. Vue中的計(jì)算屬性和監(jiān)聽(tīng)器有什么區(qū)別?

          答案:計(jì)算屬性是基于依賴的屬性,它根據(jù)其依賴的數(shù)據(jù)動(dòng)態(tài)計(jì)算得出值。計(jì)算屬性具有緩存機(jī)制,只有在依賴的數(shù)據(jù)發(fā)生變化時(shí)才會(huì)重新計(jì)算。監(jiān)聽(tīng)器是用于監(jiān)聽(tīng)數(shù)據(jù)的變化并執(zhí)行相應(yīng)的操作。當(dāng)數(shù)據(jù)發(fā)生變化時(shí),監(jiān)聽(tīng)器會(huì)立即執(zhí)行指定的回調(diào)函數(shù)。

          5. Vue中的組件通信有哪些方式?

          答案:Vue中的組件通信方式包括:

          父子組件通信:通過(guò)props向子組件傳遞數(shù)據(jù),子組件通過(guò)事件向父組件發(fā)送消息。 子父組件通信:子組件通過(guò)$emit觸發(fā)事件,父組件通過(guò)監(jiān)聽(tīng)事件并響應(yīng)。 兄弟組件通信:通過(guò)共享的父組件來(lái)傳遞數(shù)據(jù)或通過(guò)事件總線(Event Bus)進(jìn)行通信。 跨級(jí)組件通信:通過(guò)provide和inject來(lái)在祖先組件中提供數(shù)據(jù),然后在后代組件中使用。

          6. Vue中的路由是如何實(shí)現(xiàn)的?

          答案:Vue中的路由是通過(guò)Vue Router實(shí)現(xiàn)的。Vue Router是Vue.js官方提供的路由管理器,它允許開(kāi)發(fā)者在Vue應(yīng)用中實(shí)現(xiàn)單頁(yè)面應(yīng)用(SPA)。Vue Router通過(guò)配置路由映射關(guān)系,將URL路徑與組件進(jìn)行關(guān)聯(lián),并提供導(dǎo)航功能,使用戶可以在不刷新頁(yè)面的情況下切換視圖。

          7. Vue中的指令有哪些?舉例說(shuō)明它們的用法。

          答案:Vue中常用的指令包括:

          v-if:根據(jù)表達(dá)式的值條件性地渲染元素。 v-for:根據(jù)數(shù)組或?qū)ο蟮臄?shù)據(jù)進(jìn)行循環(huán)渲染。 v-bind:用于動(dòng)態(tài)綁定屬性或響應(yīng)式地更新屬性。 v-on:用于監(jiān)聽(tīng)DOM事件并執(zhí)行相應(yīng)的方法。 v-model:用于在表單元素上實(shí)現(xiàn)雙向數(shù)據(jù)綁定。 例如:

          <div v-if="show">顯示內(nèi)容</div>
          <ul>
          <li v-for="item in items" :key="item.id">{{ item.name }}</li>
          </ul>
          <img v-bind:src="imageUrl">
          <button v-on:click="handleClick">點(diǎn)擊按鈕</button>
          <input v-model="message">

          8. Vue中的watch和computed有什么區(qū)別?

          答案:watch和computed都可以用于監(jiān)聽(tīng)數(shù)據(jù)的變化,但它們的用法和實(shí)現(xiàn)方式略有不同。watch用于監(jiān)聽(tīng)指定的數(shù)據(jù)變化,并在數(shù)據(jù)變化時(shí)執(zhí)行相應(yīng)的操作。computed用于根據(jù)依賴的數(shù)據(jù)動(dòng)態(tài)計(jì)算得出一個(gè)新的值,并將該值緩存起來(lái),只有在依賴的數(shù)據(jù)發(fā)生變化時(shí)才會(huì)重新計(jì)算。

          9. Vue中的mixin是什么?它有什么作用?

          答案:Mixin是一種用于在多個(gè)組件之間共享代碼的方式。Mixin可以包含組件選項(xiàng)(如數(shù)據(jù)、方法、生命周期鉤子等),并將其合并到使用Mixin的組件中。這樣可以實(shí)現(xiàn)代碼的復(fù)用和組件的擴(kuò)展,減少重復(fù)編寫相似代碼的工作。

          10. Vue中的keep-alive是什么?它有什么作用?

          答案:是Vue中的一個(gè)內(nèi)置組件,用于緩存動(dòng)態(tài)組件。當(dāng)組件包裹在中時(shí),組件的狀態(tài)將被保留,包括它的實(shí)例、狀態(tài)和DOM結(jié)構(gòu)。這樣可以避免在組件切換時(shí)重復(fù)創(chuàng)建和銷毀組件,提高性能和用戶體驗(yàn)。

          11. 請(qǐng)解釋Vue.js中的依賴注入(Dependency Injection)是什么?它在Vue中的應(yīng)用場(chǎng)景是什么?

          答案:依賴注入是一種設(shè)計(jì)模式,用于將依賴關(guān)系從一個(gè)組件傳遞到另一個(gè)組件。在Vue中,依賴注入通過(guò)provide和inject選項(xiàng)實(shí)現(xiàn)。父組件通過(guò)provide提供數(shù)據(jù),然后子組件通過(guò)inject注入這些數(shù)據(jù)。它在跨多個(gè)層級(jí)的組件通信中非常有用。

          12. Vue.js中的渲染函數(shù)(Render Function)是什么?它與模板(Template)有什么區(qū)別?

          答案:渲染函數(shù)是一種用JavaScript代碼編寫組件的方式,它可以動(dòng)態(tài)地生成虛擬DOM。與模板相比,渲染函數(shù)提供了更大的靈活性和控制力,可以處理更復(fù)雜的邏輯和動(dòng)態(tài)渲染需求。

          13. Vue.js中的插槽(Slot)是什么?請(qǐng)?zhí)峁┮粋€(gè)具有命名插槽和作用域插槽的示例。

          答案:插槽是一種用于在組件中擴(kuò)展內(nèi)容的機(jī)制。命名插槽允許父組件向子組件插入具有特定名稱的內(nèi)容,而作用域插槽允許子組件將數(shù)據(jù)傳遞給父組件。示例:

          <!-- 父組件 -->
          <template>
          <div>
          <slot name="header"></slot>
          <slot :data="data"></slot>
          </div>
          </template>
          <!-- 子組件 -->
          <template>
          <div>
          <slot name="header">默認(rèn)標(biāo)題</slot>
          <slot :data="computedData">{{ computedData }}</slot>
          </div>
          </template>

          14. Vue.js中的動(dòng)畫(huà)系統(tǒng)是如何工作的?請(qǐng)?zhí)峁┮粋€(gè)簡(jiǎn)單的動(dòng)畫(huà)示例。

          答案:Vue.js的動(dòng)畫(huà)系統(tǒng)通過(guò)CSS過(guò)渡和動(dòng)畫(huà)類實(shí)現(xiàn)。通過(guò)在元素上添加過(guò)渡類或動(dòng)畫(huà)類,可以觸發(fā)相應(yīng)的過(guò)渡效果或動(dòng)畫(huà)效果。示例:

          <transition name="fade">
          <div v-if="show">顯示內(nèi)容</div>
          </transition>
          <!-- CSS樣式 -->
          <style>
          .fade-enter-active, .fade-leave-active {
          transition: opacity 0.5s;
          }
          .fade-enter, .fade-leave-to {
          opacity: 0;
          }
          </style>

          15. Vue.js中的錯(cuò)誤處理機(jī)制是什么?如何捕獲和處理Vue組件中的錯(cuò)誤?

          答案:Vue.js提供了全局的錯(cuò)誤處理機(jī)制和組件級(jí)別的錯(cuò)誤處理機(jī)制。全局錯(cuò)誤處理可以通過(guò)errorCaptured鉤子函數(shù)捕獲和處理錯(cuò)誤。組件級(jí)別的錯(cuò)誤處理可以通過(guò)errorCaptured鉤子函數(shù)或errorHandler選項(xiàng)捕獲和處理錯(cuò)誤。

          16. Vue.js中的服務(wù)端渲染(SSR)是什么?它有哪些優(yōu)勢(shì)和限制?

          答案:服務(wù)端渲染是指在服務(wù)器上生成HTML內(nèi)容并將其發(fā)送到瀏覽器進(jìn)行渲染的過(guò)程。Vue.js可以進(jìn)行服務(wù)端渲染,提供更好的首次加載性能和SEO優(yōu)化。然而,服務(wù)端渲染也帶來(lái)了一些限制,如增加了服務(wù)器負(fù)載和開(kāi)發(fā)復(fù)雜性。

          17. Vue.js中的響應(yīng)式數(shù)組有哪些限制?如何解決這些限制?

          答案:Vue.js的響應(yīng)式系統(tǒng)對(duì)于數(shù)組的變異方法(如push、pop、splice等)是無(wú)法追蹤的。為了解決這個(gè)限制,Vue提供了一些特殊的方法,如Vue.set、vm.$set和Array.prototype.splice。這些方法可以用于更新數(shù)組并保持響應(yīng)式。

          18. Vue.js中的性能優(yōu)化有哪些常見(jiàn)的技巧?

          答案:常見(jiàn)的Vue.js性能優(yōu)化技巧包括:

          使用v-if和v-for時(shí)注意避免不必要的渲染。 合理使用computed屬性和watch監(jiān)聽(tīng)器。 使用keep-alive組件緩存組件狀態(tài)。 使用異步組件進(jìn)行按需加載。 避免在模板中使用復(fù)雜的表達(dá)式。 使用key屬性管理組件和元素的復(fù)用。 合理使用懶加載和分割代碼。

          19. Vue.js中的路由導(dǎo)航守衛(wèi)有哪些?它們的執(zhí)行順序是怎樣的?

          答案:Vue.js中的路由導(dǎo)航守衛(wèi)包括全局前置守衛(wèi)、全局解析守衛(wèi)、全局后置守衛(wèi)、路由獨(dú)享守衛(wèi)和組件內(nèi)守衛(wèi)。它們的執(zhí)行順序如下:

          全局前置守衛(wèi)(beforeEach) 路由獨(dú)享守衛(wèi)(beforeEnter) 解析守衛(wèi)(beforeResolve) 組件內(nèi)守衛(wèi)(beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave) 全局后置守衛(wèi)(afterEach)

          20. Vue.js中的單元測(cè)試是如何進(jìn)行的?請(qǐng)?zhí)峁┮粋€(gè)簡(jiǎn)單的單元測(cè)試示例。

          答案:Vue.js的單元測(cè)試可以使用工具如Jest或Mocha進(jìn)行。示例:

          // 組件代碼
          // MyComponent.vue
          <template>
          <div class="my-component">
          <span>{{ message }}</span>
          <button @click="increment">增加</button>
          </div>
          </template>
          <script>
          export default {
          data() {
          return {
          message: 'Hello',
          count: 0
          }
          },
          methods: {
          increment() {
          this.count++
          }
          }
          }
          </script>
          // 單元測(cè)試代碼
          // MyComponent.spec.js
          import { shallowMount } from '@vue/test-utils'
          import MyComponent from './MyComponent.vue'
          describe('MyComponent', () => {
          it('renders message correctly', () => {
          const wrapper = shallowMount(MyComponent)
          expect(wrapper.find('span').text()).toBe('Hello')
          })
          it('increments count when button is clicked', () => {
          const wrapper = shallowMount(MyComponent)
          wrapper.find('button').trigger('click')
          expect(wrapper.vm.count).toBe(1)
          })
          })

          VUE3

          1. Vue.js 3中的Composition API是什么?它與Options API有什么區(qū)別?

          答案:Composition API是Vue.js 3中引入的一種新的組織組件邏輯的方式。它允許開(kāi)發(fā)者通過(guò)函數(shù)的方式組織和重用邏輯,而不是通過(guò)選項(xiàng)對(duì)象。相比之下,Options API是Vue.js 2中常用的組織組件邏輯的方式,通過(guò)選項(xiàng)對(duì)象中的屬性來(lái)定義組件的數(shù)據(jù)、方法等。

          2. Vue.js 3中的Teleport是什么?請(qǐng)給出一個(gè)Teleport的示例。

          答案:Teleport是Vue.js 3中引入的一種機(jī)制,用于將組件的內(nèi)容渲染到DOM樹(shù)中的任意位置。示例:

          <template>
          <div>
          <button @click="showModal = true">打開(kāi)模態(tài)框</button>
          <teleport to="body">
          <modal v-if="showModal" @close="showModal = false">模態(tài)框內(nèi)容</modal>
          </teleport>
          </div>
          </template>

          3. Vue.js 3中的響應(yīng)式系統(tǒng)是如何工作的?它與Vue.js 2中的響應(yīng)式系統(tǒng)有什么區(qū)別?

          答案:Vue.js 3中的響應(yīng)式系統(tǒng)使用了Proxy對(duì)象來(lái)實(shí)現(xiàn)。與Vue.js 2中的響應(yīng)式系統(tǒng)相比,Vue.js 3的響應(yīng)式系統(tǒng)具有更好的性能和更細(xì)粒度的追蹤,能夠更準(zhǔn)確地檢測(cè)到數(shù)據(jù)的變化,并且支持嵌套的響應(yīng)式數(shù)據(jù)。

          4. Vue.js 3中的Suspense是什么?它的作用是什么?

          答案:Suspense是Vue.js 3中引入的一種機(jī)制,用于處理異步組件的加載狀態(tài)。它可以在異步組件加載完成之前顯示一個(gè)占位符,并在加載完成后渲染異步組件的內(nèi)容。這樣可以更好地處理異步組件的加載過(guò)程,提供更好的用戶體驗(yàn)。

          5. Vue.js 3中的provide和inject有什么作用?請(qǐng)給出一個(gè)provide和inject的示例。

          答案:provide和inject用于實(shí)現(xiàn)組件之間的依賴注入。通過(guò)在父組件中使用provide提供數(shù)據(jù),然后在子組件中使用inject注入這些數(shù)據(jù)。示例:

          // 父組件
          const Parent = {
          provide: {
          message: 'Hello'
          },
          // ...
          }
          // 子組件
          const Child = {
          inject: ['message'],
          created() {
          console.log(this.message); // 輸出:Hello
          },
          // ...
          }

          6. Vue.js 3中的動(dòng)畫(huà)系統(tǒng)有哪些改進(jìn)?請(qǐng)列舉幾個(gè)改進(jìn)之處。

          答案:Vue.js 3中的動(dòng)畫(huà)系統(tǒng)相比Vue.js 2有以下改進(jìn)之處:

          更好的性能:Vue.js 3的動(dòng)畫(huà)系統(tǒng)使用了更高效的動(dòng)畫(huà)引擎,提供了更好的性能。 更簡(jiǎn)潔的語(yǔ)法:Vue.js 3的動(dòng)畫(huà)系統(tǒng)使用了更簡(jiǎn)潔的語(yǔ)法,使得動(dòng)畫(huà)的定義和使用更加直觀和方便。 支持更多的動(dòng)畫(huà)特性:Vue.js 3的動(dòng)畫(huà)系統(tǒng)支持更多的動(dòng)畫(huà)特性,如交互式動(dòng)畫(huà)和更復(fù)雜的動(dòng)畫(huà)效果。 Vue.js 3中的靜態(tài)提升(Static Tree Hoisting)是什么?它有什么優(yōu)勢(shì)? 答案:靜態(tài)提升是Vue.js 3中的一項(xiàng)優(yōu)化技術(shù),通過(guò)在編譯階段將靜態(tài)節(jié)點(diǎn)提升為常量,從而減少了運(yùn)行時(shí)的開(kāi)銷。這項(xiàng)優(yōu)化技術(shù)可以提高組件的渲染性能,并減少生成的代碼體積。

          7. Vue.js 3中的Fragment是什么?它的作用是什么?

          答案:Fragment是Vue.js 3中引入的一種機(jī)制,用于在組件中返回多個(gè)根節(jié)點(diǎn)。在Vue.js 2中,組件的模板只能有一個(gè) Vue.js 3中的Composition API中的ref和reactive有什么區(qū)別?什么時(shí)候使用哪個(gè)? 答案:ref用于創(chuàng)建一個(gè)響應(yīng)式的基本數(shù)據(jù)類型,而reactive用于創(chuàng)建一個(gè)響應(yīng)式的對(duì)象。當(dāng)需要?jiǎng)?chuàng)建一個(gè)簡(jiǎn)單的響應(yīng)式數(shù)據(jù)時(shí),可以使用ref,當(dāng)需要?jiǎng)?chuàng)建一個(gè)包含多個(gè)屬性的響應(yīng)式對(duì)象時(shí),可以使用reactive。

          8. Vue.js 3中的watchEffect和watch有什么區(qū)別?什么時(shí)候使用哪個(gè)?

          答案:watchEffect用于監(jiān)聽(tīng)響應(yīng)式數(shù)據(jù)的變化,并在回調(diào)函數(shù)中執(zhí)行相應(yīng)的操作。它會(huì)自動(dòng)追蹤依賴,并在依賴變化時(shí)重新運(yùn)行回調(diào)函數(shù)。watch用于監(jiān)聽(tīng)指定的響應(yīng)式數(shù)據(jù),并在其變化時(shí)執(zhí)行相應(yīng)的操作。它可以精確地指定要監(jiān)聽(tīng)的數(shù)據(jù),并提供更多的配置選項(xiàng)。一般來(lái)說(shuō),如果只需要監(jiān)聽(tīng)一個(gè)響應(yīng)式數(shù)據(jù)的變化并執(zhí)行相應(yīng)操作,可以使用watchEffect;如果需要更細(xì)粒度的控制,可以使用watch。

          9. Vue.js 3中的v-model指令在使用時(shí)有哪些注意事項(xiàng)?

          答案:在使用v-model指令時(shí),有以下注意事項(xiàng):

          v-model指令必須與一個(gè)表單元素一起使用,如、、等。 當(dāng)使用自定義組件時(shí),組件內(nèi)部必須實(shí)現(xiàn)modelValue屬性和update:modelValue事件,以支持v-model的雙向綁定。 可以使用.lazy修飾符實(shí)現(xiàn)在輸入框失去焦點(diǎn)時(shí)更新數(shù)據(jù)。 可以使用.trim修飾符自動(dòng)去除輸入框內(nèi)容的首尾空格。 可以使用.number修飾符將輸入框的值轉(zhuǎn)換為數(shù)字類型。

          10. Vue.js 3中的provide和inject是否支持響應(yīng)式數(shù)據(jù)?

          答案:默認(rèn)情況下,provide和inject不支持響應(yīng)式數(shù)據(jù)。如果需要在provide中提供一個(gè)響應(yīng)式數(shù)據(jù),可以使用ref或reactive將數(shù)據(jù)包裝起來(lái)。然后在inject中使用toRefs或toRef將數(shù)據(jù)解構(gòu)出來(lái),以獲取響應(yīng)式的引用。

          11. Vue.js 3中的nextTick方法有什么作用?在什么情況下使用它?

          答案:nextTick方法用于在下次DOM更新循環(huán)結(jié)束之后執(zhí)行回調(diào)函數(shù)。它可以用來(lái)確保在更新DOM后執(zhí)行某些操作,如操作更新后的DOM元素或獲取更新后的計(jì)算屬性的值。通常在需要等待DOM更新完成后進(jìn)行操作的情況下使用nextTick。

          12. Vue.js 3中的和組件有什么區(qū)別?

          答案:組件用于將組件的內(nèi)容渲染到DOM樹(shù)中的任意位置,而組件用于在組件進(jìn)入或離開(kāi)DOM樹(shù)時(shí)應(yīng)用過(guò)渡效果。主要用于組件的位置移動(dòng),而主要用于組件的顯示和隱藏過(guò)渡。

          13. Vue.js 3中的v-for指令中的key屬性有什么作用?為什么要使用它?

          答案:v-for指令中的key屬性用于給每個(gè)迭代項(xiàng)設(shè)置一個(gè)唯一的標(biāo)識(shí)符。它的作用是幫助Vue.js跟蹤每個(gè)節(jié)點(diǎn)的身份,以便在數(shù)據(jù)發(fā)生變化時(shí)高效地更新DOM。使用key屬性可以避免出現(xiàn)錯(cuò)誤的節(jié)點(diǎn)更新或重新排序的問(wèn)題。

          React

          1. 什么是React?它的核心概念是什么?

          答案:React是一個(gè)用于構(gòu)建用戶界面的JavaScript庫(kù)。它的核心概念是組件化和聲明式編程。React將用戶界面拆分為獨(dú)立的可重用組件,并使用聲明式語(yǔ)法描述組件的狀態(tài)和UI的關(guān)系,使得構(gòu)建復(fù)雜的UI變得簡(jiǎn)單和可維護(hù)。

          2. 什么是JSX?它與HTML有什么區(qū)別?

          答案:JSX是一種JavaScript的語(yǔ)法擴(kuò)展,用于在React中描述UI的結(jié)構(gòu)。它類似于HTML,但有一些區(qū)別:

          3. 什么是React組件?它們有哪兩種類型?

          答案:React組件是構(gòu)建用戶界面的獨(dú)立單元。React組件有兩種類型:

          函數(shù)組件:使用函數(shù)來(lái)定義組件,接收props作為參數(shù),并返回一個(gè)React元素。 類組件:使用ES6類來(lái)定義組件,繼承自React.Component類,通過(guò)render方法返回一個(gè)React元素。

          4. 什么是狀態(tài)(state)和屬性(props)?它們之間有什么區(qū)別?

          答案:狀態(tài)(state)是組件自身管理的數(shù)據(jù),可以通過(guò)setState方法來(lái)更新。屬性(props)是從父組件傳遞給子組件的數(shù)據(jù),子組件無(wú)法直接修改props,只能通過(guò)父組件的更新來(lái)改變props。

          區(qū)別:

          狀態(tài)(state)是組件內(nèi)部的數(shù)據(jù),可以在組件中自由修改和管理。 屬性(props)是從父組件傳遞給子組件的數(shù)據(jù),子組件無(wú)法直接修改,只能接收和使用。

          5. 什么是React生命周期方法?列舉一些常用的生命周期方法。

          答案:React生命周期方法是在組件不同階段執(zhí)行的特定方法。以下是一些常用的React生命周期方法:

          componentDidMount:組件掛載后立即調(diào)用。 componentDidUpdate:組件更新后調(diào)用。 componentWillUnmount:組件卸載前調(diào)用。 shouldComponentUpdate:決定組件是否需要重新渲染。 getDerivedStateFromProps:根據(jù)props的變化來(lái)更新?tīng)顟B(tài)。

          6. 什么是React Hooks?它們的作用是什么?

          答案:React Hooks是React 16.8版本引入的一種特性,用于在函數(shù)組件中使用狀態(tài)和其他React特性。Hooks提供了一種無(wú)需編寫類組件的方式來(lái)管理狀態(tài)和處理副作用,使得函數(shù)組件具有類組件的能力。

          7. 什么是React Router?它的作用是什么?

          答案:React Router是React中用于處理路由的庫(kù)。它提供了一種在單頁(yè)面應(yīng)用中實(shí)現(xiàn)導(dǎo)航和路由功能的方式。React Router可以幫助開(kāi)發(fā)者實(shí)現(xiàn)頁(yè)面之間的切換、URL參數(shù)的傳遞、嵌套路由等功能。

          8. 什么是React Context?它的作用是什么?

          答案:React Context是一種用于在組件樹(shù)中共享數(shù)據(jù)的機(jī)制。它可以避免通過(guò)props一層層傳遞數(shù)據(jù),使得跨組件的數(shù)據(jù)共享變得更加簡(jiǎn)單和高效。React Context提供了一個(gè)Provider和Consumer組件,用于提供和消費(fèi)共享的數(shù)據(jù)。

          9. 什么是React的協(xié)調(diào)(Reconciliation)過(guò)程?它是如何工作的?

          答案:React的協(xié)調(diào)過(guò)程是指React在進(jìn)行組件更新時(shí),通過(guò)比較新舊虛擬DOM樹(shù)的差異,僅對(duì)需要更新的部分進(jìn)行實(shí)際的DOM操作。協(xié)調(diào)過(guò)程的工作方式如下:

          React會(huì)逐層比較新舊虛擬DOM樹(shù)的節(jié)點(diǎn),并找出差異。 對(duì)于每個(gè)差異,React會(huì)生成相應(yīng)的DOM操作指令,如插入、更新或刪除節(jié)點(diǎn)。 React會(huì)將所有的DOM操作指令批量執(zhí)行,以減少對(duì)真實(shí)DOM的操作次數(shù)。

          10. 什么是React的事件合成(SyntheticEvent)?它的作用是什么?

          答案:React的事件合成是一種在React中處理事件的機(jī)制。它是React為了提高性能和跨瀏覽器兼容性而實(shí)現(xiàn)的一種事件系統(tǒng)。事件合成的作用包括:

          提供了一種統(tǒng)一的方式來(lái)處理事件,無(wú)需考慮瀏覽器兼容性。 可以通過(guò)事件委托的方式將事件處理程序綁定到父組件,提高性能。 可以訪問(wèn)原生事件對(duì)象的屬性和方法。

          11. 什么是React的Fiber架構(gòu)?它解決了什么問(wèn)題?

          答案:React的Fiber架構(gòu)是React 16版本引入的一種新的協(xié)調(diào)算法和架構(gòu)。它旨在解決長(zhǎng)時(shí)間渲染阻塞主線程的問(wèn)題,提高應(yīng)用的性能和用戶體驗(yàn)。Fiber架構(gòu)通過(guò)將渲染過(guò)程分解為多個(gè)小任務(wù),并使用優(yōu)先級(jí)調(diào)度算法來(lái)動(dòng)態(tài)分配時(shí)間片,使得React可以在每個(gè)幀中執(zhí)行一部分任務(wù),從而實(shí)現(xiàn)平滑的用戶界面和更好的響應(yīng)性能。

          12. 什么是React的錯(cuò)誤邊界(Error Boundary)?它的作用是什么?

          答案:React的錯(cuò)誤邊界是一種用于處理組件錯(cuò)誤的機(jī)制。它允許組件捕獲并處理其子組件中發(fā)生的JavaScript錯(cuò)誤,以避免整個(gè)應(yīng)用崩潰。錯(cuò)誤邊界的作用包括:

          捕獲并處理組件樹(shù)中的錯(cuò)誤,防止錯(cuò)誤導(dǎo)致整個(gè)應(yīng)用崩潰。 提供一種優(yōu)雅的方式來(lái)顯示錯(cuò)誤信息或備用UI。 可以用于記錄錯(cuò)誤和發(fā)送錯(cuò)誤報(bào)告。

          網(wǎng)絡(luò)

          1. 什么是HTTP?它是如何工作的?

          答案:HTTP(Hypertext Transfer Protocol)是一種用于在Web上傳輸數(shù)據(jù)的協(xié)議。它使用客戶端-服務(wù)器模型,客戶端發(fā)送HTTP請(qǐng)求到服務(wù)器,服務(wù)器返回HTTP響應(yīng)。HTTP的工作流程如下:

          客戶端發(fā)送HTTP請(qǐng)求到指定的URL。 服務(wù)器接收請(qǐng)求并處理,然后返回HTTP響應(yīng)。 客戶端接收響應(yīng)并解析,從中獲取所需的數(shù)據(jù)。

          2. 什么是HTTPS?與HTTP有什么區(qū)別?

          答案:HTTPS(Hypertext Transfer Protocol Secure)是HTTP的安全版本,通過(guò)使用SSL(Secure Sockets Layer)或TLS(Transport Layer Security)協(xié)議對(duì)通信進(jìn)行加密和身份驗(yàn)證。與HTTP相比,HTTPS具有以下區(qū)別:

          數(shù)據(jù)在傳輸過(guò)程中通過(guò)加密進(jìn)行保護(hù),提供更高的安全性。 使用數(shù)字證書(shū)對(duì)服務(wù)器進(jìn)行身份驗(yàn)證,防止中間人攻擊。 使用默認(rèn)端口443。

          3. 什么是跨域請(qǐng)求?它是如何解決的?

          答案:跨域請(qǐng)求是指在瀏覽器中向不同域名、端口或協(xié)議發(fā)送的請(qǐng)求。由于瀏覽器的同源策略(Same-Origin Policy)限制,跨域請(qǐng)求會(huì)受到限制。為了解決跨域問(wèn)題,可以使用以下方法:

          JSONP(JSON with Padding):通過(guò)動(dòng)態(tài)創(chuàng)建

          4. 什么是緩存?在前端中如何使用緩存來(lái)提高性能?

          答案:緩存是將數(shù)據(jù)或資源存儲(chǔ)在臨時(shí)存儲(chǔ)中,以便在后續(xù)請(qǐng)求中重復(fù)使用,從而提高性能和減少網(wǎng)絡(luò)流量。在前端中,可以使用以下方式來(lái)利用緩存:

          HTTP緩存:通過(guò)設(shè)置適當(dāng)?shù)木彺骖^(如Cache-Control和Expires)來(lái)指示瀏覽器緩存響應(yīng)。 資源緩存:使用文件指紋或版本號(hào)來(lái)重命名靜態(tài)資源文件,以便在文件內(nèi)容變化時(shí)使瀏覽器重新下載。 數(shù)據(jù)緩存:使用內(nèi)存緩存、瀏覽器本地存儲(chǔ)(如localStorage)或服務(wù)端緩存(如Redis)來(lái)存儲(chǔ)數(shù)據(jù),避免重復(fù)請(qǐng)求。

          5. 什么是CDN?它的作用是什么?

          答案:CDN(Content Delivery Network)是一種分布式網(wǎng)絡(luò)架構(gòu),用于在全球各地提供高性能、低延遲的內(nèi)容傳輸服務(wù)。CDN的作用包括:

          將靜態(tài)資源(如圖片、樣式表、腳本等)緩存到離用戶更近的服務(wù)器上,提供更快的加載速度。 分發(fā)網(wǎng)絡(luò)流量,減輕源服務(wù)器的負(fù)載壓力。 提供內(nèi)容壓縮、數(shù)據(jù)壓縮和緩存等優(yōu)化技術(shù),提高用戶體驗(yàn)。

          6. 什么是網(wǎng)頁(yè)加載性能優(yōu)化?可以采取哪些措施來(lái)改善網(wǎng)頁(yè)加載性能?

          答案:網(wǎng)頁(yè)加載性能優(yōu)化是指通過(guò)各種技術(shù)手段來(lái)減少網(wǎng)頁(yè)加載時(shí)間并提高用戶體驗(yàn)。可以采取以下措施來(lái)改善網(wǎng)頁(yè)加載性能:

          壓縮和合并資源文件(如CSS和JavaScript),減少文件大小和請(qǐng)求數(shù)量。 使用圖像壓縮和適當(dāng)?shù)母袷竭x擇來(lái)減小圖像文件大小。 使用瀏覽器緩存和HTTP緩存頭來(lái)緩存靜態(tài)資源。 使用懶加載延遲加載非關(guān)鍵資源,提高初始加載速度。 使用CDN(內(nèi)容分發(fā)網(wǎng)絡(luò))來(lái)分發(fā)靜態(tài)資源,減少網(wǎng)絡(luò)延遲。 優(yōu)化關(guān)鍵渲染路徑,盡早呈現(xiàn)頁(yè)面內(nèi)容。

          7. 什么是網(wǎng)頁(yè)性能監(jiān)測(cè)和分析?可以使用哪些工具來(lái)監(jiān)測(cè)和分析網(wǎng)頁(yè)性能?

          答案:網(wǎng)頁(yè)性能監(jiān)測(cè)和分析是指通過(guò)測(cè)量和收集有關(guān)網(wǎng)頁(yè)加載和交互性能的數(shù)據(jù),以便識(shí)別性能瓶頸并進(jìn)行優(yōu)化。可以使用以下工具來(lái)監(jiān)測(cè)和分析網(wǎng)頁(yè)性能:

          Web性能API:瀏覽器提供的JavaScript API,可通過(guò)performance對(duì)象來(lái)收集性能數(shù)據(jù)。 Lighthouse:一種開(kāi)源工具,可提供關(guān)于網(wǎng)頁(yè)性能、可訪問(wèn)性和最佳實(shí)踐的綜合報(bào)告。 WebPagetest:在線工具,可測(cè)量網(wǎng)頁(yè)加載時(shí)間并提供詳細(xì)的性能分析報(bào)告。 Chrome開(kāi)發(fā)者工具:瀏覽器內(nèi)置的開(kāi)發(fā)者工具,提供了性能分析、網(wǎng)絡(luò)監(jiān)控和頁(yè)面審查等功能。

          8. 什么是漸進(jìn)式圖像加載(Progressive Image Loading)?它如何改善網(wǎng)頁(yè)加載性能?

          答案:漸進(jìn)式圖像加載是一種技術(shù),通過(guò)逐步加載圖像的模糊或低分辨率版本,然后逐漸提高圖像的清晰度,以改善網(wǎng)頁(yè)加載性能和用戶體驗(yàn)。漸進(jìn)式圖像加載的好處包括:

          用戶可以更快地看到頁(yè)面內(nèi)容,提高感知速度。 逐步加載圖像可以減少網(wǎng)頁(yè)整體的加載時(shí)間。 漸進(jìn)式圖像加載可以提供平滑的過(guò)渡效果,避免頁(yè)面內(nèi)容突然閃爍或變化。

          9. 什么是前端資源優(yōu)先級(jí)(Resource Prioritization)?如何設(shè)置資源的優(yōu)先級(jí)?

          答案:前端資源優(yōu)先級(jí)是指為不同類型的資源分配加載優(yōu)先級(jí),以優(yōu)化網(wǎng)頁(yè)加載性能。可以使用以下方法設(shè)置資源的優(yōu)先級(jí):

          使用標(biāo)簽來(lái)指定資源的預(yù)加載,以確保關(guān)鍵資源盡早加載。 使用標(biāo)簽來(lái)指定可能在未來(lái)頁(yè)面中使用的資源,以提前加載。 使用標(biāo)簽來(lái)指定要預(yù)解析的域名,以減少DNS查找時(shí)間。 使用標(biāo)簽來(lái)指定要預(yù)連接的域名,以減少建立連接的時(shí)間。

          瀏覽器

          1.解釋一下瀏覽器的工作原理。

          答案:瀏覽器的工作原理包括以下幾個(gè)關(guān)鍵步驟:

          解析:瀏覽器將接收到的HTML、CSS和JavaScript代碼解析成DOM樹(shù)、CSSOM樹(shù)和JavaScript引擎可執(zhí)行的代碼。 渲染:瀏覽器使用DOM樹(shù)和CSSOM樹(shù)構(gòu)建渲染樹(shù),然后根據(jù)渲染樹(shù)進(jìn)行布局(計(jì)算元素的位置和大小)和繪制(將元素繪制到屏幕上)。 布局和繪制:瀏覽器根據(jù)渲染樹(shù)的變化進(jìn)行布局和繪制,然后將最終的頁(yè)面呈現(xiàn)給用戶。 JavaScript引擎執(zhí)行:瀏覽器的JavaScript引擎解釋和執(zhí)行JavaScript代碼,并根據(jù)需要更新渲染樹(shù)和重新渲染頁(yè)面。

          2. 什么是重繪(Repaint)和重排(Reflow)?它們之間有什么區(qū)別?

          答案:重繪是指當(dāng)元素的外觀(如顏色、背景等)發(fā)生改變,但布局不受影響時(shí)的更新過(guò)程。重繪不會(huì)導(dǎo)致元素的位置或大小發(fā)生變化。

          重排是指當(dāng)元素的布局屬性(如寬度、高度、位置等)發(fā)生改變時(shí)的更新過(guò)程。重排會(huì)導(dǎo)致瀏覽器重新計(jì)算渲染樹(shù)和重新繪制頁(yè)面的一部分或全部。

          區(qū)別在于重繪只涉及外觀的更改,而重排涉及布局的更改。重排比重繪更消耗性能,因?yàn)樗枰匦掠?jì)算布局和繪制整個(gè)頁(yè)面。

          3. 什么是事件冒泡和事件捕獲?它們之間有什么區(qū)別?

          答案:事件冒泡和事件捕獲是指瀏覽器處理事件時(shí)的兩種不同的傳播方式。

          事件冒泡是指事件從最內(nèi)層的元素開(kāi)始觸發(fā),然后逐級(jí)向上傳播到父元素,直到傳播到最外層的元素。

          事件捕獲是指事件從最外層的元素開(kāi)始觸發(fā),然后逐級(jí)向下傳播到最內(nèi)層的元素。

          區(qū)別在于傳播方向的不同。事件冒泡是從內(nèi)向外傳播,而事件捕獲是從外向內(nèi)傳播。

          4. 解釋一下同步和異步的JavaScript代碼執(zhí)行方式。

          答案:同步代碼是按照順序執(zhí)行的代碼,每個(gè)任務(wù)必須等待前一個(gè)任務(wù)完成后才能執(zhí)行。同步代碼會(huì)阻塞后續(xù)代碼的執(zhí)行,直到當(dāng)前任務(wù)完成。

          異步代碼是不按照順序執(zhí)行的代碼,它會(huì)在后臺(tái)執(zhí)行,不會(huì)阻塞后續(xù)代碼的執(zhí)行。異步代碼通常使用回調(diào)函數(shù)、Promise、async/await等方式來(lái)處理異步操作的結(jié)果。

          通過(guò)異步執(zhí)行,可以避免阻塞主線程,提高頁(yè)面的響應(yīng)性能。

          5. 什么是事件循環(huán)(Event Loop)?它在JavaScript中的作用是什么?

          答案:事件循環(huán)是JavaScript中處理異步代碼執(zhí)行的機(jī)制。它負(fù)責(zé)管理調(diào)度和執(zhí)行異步任務(wù),并將它們添加到執(zhí)行隊(duì)列中。

          在JavaScript中,事件循環(huán)的作用是確保異步任務(wù)按照正確的順序執(zhí)行,并且不會(huì)阻塞主線程。它通過(guò)不斷地從執(zhí)行隊(duì)列中取出任務(wù)并執(zhí)行,以實(shí)現(xiàn)非阻塞的異步操作。

          6. 解釋一下瀏覽器的垃圾回收機(jī)制是如何工作的。

          答案:瀏覽器的垃圾回收機(jī)制是一種自動(dòng)管理內(nèi)存的機(jī)制,用于檢測(cè)和回收不再使用的對(duì)象,以釋放內(nèi)存資源。

          垃圾回收機(jī)制通過(guò)標(biāo)記-清除算法實(shí)現(xiàn)。它的工作原理如下:

          標(biāo)記階段:垃圾回收器會(huì)從根對(duì)象(如全局對(duì)象)開(kāi)始,遞歸遍歷所有對(duì)象,并標(biāo)記仍然可訪問(wèn)的對(duì)象。 清除階段:垃圾回收器會(huì)掃描堆內(nèi)存,清除未被標(biāo)記的對(duì)象,并回收它們所占用的內(nèi)存空間。 垃圾回收機(jī)制的目標(biāo)是識(shí)別和回收不再使用的對(duì)象,以避免內(nèi)存泄漏和提高內(nèi)存利用率。

          7. 解釋一下瀏覽器的同源策略(Same-Origin Policy)及其限制。

          答案:同源策略是瀏覽器的一項(xiàng)安全機(jī)制,用于限制來(lái)自不同源的網(wǎng)頁(yè)之間的交互。同源是指協(xié)議、域名和端口號(hào)完全相同。

          同源策略的限制包括:

          腳本訪問(wèn)限制:不同源的腳本無(wú)法直接訪問(wèn)彼此的數(shù)據(jù)和操作。 DOM訪問(wèn)限制:不同源的網(wǎng)頁(yè)無(wú)法通過(guò)JavaScript訪問(wèn)彼此的DOM元素。 Cookie限制:不同源的網(wǎng)頁(yè)無(wú)法讀取或修改彼此的Cookie。 AJAX請(qǐng)求限制:不同源的網(wǎng)頁(yè)無(wú)法通過(guò)AJAX請(qǐng)求訪問(wèn)彼此的數(shù)據(jù)。 同源策略的存在可以防止惡意網(wǎng)站獲取用戶的敏感信息或進(jìn)行惡意操作。

          8. 什么是Web Workers?它們?cè)跒g覽器中的作用是什么?

          答案:Web Workers是一種瀏覽器提供的JavaScript API,用于在后臺(tái)線程中執(zhí)行耗時(shí)的計(jì)算任務(wù),以避免阻塞主線程。

          Web Workers的作用是提高瀏覽器的響應(yīng)性能,使得在執(zhí)行復(fù)雜計(jì)算或處理大量數(shù)據(jù)時(shí),不會(huì)影響用戶界面的流暢性。

          Web Workers通過(guò)將任務(wù)委托給后臺(tái)線程來(lái)實(shí)現(xiàn)并行處理,從而充分利用多核處理器的能力。它們可以與主線程進(jìn)行通信,但不能直接訪問(wèn)DOM或執(zhí)行UI相關(guān)的操作。

          9. 解釋一下瀏覽器緩存(Browser Cache)是什么,以及它的作用是什么?

          答案:瀏覽器緩存是瀏覽器在本地存儲(chǔ)Web頁(yè)面和資源的副本,以便在后續(xù)訪問(wèn)時(shí)可以快速加載。它的作用是減少對(duì)服務(wù)器的請(qǐng)求次數(shù)和網(wǎng)絡(luò)傳輸量,提高頁(yè)面加載速度和用戶體驗(yàn)。

          瀏覽器緩存通過(guò)在首次請(qǐng)求時(shí)將資源保存到本地,并在后續(xù)請(qǐng)求時(shí)檢查資源是否已經(jīng)存在并且沒(méi)有過(guò)期來(lái)工作。如果資源已經(jīng)存在且未過(guò)期,瀏覽器會(huì)直接從緩存中加載資源,而不是從服務(wù)器重新下載。

          10. 什么是重定向(Redirect)?它在瀏覽器中的作用是什么?

          答案:重定向是指當(dāng)瀏覽器請(qǐng)求一個(gè)URL時(shí),服務(wù)器返回一個(gè)不同的URL,從而將瀏覽器的請(qǐng)求重定向到新的URL上。

          重定向在瀏覽器中的作用是實(shí)現(xiàn)頁(yè)面的跳轉(zhuǎn)、URL的修改或資源的重定向。它可以用于多種情況,例如處理舊鏈接的跳轉(zhuǎn)、實(shí)現(xiàn)URL的規(guī)范化、處理用戶認(rèn)證等。

          重定向通過(guò)在HTTP響應(yīng)中設(shè)置特定的狀態(tài)碼(如301永久重定向、302臨時(shí)重定向)和Location頭部字段來(lái)實(shí)現(xiàn)。

          11. 什么是瀏覽器存儲(chǔ)(Browser Storage)?它有哪些不同的存儲(chǔ)機(jī)制?

          答案:瀏覽器存儲(chǔ)是瀏覽器提供的一種在客戶端存儲(chǔ)數(shù)據(jù)的機(jī)制,用于在不同的網(wǎng)頁(yè)間共享數(shù)據(jù)或持久保存數(shù)據(jù)。

          瀏覽器存儲(chǔ)有以下不同的存儲(chǔ)機(jī)制:

          Cookie:小型文本文件,可以存儲(chǔ)少量數(shù)據(jù),并在每次HTTP請(qǐng)求中自動(dòng)發(fā)送到服務(wù)器。 Web Storage(localStorage和sessionStorage):可以存儲(chǔ)較大量的數(shù)據(jù),以鍵值對(duì)的形式存儲(chǔ)在瀏覽器中。 IndexedDB:一種高級(jí)的客戶端數(shù)據(jù)庫(kù),可以存儲(chǔ)大量結(jié)構(gòu)化數(shù)據(jù),并支持索引和事務(wù)操作。 Cache API:用于緩存網(wǎng)絡(luò)請(qǐng)求的響應(yīng),以便離線訪問(wèn)或提高頁(yè)面加載速度。 不同的存儲(chǔ)機(jī)制適用于不同的需求,開(kāi)發(fā)者可以根據(jù)具體情況選擇合適的存儲(chǔ)方式。


          原文鏈接:https://juejin.cn/post/7276407803618656295

          2023金九銀十必看前端面試題! 金九銀十黃金期來(lái)了 想要跳槽的小伙伴快來(lái)看啊

          CSS

          1. 請(qǐng)解釋CSS的盒模型是什么,并描述其組成部分。

          答案:CSS的盒模型是用于布局和定位元素的概念。它由內(nèi)容區(qū)域、內(nèi)邊距、邊框和外邊距組成,這些部分依次包裹在元素周圍。

          2. 解釋CSS中的選擇器及其優(yōu)先級(jí)。

          答案:CSS選擇器用于選擇要應(yīng)用樣式的HTML元素。選擇器的優(yōu)先級(jí)規(guī)則是:內(nèi)聯(lián)樣式 > ID選擇器 > 類選擇器、屬性選擇器、偽類選擇器 > 元素選擇器 > 通用選擇器。同時(shí),使用!important可以提升樣式的優(yōu)先級(jí)。

          3. 解釋CSS中的浮動(dòng)(float)是如何工作的,并提供一個(gè)示例。

          答案:浮動(dòng)(float)是CSS中用于實(shí)現(xiàn)元素的左浮動(dòng)或右浮動(dòng),使其脫離文檔流并環(huán)繞在其周圍的元素。例如:

          .float-example {
            float: left;
            width: 200px;
            height: 200px;
          }

          4. 解釋CSS中的定位(position)屬性及其不同的取值。

          答案:定位(position)屬性用于控制元素的定位方式。常見(jiàn)的取值有:static(默認(rèn),按照文檔流定位)、relative(相對(duì)定位)、absolute(絕對(duì)定位)、fixed(固定定位)和sticky(粘性定位)。

          5. 解釋CSS中的層疊順序(z-index)是如何工作的。

          答案:層疊順序(z-index)用于控制元素在垂直方向上的堆疊順序。具有較高層疊順序值的元素將顯示在較低層疊順序值的元素之上。默認(rèn)情況下,層疊順序值為auto。

          6. 解釋CSS中的偽類和偽元素的區(qū)別,并給出一個(gè)示例。

          答案:偽類用于向選擇器添加特殊的狀態(tài),如:hover、:active等。偽元素用于向選擇器添加特殊的元素,如::before、::after等。例如:

          /* 偽類示例 */
          a:hover {
            color: red;
          }
          
          /* 偽元素示例 */
          p::before {
            content: "前綴";
          }

          7. 解釋CSS中的盒子模型的兩種模式:標(biāo)準(zhǔn)模式和怪異模式。

          答案:標(biāo)準(zhǔn)模式是按照W3C標(biāo)準(zhǔn)解析渲染頁(yè)面的模式。怪異模式是兼容舊版本瀏覽器的解析渲染頁(yè)面的模式。可以通過(guò)聲明來(lái)指定使用哪種模式。

          8. 解釋CSS中的BFC是什么,它的作用是什么?

          答案:BFC(塊級(jí)格式化上下文)是CSS中的一種渲染模式,它創(chuàng)建了一個(gè)獨(dú)立的渲染環(huán)境,其中的元素按照一定的規(guī)則進(jìn)行布局和定位。BFC的作用包括:清除浮動(dòng)、防止外邊距重疊等。

          9. 解釋CSS中的flexbox布局是什么,它的優(yōu)勢(shì)是什么?

          答案:flexbox布局是一種用于創(chuàng)建靈活的、響應(yīng)式的布局的CSS模塊。它通過(guò)flex容器和flex項(xiàng)目的組合來(lái)實(shí)現(xiàn)強(qiáng)大的布局能力。其優(yōu)勢(shì)包括簡(jiǎn)單易用、自適應(yīng)性強(qiáng)、對(duì)齊和分布控制靈活等。

          10.解釋CSS中的媒體查詢是什么,它的作用是什么?

          答案:媒體查詢是CSS中的一種技術(shù),用于根據(jù)設(shè)備的特性和屬性來(lái)應(yīng)用不同的樣式。通過(guò)媒體查詢,可以根據(jù)屏幕尺寸、設(shè)備類型、分辨率等條件來(lái)優(yōu)化頁(yè)面的布局和樣式。

          JavaScript

          1. 解釋JavaScript的數(shù)據(jù)類型,并舉例說(shuō)明每種類型。

          答案:JavaScript有七種數(shù)據(jù)類型:字符串(String)、數(shù)字(Number)、布爾值(Boolean)、對(duì)象(Object)、數(shù)組(Array)、空值(Null)和未定義(Undefined)。例如:

          let str = "Hello";
          let num = 10;
          let bool = true;
          let obj = { name: "John" };
          let arr = [1, 2, 3];
          let n = null;
          let undef;

          2. 解釋JavaScript中的變量提升(Hoisting)是什么。

          答案:變量提升是指在JavaScript中,變量和函數(shù)聲明會(huì)在代碼執(zhí)行之前被提升到作用域的頂部。這意味著可以在聲明之前使用變量和函數(shù)。例如:

          console.log(x); // 輸出 undefined
          var x = 5;

          3. 解釋JavaScript中的閉包(Closure)是什么,并舉例說(shuō)明。

          答案:閉包是指函數(shù)可以訪問(wèn)并操作其詞法作用域之外的變量。它通過(guò)在函數(shù)內(nèi)部創(chuàng)建一個(gè)內(nèi)部函數(shù),并返回該內(nèi)部函數(shù)來(lái)實(shí)現(xiàn)。例如:

          function outer() {
            let x = 10;
            function inner() {
              console.log(x);
            }
            return inner;
          }
          
          let closure = outer();
          closure(); // 輸出 10
          

          4. 解釋JavaScript中的事件冒泡(Event Bubbling)和事件捕獲(Event Capturing)。

          答案:事件冒泡是指事件從最具體的元素開(kāi)始向父元素逐級(jí)觸發(fā),直到觸發(fā)到根元素。事件捕獲是指事件從根元素開(kāi)始,逐級(jí)向最具體的元素觸發(fā)。可以使用addEventListener方法的第三個(gè)參數(shù)來(lái)控制是使用事件冒泡還是事件捕獲。

          5. 解釋JavaScript中的原型繼承(Prototype Inheritance)是什么。

          答案:原型繼承是JavaScript中實(shí)現(xiàn)對(duì)象之間繼承關(guān)系的一種機(jī)制。每個(gè)對(duì)象都有一個(gè)原型對(duì)象,它包含了共享的屬性和方法。當(dāng)訪問(wèn)對(duì)象的屬性或方法時(shí),如果對(duì)象本身沒(méi)有,則會(huì)沿著原型鏈向上查找。可以使用Object.create()方法或設(shè)置對(duì)象的__proto__屬性來(lái)實(shí)現(xiàn)原型繼承。

          6. 解釋JavaScript中的異步編程,并提供一個(gè)異步操作的示例。

          答案:異步編程是指在代碼執(zhí)行過(guò)程中,不會(huì)阻塞后續(xù)代碼執(zhí)行的一種編程方式。常見(jiàn)的異步操作包括網(wǎng)絡(luò)請(qǐng)求、定時(shí)器等。例如:

          console.log("開(kāi)始");
          setTimeout(function() {
            console.log("異步操作");
          }, 1000);
          console.log("結(jié)束");

          7. 解釋JavaScript中的閉包(Closure)是什么,并舉例說(shuō)明。

          答案:閉包是指函數(shù)可以訪問(wèn)并操作其詞法作用域之外的變量。它通過(guò)在函數(shù)內(nèi)部創(chuàng)建一個(gè)內(nèi)部函數(shù),并返回該內(nèi)部函數(shù)來(lái)實(shí)現(xiàn)。例如:

          function outer() {
            let x = 10;
            function inner() {
              console.log(x);
            }
            return inner;
          }
          
          let closure = outer();
          closure(); // 輸出 10

          8. 解釋JavaScript中的this關(guān)鍵字的作用和使用場(chǎng)景。

          答案:this關(guān)鍵字在JavaScript中表示當(dāng)前執(zhí)行上下文的對(duì)象。它的具體取值根據(jù)函數(shù)的調(diào)用方式而定。在全局作用域中,this指向全局對(duì)象(瀏覽器環(huán)境中為window對(duì)象)。在函數(shù)中,this的指向取決于函數(shù)的調(diào)用方式,可以通過(guò)call、apply、bind等方法來(lái)顯式地指定this的值。

          9. 解釋JavaScript中的事件委托(Event Delegation)是什么,并提供一個(gè)使用事件委托的示例。

          答案:事件委托是指將事件處理程序綁定到父元素上,而不是直接綁定到每個(gè)子元素上。當(dāng)事件觸發(fā)時(shí),事件會(huì)冒泡到父元素,然后通過(guò)判斷事件的目標(biāo)來(lái)執(zhí)行相應(yīng)的處理邏輯。這樣可以減少事件處理程序的數(shù)量,提高性能。例如:

          <ul id="list">
            <li>Item 1</li>
            <li>Item 2</li>
            <li>Item 3</li>
          </ul>
          
          <script>
          document.getElementById("list").addEventListener("click", function(event) {
            if (event.target.tagName === "LI") {
              console.log(event.target.textContent);
            }
          });
          </script>

          10. 解釋JavaScript中的模塊化編程,并提供一個(gè)使用模塊的示例。

          答案:模塊化編程是指將代碼劃分為獨(dú)立的模塊,每個(gè)模塊負(fù)責(zé)特定的功能,并通過(guò)導(dǎo)入和導(dǎo)出來(lái)實(shí)現(xiàn)模塊之間的依賴關(guān)系。ES6引入了模塊化的語(yǔ)法,可以使用import和export關(guān)鍵字來(lái)導(dǎo)入和導(dǎo)出模塊。例如:

          // module.js
          export function sayHello() {
            console.log("Hello!");
          }
          
          // main.js
          import { sayHello } from "./module.js";
          sayHello(); // 輸出 "Hello!"

          11. 解釋JavaScript中的事件冒泡(Event Bubbling)和事件捕獲(Event Capturing)。

          答案:事件冒泡是指當(dāng)一個(gè)事件在DOM樹(shù)中觸發(fā)時(shí),它會(huì)從最內(nèi)層的元素開(kāi)始向外傳播至最外層的元素。事件捕獲是指當(dāng)一個(gè)事件在DOM樹(shù)中觸發(fā)時(shí),它會(huì)從最外層的元素開(kāi)始向內(nèi)傳播至最內(nèi)層的元素。

          12. 什么是原型鏈(Prototype Chain)?如何利用原型鏈實(shí)現(xiàn)繼承?

          答案:原型鏈?zhǔn)荍avaScript中對(duì)象之間的連接關(guān)系,每個(gè)對(duì)象都有一個(gè)指向其原型(prototype)的引用。通過(guò)原型鏈,對(duì)象可以繼承其原型對(duì)象的屬性和方法。可以使用原型鏈實(shí)現(xiàn)繼承,通過(guò)將一個(gè)對(duì)象的原型指向另一個(gè)對(duì)象,從而使得該對(duì)象可以訪問(wèn)另一個(gè)對(duì)象的屬性和方法。

          13. 解釋JavaScript中的防抖(Debounce)和節(jié)流(Throttle)。

          答案:防抖和節(jié)流都是用于控制函數(shù)執(zhí)行頻率的技術(shù)。防抖指的是在某個(gè)時(shí)間段內(nèi),只執(zhí)行最后一次觸發(fā)的函數(shù)調(diào)用。節(jié)流指的是在某個(gè)時(shí)間段內(nèi),按照固定的時(shí)間間隔執(zhí)行函數(shù)調(diào)用。

          14. 什么是事件循環(huán)(Event Loop)?請(qǐng)解釋JavaScript中的事件循環(huán)機(jī)制。

          答案:事件循環(huán)是JavaScript中處理異步操作的機(jī)制。事件循環(huán)不斷地從任務(wù)隊(duì)列中取出任務(wù)并執(zhí)行,直到任務(wù)隊(duì)列為空。事件循環(huán)由主線程和任務(wù)隊(duì)列組成,主線程負(fù)責(zé)執(zhí)行同步任務(wù),異步任務(wù)會(huì)被放入任務(wù)隊(duì)列中,等待主線程空閑時(shí)被執(zhí)行。

          15. 解釋JavaScript中的深拷貝和淺拷貝。

          答案:深拷貝是指創(chuàng)建一個(gè)新對(duì)象,將原始對(duì)象的所有屬性和嵌套對(duì)象的屬性都復(fù)制到新對(duì)象中。淺拷貝是指創(chuàng)建一個(gè)新對(duì)象,將原始對(duì)象的屬性復(fù)制到新對(duì)象中,但嵌套對(duì)象的引用仍然是共享的。

          16. 什么是異步編程?請(qǐng)列舉幾種處理異步操作的方法。

          答案:異步編程是一種處理可能耗時(shí)的操作而不阻塞主線程的編程方式。常見(jiàn)的處理異步操作的方法有回調(diào)函數(shù)、Promise、async/await和事件監(jiān)聽(tīng)等。

          17. 解釋JavaScript中的Hoisting(變量提升)。

          答案:變量提升是指在JavaScript中,變量和函數(shù)的聲明會(huì)被提升到當(dāng)前作用域的頂部。這意味著可以在聲明之前使用變量和函數(shù),但它們的賦值或定義仍然在原來(lái)的位置。

          18. 什么是柯里化(Currying)?請(qǐng)給出一個(gè)柯里化的示例。

          答案:柯里化是一種將接受多個(gè)參數(shù)的函數(shù)轉(zhuǎn)換為接受一個(gè)參數(shù)并返回一個(gè)新函數(shù)的過(guò)程。示例:

          function add(a) {
            return function(b) {
              return a + b;
            }
          }
          
          var add5 = add(5);
          console.log(add5(3)); // 輸出:8

          19. 解釋JavaScript中的嚴(yán)格模式(Strict Mode)。

          答案:嚴(yán)格模式是一種JavaScript的執(zhí)行模式,它提供了更嚴(yán)格的語(yǔ)法和錯(cuò)誤檢查。在嚴(yán)格模式下,一些不安全或不推薦的語(yǔ)法會(huì)被禁用,同時(shí)會(huì)引入一些新的特性,如變量必須先聲明才能使用、禁止使用this指向全局對(duì)象等。

          TypeScript

          1. 解釋TypeScript和JavaScript之間的關(guān)系。

          答案:TypeScript是JavaScript的超集,它添加了靜態(tài)類型和其他一些特性。TypeScript代碼可以編譯成JavaScript代碼,因此可以在任何支持JavaScript的環(huán)境中運(yùn)行。

          2. TypeScript中的類型注解是什么?如何使用類型注解?

          答案:類型注解是指在變量、函數(shù)參數(shù)、函數(shù)返回值等地方顯式地聲明類型信息。可以使用冒號(hào)(:)后跟類型來(lái)添加類型注解。例如:

          let num: number = 10;
          
          function add(a: number, b: number): number {
            return a + b;
          }

          3. TypeScript中的接口是什么?如何定義和使用接口?

          答案:接口是一種用于定義對(duì)象的結(jié)構(gòu)和類型的語(yǔ)法。可以使用interface關(guān)鍵字來(lái)定義接口。例如:

          interface Person {
            name: string;
            age: number;
          }
          
          function greet(person: Person) {
            console.log(`Hello, ${person.name}!`);
          }
          
          let john: Person = { name: "John", age: 25 };
          greet(john); // 輸出 "Hello, John!"

          4. TypeScript中的類是什么?如何定義和使用類?

          答案:類是一種用于創(chuàng)建對(duì)象的藍(lán)圖,它包含屬性和方法。可以使用class關(guān)鍵字來(lái)定義類。例如:

          class Person {
            name: string;
            age: number;
          
            constructor(name: string, age: number) {
              this.name = name;
              this.age = age;
            }
          
            greet() {
              console.log(`Hello, ${this.name}!`);
            }
          }
          
          let john = new Person("John", 25);
          john.greet(); // 輸出 "Hello, John!"

          5. TypeScript中的泛型是什么?如何使用泛型?

          答案:泛型是一種用于創(chuàng)建可重用代碼的工具,它允許在定義函數(shù)、類或接口時(shí)使用占位符類型。可以使用尖括號(hào)(<>)來(lái)指定泛型類型。例如:

          function identity<T>(value: T): T {
            return value;
          }
          
          let result = identity<string>("Hello");
          console.log(result); // 輸出 "Hello"

          6. TypeScript中的枚舉是什么?如何定義和使用枚舉?

          答案:枚舉是一種用于定義命名常量集合的語(yǔ)法。可以使用enum關(guān)鍵字來(lái)定義枚舉。例如:

          enum Color {
            Red,
            Green,
            Blue,
          }
          
          let color: Color = Color.Green;
          console.log(color); // 輸出 1

          7. TypeScript中的模塊是什么?如何導(dǎo)出和導(dǎo)入模塊?

          答案:模塊是用于組織和封裝代碼的單元。可以使用export關(guān)鍵字將模塊中的變量、函數(shù)、類等導(dǎo)出,以便其他模塊可以使用。可以使用import關(guān)鍵字來(lái)導(dǎo)入其他模塊的導(dǎo)出。例如:

          // module.ts
          export function greet(name: string) {
            console.log(`Hello, ${name}!`);
          }
          
          // main.ts
          import { greet } from "./module";
          greet("John"); // 輸出 "Hello, John!"

          8. TypeScript中的類型推斷是什么?如何使用類型推斷?

          答案:類型推斷是指TypeScript根據(jù)上下文自動(dòng)推斷變量的類型,而無(wú)需顯式地添加類型注解。例如:

          let num = 10; // 推斷為 number 類型
          let str = "Hello"; // 推斷為 string 類型

          9. TypeScript中的命名空間是什么?如何定義和使用命名空間?

          答案:命名空間是一種用于組織和封裝代碼的機(jī)制,它避免了全局命名沖突。可以使用namespace關(guān)鍵字來(lái)定義命名空間。例如:

          namespace MyNamespace {
            export function greet(name: string) {
              console.log(`Hello, ${name}!`);
            }
          }
          
          MyNamespace.greet("John"); // 輸出 "Hello, John!"

          10. TypeScript中的類型別名是什么?如何定義和使用類型別名?

          答案:類型別名是給類型起一個(gè)別名,以便在代碼中更方便地引用。可以使用type關(guān)鍵字來(lái)定義類型別名。例如:

          type Point = { x: number; y: number };
          
          function printPoint(point: Point) {
            console.log(`(${point.x}, ${point.y})`);
          }
          
          let p: Point = { x: 1, y: 2 };
          printPoint(p); // 輸出 "(1, 2)"

          VUE2

          1. Vue.js是什么?它有哪些特點(diǎn)?

          答案:Vue.js是一個(gè)用于構(gòu)建用戶界面的JavaScript框架。它具有以下特點(diǎn):

          響應(yīng)式數(shù)據(jù)綁定:通過(guò)使用Vue的數(shù)據(jù)綁定語(yǔ)法,可以實(shí)現(xiàn)數(shù)據(jù)的自動(dòng)更新。 組件化開(kāi)發(fā):Vue允許將頁(yè)面劃分為獨(dú)立的組件,提高了代碼的可維護(hù)性和復(fù)用性。 虛擬DOM:Vue使用虛擬DOM來(lái)跟蹤頁(yè)面上的變化,并高效地更新實(shí)際的DOM。 指令系統(tǒng):Vue提供了豐富的內(nèi)置指令,用于處理常見(jiàn)的DOM操作和邏輯控制。 生態(tài)系統(tǒng):Vue擁有龐大的生態(tài)系統(tǒng),包括插件、工具和第三方庫(kù),可以滿足各種開(kāi)發(fā)需求。

          2. Vue中的雙向數(shù)據(jù)綁定是如何實(shí)現(xiàn)的?

          答案:Vue中的雙向數(shù)據(jù)綁定是通過(guò)v-model指令實(shí)現(xiàn)的。v-model可以在表單元素(如、、)上創(chuàng)建雙向數(shù)據(jù)綁定。當(dāng)用戶輸入改變表單元素的值時(shí),數(shù)據(jù)模型會(huì)自動(dòng)更新;反之,當(dāng)數(shù)據(jù)模型的值改變時(shí),表單元素也會(huì)自動(dòng)更新。

          3. Vue中的生命周期鉤子有哪些?它們的執(zhí)行順序是怎樣的?

          答案:Vue中的生命周期鉤子包括beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy和destroyed。它們的執(zhí)行順序如下:

          beforeCreate created beforeMount mounted beforeUpdate updated beforeDestroy destroyed

          4. Vue中的計(jì)算屬性和監(jiān)聽(tīng)器有什么區(qū)別?

          答案:計(jì)算屬性是基于依賴的屬性,它根據(jù)其依賴的數(shù)據(jù)動(dòng)態(tài)計(jì)算得出值。計(jì)算屬性具有緩存機(jī)制,只有在依賴的數(shù)據(jù)發(fā)生變化時(shí)才會(huì)重新計(jì)算。監(jiān)聽(tīng)器是用于監(jiān)聽(tīng)數(shù)據(jù)的變化并執(zhí)行相應(yīng)的操作。當(dāng)數(shù)據(jù)發(fā)生變化時(shí),監(jiān)聽(tīng)器會(huì)立即執(zhí)行指定的回調(diào)函數(shù)。

          5. Vue中的組件通信有哪些方式?

          答案:Vue中的組件通信方式包括:

          父子組件通信:通過(guò)props向子組件傳遞數(shù)據(jù),子組件通過(guò)事件向父組件發(fā)送消息。 子父組件通信:子組件通過(guò)$emit觸發(fā)事件,父組件通過(guò)監(jiān)聽(tīng)事件并響應(yīng)。 兄弟組件通信:通過(guò)共享的父組件來(lái)傳遞數(shù)據(jù)或通過(guò)事件總線(Event Bus)進(jìn)行通信。 跨級(jí)組件通信:通過(guò)provide和inject來(lái)在祖先組件中提供數(shù)據(jù),然后在后代組件中使用。

          6. Vue中的路由是如何實(shí)現(xiàn)的?

          答案:Vue中的路由是通過(guò)Vue Router實(shí)現(xiàn)的。Vue Router是Vue.js官方提供的路由管理器,它允許開(kāi)發(fā)者在Vue應(yīng)用中實(shí)現(xiàn)單頁(yè)面應(yīng)用(SPA)。Vue Router通過(guò)配置路由映射關(guān)系,將URL路徑與組件進(jìn)行關(guān)聯(lián),并提供導(dǎo)航功能,使用戶可以在不刷新頁(yè)面的情況下切換視圖。

          7. Vue中的指令有哪些?舉例說(shuō)明它們的用法。

          答案:Vue中常用的指令包括:

          v-if:根據(jù)表達(dá)式的值條件性地渲染元素。 v-for:根據(jù)數(shù)組或?qū)ο蟮臄?shù)據(jù)進(jìn)行循環(huán)渲染。 v-bind:用于動(dòng)態(tài)綁定屬性或響應(yīng)式地更新屬性。 v-on:用于監(jiān)聽(tīng)DOM事件并執(zhí)行相應(yīng)的方法。 v-model:用于在表單元素上實(shí)現(xiàn)雙向數(shù)據(jù)綁定。 例如:

          <div v-if="show">顯示內(nèi)容</div>
          
          <ul>
            <li v-for="item in items" :key="item.id">{{ item.name }}</li>
          </ul>
          
          <img v-bind:src="imageUrl">
          
          <button v-on:click="handleClick">點(diǎn)擊按鈕</button>
          
          <input v-model="message">

          8. Vue中的watch和computed有什么區(qū)別?

          答案:watch和computed都可以用于監(jiān)聽(tīng)數(shù)據(jù)的變化,但它們的用法和實(shí)現(xiàn)方式略有不同。watch用于監(jiān)聽(tīng)指定的數(shù)據(jù)變化,并在數(shù)據(jù)變化時(shí)執(zhí)行相應(yīng)的操作。computed用于根據(jù)依賴的數(shù)據(jù)動(dòng)態(tài)計(jì)算得出一個(gè)新的值,并將該值緩存起來(lái),只有在依賴的數(shù)據(jù)發(fā)生變化時(shí)才會(huì)重新計(jì)算。

          9. Vue中的mixin是什么?它有什么作用?

          答案:Mixin是一種用于在多個(gè)組件之間共享代碼的方式。Mixin可以包含組件選項(xiàng)(如數(shù)據(jù)、方法、生命周期鉤子等),并將其合并到使用Mixin的組件中。這樣可以實(shí)現(xiàn)代碼的復(fù)用和組件的擴(kuò)展,減少重復(fù)編寫相似代碼的工作。

          10. Vue中的keep-alive是什么?它有什么作用?

          答案:是Vue中的一個(gè)內(nèi)置組件,用于緩存動(dòng)態(tài)組件。當(dāng)組件包裹在中時(shí),組件的狀態(tài)將被保留,包括它的實(shí)例、狀態(tài)和DOM結(jié)構(gòu)。這樣可以避免在組件切換時(shí)重復(fù)創(chuàng)建和銷毀組件,提高性能和用戶體驗(yàn)。

          11. 請(qǐng)解釋Vue.js中的依賴注入(Dependency Injection)是什么?它在Vue中的應(yīng)用場(chǎng)景是什么?

          答案:依賴注入是一種設(shè)計(jì)模式,用于將依賴關(guān)系從一個(gè)組件傳遞到另一個(gè)組件。在Vue中,依賴注入通過(guò)provide和inject選項(xiàng)實(shí)現(xiàn)。父組件通過(guò)provide提供數(shù)據(jù),然后子組件通過(guò)inject注入這些數(shù)據(jù)。它在跨多個(gè)層級(jí)的組件通信中非常有用。

          12. Vue.js中的渲染函數(shù)(Render Function)是什么?它與模板(Template)有什么區(qū)別?

          答案:渲染函數(shù)是一種用JavaScript代碼編寫組件的方式,它可以動(dòng)態(tài)地生成虛擬DOM。與模板相比,渲染函數(shù)提供了更大的靈活性和控制力,可以處理更復(fù)雜的邏輯和動(dòng)態(tài)渲染需求。

          13. Vue.js中的插槽(Slot)是什么?請(qǐng)?zhí)峁┮粋€(gè)具有命名插槽和作用域插槽的示例。

          答案:插槽是一種用于在組件中擴(kuò)展內(nèi)容的機(jī)制。命名插槽允許父組件向子組件插入具有特定名稱的內(nèi)容,而作用域插槽允許子組件將數(shù)據(jù)傳遞給父組件。示例:

          <!-- 父組件 -->
          <template>
            <div>
              <slot name="header"></slot>
              <slot :data="data"></slot>
            </div>
          </template>
          
          <!-- 子組件 -->
          <template>
            <div>
              <slot name="header">默認(rèn)標(biāo)題</slot>
              <slot :data="computedData">{{ computedData }}</slot>
            </div>
          </template>

          14. Vue.js中的動(dòng)畫(huà)系統(tǒng)是如何工作的?請(qǐng)?zhí)峁┮粋€(gè)簡(jiǎn)單的動(dòng)畫(huà)示例。

          答案:Vue.js的動(dòng)畫(huà)系統(tǒng)通過(guò)CSS過(guò)渡和動(dòng)畫(huà)類實(shí)現(xiàn)。通過(guò)在元素上添加過(guò)渡類或動(dòng)畫(huà)類,可以觸發(fā)相應(yīng)的過(guò)渡效果或動(dòng)畫(huà)效果。示例:

          <transition name="fade">
            <div v-if="show">顯示內(nèi)容</div>
          </transition>
          
          <!-- CSS樣式 -->
          <style>
          .fade-enter-active, .fade-leave-active {
            transition: opacity 0.5s;
          }
          .fade-enter, .fade-leave-to {
            opacity: 0;
          }
          </style>

          15. Vue.js中的錯(cuò)誤處理機(jī)制是什么?如何捕獲和處理Vue組件中的錯(cuò)誤?

          答案:Vue.js提供了全局的錯(cuò)誤處理機(jī)制和組件級(jí)別的錯(cuò)誤處理機(jī)制。全局錯(cuò)誤處理可以通過(guò)errorCaptured鉤子函數(shù)捕獲和處理錯(cuò)誤。組件級(jí)別的錯(cuò)誤處理可以通過(guò)errorCaptured鉤子函數(shù)或errorHandler選項(xiàng)捕獲和處理錯(cuò)誤。

          16. Vue.js中的服務(wù)端渲染(SSR)是什么?它有哪些優(yōu)勢(shì)和限制?

          答案:服務(wù)端渲染是指在服務(wù)器上生成HTML內(nèi)容并將其發(fā)送到瀏覽器進(jìn)行渲染的過(guò)程。Vue.js可以進(jìn)行服務(wù)端渲染,提供更好的首次加載性能和SEO優(yōu)化。然而,服務(wù)端渲染也帶來(lái)了一些限制,如增加了服務(wù)器負(fù)載和開(kāi)發(fā)復(fù)雜性。

          17. Vue.js中的響應(yīng)式數(shù)組有哪些限制?如何解決這些限制?

          答案:Vue.js的響應(yīng)式系統(tǒng)對(duì)于數(shù)組的變異方法(如push、pop、splice等)是無(wú)法追蹤的。為了解決這個(gè)限制,Vue提供了一些特殊的方法,如Vue.set、vm.$set和Array.prototype.splice。這些方法可以用于更新數(shù)組并保持響應(yīng)式。

          18. Vue.js中的性能優(yōu)化有哪些常見(jiàn)的技巧?

          答案:常見(jiàn)的Vue.js性能優(yōu)化技巧包括:

          使用v-if和v-for時(shí)注意避免不必要的渲染。 合理使用computed屬性和watch監(jiān)聽(tīng)器。 使用keep-alive組件緩存組件狀態(tài)。 使用異步組件進(jìn)行按需加載。 避免在模板中使用復(fù)雜的表達(dá)式。 使用key屬性管理組件和元素的復(fù)用。 合理使用懶加載和分割代碼。

          19. Vue.js中的路由導(dǎo)航守衛(wèi)有哪些?它們的執(zhí)行順序是怎樣的?

          答案:Vue.js中的路由導(dǎo)航守衛(wèi)包括全局前置守衛(wèi)、全局解析守衛(wèi)、全局后置守衛(wèi)、路由獨(dú)享守衛(wèi)和組件內(nèi)守衛(wèi)。它們的執(zhí)行順序如下:

          全局前置守衛(wèi)(beforeEach) 路由獨(dú)享守衛(wèi)(beforeEnter) 解析守衛(wèi)(beforeResolve) 組件內(nèi)守衛(wèi)(beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave) 全局后置守衛(wèi)(afterEach)

          20. Vue.js中的單元測(cè)試是如何進(jìn)行的?請(qǐng)?zhí)峁┮粋€(gè)簡(jiǎn)單的單元測(cè)試示例。

          答案:Vue.js的單元測(cè)試可以使用工具如Jest或Mocha進(jìn)行。示例:

          // 組件代碼
          // MyComponent.vue
          <template>
            <div class="my-component">
              <span>{{ message }}</span>
              <button @click="increment">增加</button>
            </div>
          </template>
          
          <script>
          export default {
            data() {
              return {
                message: 'Hello',
                count: 0
              }
            },
            methods: {
              increment() {
                this.count++
              }
            }
          }
          </script>
          
          // 單元測(cè)試代碼
          // MyComponent.spec.js
          import { shallowMount } from '@vue/test-utils'
          import MyComponent from './MyComponent.vue'
          
          describe('MyComponent', () => {
            it('renders message correctly', () => {
              const wrapper = shallowMount(MyComponent)
              expect(wrapper.find('span').text()).toBe('Hello')
            })
          
            it('increments count when button is clicked', () => {
              const wrapper = shallowMount(MyComponent)
              wrapper.find('button').trigger('click')
              expect(wrapper.vm.count).toBe(1)
            })
          })

          VUE3

          1. Vue.js 3中的Composition API是什么?它與Options API有什么區(qū)別?

          答案:Composition API是Vue.js 3中引入的一種新的組織組件邏輯的方式。它允許開(kāi)發(fā)者通過(guò)函數(shù)的方式組織和重用邏輯,而不是通過(guò)選項(xiàng)對(duì)象。相比之下,Options API是Vue.js 2中常用的組織組件邏輯的方式,通過(guò)選項(xiàng)對(duì)象中的屬性來(lái)定義組件的數(shù)據(jù)、方法等。

          2. Vue.js 3中的Teleport是什么?請(qǐng)給出一個(gè)Teleport的示例。

          答案:Teleport是Vue.js 3中引入的一種機(jī)制,用于將組件的內(nèi)容渲染到DOM樹(shù)中的任意位置。示例:

          <template>
            <div>
              <button @click="showModal = true">打開(kāi)模態(tài)框</button>
              <teleport to="body">
                <modal v-if="showModal" @close="showModal = false">模態(tài)框內(nèi)容</modal>
              </teleport>
            </div>
          </template>

          3. Vue.js 3中的響應(yīng)式系統(tǒng)是如何工作的?它與Vue.js 2中的響應(yīng)式系統(tǒng)有什么區(qū)別?

          答案:Vue.js 3中的響應(yīng)式系統(tǒng)使用了Proxy對(duì)象來(lái)實(shí)現(xiàn)。與Vue.js 2中的響應(yīng)式系統(tǒng)相比,Vue.js 3的響應(yīng)式系統(tǒng)具有更好的性能和更細(xì)粒度的追蹤,能夠更準(zhǔn)確地檢測(cè)到數(shù)據(jù)的變化,并且支持嵌套的響應(yīng)式數(shù)據(jù)。

          4. Vue.js 3中的Suspense是什么?它的作用是什么?

          答案:Suspense是Vue.js 3中引入的一種機(jī)制,用于處理異步組件的加載狀態(tài)。它可以在異步組件加載完成之前顯示一個(gè)占位符,并在加載完成后渲染異步組件的內(nèi)容。這樣可以更好地處理異步組件的加載過(guò)程,提供更好的用戶體驗(yàn)。

          5. Vue.js 3中的provide和inject有什么作用?請(qǐng)給出一個(gè)provide和inject的示例。

          答案:provide和inject用于實(shí)現(xiàn)組件之間的依賴注入。通過(guò)在父組件中使用provide提供數(shù)據(jù),然后在子組件中使用inject注入這些數(shù)據(jù)。示例:

          // 父組件
          const Parent = {
            provide: {
              message: 'Hello'
            },
            // ...
          }
          
          // 子組件
          const Child = {
            inject: ['message'],
            created() {
              console.log(this.message); // 輸出:Hello
            },
            // ...
          }

          6. Vue.js 3中的動(dòng)畫(huà)系統(tǒng)有哪些改進(jìn)?請(qǐng)列舉幾個(gè)改進(jìn)之處。

          答案:Vue.js 3中的動(dòng)畫(huà)系統(tǒng)相比Vue.js 2有以下改進(jìn)之處:

          更好的性能:Vue.js 3的動(dòng)畫(huà)系統(tǒng)使用了更高效的動(dòng)畫(huà)引擎,提供了更好的性能。 更簡(jiǎn)潔的語(yǔ)法:Vue.js 3的動(dòng)畫(huà)系統(tǒng)使用了更簡(jiǎn)潔的語(yǔ)法,使得動(dòng)畫(huà)的定義和使用更加直觀和方便。 支持更多的動(dòng)畫(huà)特性:Vue.js 3的動(dòng)畫(huà)系統(tǒng)支持更多的動(dòng)畫(huà)特性,如交互式動(dòng)畫(huà)和更復(fù)雜的動(dòng)畫(huà)效果。 Vue.js 3中的靜態(tài)提升(Static Tree Hoisting)是什么?它有什么優(yōu)勢(shì)? 答案:靜態(tài)提升是Vue.js 3中的一項(xiàng)優(yōu)化技術(shù),通過(guò)在編譯階段將靜態(tài)節(jié)點(diǎn)提升為常量,從而減少了運(yùn)行時(shí)的開(kāi)銷。這項(xiàng)優(yōu)化技術(shù)可以提高組件的渲染性能,并減少生成的代碼體積。

          7. Vue.js 3中的Fragment是什么?它的作用是什么?

          答案:Fragment是Vue.js 3中引入的一種機(jī)制,用于在組件中返回多個(gè)根節(jié)點(diǎn)。在Vue.js 2中,組件的模板只能有一個(gè) Vue.js 3中的Composition API中的ref和reactive有什么區(qū)別?什么時(shí)候使用哪個(gè)? 答案:ref用于創(chuàng)建一個(gè)響應(yīng)式的基本數(shù)據(jù)類型,而reactive用于創(chuàng)建一個(gè)響應(yīng)式的對(duì)象。當(dāng)需要?jiǎng)?chuàng)建一個(gè)簡(jiǎn)單的響應(yīng)式數(shù)據(jù)時(shí),可以使用ref,當(dāng)需要?jiǎng)?chuàng)建一個(gè)包含多個(gè)屬性的響應(yīng)式對(duì)象時(shí),可以使用reactive。

          8. Vue.js 3中的watchEffect和watch有什么區(qū)別?什么時(shí)候使用哪個(gè)?

          答案:watchEffect用于監(jiān)聽(tīng)響應(yīng)式數(shù)據(jù)的變化,并在回調(diào)函數(shù)中執(zhí)行相應(yīng)的操作。它會(huì)自動(dòng)追蹤依賴,并在依賴變化時(shí)重新運(yùn)行回調(diào)函數(shù)。watch用于監(jiān)聽(tīng)指定的響應(yīng)式數(shù)據(jù),并在其變化時(shí)執(zhí)行相應(yīng)的操作。它可以精確地指定要監(jiān)聽(tīng)的數(shù)據(jù),并提供更多的配置選項(xiàng)。一般來(lái)說(shuō),如果只需要監(jiān)聽(tīng)一個(gè)響應(yīng)式數(shù)據(jù)的變化并執(zhí)行相應(yīng)操作,可以使用watchEffect;如果需要更細(xì)粒度的控制,可以使用watch。

          9. Vue.js 3中的v-model指令在使用時(shí)有哪些注意事項(xiàng)?

          答案:在使用v-model指令時(shí),有以下注意事項(xiàng):

          v-model指令必須與一個(gè)表單元素一起使用,如、、等。 當(dāng)使用自定義組件時(shí),組件內(nèi)部必須實(shí)現(xiàn)modelValue屬性和update:modelValue事件,以支持v-model的雙向綁定。 可以使用.lazy修飾符實(shí)現(xiàn)在輸入框失去焦點(diǎn)時(shí)更新數(shù)據(jù)。 可以使用.trim修飾符自動(dòng)去除輸入框內(nèi)容的首尾空格。 可以使用.number修飾符將輸入框的值轉(zhuǎn)換為數(shù)字類型。

          10. Vue.js 3中的provide和inject是否支持響應(yīng)式數(shù)據(jù)?

          答案:默認(rèn)情況下,provide和inject不支持響應(yīng)式數(shù)據(jù)。如果需要在provide中提供一個(gè)響應(yīng)式數(shù)據(jù),可以使用ref或reactive將數(shù)據(jù)包裝起來(lái)。然后在inject中使用toRefs或toRef將數(shù)據(jù)解構(gòu)出來(lái),以獲取響應(yīng)式的引用。

          11. Vue.js 3中的nextTick方法有什么作用?在什么情況下使用它?

          答案:nextTick方法用于在下次DOM更新循環(huán)結(jié)束之后執(zhí)行回調(diào)函數(shù)。它可以用來(lái)確保在更新DOM后執(zhí)行某些操作,如操作更新后的DOM元素或獲取更新后的計(jì)算屬性的值。通常在需要等待DOM更新完成后進(jìn)行操作的情況下使用nextTick。

          12. Vue.js 3中的和組件有什么區(qū)別?

          答案:組件用于將組件的內(nèi)容渲染到DOM樹(shù)中的任意位置,而組件用于在組件進(jìn)入或離開(kāi)DOM樹(shù)時(shí)應(yīng)用過(guò)渡效果。主要用于組件的位置移動(dòng),而主要用于組件的顯示和隱藏過(guò)渡。

          13. Vue.js 3中的v-for指令中的key屬性有什么作用?為什么要使用它?

          答案:v-for指令中的key屬性用于給每個(gè)迭代項(xiàng)設(shè)置一個(gè)唯一的標(biāo)識(shí)符。它的作用是幫助Vue.js跟蹤每個(gè)節(jié)點(diǎn)的身份,以便在數(shù)據(jù)發(fā)生變化時(shí)高效地更新DOM。使用key屬性可以避免出現(xiàn)錯(cuò)誤的節(jié)點(diǎn)更新或重新排序的問(wèn)題。

          React

          1. 什么是React?它的核心概念是什么?

          答案:React是一個(gè)用于構(gòu)建用戶界面的JavaScript庫(kù)。它的核心概念是組件化和聲明式編程。React將用戶界面拆分為獨(dú)立的可重用組件,并使用聲明式語(yǔ)法描述組件的狀態(tài)和UI的關(guān)系,使得構(gòu)建復(fù)雜的UI變得簡(jiǎn)單和可維護(hù)。

          2. 什么是JSX?它與HTML有什么區(qū)別?

          答案:JSX是一種JavaScript的語(yǔ)法擴(kuò)展,用于在React中描述UI的結(jié)構(gòu)。它類似于HTML,但有一些區(qū)別:

          3. 什么是React組件?它們有哪兩種類型?

          答案:React組件是構(gòu)建用戶界面的獨(dú)立單元。React組件有兩種類型:

          函數(shù)組件:使用函數(shù)來(lái)定義組件,接收props作為參數(shù),并返回一個(gè)React元素。 類組件:使用ES6類來(lái)定義組件,繼承自React.Component類,通過(guò)render方法返回一個(gè)React元素。

          4. 什么是狀態(tài)(state)和屬性(props)?它們之間有什么區(qū)別?

          答案:狀態(tài)(state)是組件自身管理的數(shù)據(jù),可以通過(guò)setState方法來(lái)更新。屬性(props)是從父組件傳遞給子組件的數(shù)據(jù),子組件無(wú)法直接修改props,只能通過(guò)父組件的更新來(lái)改變props。

          區(qū)別:

          狀態(tài)(state)是組件內(nèi)部的數(shù)據(jù),可以在組件中自由修改和管理。 屬性(props)是從父組件傳遞給子組件的數(shù)據(jù),子組件無(wú)法直接修改,只能接收和使用。

          5. 什么是React生命周期方法?列舉一些常用的生命周期方法。

          答案:React生命周期方法是在組件不同階段執(zhí)行的特定方法。以下是一些常用的React生命周期方法:

          componentDidMount:組件掛載后立即調(diào)用。 componentDidUpdate:組件更新后調(diào)用。 componentWillUnmount:組件卸載前調(diào)用。 shouldComponentUpdate:決定組件是否需要重新渲染。 getDerivedStateFromProps:根據(jù)props的變化來(lái)更新?tīng)顟B(tài)。

          6. 什么是React Hooks?它們的作用是什么?

          答案:React Hooks是React 16.8版本引入的一種特性,用于在函數(shù)組件中使用狀態(tài)和其他React特性。Hooks提供了一種無(wú)需編寫類組件的方式來(lái)管理狀態(tài)和處理副作用,使得函數(shù)組件具有類組件的能力。

          7. 什么是React Router?它的作用是什么?

          答案:React Router是React中用于處理路由的庫(kù)。它提供了一種在單頁(yè)面應(yīng)用中實(shí)現(xiàn)導(dǎo)航和路由功能的方式。React Router可以幫助開(kāi)發(fā)者實(shí)現(xiàn)頁(yè)面之間的切換、URL參數(shù)的傳遞、嵌套路由等功能。

          8. 什么是React Context?它的作用是什么?

          答案:React Context是一種用于在組件樹(shù)中共享數(shù)據(jù)的機(jī)制。它可以避免通過(guò)props一層層傳遞數(shù)據(jù),使得跨組件的數(shù)據(jù)共享變得更加簡(jiǎn)單和高效。React Context提供了一個(gè)Provider和Consumer組件,用于提供和消費(fèi)共享的數(shù)據(jù)。

          9. 什么是React的協(xié)調(diào)(Reconciliation)過(guò)程?它是如何工作的?

          答案:React的協(xié)調(diào)過(guò)程是指React在進(jìn)行組件更新時(shí),通過(guò)比較新舊虛擬DOM樹(shù)的差異,僅對(duì)需要更新的部分進(jìn)行實(shí)際的DOM操作。協(xié)調(diào)過(guò)程的工作方式如下:

          React會(huì)逐層比較新舊虛擬DOM樹(shù)的節(jié)點(diǎn),并找出差異。 對(duì)于每個(gè)差異,React會(huì)生成相應(yīng)的DOM操作指令,如插入、更新或刪除節(jié)點(diǎn)。 React會(huì)將所有的DOM操作指令批量執(zhí)行,以減少對(duì)真實(shí)DOM的操作次數(shù)。

          10. 什么是React的事件合成(SyntheticEvent)?它的作用是什么?

          答案:React的事件合成是一種在React中處理事件的機(jī)制。它是React為了提高性能和跨瀏覽器兼容性而實(shí)現(xiàn)的一種事件系統(tǒng)。事件合成的作用包括:

          提供了一種統(tǒng)一的方式來(lái)處理事件,無(wú)需考慮瀏覽器兼容性。 可以通過(guò)事件委托的方式將事件處理程序綁定到父組件,提高性能。 可以訪問(wèn)原生事件對(duì)象的屬性和方法。

          11. 什么是React的Fiber架構(gòu)?它解決了什么問(wèn)題?

          答案:React的Fiber架構(gòu)是React 16版本引入的一種新的協(xié)調(diào)算法和架構(gòu)。它旨在解決長(zhǎng)時(shí)間渲染阻塞主線程的問(wèn)題,提高應(yīng)用的性能和用戶體驗(yàn)。Fiber架構(gòu)通過(guò)將渲染過(guò)程分解為多個(gè)小任務(wù),并使用優(yōu)先級(jí)調(diào)度算法來(lái)動(dòng)態(tài)分配時(shí)間片,使得React可以在每個(gè)幀中執(zhí)行一部分任務(wù),從而實(shí)現(xiàn)平滑的用戶界面和更好的響應(yīng)性能。

          12. 什么是React的錯(cuò)誤邊界(Error Boundary)?它的作用是什么?

          答案:React的錯(cuò)誤邊界是一種用于處理組件錯(cuò)誤的機(jī)制。它允許組件捕獲并處理其子組件中發(fā)生的JavaScript錯(cuò)誤,以避免整個(gè)應(yīng)用崩潰。錯(cuò)誤邊界的作用包括:

          捕獲并處理組件樹(shù)中的錯(cuò)誤,防止錯(cuò)誤導(dǎo)致整個(gè)應(yīng)用崩潰。 提供一種優(yōu)雅的方式來(lái)顯示錯(cuò)誤信息或備用UI。 可以用于記錄錯(cuò)誤和發(fā)送錯(cuò)誤報(bào)告。

          網(wǎng)絡(luò)

          1. 什么是HTTP?它是如何工作的?

          答案:HTTP(Hypertext Transfer Protocol)是一種用于在Web上傳輸數(shù)據(jù)的協(xié)議。它使用客戶端-服務(wù)器模型,客戶端發(fā)送HTTP請(qǐng)求到服務(wù)器,服務(wù)器返回HTTP響應(yīng)。HTTP的工作流程如下:

          客戶端發(fā)送HTTP請(qǐng)求到指定的URL。 服務(wù)器接收請(qǐng)求并處理,然后返回HTTP響應(yīng)。 客戶端接收響應(yīng)并解析,從中獲取所需的數(shù)據(jù)。

          2. 什么是HTTPS?與HTTP有什么區(qū)別?

          答案:HTTPS(Hypertext Transfer Protocol Secure)是HTTP的安全版本,通過(guò)使用SSL(Secure Sockets Layer)或TLS(Transport Layer Security)協(xié)議對(duì)通信進(jìn)行加密和身份驗(yàn)證。與HTTP相比,HTTPS具有以下區(qū)別:

          數(shù)據(jù)在傳輸過(guò)程中通過(guò)加密進(jìn)行保護(hù),提供更高的安全性。 使用數(shù)字證書(shū)對(duì)服務(wù)器進(jìn)行身份驗(yàn)證,防止中間人攻擊。 使用默認(rèn)端口443。

          3. 什么是跨域請(qǐng)求?它是如何解決的?

          答案:跨域請(qǐng)求是指在瀏覽器中向不同域名、端口或協(xié)議發(fā)送的請(qǐng)求。由于瀏覽器的同源策略(Same-Origin Policy)限制,跨域請(qǐng)求會(huì)受到限制。為了解決跨域問(wèn)題,可以使用以下方法:

          JSONP(JSON with Padding):通過(guò)動(dòng)態(tài)創(chuàng)建

          4. 什么是緩存?在前端中如何使用緩存來(lái)提高性能?

          答案:緩存是將數(shù)據(jù)或資源存儲(chǔ)在臨時(shí)存儲(chǔ)中,以便在后續(xù)請(qǐng)求中重復(fù)使用,從而提高性能和減少網(wǎng)絡(luò)流量。在前端中,可以使用以下方式來(lái)利用緩存:

          HTTP緩存:通過(guò)設(shè)置適當(dāng)?shù)木彺骖^(如Cache-Control和Expires)來(lái)指示瀏覽器緩存響應(yīng)。 資源緩存:使用文件指紋或版本號(hào)來(lái)重命名靜態(tài)資源文件,以便在文件內(nèi)容變化時(shí)使瀏覽器重新下載。 數(shù)據(jù)緩存:使用內(nèi)存緩存、瀏覽器本地存儲(chǔ)(如localStorage)或服務(wù)端緩存(如Redis)來(lái)存儲(chǔ)數(shù)據(jù),避免重復(fù)請(qǐng)求。

          5. 什么是CDN?它的作用是什么?

          答案:CDN(Content Delivery Network)是一種分布式網(wǎng)絡(luò)架構(gòu),用于在全球各地提供高性能、低延遲的內(nèi)容傳輸服務(wù)。CDN的作用包括:

          將靜態(tài)資源(如圖片、樣式表、腳本等)緩存到離用戶更近的服務(wù)器上,提供更快的加載速度。 分發(fā)網(wǎng)絡(luò)流量,減輕源服務(wù)器的負(fù)載壓力。 提供內(nèi)容壓縮、數(shù)據(jù)壓縮和緩存等優(yōu)化技術(shù),提高用戶體驗(yàn)。

          6. 什么是網(wǎng)頁(yè)加載性能優(yōu)化?可以采取哪些措施來(lái)改善網(wǎng)頁(yè)加載性能?

          答案:網(wǎng)頁(yè)加載性能優(yōu)化是指通過(guò)各種技術(shù)手段來(lái)減少網(wǎng)頁(yè)加載時(shí)間并提高用戶體驗(yàn)。可以采取以下措施來(lái)改善網(wǎng)頁(yè)加載性能:

          壓縮和合并資源文件(如CSS和JavaScript),減少文件大小和請(qǐng)求數(shù)量。 使用圖像壓縮和適當(dāng)?shù)母袷竭x擇來(lái)減小圖像文件大小。 使用瀏覽器緩存和HTTP緩存頭來(lái)緩存靜態(tài)資源。 使用懶加載延遲加載非關(guān)鍵資源,提高初始加載速度。 使用CDN(內(nèi)容分發(fā)網(wǎng)絡(luò))來(lái)分發(fā)靜態(tài)資源,減少網(wǎng)絡(luò)延遲。 優(yōu)化關(guān)鍵渲染路徑,盡早呈現(xiàn)頁(yè)面內(nèi)容。

          7. 什么是網(wǎng)頁(yè)性能監(jiān)測(cè)和分析?可以使用哪些工具來(lái)監(jiān)測(cè)和分析網(wǎng)頁(yè)性能?

          答案:網(wǎng)頁(yè)性能監(jiān)測(cè)和分析是指通過(guò)測(cè)量和收集有關(guān)網(wǎng)頁(yè)加載和交互性能的數(shù)據(jù),以便識(shí)別性能瓶頸并進(jìn)行優(yōu)化。可以使用以下工具來(lái)監(jiān)測(cè)和分析網(wǎng)頁(yè)性能:

          Web性能API:瀏覽器提供的JavaScript API,可通過(guò)performance對(duì)象來(lái)收集性能數(shù)據(jù)。 Lighthouse:一種開(kāi)源工具,可提供關(guān)于網(wǎng)頁(yè)性能、可訪問(wèn)性和最佳實(shí)踐的綜合報(bào)告。 WebPagetest:在線工具,可測(cè)量網(wǎng)頁(yè)加載時(shí)間并提供詳細(xì)的性能分析報(bào)告。 Chrome開(kāi)發(fā)者工具:瀏覽器內(nèi)置的開(kāi)發(fā)者工具,提供了性能分析、網(wǎng)絡(luò)監(jiān)控和頁(yè)面審查等功能。

          8. 什么是漸進(jìn)式圖像加載(Progressive Image Loading)?它如何改善網(wǎng)頁(yè)加載性能?

          答案:漸進(jìn)式圖像加載是一種技術(shù),通過(guò)逐步加載圖像的模糊或低分辨率版本,然后逐漸提高圖像的清晰度,以改善網(wǎng)頁(yè)加載性能和用戶體驗(yàn)。漸進(jìn)式圖像加載的好處包括:

          用戶可以更快地看到頁(yè)面內(nèi)容,提高感知速度。 逐步加載圖像可以減少網(wǎng)頁(yè)整體的加載時(shí)間。 漸進(jìn)式圖像加載可以提供平滑的過(guò)渡效果,避免頁(yè)面內(nèi)容突然閃爍或變化。

          9. 什么是前端資源優(yōu)先級(jí)(Resource Prioritization)?如何設(shè)置資源的優(yōu)先級(jí)?

          答案:前端資源優(yōu)先級(jí)是指為不同類型的資源分配加載優(yōu)先級(jí),以優(yōu)化網(wǎng)頁(yè)加載性能。可以使用以下方法設(shè)置資源的優(yōu)先級(jí):

          使用標(biāo)簽來(lái)指定資源的預(yù)加載,以確保關(guān)鍵資源盡早加載。 使用標(biāo)簽來(lái)指定可能在未來(lái)頁(yè)面中使用的資源,以提前加載。 使用標(biāo)簽來(lái)指定要預(yù)解析的域名,以減少DNS查找時(shí)間。 使用標(biāo)簽來(lái)指定要預(yù)連接的域名,以減少建立連接的時(shí)間。

          瀏覽器

          1.解釋一下瀏覽器的工作原理。

          答案:瀏覽器的工作原理包括以下幾個(gè)關(guān)鍵步驟:

          解析:瀏覽器將接收到的HTML、CSS和JavaScript代碼解析成DOM樹(shù)、CSSOM樹(shù)和JavaScript引擎可執(zhí)行的代碼。 渲染:瀏覽器使用DOM樹(shù)和CSSOM樹(shù)構(gòu)建渲染樹(shù),然后根據(jù)渲染樹(shù)進(jìn)行布局(計(jì)算元素的位置和大小)和繪制(將元素繪制到屏幕上)。 布局和繪制:瀏覽器根據(jù)渲染樹(shù)的變化進(jìn)行布局和繪制,然后將最終的頁(yè)面呈現(xiàn)給用戶。 JavaScript引擎執(zhí)行:瀏覽器的JavaScript引擎解釋和執(zhí)行JavaScript代碼,并根據(jù)需要更新渲染樹(shù)和重新渲染頁(yè)面。

          2. 什么是重繪(Repaint)和重排(Reflow)?它們之間有什么區(qū)別?

          答案:重繪是指當(dāng)元素的外觀(如顏色、背景等)發(fā)生改變,但布局不受影響時(shí)的更新過(guò)程。重繪不會(huì)導(dǎo)致元素的位置或大小發(fā)生變化。

          重排是指當(dāng)元素的布局屬性(如寬度、高度、位置等)發(fā)生改變時(shí)的更新過(guò)程。重排會(huì)導(dǎo)致瀏覽器重新計(jì)算渲染樹(shù)和重新繪制頁(yè)面的一部分或全部。

          區(qū)別在于重繪只涉及外觀的更改,而重排涉及布局的更改。重排比重繪更消耗性能,因?yàn)樗枰匦掠?jì)算布局和繪制整個(gè)頁(yè)面。

          3. 什么是事件冒泡和事件捕獲?它們之間有什么區(qū)別?

          答案:事件冒泡和事件捕獲是指瀏覽器處理事件時(shí)的兩種不同的傳播方式。

          事件冒泡是指事件從最內(nèi)層的元素開(kāi)始觸發(fā),然后逐級(jí)向上傳播到父元素,直到傳播到最外層的元素。

          事件捕獲是指事件從最外層的元素開(kāi)始觸發(fā),然后逐級(jí)向下傳播到最內(nèi)層的元素。

          區(qū)別在于傳播方向的不同。事件冒泡是從內(nèi)向外傳播,而事件捕獲是從外向內(nèi)傳播。

          4. 解釋一下同步和異步的JavaScript代碼執(zhí)行方式。

          答案:同步代碼是按照順序執(zhí)行的代碼,每個(gè)任務(wù)必須等待前一個(gè)任務(wù)完成后才能執(zhí)行。同步代碼會(huì)阻塞后續(xù)代碼的執(zhí)行,直到當(dāng)前任務(wù)完成。

          異步代碼是不按照順序執(zhí)行的代碼,它會(huì)在后臺(tái)執(zhí)行,不會(huì)阻塞后續(xù)代碼的執(zhí)行。異步代碼通常使用回調(diào)函數(shù)、Promise、async/await等方式來(lái)處理異步操作的結(jié)果。

          通過(guò)異步執(zhí)行,可以避免阻塞主線程,提高頁(yè)面的響應(yīng)性能。

          5. 什么是事件循環(huán)(Event Loop)?它在JavaScript中的作用是什么?

          答案:事件循環(huán)是JavaScript中處理異步代碼執(zhí)行的機(jī)制。它負(fù)責(zé)管理調(diào)度和執(zhí)行異步任務(wù),并將它們添加到執(zhí)行隊(duì)列中。

          在JavaScript中,事件循環(huán)的作用是確保異步任務(wù)按照正確的順序執(zhí)行,并且不會(huì)阻塞主線程。它通過(guò)不斷地從執(zhí)行隊(duì)列中取出任務(wù)并執(zhí)行,以實(shí)現(xiàn)非阻塞的異步操作。

          6. 解釋一下瀏覽器的垃圾回收機(jī)制是如何工作的。

          答案:瀏覽器的垃圾回收機(jī)制是一種自動(dòng)管理內(nèi)存的機(jī)制,用于檢測(cè)和回收不再使用的對(duì)象,以釋放內(nèi)存資源。

          垃圾回收機(jī)制通過(guò)標(biāo)記-清除算法實(shí)現(xiàn)。它的工作原理如下:

          標(biāo)記階段:垃圾回收器會(huì)從根對(duì)象(如全局對(duì)象)開(kāi)始,遞歸遍歷所有對(duì)象,并標(biāo)記仍然可訪問(wèn)的對(duì)象。 清除階段:垃圾回收器會(huì)掃描堆內(nèi)存,清除未被標(biāo)記的對(duì)象,并回收它們所占用的內(nèi)存空間。 垃圾回收機(jī)制的目標(biāo)是識(shí)別和回收不再使用的對(duì)象,以避免內(nèi)存泄漏和提高內(nèi)存利用率。

          7. 解釋一下瀏覽器的同源策略(Same-Origin Policy)及其限制。

          答案:同源策略是瀏覽器的一項(xiàng)安全機(jī)制,用于限制來(lái)自不同源的網(wǎng)頁(yè)之間的交互。同源是指協(xié)議、域名和端口號(hào)完全相同。

          同源策略的限制包括:

          腳本訪問(wèn)限制:不同源的腳本無(wú)法直接訪問(wèn)彼此的數(shù)據(jù)和操作。 DOM訪問(wèn)限制:不同源的網(wǎng)頁(yè)無(wú)法通過(guò)JavaScript訪問(wèn)彼此的DOM元素。 Cookie限制:不同源的網(wǎng)頁(yè)無(wú)法讀取或修改彼此的Cookie。 AJAX請(qǐng)求限制:不同源的網(wǎng)頁(yè)無(wú)法通過(guò)AJAX請(qǐng)求訪問(wèn)彼此的數(shù)據(jù)。 同源策略的存在可以防止惡意網(wǎng)站獲取用戶的敏感信息或進(jìn)行惡意操作。

          8. 什么是Web Workers?它們?cè)跒g覽器中的作用是什么?

          答案:Web Workers是一種瀏覽器提供的JavaScript API,用于在后臺(tái)線程中執(zhí)行耗時(shí)的計(jì)算任務(wù),以避免阻塞主線程。

          Web Workers的作用是提高瀏覽器的響應(yīng)性能,使得在執(zhí)行復(fù)雜計(jì)算或處理大量數(shù)據(jù)時(shí),不會(huì)影響用戶界面的流暢性。

          Web Workers通過(guò)將任務(wù)委托給后臺(tái)線程來(lái)實(shí)現(xiàn)并行處理,從而充分利用多核處理器的能力。它們可以與主線程進(jìn)行通信,但不能直接訪問(wèn)DOM或執(zhí)行UI相關(guān)的操作。

          9. 解釋一下瀏覽器緩存(Browser Cache)是什么,以及它的作用是什么?

          答案:瀏覽器緩存是瀏覽器在本地存儲(chǔ)Web頁(yè)面和資源的副本,以便在后續(xù)訪問(wèn)時(shí)可以快速加載。它的作用是減少對(duì)服務(wù)器的請(qǐng)求次數(shù)和網(wǎng)絡(luò)傳輸量,提高頁(yè)面加載速度和用戶體驗(yàn)。

          瀏覽器緩存通過(guò)在首次請(qǐng)求時(shí)將資源保存到本地,并在后續(xù)請(qǐng)求時(shí)檢查資源是否已經(jīng)存在并且沒(méi)有過(guò)期來(lái)工作。如果資源已經(jīng)存在且未過(guò)期,瀏覽器會(huì)直接從緩存中加載資源,而不是從服務(wù)器重新下載。

          10. 什么是重定向(Redirect)?它在瀏覽器中的作用是什么?

          答案:重定向是指當(dāng)瀏覽器請(qǐng)求一個(gè)URL時(shí),服務(wù)器返回一個(gè)不同的URL,從而將瀏覽器的請(qǐng)求重定向到新的URL上。

          重定向在瀏覽器中的作用是實(shí)現(xiàn)頁(yè)面的跳轉(zhuǎn)、URL的修改或資源的重定向。它可以用于多種情況,例如處理舊鏈接的跳轉(zhuǎn)、實(shí)現(xiàn)URL的規(guī)范化、處理用戶認(rèn)證等。

          重定向通過(guò)在HTTP響應(yīng)中設(shè)置特定的狀態(tài)碼(如301永久重定向、302臨時(shí)重定向)和Location頭部字段來(lái)實(shí)現(xiàn)。

          11. 什么是瀏覽器存儲(chǔ)(Browser Storage)?它有哪些不同的存儲(chǔ)機(jī)制?

          答案:瀏覽器存儲(chǔ)是瀏覽器提供的一種在客戶端存儲(chǔ)數(shù)據(jù)的機(jī)制,用于在不同的網(wǎng)頁(yè)間共享數(shù)據(jù)或持久保存數(shù)據(jù)。

          瀏覽器存儲(chǔ)有以下不同的存儲(chǔ)機(jī)制:

          Cookie:小型文本文件,可以存儲(chǔ)少量數(shù)據(jù),并在每次HTTP請(qǐng)求中自動(dòng)發(fā)送到服務(wù)器。 Web Storage(localStorage和sessionStorage):可以存儲(chǔ)較大量的數(shù)據(jù),以鍵值對(duì)的形式存儲(chǔ)在瀏覽器中。 IndexedDB:一種高級(jí)的客戶端數(shù)據(jù)庫(kù),可以存儲(chǔ)大量結(jié)構(gòu)化數(shù)據(jù),并支持索引和事務(wù)操作。 Cache API:用于緩存網(wǎng)絡(luò)請(qǐng)求的響應(yīng),以便離線訪問(wèn)或提高頁(yè)面加載速度。 不同的存儲(chǔ)機(jī)制適用于不同的需求,開(kāi)發(fā)者可以根據(jù)具體情況選擇合適的存儲(chǔ)方式。

          祝想跳槽的小伙伴們都能成功!需要更多完整面試題可以私信我!


          主站蜘蛛池模板: 久久精品国产亚洲一区二区| 久久婷婷色综合一区二区| 中文字幕乱码亚洲精品一区 | 黄桃AV无码免费一区二区三区 | 亚洲欧洲精品一区二区三区| 偷拍激情视频一区二区三区| 亚洲AV无码一区二三区| 无码少妇精品一区二区免费动态| 久久精品日韩一区国产二区 | 久久精品无码一区二区三区日韩| 亚洲欧洲精品一区二区三区| 激情内射日本一区二区三区| 精品免费国产一区二区三区| 丰满少妇内射一区| 视频一区视频二区在线观看| tom影院亚洲国产一区二区| 东京热人妻无码一区二区av| 一区二区三区午夜| 国产精品亚洲综合一区在线观看| 91国偷自产一区二区三区| 亚洲一区二区三区首页| 偷拍激情视频一区二区三区| 免费无码A片一区二三区| 日韩三级一区二区| 日韩精品无码一区二区三区四区 | 精品日产一区二区三区手机| 亚洲午夜福利AV一区二区无码| 日本精品一区二区三区在线观看| 亚洲一区二区三区播放在线| 国产激情一区二区三区小说 | 日本一区二区三区精品国产 | 亚洲a∨无码一区二区| 日韩综合无码一区二区| 国产福利一区视频| 精品一区二区三区无码视频| 国产日韩高清一区二区三区| 国产精品无码一区二区在线观一 | 91精品福利一区二区| 无码少妇A片一区二区三区 | 国产一区二区三区电影| 无码毛片一区二区三区中文字幕|