Vue3.x 從零開始(二)—— 重新認識 Vue 組件


Vue 3 更新了許多組件中的語法,包括生命周期、filter、setup、teleport 等

為了介紹這些特性,需要先了解一下 Vue 組件的基本玩法

這篇文章介紹的內容基本都是沿用 Vue 2 的語法,只在一些細節上有所調整

 

一、單文件組件

通過 Vue.createApp() 創建的應用,可以使用 component 方法創建自定義組件

const app = Vue.createApp({}); app.component('my-component', { data() { return { name: 'Wise.Wrong' } }, template: `<div>hello {{name}}</div>`, });

不過在實際項目中,都是使用“單文件組件”,也就是以 .vue 文件的形式開發

比如上面組件,改寫成單文件組件就是這樣的:

<template>
  <div>hello {{ name }}</div>
</template>

<script lang="ts">
/* 當前文件路徑: src/components/my-component.vue */ import { defineComponent } from 'vue';
export
default defineComponent({ name: 'MyComponent', data() { return { name: 'Wise.Wrong', }; }, }); </script>

這里的 data 必須通過函數的形式返回一個對象,而不能直接使用對象

// 2.x 可以接收對象,但 3.x 的 data 只能是 function 

 

假如現在還有另一個組件 <home> ,我們希望在 <home> 組件中使用 <my-component>

可以直接在 <home> 中引入 my-component.vue 文件,然后通過 components 屬性注冊組件

上面的代碼中,我在 components 中使用的是大駝峰命名組件,而在 <template> 中使用的是短線命名

這是因為 HTML 本身不區分大小寫,Vue 更建議我們在 DOM 中使用全小寫的短線命名的方式

 

二、Props

現在我們有了一個父組件 <home> 與子組件 <my-component>

如果我想在父組件中向子組件傳遞參數,可以通過 Props

首先在子組件定義 props

然后父組件傳入對應的 props 屬性值

最終結果

除了定義數組形式的 props 之外,還可以使用對象類型,這樣就能對 props 做更多限制

export default defineComponent({ // ...
 props: { likes: String, // 僅限定類型
 years: { type: [String, Number], required: true, // 必填
 }, info: { type: Object, default: () => ({ // 對象和數組類型的默認值只能用函數返回
        title: '這里是對象類型的 prop', }), }, type: { // 自定義校驗函數
      validator: (val: string) => ( ['success', 'warning', 'danger'].indexOf(val) !== -1 ), }, }, // ...
});

如果父組件傳參不符合子組件中 props 定義的規則,Vue 會在控制台拋錯

更多關於 Props 的使用可以查看官方文檔

 

三、無狀態組件

在子組件中,props 和 data 一樣都是直接掛載到 this 對象下的,可以通過 this.xxx 的方式取值

對於某些功能型組件,只需要 props 不需要 data。比如這樣的一個提示框組件:

<template>
  <div :class="['alert', type]">
    <div class="alert-content">{{content}}</div>
  </div>
</template>

<script lang="ts"> import { defineComponent } from 'vue'; export default defineComponent({ name: 'Alert', props: ['type', 'content'], }); </script>

這種只接收 props,沒有定義 data、methods、computed 等響應數據的組件,被稱為無狀態組件

在 Vue 2 中,無狀態組件的初始化比普通組件快得多,所以經常會作為性能優化的一個考量

為了創建一個無狀態組件,必須在 <template> 中聲明 functional

<template functional> Vue 2 </template>

但是在 Vue 3 中,無狀態組件不再需要聲明 functional

只需要像一個普通組件一樣定義,只是不要添加 data 等響應數據,就像上面的提示框組件那樣

官方文檔是這樣解釋的:

However, in Vue 3, the performance of stateful components has improved to the point that the difference is negligible.

但是,在Vue 3中,有狀態組件的性能已提高到比肩無狀態組件的程度。

emmmmmm... 相當的膨脹...

不過我喜歡~

 

四、Mixin

與無狀態組件相對應的是有狀態組件,也就是帶有 data 等響應數據的組件,我們工作中寫的組件大部分都是有狀態組件

而隨着業務的不斷擴大,整個應用變得非常臃腫,這時候組件共用和邏輯抽取就尤為重要,這時候可以使用 mixin

 

假如我們有三個組件,它們的 js 部分都包含以下內容:

<script> export default { // ...
 data() { return { // ...
 company: { name: 'Perfect World', address: 'Chongqing China', }, loading: false, } }, props: { // ...
 title: String }, methods: { // ...
 fetchCompanyInfo(data) { this.loading = true; return fetch('/api') .then(res => res.json()) .then(res => { this.company = { ...res.data }; }) .finally(_ => { this.loading = false; }) } }, }; </script>

三個組件都包含響應數據(data) loading 和 company,以及相應的查詢方法(methods) fetchInfo,還有一個來自父組件的參數(props) title

這些邏輯完全一樣,如果要在三個組件中各寫一份完全一樣的代碼,就會非常難受,不利於維護

有了 mixin 之后,我們就能把這些邏輯寫在一個對象里面並導出

/* mixin-test.js */ export default { data: () => ({ loading: false }), props: { title: String }, methods: { fetchCompanyInfo(data) { // ...
 } } }

然后在需要用到這部分邏輯的組件中引入,並注冊到 mixins

mixins 接收的是一個數組,也就是說可以同時注冊多個 mixin

<script> import MixinTest from "./mixin/mixin-test.js"; export default { // ...
 mixins: [ MixinTest ], }; </script>

Vue 在初始化組件的時候,會將引入的 mixin 對象和當前組件進行合並

在合並的時候如果遇到了同名選項,對於不同的類型 (data、props、methods) 會有不同的策略

1. 如果是 props、methods、components、directives 沖突,會以組件本身的鍵值對覆蓋 mixin

2. 對於生命周期這樣的鈎子函數出現沖突,會先觸發 mixin 中的鈎子函數,然后觸發組件中的鈎子函數

3. 如果 data 發生沖突,將執行淺層次的合並:

const Mixin = { data: ()=> ({ user: { name: 'Jack', id: 1 } }) } const Comp = { mixins: [Mixin], data: () => ({ user: { id: 2 } }) } // 最終的結果是:
{ user: { id: 2 } }

而在 Vue 2 中,data 會執行深層次的合並,上例的結果會變成:

{ user: { id: 2, name: 'Jack' } }

在 Vue 2 的時代,Mixin 是封裝的共用邏輯的常用手段,但這種方式一直都受到很多開發者的質疑

首先就是 mixin 的重名問題,雖然 Vue 有一套合並策略(這個合並策略可以自定義)來處理 mixin 的重名問題

但組件內部是無法知道 mixin 到底提供了哪些字段,如果后來的維護人員不熟悉組件中的 mixin,在維護代碼的時候很容易因為重名的問題導致 bug

而且 mixin 可以使用組件中的數據,如果維護組件的時候更改了 mixin 所依賴的數據,也會導致 bug

為了解決這些問題,Vue 3 推出了 Composition API ,用函數式編程的思想來封裝組件邏輯

欲知 Composition API 如何,請聽下回分解~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM