廣州藍景知識點分享——如何理解前端和Vue

最近身邊學習 Vue 的人也越來越多了,大家都有很多的疑問,爲什麼前端要用框架、Vue 做了些什麼、要怎麼上手,等等。距離上一次寫 Vue 也過去三年了,是時候再把這三年自己的理解再整理進去了。由於這個系列主要是希望寫給可能前端掌握也不深的人,所以會鋪墊一些自己認爲需要的內容,本節先來講講入門前端,作爲鋪墊,來理解 Vue 這個框架吧。

前端頁面解析
頁面組成

我們打開一個前端項目,經常會看到很多不同後綴的文件,例如一個頁面可能包括a.html、a.css、a.js,用了 Vue 還有a.vue,再加上 Typescript 可能還有a.ts。

相信有些沒寫過前端的開發們是有點崩潰的,我們先來分別看看一個前端頁面都是由什麼組成的。其實最終跑在瀏覽器中的代碼,主要包括三種:HTML、CSS、Javascript。

HTML
直接從代碼說起,最簡單的莫過於:
在這裏插入圖片描述
這裏麪包括兩個子模快:

:常包括控制樣式的標籤、控制瀏覽器特殊邏輯的標籤、控制代碼執行邏輯的

通常來說,一段 HTML 代碼,最終在瀏覽器中會生成一堆 DOM 節點樹,例如:在這裏插入圖片描述
這段代碼在瀏覽器中渲染時,其實是長這個樣子的:在這裏插入圖片描述
這不一定是最終的結果,因爲我們還可以這樣操作:
1.通過 CSS 樣式,例如display: none來讓其中某個節點消失。
2.通過 JS 代碼操作 DOM,例如使用document.getElementById獲取到某個節點元素,然後再通過設置.innerHTML來改變元素的內容。

CSS
CSS 主要是給我們的 HTML 元素添加樣式,可以通過幾個方式匹配:

  • DOM 元素匹配:例如p{color: red}會讓所有

    元素的文字都變成紅色

  • class 匹配:類的匹配,例如.color-red{color: red}會讓所有元素的文字都變成紅色
  • id 匹配:id標識符的匹配,例如#color-red{color: red}會讓元素的文字都變成紅色(若頁面內有多個相同的 id,則只有第一個生效)
    CSS 的調試和編寫上手不簡單,會需要很多的踩坑和練習,它也不像 JS 那樣可以完全根據語法或是邏輯理解,總有兼容性會顛覆你之前的認知。不過 CSS 寫好了,對寫頁面的效率會有很大的提升。

Javascript
HTML 是簡單的網頁靜態信息,而 JavaScript 可以在網頁上實現複雜的功能。

我們常常使用 Javascript 來做以下事情:

  • 處理事件(點擊、輸入等)
  • 改變 HTML 內容、位置和樣式
  • 處理 Http 請求、各種業務邏輯的執行
  • 很多其他的事情也可以做
    Javascript 是單線程的,更多是因爲對頁面交互的同步處理。作爲瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操作 DOM,若是多線程會導致嚴重的同步問題。

頁面渲染
瀏覽器的渲染機制

我們現在知道一個頁面的代碼裏,主要包括了 HTML、CSS、Javascript 三大塊內容,那麼瀏覽器是怎麼解析和加載這些內容的呢?
一次瀏覽器的頁面渲染過程中,瀏覽器會解析三種文件:
在這裏插入圖片描述
CSS 規則樹與 DOM 結構樹結合,最終生成一個 Render 樹(即最終呈現的頁面,例如其中會移除 DOM 結構樹中匹配到 CSS 裏面display:none的 DOM 節點)。一般來說瀏覽器繪製頁面的過程是:

1.計算 CSS 規則樹。
2.生成 Render 樹。
3.計算各個節點的大小/position/z-index。
4.繪製。

頁面的局部刷新
一般看來,瀏覽器生成了最終的 Render 樹,頁面也已經渲染完畢,似乎瀏覽器已經完成了它的工作了。但現實中我們的頁面更多的不只是靜態的頁面,還會包括點擊、拖拽等事件操作,以及接口請求、數據渲染到頁面等動態的交互邏輯,這時候我們會需要更新頁面的信息。

我們的業務代碼中情況會複雜得多,除了插入內容,還包括內容更新、刪除元素節點等。不管是那種情況,目前來說前端一般分爲兩種方式:

1.綁定映射表方式。
2.直接替換內容方式。

