什麼是前端框架
儘管我們的前端三件套(HTML、CSS和JavaScript)已經非常強大,能夠完成所有的前端開發工作,但在有的時候,一些開發過程也稍顯繁瑣。例如,我們有下面一個例子:
從後端請求到一個list,需要把這個list中的每一項內容都渲染到頁面上。
這是一個極爲常見的需求。如果我們使用三件套來實現它,我們需要這樣去寫:
1 | <div id="father"></div> |
1 | // 假設下面的變數list就是我們得到的list |
這樣的邏輯顯然是明瞭的。
然而,讀者是否認爲這樣的步驟太過於繁瑣?我們爲了將一個列表動態渲染到頁面上,竟然要手動地一個一個創造節點、添加節點。儘管有for迴圈幫助我們,這也顯得過於繁瑣了些。
框架(framework)就是爲我們解決類似問題的一個解。
所謂的框架,就是將一些複雜但是沒有什麼親自書寫必要的步驟封裝起來,開發人員只需要聚焦於具體功能的實現,其餘的交給框架來做即可。框架的出現大大提高了開發效率,避免了開發人員將大量時間耗費在沒有意義的冗餘程式碼中。
比如上面的這個例子,如果使用框架來做,什麼獲取父節點,什麼創建子節點之類的步驟統統都可以省略掉。如果使用Vue框架,僅需如下程式碼即可:
1 | <div id="father"> |
1 | let list = reactive(["小王", "小李", "小張", "小劉"]) |
至於這段程式碼是什麼意思,讀者暫時不需要去了解它,在之後的學習中,筆者會詳細爲您講述。
從上面這個例子中,我們不難看出,使用框架前後的代碼開發難度簡直是改天換地的。這也是我們使用框架最重要的意義所在。
目前在前端比較流行的框架有Vue、React、BootStrap等。後端比較流行的框架有Springboot(Java)、Gin(Go)、Flask(Python)等。本系列課程使用的框架是Vue
(音標/vju:/)。使用的框架版本是Vue 3.0。
Vue 3框架簡介
在遙遠的東南亞,有一個神奇的國家叫馬來西亞,這個神奇的國家有兩塊土地,分別是半島部分和婆羅洲島部分——但這不重要。重要的是在這兩部分中間,夾着一個面積極小的國家,這個國家就是大名鼎鼎的新加坡。在這個小國家中,生活着一個偉大的人類,這個人類幾乎以一己之力賞了全球近一半的前端程序員的飯。這個偉大的人類,名字叫做Evan You,或者作爲中國人,我們更熟悉他的中文名——尤雨溪。
尤雨溪,Vue框架和Vite構建工具的作者,全球一半前端程序員心中祖師爺一般的存在。此人長期混跡於各大論壇,在中國社群媒體上極受歡迎。
他所發展的Vue框架一經問世即風靡全球。 其後推出的Vue 3版本雖然基本上不相容之前的Vue 2.0,但得益於Vue 3的強大特性和與Vite工具結合之後令人難以置信的構建速度,Vue 3正在快速搶佔前端程式設計師的心臟。
Vue 3框架非常簡單、高效、直觀且快速。Vue 3官網對它的自我介紹是“The Progressive
JavaScript Framework”,漸進式JavaScript框架。
上圖這個花裏胡哨像夜店一樣的主頁就是Vue 3項目的主頁。由於尤雨溪大佬是新加坡華人,故Vue 3的文檔也有很舒適的中文版本。在接下來的學習中,我們將主要使用Vue 3的官方文檔。
Vue 3專案建立
Vue官方推薦使用自家的Vite構建工具來搭建Vue 3專案,筆者亦推薦這種方式。因爲這種方式非常便捷,且搭建出來的項目默認使用Vite構建工具,該工具以其高速準確的構建水平而享譽世界。搭建過程如下:
- 驗證npm安裝:
1 | npm -v |
如果輸出了npm的版本號,證明npm安裝成功。這一步相信讀者已經完成了。
- 初始化vue 3項目:
1 | npm create vite@latest |
輸入專案名稱,然後選擇vue
這個專案模板。我們暫時不使用TypeScript,而是繼續使用JavaScript進行開發。
- 進入專案內部,執行
npm install
:
1 | 進入某個目錄 |
這樣,一個vue 3專案就已經被new了出來。
專案目錄解析
建立好專案之後,我們會得到以下專案目錄:
下面我們來具體來看一下目錄結構。
flake.lock和flake.nix
這兩個檔案是筆者使用的作業系統Nix OS特有的,用於配置該專案在Nix OS上的開發環境,讀者不會有這兩個文件,忽略即可。
index.html
這個檔案我們已經非常熟悉了,這是最後放到瀏覽器裏面的HTML檔案。在Vue中,我們是透過Mount
這個操作,將Vue框架的程式碼的編譯結果交給HTML去執行。因此,我們需要在這裏明白一件事情:任何框架,都只是簡化了開發過程,而不是改變三件套的底層邏輯。 也就是說,瀏覽器根本不認識Vue框架,它只認識前端三件套。Vue框架的程式碼必須編譯成前端三件套,才能夠被瀏覽器識別到。所以在這個專案結構中,纔會有index.html檔案的出現。
package.json和package-lock.json
這兩個檔案讀者不應該陌生。它們是node.js的依賴管理檔案。當我們使用npm install的時候,依賴會自動寫入這兩個檔案,並鎖定版本,確保專案的可復現性。大家可以將其理解成一個依賴索引,之後在不同的電腦上重建專案的時候,只需要按照索引去npm倉庫裏面找依賴就可以了。
public目錄
這個目錄用來存放一些static的資源,例如圖片、影片等。
README.md
專案自述文件,可以暫時忽略。
vite.config.js
Vite構建工具的配置檔案,構建過程中的一些option可以在其中定義。
src目錄
項目的主要目錄! 我們大部分時間都將在這個目錄中書寫我們的程式碼。
src/App.vue
項目的根component,在學習Vue的前期,我們主要在這個檔案中深耕,書寫我們的程式碼。
src/assets
也用於存放static檔案,在前期不推薦讀者使用這個目錄,因其在構建過程中會出現路徑問題,故需要特別配置。在讀者對Vue和JS足夠熟悉之前,建議大家直接使用public目錄。該目錄可以直接刪除。
src/components
component目錄。在Vue中,一個極其重要的思想是:一切皆component。關於component的概念,將在後面詳細介紹。
src/main.js
專案的主要配置檔案。在這裏我們可以定義全局component,管理npm軟體包的全局使用等等。
src/style.css
專案的全局css,可以用於所有的component。
專案啓動
我們可以透過:
1 | npm run dev |
來啓動一個開發伺服器。該伺服器默認運行在http://localhost:5173/ 位址。修改將自動熱更新,不需要手動更新頁面,也不需要手動啓停伺服器。
Vue 3基礎部分
模板語法
Vue 3第一個強大的點在與其擁有一套高效且簡介的模板語法。我們之前的那個例子就是應用了這套模板語法。
通俗來講,所謂模板語法,就是能夠將JavaScript中的資料快速動態渲染到HTML中。
Vue 3提供的模板語法包括下面幾類:
- 文本插值:
1 | <span> {{ msg }} </span> |
msg
爲需要插入到這個地方的JS變數值。同時,每次該值更新,該處內容也會同步自動更新。
- 屬性綁定:
文本插值是將JS變數直接插入到對應的HTML標籤之間。那麼標籤的屬性有沒有可能使用JS變數動態去調整呢?當然也是可以的。語法如下:
1 | <span :id="id_js"></span> |
我們可以看到,只要在屬性名稱之前加一個:
,就可以在後面使用JS變數作爲屬性的值。同樣的,變數值改變,屬性值也會同步改變。
這個模板語法被大量使用,其中有一種是極爲常用的,那就是Boolean值的綁定。例如,我們想要一個按鈕在variable(Boolean)變數值爲真的時候啓用,其餘情況禁用。我們就可以這樣來做:
1 | <button :disabled="!variable"></button> |
- 使用JavaScript表達式
至此,我們僅在模板中綁定了一些簡單的屬性名稱。 但是 Vue 實際上在所有的資料綁定中都支援完整的 JavaScript 表達式:
1 | {{ number + 1 }} |
每個綁定只支援單一表達式,也就是一段能夠被求值的 JavaScript 程式碼。 一個簡單的判斷方法是是否可以合法地寫在return
關鍵字後面。
1 | <!-- 這是一個語句,而非表達式 --> |
- 呼叫函式
1 | <time :title="toTitleDate(date)" :datetime="date"> |
其中title的值就是toTitleDate()
這個函式的返回結果。
ref()和reactive()
渲染到HTML模板上的JS變數,必須使用ref()
或reactive()
包裹。我們稱之爲響應式變數 。只有使用ref()
或reactive()
包裹的變數,才能夠在其發生改變時,自動觸發HTML模板的同步改變。
一般來講,當所渲染的資料類型爲比較簡單的類型,譬如字串、數字、Boolean等的時候,我們使用ref()
包裹;當其比較複雜,譬如數組、物件的時候,我們使用reactive()
包裹。但是在初級階段,筆者推薦所有需要渲染的變數均使用ref()
來渲染 。
接下來我們來看一個例子:
1 | import { ref } from 'vue'; |
1 | <!-- 在HTML模板部分使用模板語法,不能使用.value --> |
計算屬性
模板中的表達式雖然方便,但也只能用來做簡單的操作。 如果在模板中寫太多邏輯,會讓模板變得臃腫,難以維護。 比如說,我們有這樣一個包含巢狀數組的物件:
1 | const author = reactive({ |
我們想根據 author 是否已有一些書籍來展示不同的訊息:
1 | <p>Has published books:</p> |
如果在模板中需要不只一次這樣的計算,我們可不想將這樣的程式碼在模板裡重複好多遍。
因此我們建議使用計算屬性來描述依賴響應式狀態的複雜邏輯。
重構之後的程式碼如下:
1 | <script setup> |
綁定class和style
前面我們講到了模板語法中存在着對屬性的綁定,而class和style嚴格來講,當然也是HTML標籤的屬性。但是這兩個屬性同一般的屬性來講有所不同。
class的動態綁定
通常用於動態綁定某個類別。即在某個條件滿足的情況下綁定該類別,而不滿足的情況下則不綁定。語法如下:
1 | <div :class="{ class_name : isActive }"></div> |
其中,class_name
是需要綁定的類別,而isActive
則是一個Boolean類型的響應式JavaScript變數。在isActive爲true時,渲染如下:
1 | <div class="class_name"></div> |
同理,在isActive爲false時,渲染如下:
1 | <div></div> |
style的動態綁定
style屬性的動態綁定則通常用於希望某個css屬性的值是動態的JavaScript變數。
例如,我們希望將如下div的style中color同JS變數color_div綁定起來,我們可以這樣做:
1 | <div :style="{ 'color' : color_div }"></div> |
這樣,當color_div的值發生改變,該div的style中color值也會相應改變。
條件渲染
請讀者的回想一下,以下場景是否在之前的開發過程中經常遇到:希望某一個元素在需要的時候顯示,但在不需要的時候消失?
答案是肯定的。例如,我們的結業功課中,有一項要求是:當點擊某個按鈕之後,頁面中的某個元素消失掉,重新點擊那個按鈕,元素又回來。
在之前的開發過程中,讀者想到了五花八門的方法來解決這個問題,有使用JS動態添加和刪除元素的(這也是我們推薦的標準方法),有使用JS處理style,讓元素移出屏幕之外的(很不錯的想法,在實際開發中也經常這樣使用),甚至還有寫另一個沒有該元素的頁面和當前頁面互相切換的(這個方法有點子差,但的確是劍走偏鋒)。在Vue框架中,我們使用一種更爲簡便的方法來實現這一目標,那就是條件渲染。
條件渲染的標誌是v-if
和v-else
。例如,我們需要在isActive變數爲true時顯示div,而在其爲false時不顯示它,我們只需要這樣寫:
1 | <div v-if="isActive"></div> |
如果我們想要讓這個div不顯示的同時顯示另一個元素,我們當然可以這樣寫:
1 | <div v-if="isActive"></div> |
這樣,當第一個div不顯示的時候,第二個div將會顯示;當第一個div顯示的時候,第二個div將不會顯示。
而如果這兩個div緊緊靠在一起,那我們就可以這樣簡化之:
1 | <div v-if="isActive"></div> |
使用v-else的要求是:使用v-else的元素必須緊跟在使用v-if的標籤之後。因爲Vue透過這種方式判斷這個v-else屬於哪個v-if。這很類似JS中的if-else語句,else關鍵字也是跟在if後面的。
列表渲染
列表渲染適用於什麼樣的場景呢?適用於我們這節課最開始的那個例子:現在有一個list,需要把這個list中的每一項內容都渲染到頁面上。
爲了方便讀者觀察,我再次把之前的程式碼貼到這裏來:
1 | // 假設下面的變數list就是我們得到的list |
以上是使用原生三件套實現該任務所執行的程式碼。
Vue中,實現這個任務再簡單不過:使用v-for
。例如上面的例子:
1 | <div v-for="item in list">{{ item }}</div> |
我們來解釋一下:
v-for
關鍵字表示列表渲染,即將list中的每一項渲染到HTML中。
item in list
表達式:item是臨時的一個變數,名字可以隨便起,就像定義一個變數一樣。它僅在此列表渲染中有效,在被渲染元素和該元素的所有子元素中適用,代表列表中的每一個列表項。in關鍵字很直觀,不多解釋。list即爲需要渲染的list的變數名稱。
{{ item }}
是模板語法,表示將item這個臨時變數的值渲染到這個位置。
上述列表渲染的結果是:
1 | <div>小王</div> |
事件處理
對應原生JS中的事件處理。在原生JS中,我們是透過addEventListener()
函式來監聽某個元素觸發的事件,例如click、mouseenter、mouseleave等。在Vue中,我們可以直接在元素上添加監聽,並將該監聽綁定到某個函式上:
1 | <div @click="func"></div> |
1 | const func = () => { |
按鍵修飾符
滑鼠的click事件可以對應着三種情況:點擊左鍵,點擊右鍵,點擊中間鍵。當然,讀者要是非說Apple的滑鼠只有一個按鍵,那我也不能多說什麼(笑)。
那麼如何表示這三種情況呢?這就需要使用到按鍵修飾符的概念。例如:
1 | <div @click.left="clickLeft"></div> |
還有許多按鍵修飾符,讀者可以自行參考Vue官方文檔。
表單輸入綁定
當我們輸入一段文字、點選一個按鈕,或者選擇一個抽屜的時候,我們會將選擇的結果放到JS變數中去。我們希望這個過程是自動的。例如,我們在輸入文字的時候,總是希望每輸入一個字元,對應的JS變數都會自動更新爲這個值。在原生三件套中,我們只能夠這樣寫:
1 | let val = "" |
1 | <input id="input_box"> |
如果我們需要雙向綁定呢?即當val的值發生改變的時候,input輸入框中的內容也可以放生改變。坦白講,筆者也不會寫。但是筆者找到了一個看起來還算OK的解決方案,讀者可以感受一下:
這顯然是極爲恐怖的。而在Vue下,框架用一個屬性——v-model
即幫你實現了表單元素與JS變數的雙向綁定:
1 | <input v-model="val"> |
這樣,當input有輸入的時候,val將會同步更新爲輸入的內容;當val發生改變的時候,input輸入框中的內容也會同步更新。
關於其他表單元素的雙向綁定,請讀者自行查閱Vue官方文檔。
偵聽器
我們有的時候希望在某個變數的值發生變化的時候,自動執行某個函式。那麼我們即可使用Vue提供的偵聽器——watch()
。下面的程式碼表示偵聽變數variable,當其值發生改變的時候,自動將新值列印出來。
1 | watch(variable, (newValue) => { |
watch()函式包括兩個引數:第一個是要偵聽的對象,第二個是一個回呼函式,代表偵聽對象發生改變的時候需要執行的動作。
生命週期
這個概念十分重要!!!
我們先來了解一下頁面從生到死的全過程:
- 創建(create):指某個頁面剛剛被創建出來,元素還沒有開始渲染,JS剛剛開始執行。
- 掛載(mount):指頁面中元素渲染的過程。
- 更新(update):頁面中元素渲染完成後某些元素髮生更新的過程。
- 卸載(unmount):指頁面中元素解除渲染的過程。
- 消亡(destroy):指頁面完全消亡。
這一整個過程,包含了這個頁面從生到死的全過程,稱之爲這個頁面的生命週期。
我們可以將我們的函式添加到這個生命週期的任意位置,並且在該時刻執行。下圖表示了Vue中頁面的生命週期:
結語
Vue的基礎部分到這裏基本就講得蠻全面了。在這裏給讀者提幾點學習Vue的建議:
熟讀Vue官方文檔,由於官方文檔有順暢的中文版本,所以這是我們閱讀很大的優勢。Vue官方文檔永遠都是最新、最權威、最完整的Vue學習資料。當我們遇到問題的時候,去翻一翻官方文檔,說不定就找到了解決辦法。
和原生三件套的寫法做對比。Vue作爲前端框架,自然簡化了大量原生的開發工作。因此在學習一個Vue特性的時候,我們腦中可以舉一個例子,然後分別使用原生三件套和Vue來實現,這樣我們就可以很清楚地知道Vue到底可以應用到什麼地方,又簡化了什麼。
多造訪一些著名的論壇。遇到問題,一找官方文檔,二找Google,三找論壇,四找GPT,這也應該成爲讀者經過訓練之後的一個條件反射。