前端人100% 要掌握的Vue(萬字總結 持續更新)

語言: CN / TW / HK

theme: orange

前言

  不知不覺已經兩個月沒有堅持寫部落格了,這段時間發生了許多事情(所以偷懶懈怠了),回想起來前端路已經走了一年之久,回首往事,累過,焦慮過,也想要放棄過。在我的職業生涯中,我最開心的時候並不是因為找到了一份體面的工作,而是從一名職高生,成為一名合格的前端工程師。

1. Vue的介紹

  • Vue 是一個漸進式框架,可以部分採用vue開發,其他元件或頁面採用其他框架開發
  • Vue 宣告式程式設計(程式設計正規化)

2. Vue如何引入使用呢?

  1. 在頁面中通過CDN的方式來引入
    • CDN (內容分發網路),會把資源和圖片部署在離使用者最近的節點上,從而達到減少請求時間,可以進行效能優化
  2. 下載Vue的JavaScript檔案,並且自己手動引入
  3. 通過npm包管理工具安裝使用它
  4. Vue CLI建立專案,並且使用它
    • 元件化開發使用 CLI建立專案

3. API 風格

  • Vue 的元件可以按兩種不同的風格書寫:選項式 API 和組合式 API
    • 選項式 API (Vue2 Options API 並且不會廢棄)
    • 組合式 API (Vue3 Composition API)

4. Mustache 插值語法

<span>Message: {{ msg }}</span> <span>Counter: {{ counter * 2 }}</span> <span> {{ isShy * 'shy' : 'noShy' }}</span> <span> {{ formatCount(10000) }}</span>

  • 表示式都可以在 {{}} 語法中寫到
    • 表示式即:左側可以用變數來接受的,也就是有返回值的(不嚴謹)
      • 函式的呼叫
      • 三元運算
      • 計算
      • ... 表示式

5. 事件繫結

```

`` - @click="sayHi()"的方式進行事件繫結 - sayHi()這裡並不是直接呼叫,而是點選之後進行回撥,也能進行接收引數 - 如果多個引數,可通過$event, 指定event的位置,其餘引數按順序傳入 - 如果不需要引數傳遞, 只需要sayHi傳遞函式的引用即可,event會被自動傳入sayHi`函式體中,函式只要寫入形參即可

6. Vue的起手式

```js // 通過cdn引入 採用options api

`` 1.Vue.createApp()Vue是一個全域性物件,呼叫createApp方法 2. 其中這個方法傳入一個物件,可以寫入很多屬性配置 -data為一個函式(why fn?後續介紹),return物件裡中的資料會被資料劫持,從而實現響應式 -template中編寫元素採用雙大括號語法,獲取解析變數 -methods- ...還有很多屬性後續講解 4. 返回app(application的縮寫)物件,掛載到dom`元素上

7. MVC/MVVM模型

  • Model View Controller 三層架構,即資料模型和檢視,通過Controller把資料模型和檢視進行繫結,展示資料,響應資料
  • Model View ViewModel 資料模型和檢視 通過ViewModel(VM)進行關聯,從而達到響應式,Vue中的VM進行了兩點操作
    1. DOM的事件監聽
    2. 資料的繫結
      • Vue,雖然沒有完全遵循 MVVM 模型,但是 Vue 的設計也受到了它的啟發。 -1667646765455.jpg

8. 計數器案例

```

{{counter}}

```

9. data屬性

  • data屬性傳入是一個函式,並且該函式需要返回一個物件
    • Vue2可傳入一個物件,官方推薦傳入函式
    • Vue3只能傳入函式,傳入物件會直接報錯
  • 計數器案例中能實現響應式,對data該物件的修改或者訪問進行了資料劫持
    • Vue2中採用的Object.defineProperty (資料劫持)
    • Vue3中採用Proxy (資料劫持)

10. methods屬性

  • methods(方法複數)是一個物件,我們在這裡面定義很多方法
    • 這些方法會被繫結到模板中
    • methods中的this指向
      • 在方法中,我們可以通過this直接訪問到data中返回的物件的屬性
      • 在methods中為什麼不能定義箭頭函式?
        • Vue原始碼中,是遍歷methods,拿到一個一個方法,通過bind繫結的this,如果是箭頭函式則不繫結this,繫結的是上層作用域this
        • this不熟悉的同學,可以翻閱下我之前的文章

11. 不常用的指令

11.1 v-once

```

{{counter}}

``` - 僅渲染元素和元件一次,並跳過之後的更新,優化更新時的效能

11.2 v-text

```

{{msg}} ``` - 推薦使用插值語法,插值語法更加靈活

11.3 v-html

```

data() { return { html: "

hi ice

", }; } ```

  • v-html 的內容直接作為普通 HTML 插入
    • 富文字應用,伺服器發返回HTML, CSS字串

11.4 v-pre

```

{{mes}}

//頁面中顯示

{{mes}}

``` - 顯示原始雙大括號標籤及內容,不會讀取data中的變數

11.5 v-cloak

``` //style [v-cloak] { display: none; }

{{mes}}

`` - cloak (斗篷) - 和css一起使用,它可以在元件編譯完畢前隱藏原始模板,直到編譯完成前,

` 將不可見。

11.6 v-memo

```

...

`` - 瞭解React的同學,一看memo就知道是用於效能優化的 - 如果數組裡的每個值都與最後一次的渲染相同,那麼整個子樹的更新將被跳過。 -v-momo="[]"` 傳入空陣列時,就跟v-once效果相同

12. 常用指令

12.1 v-bind

12.1.1 屬性繫結

  • 用來繫結屬性,或者元件傳遞prop(元件後面解析) ``` `` -v-bind/:attr是去獲取解析變數 -src="src"則是固定的字串 - 動態屬性名中, 其中keysrc`都應該是變數

    12.1.2 class類繫結

    • 我們有很多場景需要動態繫結class,通過控制class來實現一些互動
      • Tap切換,哪個選中加入active類,新增一些css樣式

    ``` `` -:class 等同於 v-bind:classs1. 物件語法 當isRed`變數為真,使用red類 2. 陣列寫 是解析這兩個變數 新增class 3. 三元運算與React類似,但物件語法能實現相同的功能,Vue中一般不用

    12.1.3 style樣式繫結

    • 應用場景有的時候伺服器會返回樣式,需要動態新增上去 ```

    ``` - 其中陣列寫法,可以把多個物件,新增到同一個元素上 - 拼接寫法,在樣式中可以讀取單個變數

    12.1.4 繫結一個物件

    ```

    `` - 當有許多屬性需要動態繫結的時候,一個一個繫結就會顯得繁瑣,可以包裝成一個物件,一次性繫結,會更加簡潔明瞭 - React 語法則為{...info}`

    12.2 v-on繫結事件

    • 我們在前面說過,MVVM其中的VM最主要的兩點就是,1.資料繫結 2.事件監聽。我們已經解析瞭如何繫結元素的內容和屬性,另外一個就是互動
      • 使用者的互動事件
        1. 點選
        2. 滾動
        3. 拖拽
        4. 鍵盤事件
    • 我們知道在原生js中,可以通過以下兩種方法進行監聽
      • dom.event = fn
      • window.addEventListener(event, fn)

    事件監聽

    • 在Vue中,則可以用v-on:event="fn"來進行監聽 ```

    ``` - 我們演示的只是點選事件,當然還有其他的事件。當用於普通元素,只能監聽原生Dom事件,如果是元件的話可以監聽自定義事件(我們後面會介紹到)

    事件傳參 ``` export default { methods: { handleClick(e) { console.log(e, 111); }, handleClick1(name, event) { console.log(name, event); } }, };

    `` - 如果handleClick沒有額外實參傳入就不需要新增括號,Vue內部回撥的時候,會把event物件,傳遞給handleClick第一個形參中 - 如果handleClick1要額外傳遞引數,並且同時傳入event`,實參傳入時,$event可以指定接受event物件

    事件的修飾符 - 在原生事件中,我們會有阻止預設行為、阻止事件冒泡,等 ```

    ```

    • .stop ——呼叫 event.stopPropagation()
    • .prevent ——呼叫 event.preventDefault()
    • ...

    12.3 條件渲染

    • 在某些情況下,我們需要根據當前的條件決定某些元素或元件是否渲染,或者根據條件渲染不同的元素

    12.3.1 v-if v-else-if v-else

    ```

    優秀

    良好

    及格

    不及格

    `` - v-if是惰性的 - 條件為true時,才會被渲染出來 - 為false`則,完全不會渲染,或者會被解除安裝掉

    條件渲染多個元素 - 上面的案例,我們只能渲染單個元素,如果需要渲染多個元素如何操作呢? 1. 可以在最外層包裹一個div(但是會出現沒必要的元素) 2. 最外層包裹一個 <tempplate>元素

    <template v-if="isShow"> <h2>111</h2> <h2>222</h2> </template> <template v-else> <h2>333</h2> <h2>444</h2> </template> #### 12.3.2 v-show ```

    元素

    ``` - v-show和v-if的用法看起來是一致的,也是根據一個條件決定是否顯示元素或者元件

    v-if與v-show的區別 - 用法 - v-show 不能和v-else v-else-if一起使用 - v-show 不能和template一起使用(會不顯示) - 本質 - v-if 如果為真顯示,如果為假,元素不會渲染在dom中 - v-show 則是控制css display顯示和隱藏

    這兩者如何選擇 - 如果元素會被頻繁的切換, 選擇v-show會提高一點效能 - 如果不頻繁切換,則使用v-if

    12.4 v-for

    12.4.1 v-for的基本介紹

    • 在實際開發中,我們資料大多數來自伺服器,或者自己配置一些迴圈資料
    • v-for 就類似於原生js中的迴圈 ``` `` - 基本格式 -item in data其中item我們可以命名 - v-for 不僅能遍歷陣列,也能遍歷物件,還能遍歷數字,而且有對應的形參 -(item, index) in arr/num- 當是一個數組時,第一個值是item專案,第二個則是對應的索引,可以接受一個或兩個,有的時候索引就很有用(比如點選哪個專案,知道哪個索引) - 陣列則同理 -(value, key, index) in obj` - 可以接受一個/兩個/三個,會傳入對應的實參
      - 注意:形參不可更換位置,因為框架如何實參傳入,你就要對應的形參接受引數 - 注意: v-for指令寫在哪個元素上面,哪個元素就會有多個, template實際不會顯示在dom中

      12.4.2 template元素

      • 前面我們已經使用了大量的template元素,跟React中的Fragment,用法如下
        • 它可以把多個元素包裹在一起,當然你使用div標籤包裹也沒有問題,但是會出現一個沒必要的元素,也能上一些指令或者屬性
          • v-if
          • v-for
          • ... ``` ```

            12.4.3 陣列的更新

            • 首先我們要知道Vue跟React中的響應式理念是完全不同的
              • 在Vue中會劫持響應式物件,需要改變被劫持的響應式陣列(改變原陣列),或者重新賦值一個新陣列都是會進行響應式的
              • React中改變狀態,重新執行render函式,且不推薦改變原陣列,要對陣列進行淺拷貝,改變拷貝出來的陣列,重新setState
            • Vue中改變原陣列的方法如下,並且是響應式的 push() pop() shift() unshift() splice() sort() reverse()

            12.4.4 key屬性

            ```

            ``` - 當我們v-for進行渲染元素,我們通常會給元素或者元件繫結一個key屬性 - key屬性的作用 - key屬性主要用在Vue的虛擬DOM演算法,在新舊nodes對比時辨識VNodes; - 什麼vnodes(虛擬節點)? template裡面的元素,本質都會編譯成一個一個vnodes,vnodes本質就是一個物件,多個vnodes形成的樹結構,就可以稱之為vdom(虛擬dom樹) - 渲染流程 template元素 -> vnodes -> vdom -> 真實dom渲染到頁面上 - 更新流程 (新老vnods比較找出差異) -> vdom -> 真實dom渲染到頁面上 - 如果不使用key,Vue會使用一種最大限度減少動態元素並且儘可能的嘗試就地修改/複用相同型別元素的演算法 - 而使用key時,它會基於key的變化重新排列元素順序,並且會移除/銷燬key不存在的元素;
            - diff演算法這裡就不在深入探究,後續會出一些進階文章,我們一起好好聊聊

            總結:key屬性優先繫結伺服器返回的唯一值,如果沒有唯一值使用index當作key也無傷大雅,(如果涉及到向前或中間運算元組,則不能使用index作為key)

            12.4 v-model

            • 表單提交是開發中非常常見的功能,也是和使用者互動的重要手段
              • 比如使用者註冊/登入,更新/搜尋/新增,提交一些資料的時候
            • 在程式碼邏輯中獲取到使用者提交的資料,我們通常會使用v-model指令來完成
              • v-model指令可以在表單 input、textarea以及select元素上建立雙向資料繫結

            12.4.1 登入案例

            ```

            ``` - 當我們點選按鈕的時候,就可以打印出對應的使用者名稱和密碼了,因為資料已經進行了雙向繫結。

            12.4.2 v-model 淺層原理

            ```

            `` - 從上面的案例我們可以看到v-model,只不過是以下方式的語法糖罷了 1.:value="value2"- v-bind繫結value屬性的值 3.@input="(e) => (value2 = e.target.value)"` - v-on繫結input事件監聽到函式中,函式會獲取最新的值賦值到繫結的屬性中

            12.4.3 v-model 修飾符

            • .lazy 監聽 change 事件而不是 input
            • .number 將輸入的合法符串轉為數字
            • .trim 移除輸入內容兩端空格

            13. Options API (選項式API)

            data/methods 我們前面已經介紹過了

            13.1 computed

            • 前面已經介紹了data函式,返回值為一個物件,物件中定義的屬性會被響應式系統劫持,從而實現響應式,在模板中可以利用插值語法直接繫結到元素上,但是不推薦寫較為複雜的表示式在模板中,這樣看起來程式碼會非常的冗餘,而且不好複用
              • 多個data資料進行運算
              • 三元運算子來決定結果
              • 資料進行某種轉化
            • 任何包含響應式資料的複雜邏輯,你都應該使用計算屬性

            ```

            ``` - 用了三種不同的方式進行了實現 1. 模板語法 - 缺點如下 1. 如果邏輯過多,不利於維護 2. 如果有一樣的邏輯,存在重複程式碼,不利於封裝 3. 沒有快取,運算多次,也需要執行多次 2. method方法實現 - 缺點如下 1. 變為方法的呼叫,而我們只是想顯示一個結果 2. 沒有快取,呼叫多次執行多次 3. computed實現 - computed不需要小括號呼叫,看起來更加直觀 - computed是有快取的

            13.1.1 methods VS computed
            • 共同點
              • 都可以對複雜邏輯進行封裝,有利於程式碼的複用性
            • 不同點:methods中的方法是沒有快取的,而computed中的是有快取的,那什麼是快取呢?

            ``` methods: { fullNameFn() { console.log("method 被呼叫了"); return this.firstName + " " + this.lastName; }, }, computed: { fullName() { console.log("computed 被呼叫了"); return this.firstName + " " + this.lastName; }, }

            fullNameC: {{ fullName }}

            fullNameC: {{ fullName }}

            fullNameC: {{ fullName }}

            fullNameFn: {{ fullNameFn() }}

            fullNameFn: {{ fullNameFn() }}

            fullNameFn: {{ fllNameFn() }}

            // console

            // computed 被呼叫了 // method 被呼叫了 // method 被呼叫了 // method 被呼叫了 ``` - 從列印結果看,我們能發現,當計算屬性呼叫了多次,實際的計算屬性只會呼叫一次,而method呼叫一次就會執行一次,因為計算屬性是有快取的 1. 收集依賴,進行快取,在資料不發生變化時,計算屬性是不需要重新計算的 2. 但是如果依賴的資料發生變化,在使用時,計算屬性依然會重新進行計算

            13.1.2 計算屬性的getter/setter

            ```js computed: { // 大多數情況下,getter方法即可,所以我們會將計算屬性直接寫成一個函式 fullName() { return this.firstName + " " + this.lastName; }, // 但是有些情況下,我們需要設定計算屬性的值,那我們就需要實現它的setter方法 fullName2: { get() { return this.firstName + " " + this.lastName; }, set(newVal, oldVal) { const [firstName, lastName] = newVal.split(" "); this.firstName = firstName; this.lastName = lastName; }, } }

            fullNameC: {{ fullName }}

            fullNameC: {{ fullName2 }}

            ```

            13.2 watch 偵聽器

            • 首先什麼是偵聽器呢?
              • 當我們定義響應式資料,資料通過插值語法插入到模板中,當資料發生改變的時候,template會自動更新顯示最新的資料
              • 如果需要偵聽哪個資料發生了變化,那這個時候就需要用watch來完成了(偵聽響應式資料發生變化,同時能拿到新值和舊值),在React中可以用hook useEffect來完成
            13.2.1 搜尋案例練習
            • 當我在輸入框輸入文字的時候,當我們輸入框的值發生了改變你就去請求最新最新的資料

            ```

            ```

            • 其中watch也是一個物件,裡面能寫入要偵聽的資料來源,我們寫入的資料來源就是data中的searchValue,當這個資料發生改變,Vue內部就會回撥這個函式,並且傳入兩個引數,新值/上一個值
            13.2.1 偵聽器的配置選項

            ``` export default { data() { return { a: { b: 1 }, c: 2, d: 3 } }, watch: { // 1. 該回調將會在被偵聽的物件的屬性改變時調動,無論其被巢狀多深 a: { handler(val, oldVal) { console.log('c changed') }, deep: true }, // 2. 偵聽單個巢狀屬性: 'a.b': function (val, oldVal) { // do something }, // 3. 該回調將會在偵聽開始之後立即呼叫 c: { handler(val, oldVal) { console.log('e changed') }, immediate: true }, // 4. 你可以傳入回撥陣列,它們將會被逐一呼叫 d: [ 'handle1', function handle2(val, oldVal) { console.log('handle2 triggered') }, { handler: function handle3(val, oldVal) { console.log('handle3 triggered') } / ... / } ] }, methods: { handle1() { console.log('handle 1 triggered') } }, created() { this.a.b = 3 // => new: 3, old: 1 } }

            `` - **create** 是生命週期函式,當元件例項被建立之後,修改響應式資料 - **immediate** 在偵聽器建立時立即觸發回撥。第一次呼叫時,舊值將為undefined- **deep`**:如果源是物件或陣列,則強制深度遍歷源,以便在深度變更時觸發回撥。

            14. 元件化開發

            14.1 元件化開發思想

            • 如果我們將一個頁面中所有的處理邏輯全部放在一起,處理起來就會變得非常複雜,而且不 利於後續的管理以及擴充套件
            • 但如果,我們將一個頁面拆分成一個個小的功能塊,每個功能塊完成屬於自己這部分獨立的 功能,那麼之後整個頁面的管理和維護就變得非常容易了

            cff9a69d5473905556fad8c7f7e1f6d.jpg

            多個元件形成的樹結構,稱之為元件樹

            14.2 Vue的開發模式和腳手架

            14.2.1 單檔案元件(.vue)

            ```js

            ``` - script用來編寫vue的邏輯程式碼 - template用來編寫結構,能讀取data中定義的資料 - style 用來編寫元件的樣式

            如何支援.vue檔案呢?
            - 使用Vue CLI來建立專案,專案會預設幫助我們配置好所有的配置選項,可以在其中直接使用.vue檔案 - 自己使用webpack或rollup或vite這類打包工具,對其進行打包處

            .vue檔案又是如何編譯的呢? - 拿webpack環境來說,它是不認識.vue檔案的,那如何才能認識vue檔案呢?這其實是vue-loader在起作用

            14.2.2 腳手架

            ```js //1. 官方推薦 基於vite npm init [email protected]

            //2. Vue/Cli 基於webpack

            //2.1 安裝Cli npm install -g @vue/cli // OR yarn global add @vue/cl

            //2.2 建立專案 vue create hello-world ```

            14.3 元件的巢狀

            ``` ```

            • 前面我們說到:元件化的核心思想應該是對元件進行拆分,拆分成一個個小的元件,從上列示例我們可以看見,如果把所有的程式碼都放在同一個檔案中,隨著專案的不斷迭代,會越來越臃腫難以迭代,所以元件化思想極為重要,無論是前端、還是跨平臺開發Flutter都是採用的這種方式。

            可以採用以下方式進行才拆分元件

            1668339205065.jpg

            ``` //App.vue

            //Header.vue

            //Main.vue

            //Footer.vue ``` - 一個vue檔案就是一個元件,單一職責,一個元件就展示對應的內容,可以更好的複用 - 當然它們也有屬於自己的 結構/樣式/資料 - 這種元件的巢狀,外層稱之為父元件,父元件包含的元件稱之為子元件

            14.4 元件的通訊

            • 在開發過程中,我們會經常遇到需要元件之間相互進行通訊
              • 採用元件化開發思想,元件會進行復用
                • 有些元件的資料不是一成不變的,需要外部來決定 (父傳子)
                • 子元件內部發生了某個事件,需要告訴父元件/傳遞資料 (子傳父)

            14.4.1 父子元件通訊

            • 父傳子 props
            • 子傳父 $emit

            1668341929338.jpg

            14.4.1.1 父傳子案例
            • Title元件的複用,我傳入什麼,你就顯示什麼 ```js //App.vue