1. 綁定映射表方式
這其實是挺經常使用的一種方式,例如下面這段代碼:在這裏插入圖片描述
這裏拿到了的這樣一個元素映射,我們在更新內容、處理節點的時候就可以用這個映射來直接操作,如:在這裏插入圖片描述
如果我們一個頁面裏需要綁定變量的元素很多,那每次要更新某塊的頁面數據,可能會需要保存很多的元素映射,同時需要調用很多很多的createElement()/appendChild()/removeChild()這類方法,也是個不小的開銷。這種情況下,我們可以使用直接替換內容的方式。

2. 直接替換內容方式
我們每次更新頁面數據和狀態,還可以通過innerHTML方法來用新的HTML String替換舊的,這種方法寫起來很簡單,無非是將各種節點使用字符串的方式拼接起來而已。
例如,上面的幾次更新 a 元素節點,可以調整成這樣實現:在這裏插入圖片描述
這種方式來更新頁面簡單粗暴,但是如果我們更新的節點範圍比較大,這時候我們需要替換掉很大一片的HTML String。這種情況下,會面臨着可能導致更多的瀏覽器計算。

頁面迴流、重繪
前面也介紹了,瀏覽器繪製頁面的過程是:1.計算CSS規則樹 => 2.生成Render樹 => 3.計算各個節點的大小/position/z-index => 4.繪製。其中計算的環節也是消耗較大的地方。

我們使用 DOM API 和 CSS API 的時候,通常會觸發瀏覽器的兩種操作:Repaint(重繪) 和 Reflow(迴流):在這裏插入圖片描述
迴流的花銷跟render tree有多少節點需要重新構建有關係,這也是爲什麼前面說使用innerHTML會導致更多的開銷。所以到底是使用綁定映射表方式,還是使用直接替換內容方式,都是需要具體問題具體分析的。

事件驅動
事件驅動其實是前端開發中最容易理解的編碼方式,例如我們寫一個提交表單的頁面,用事件驅動的方式來寫的話,會是這樣一個流程:

1.編寫靜態頁面
在這裏插入圖片描述
2.給對應的元素綁定對應的事件。例如給 input 輸入框綁定輸入事件:在這裏插入圖片描述
3.事件觸發時,更新頁面內容
在這裏插入圖片描述
以上這個流程,是很常見的前端編碼思維,我們稱之爲事件驅動模式。

前端思維轉變
很多人不理解這幾年來前端的變化,爲什麼不能再用 jQuery 統一天下呢?爲什麼要搞那麼多的庫,還要按照環境呢?不是用個 txt 編輯器就能寫完一個頁面嗎,前端弄那麼複雜是爲了什麼呢?

既然稱之爲思維轉變,那麼可以將事件驅動的思維模式作爲過去常見的一種方式,而如今的前端開發過程中,多了很多的新框架、新工具,還有了工程化,這些帶來了怎樣的思維模式的轉變呢?

前端框架的出現
其實最初是 AngularJS 開始佔領了比較多的地位,後面 React 迎面趕上,在 Angular 斷崖升級的幫助下,Vue 結合了各種框架的優勢,以及非常容易入門的文檔,成功成爲了那一匹黑馬。既然這一系列寫的是 Vue 的入門和使用,那這裏當然是基於 Vue 來介紹了。

Vue 文本插值
在 Vue 中,最基礎的模板語法是數據綁定,例如:在這裏插入圖片描述
這裏綁定了一個 msg 的變量,開發者在 Vue 實例 data 中綁定該變量:在這裏插入圖片描述
最終頁面展示內容爲

測試文本

數據綁定的實現
這種使用雙大括號來綁定變量的方式,我們稱之爲數據綁定。它是怎麼實現的呢,數據綁定的過程其實不復雜:在這裏插入圖片描述
上述這個過程,是模板引擎在做的事情。我們來看看上面在 Vue 裏的代碼片段
,我們可以解析後獲得這樣一個 AST 對象:
在這裏插入圖片描述
這樣,我們在生成一個 DOM 的時候,同時添加對data的監聽,數據更新時我們會找到對應的nodeIndex,更新值:在這裏插入圖片描述
虛擬 DOM
虛擬 DOM 如今已經被作爲前端面試基礎題了,多多少少面試者都要去了解下,當初 React 就是因爲虛擬 DOM 的提出,暫時贏下了瀏覽器性能之爭。當然,這都是幾年前的事情了,如今幾大框架的性能問題,早也不是什麼大問題了。

虛擬 DOM 大概是這麼個過程:
(1) 用 JS 對象模擬 DOM 樹,得到一棵虛擬 DOM 樹。
(2) 當頁面數據變更時,生成新的虛擬 DOM 樹,比較新舊兩棵虛擬 DOM 樹的差異。
(3) 把差異應用到真正的 DOM 樹上。

爲什麼要用到虛擬 DOM 呢?這是因爲一個 DOM 節點它包括了太多太多的屬性、元素和事件對象,感覺有上百個。但是我們並不是全部都會用到,通常包括節點內容、元素位置、樣式、節點的添加刪除等方法,而我們通過用 JS 對象表示 DOM 元素的方式,大大降低了比較差異的計算量。

虛擬 DOM 中,差異對比也是很關鍵的一步,這裏簡單說一下。當狀態變更的時候,重新構造一棵新的對象樹。然後用新的樹和舊的樹進行比較,記錄兩棵樹差異。通常來說這樣的差異需要記錄:需要替換掉原來的節點、移動、刪除、新增子節點、修改了節點的屬性、 對於文本節點的文本內容改變。經過差異對比之後,我們能獲得一組差異記錄,接下里我們需要使用它。
在這裏插入圖片描述
如圖,這裏我們對比兩棵 DOM 樹,得到的差異有:p 元素插入了一個 span 元素子節點,然後原先的文本節點挪到了span 元素子節點下面,最後通過 JS 操作就可以實現完。

XSS 漏洞
模板引擎還可以協助預防下 XSS 相關漏洞。我們知道,XSS 的整個攻擊過程大概爲:在這裏插入圖片描述
避免 XSS 的方法之一主要是將用戶所提供的內容進行過濾,而大多數模板引擎會自帶 HTML 轉義功能。在 Vue 中,默認的數據綁定方式(雙大括號、v-bind等)會進行 HTML 轉義,將數據解釋爲普通文本,而非 HTML 代碼。

當然,如果你一定要輸出 HTML 代碼,也可以使用v-html指令輸出。官方文檔也有特殊說明:在這裏插入圖片描述
Vue簡介

看看這些模板引擎都做了啥事,原本就是一個

,經過 AST 生成一個對象,最終還是生成一個
,這是多餘的步驟嗎?不是的,在這個過程中我們可以實現一些功能:

  • 排除無效 DOM 元素,並在構建過程可進行報錯
  • 使用自定義組件的時候,可匹配出來
  • 可方便地實現數據綁定、事件綁定等,具備自動更新頁面的功能
  • 爲虛擬 DOM Diff 過程打下鋪墊
  • HTML 轉義(預防 XSS 漏洞)
    所以 Vue 它只是一個模板引擎嗎?怎麼說呢,模板引擎可能是我們選擇框架的原因裏最重要的一個,畢竟如果沒有框架的話,所有上述這些很好用的能力都需要自己搭建,不然開發效率會很受影響。

我們看看 Vue 官方的介紹:
在這裏插入圖片描述
數據驅動

前面也介紹了,在 jQuery 年代,我們通常是使用事件驅動的模式去進行開發了。那麼使用了 Vue 之後,寫代碼的方式會有哪些不一樣嗎?

既然前面介紹了事件模型一般的編碼流程,我們再來看看,同樣的們寫一個提交表單的頁面,用數據驅動的方式來寫的話,會變成這麼一個流程:

1:設計數據結構。
在這裏插入圖片描述
2:把數據綁定到頁面中需要使用/展示的地方在這裏插入圖片描述
3.事件觸發時,更新數據。
在這裏插入圖片描述
我們在設置數據(this.name = event.target.value)的時候,Vue 已經替我們把將數據更新到頁面的邏輯處理了。大家也可以去 codepen 或者 jsfiddle、stackblitz 這些在線編碼網站上嘗試下。

所以事件驅動和數據驅動一個很重要的區別在於,我們是從每個事件的觸發開始設計我們的代碼,還是以數據爲中心,接收事件觸發和更新數據狀態的方式來寫代碼。

頁面編寫

如果要問,vue 和 jQuery 有什麼不一樣?其實它們從定位到設計到實現上都完全不一樣,但是對開發者來說,我們可以做個簡單直觀的區別:
在這裏插入圖片描述
當我們在 Vue 中,模板引擎幫我們處理了模板渲染、數據綁定的過程,我們只需要知道這裏面只有一個有效數據,即輸入框的值。

頁面抽象

既然使用了數據驅動,那麼對頁面的一個抽象能力也是很重要的。例如我們現在要寫一個列表,數據從後臺獲取到之後,展示到頁面中。

1.當我們需要渲染成列表時:
在這裏插入圖片描述
2.當我們需要更新一個列表中某個 id 的其中一個數據時(這裏需要更改 id 爲 3 的 name 值):在這裏插入圖片描述
在使用數據驅動的時候,模板渲染的事情會交給框架去完成,我們需要做的就是數據處理而已。那麼轉換了數據驅動之後,有什麼好處呢?

當我們把一個頁面抽象成數據來表示之後,可以做的事情就多了。如果我們把所有的頁面、組件、展示內容和接口配置等都變成了配置數據,那麼我們就可以把所有的東西都進行配置化。

前端工程化

其實前端工程化這塊,我並不是能理解得很深刻,能講給大家的,應該只是自己的一種理解了。一般來說,現在的主流構建工具應該是 Webpack,包括我們使用 Vue 官方腳手架生成的代碼,構建工具也是 Webpack。

我們在代碼中會使用到很多的資源,圖片、樣式、代碼,還有各式各樣的依賴包,而打包的時候怎麼實現按需分塊、處理依賴關係、不包含多餘的文件或內容,同時提供開發和生產環境,包括本地調試自動更新到瀏覽器這些能力,都是由 Webpack 整合起來的。

npm 依賴包
要實現工程化,前端開發幾乎都離不開 nodejs 的包管理器 npm,比如前端在搭建本地開發服務以及打包編譯前端代碼等都會用到。在前端開發過程中,經常用到npm install來安裝所需的依賴。

爲什麼會有 npm 包的出現呢?因爲一個人的力量是有限的,我們在寫代碼的時候,爲了可以將注意力集中到業務開發中,會需要使用別人開源的很多工具、框架和代碼包。在很早以前,我們是一個個地下載,或是通過的方式去引用。

當一個網站依賴的代碼越來越多,其實管理依賴和版本是一件很麻煩的事情。然後 npm 就出現了,作爲一個把這些代碼集中到一起來管理的工具。

同時,我們可以結合一些 tree shaking 的能力,在本地構建的時候,把使用的別人的依賴包裏沒用用到的部分去掉,減小代碼包的大小等。

在安裝 Node.js 的時候,npm 的能力也會一塊提供到,按照完之後就能直接在機器終端使用npm install xxx這種能力啦,需要安裝什麼依賴包呢,你可以去npmjs官網搜一下。

vue cli
通常來說,腳手架可以讓你快速地生成示例代碼、搭建本地環境,也可以更新依賴的版本等,避免了每個開發者自行調整開發環境、打包邏輯等配置。
Vue cli 也提供了這樣的能力,更多的可以參考官方文檔。在這裏插入圖片描述
使用方式很簡單:
在這裏插入圖片描述
生成之後的代碼目錄是這樣的:
在這裏插入圖片描述
啓動項目

一般來說,項目會有個 README.md 文件,你能看到一些簡單的說明,例如這裏生成的:在這裏插入圖片描述
yarn 跟 npm 都是差不多的包管理器,區別在於 yarn 在安裝時會速度更快(並行、離線等),以及版本統一管理的比較好。但如果你不是有特殊的喜好或者習慣,其實兩個都可以用,例如這裏的yarn run serve也可以用npm run serve來運行。

如果有些習慣不好的項目缺了 README,這種時候要怎麼去啓動一個項目呢?可以查看package.json文件:在這裏插入圖片描述
一般來說,開發環境是dev、serve等,生產環境是build,scripts裏是一些任務,運行命令npm run taskName就可以啓動了。
在這裏插入圖片描述
上圖中,我們可以看到任務已經啓動了,訪問輸出的地址(這裏是http://localhost:8080/或者http://10.40.120.53:8080/)就能看到我們的項目跑起來了。在這裏插入圖片描述
第一 part 結束了,更多的內容還是前端相關。這些主要是這幾年對頁面渲染的一些新的理解,然後簡單用腳手架啓動了個 demo 項目。內容是按照自己覺得較清晰的邏輯展開來講的,如果說你有更好的想法,或是發現我的描述中有哪些不到位的地方,也十分歡迎來交流。
工具始終是工具沒錯,但一個工具爲什麼受這麼多人追捧,它到底解決了什麼,你可以從中學習到什麼,這些纔是個人認爲的在使用工具時候收穫的很重要的東西。在 Vue 官方文檔很完善的情況下,我來給你們補上文檔以外的一些技巧和內容吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章