国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Vue3 組件之間的通信

這篇具有很好參考價值的文章主要介紹了Vue3 組件之間的通信。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報違法"按鈕提交疑問。

組件之間的通信

經(jīng)過前面幾章的閱讀,相信開發(fā)者已經(jīng)可以搭建一個基礎(chǔ)的 Vue 3 項目了!

但實(shí)際業(yè)務(wù)開發(fā)過程中,還會遇到一些組件之間的通信問題,父子組件通信、兄弟組件通信、爺孫組件通信,還有一些全局通信的場景。

TIP

這一章節(jié)的內(nèi)容,Vue 3 對比 Vue 2 的變化都比較大!

這一章就按使用場景來劃分對應(yīng)的章節(jié)吧,在什么場景下遇到問題,也方便快速找到對應(yīng)的處理辦法。
父子組件通信
爺孫組件通信
兄弟組件通信
全局組件通信

父子組件通信
父子組件通信是指,B 組件引入到 A 組件里渲染,此時 A 是 B 的父級;B 組件的一些數(shù)據(jù)需要從 A 組件拿,B 組件有時也要告知 A 組件一些數(shù)據(jù)變化情況。

他們之間的關(guān)系如下, Child.vue 是直接掛載在 Father.vue 下面:

# 父組件
Father.vue
│ # 子組件
└─Child.vue

常用的方法有:
Vue3 組件之間的通信
為了方便閱讀,下面的父組件統(tǒng)一叫 Father.vue ,子組件統(tǒng)一叫 Child.vue 。

WARNING

在 Vue 2 ,有的開發(fā)者可能喜歡用 $attrs / $listeners 來進(jìn)行通信,但該方案在 Vue 3 已經(jīng)移除了,詳見 移除 $listeners 。

props / emits
這是 Vue 跨組件通信最常用,也是基礎(chǔ)的一個方案,它的通信過程是:

1.父組件 Father.vue 通過 props 向子組件 Child.vue 傳值
2.子組件 Child.vue 則可以通過 emits 向父組件 Father.vue 發(fā)起事件通知

最常見的場景就是統(tǒng)一在父組件發(fā)起 AJAX 請求,拿到數(shù)據(jù)后,再根據(jù)子組件的渲染需要傳遞不同的 props 給不同的子組件使用。

下發(fā) props
注:這一小節(jié)的步驟是在 Father.vue 里操作。

下發(fā)的過程是在 Father.vue 里完成的,父組件在向子組件下發(fā) props 之前,需要導(dǎo)入子組件并啟用它作為自身的模板,然后在 setup 里處理好數(shù)據(jù)并 return 給 用。

在 Father.vue 的 script /> 里:

// Father.vue
import { defineComponent } from 'vue'
import Child from '@cp/Child.vue'

interface Member {
  id: number
  name: string
}

export default defineComponent({
  // 需要啟用子組件作為模板
  components: {
    Child,
  },

  // 定義一些數(shù)據(jù)并 `return` 給 `<template />` 用
  setup() {
    const userInfo: Member = {
      id: 1,
      name: 'Petter',
    }

    // 不要忘記 `return` ,否則 `<template />` 拿不到數(shù)據(jù)
    return {
      userInfo,
    }
  },
})

然后在 Father.vue 的 template /> 這邊拿到 return 出來的數(shù)據(jù),把要傳遞的數(shù)據(jù)通過屬性的方式綁定在組件標(biāo)簽上。

<!-- Father.vue -->
<template>
  <Child
    title="用戶信息"
    :index="1"
    :uid="userInfo.id"
    :user-name="userInfo.name"
  />
</template>

這樣就完成了 props 數(shù)據(jù)的下發(fā)。

在 template /> 綁定屬性這里,如果是普通的字符串,比如上面的 title,則直接給屬性名賦值就可以。

如果是變量名,或者其他類型如 number 、 boolean 等,比如上面的 index,則需要通過屬性動態(tài)綁定的方式來添加,使用 v-bind: 或者 : 符號進(jìn)行綁定。

另外官方文檔推薦對 camelCase 風(fēng)格(小駝峰)命名的 props ,在綁定時使用和 HTML attribute 一樣的 kebab-case 風(fēng)格(短橫線),例如使用 user-name 代替 userName 傳遞,詳見官網(wǎng)的 傳遞 prop 的細(xì)節(jié) 一節(jié)。

接收 props
注:這一小節(jié)的步驟是在 Child.vue 里操作。

接收的過程是在 Child.vue 里完成的,在 script /> 部分,子組件通過與 setup 同級的 props 來接收數(shù)據(jù)。

它可以是一個 string[] 數(shù)組,把要接受的變量名放到這個數(shù)組里,直接放進(jìn)來作為數(shù)組的 item :

// Child.vue
export default defineComponent({
  props: ['title', 'index', 'userName', 'uid'],
})

但這種情況下,使用者不知道這些屬性的使用限制,例如是什么類型的值、是否必傳等等。

帶有類型限制的 props
注:這一小節(jié)的步驟是在 Child.vue 里操作。

和 TypeScript 一樣,類型限制可以為程序帶來更好的健壯性, Vue 的 props 也支持增加類型限制。

相對于傳遞一個 string[] 類型的數(shù)組,更推薦的方式是把 props 定義為一個對象,以對象形式列出,每個 Property 的名稱和值分別是各自的名稱和類型,只有合法的類型才允許傳入。

TIP

注意,和 TS 的類型定義不同, props 這里的類型,首字母需要大寫,也就是 JavaScript 的基本類型。

支持的類型有:
Vue3 組件之間的通信
了解了基本的類型限制用法之后,接下來給 props 加上類型限制:

// Child.vue
export default defineComponent({
  props: {
    title: String,
    index: Number,
    userName: String,
    uid: Number,
  },
})

現(xiàn)在如果傳入不正確的類型,程序就會拋出警告信息,告知開發(fā)者必須正確傳值。

如果需要對某個 Prop 允許多類型,比如這個 uid 字段,可能是數(shù)值,也可能是字符串,那么可以在類型這里,使用一個數(shù)組,把允許的類型都加進(jìn)去。

// Child.vue
export default defineComponent({
  props: {
    // 單類型
    title: String,
    index: Number,
    userName: String,

    // 這里使用了多種類型
    uid: [Number, String],
  },
})

可選以及帶有默認(rèn)值的 props
注:這一小節(jié)的步驟是在 Child.vue 里操作。

所有 props 默認(rèn)都是可選的,如果不傳遞具體的值,則默認(rèn)值都是 undefined ,可能引起程序運(yùn)行崩潰, Vue 支持對可選的 props 設(shè)置默認(rèn)值,也是通過對象的形式配置 props 的選項。

其中支持配置的選項有:
Vue3 組件之間的通信
了解了配置選項后,接下來再對 props 進(jìn)行改造,將其中部分選項設(shè)置為可選,并提供默認(rèn)值:

// Child.vue
export default defineComponent({
  props: {
    // 可選,并提供默認(rèn)值
    title: {
      type: String,
      required: false,
      default: '默認(rèn)標(biāo)題',
    },

    // 默認(rèn)可選,單類型
    index: Number,

    // 添加一些自定義校驗
    userName: {
      type: String,

      // 在這里校驗用戶名必須至少 3 個字
      validator: (v) => v.length >= 3,
    },

    // 默認(rèn)可選,但允許多種類型
    uid: [Number, String],
  },
})

使用 props
注:這一小節(jié)的步驟是在 Child.vue 里操作。

在 template /> 部分, Vue 3 的使用方法和 Vue 2 是一樣的,比如要渲染父組件傳入的 props :

<!-- Child.vue -->
<template>
  <p>標(biāo)題:{{ title }}</p>
  <p>索引:{{ index }}</p>
  <p>用戶id:{{ uid }}</p>
  <p>用戶名:{{ userName }}</p>
</template>

但是 script /> 部分,變化非常大!

在 Vue 2 里,只需要通過 this.uid 、 this.userName 就可以使用父組件傳下來的 Prop ,但是 Vue 3 沒有了 this ,所以是通過 setup 的入?yún)⑦M(jìn)行操作。

// Child.vue
export default defineComponent({
  props: {
    title: String,
    index: Number,
    userName: String,
    uid: Number,
  },

  // 在這里需要添加一個入?yún)?/span>
  setup(props) {
    // 該入?yún)水?dāng)前組件定義的所有 props
    console.log(props)
  },
})

關(guān)于 Setup 函數(shù)的第一個入?yún)?props :

1.該入?yún)水?dāng)前組件定義的所有 props (如果父組件 Father.vue 傳進(jìn)來的數(shù)據(jù)在 Child.vue 里未定義,不僅不會拿到,并且在控制臺會有警告信息)。
2.該入?yún)⒖梢噪S意命名,比如可以寫成一個下劃線 _ ,通過 _.uid 也可以拿到數(shù)據(jù),但是語義化命名是一個良好的編程習(xí)慣。
3.該入?yún)⒕邆漤憫?yīng)性,父組件修改了傳遞下來的值,子組件也會同步得到更新,因此請不要直接解構(gòu),可以通過 toRef 或 toRefs API 轉(zhuǎn)換為響應(yīng)式變量

傳遞非 props 的屬性
上一小節(jié)最后有一句提示是:
如果父組件 Father.vue 傳進(jìn)來的數(shù)據(jù)在 Child.vue 里未定義,不僅不會拿到,并且在控制臺會有警告信息。

這種情況雖然無法從 props 里拿到對應(yīng)的數(shù)據(jù),但也不意味著不能傳遞任何未定義的屬性數(shù)據(jù),在父組件,除了可以給子組件綁定 props ,還可以根據(jù)實(shí)際需要去綁定一些特殊的屬性。

比如給子組件設(shè)置 class、id,或者 data-xxx 之類的一些自定義屬性,如果子組件 Child.vue 的 template /> 里只有一個根節(jié)點(diǎn),那么這些屬性默認(rèn)會自動繼承并渲染在 Node 節(jié)點(diǎn)上。

假設(shè)當(dāng)前在子組件 Child.vue 是如下這樣只有一個根節(jié)點(diǎn),并且未接收任何 props :

TIP

如果已安裝 Vue VSCode Snippets 這個 VSCode 插件,可以在空的 .vue 文件里輸入 v3 ,在出現(xiàn)的代碼片段菜單里選擇 vbase-3-ts 生成一個 Vue 組件的基礎(chǔ)代碼片段。
<!-- Child.vue -->
<template>
  <div class="child">子組件</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  setup() {
    return {}
  },
})
</script>

<style scoped>
.child {
  width: 100%;
}
</style>

在 Father.vue 里對 Child.vue 傳遞了多個屬性:

<!-- Father.vue -->
<template>
  <Child
    id="child-component"
    class="class-name-from-father"
    :keys="['foo', 'bar']"
    :obj="{ foo: 'bar' }"
    data-hash="b10a8db164e0754105b7a99be72e3fe5"
  />
</template>

回到瀏覽器,通過 Chrome 的審查元素可以看到子組件 Child.vue 在渲染后,按照 HTML 屬性的渲染規(guī)則生成了多個屬性:

<!-- Child.vue 在瀏覽器里渲染后的 HTML DOM 結(jié)構(gòu) -->
<div
  class="child class-name-from-father"
  id="child-component"
  keys="foo,bar"
  obj="[object Object]"
  data-hash="b10a8db164e0754105b7a99be72e3fe5"
  data-v-2dcc19c8=""
  data-v-7eb2bc79=""
>
  子組件
</div>

TIP

其中有兩個以 data-v- 開頭的屬性是 <style /> 標(biāo)簽開啟了 Style Scoped 功能自動生成的 Hash 值。

可以在 Child.vue 配置 inheritAttrs 為 false 來屏蔽這些非 props 屬性的渲染。

// Child.vue
export default defineComponent({
  inheritAttrs: false,
  setup() {
    // ...
  },
})

關(guān)閉了 之后,現(xiàn)在的 DOM 結(jié)構(gòu)如下,只保留了兩個由 Style Scoped 生成的 Hash 值:

<!-- Child.vue 在瀏覽器里渲染后的 HTML DOM 解構(gòu) -->
<div class="child" data-v-2dcc19c8="" data-v-7eb2bc79="">子組件</div>

這一類非 props 屬性通常稱之為 attrs 。

剛接觸 Vue 的開發(fā)者可能容易混淆這兩者,確實(shí)是非常接近,都是由父組件傳遞,由子組件接收,支持傳遞的數(shù)據(jù)類型也一樣,但為什么一部分是在 props 獲取,一部分在 attrs 獲取呢?筆者給出一個比較容易記憶的方式,不一定特別準(zhǔn)確,但相信可以幫助開發(fā)者加深兩者的區(qū)別理解。

根據(jù)它們的縮寫,其實(shí)是可以知道 Prop 是指 Property ,而 Attr 是指 Attribute ,雖然都是 “屬性” ,但 Property 更接近于事物本身的屬性,因此需要在組件里聲明,而 Attribute 更偏向于賦予的屬性,因此用于指代父組件傳遞的其他未被聲明為 Property 的屬性。

獲取非 props 的屬性
注:這一小節(jié)的步驟是在 Child.vue 里操作。

在上一小節(jié) 傳遞非 props 的屬性 已經(jīng)在父組件 Father.vue 里向子組件 Child.vue 傳遞了一些 attrs 自定義屬性,在子組件里想要拿到這些屬性,使用原生 JavaScript 操作是需要通過 Element.getAttribute() 方法,但 Vue 提供了更簡單的操作方式。

在 Child.vue 里,可以通過 setup 的第二個參數(shù) context 里的 attrs 來獲取到這些屬性,并且父組件傳遞了什么類型的值,獲取到的也是一樣的類型,這一點(diǎn)和使用 Element.getAttribute() 完全不同。

// Child.vue
export default defineComponent({
  setup(props, { attrs }) {
    // `attrs` 是個對象,每個 Attribute 都是它的 `key`
    console.log(attrs.id) // child-component
    console.log(attrs.class) // class-name-from-father

    // 傳遞數(shù)組會被保留類型,不會被轉(zhuǎn)換為 `key1,key2` 這樣的字符串
    // 這一點(diǎn)與 `Element.getAttribute()` 完全不同
    console.log(attrs.keys) // ['foo', 'bar']

    // 傳遞對象也可以正常獲取
    console.log(attrs.obj) // {foo: 'bar'}

    // 如果傳下來的 Attribute 帶有短橫線,需要通過這種方式獲取
    console.log(attrs['data-hash']) // b10a8db164e0754105b7a99be72e3fe5
  },
})

TIP

子組件不論是否設(shè)置 inheritAttrs 屬性,都可以通過 attrs 拿到父組件傳遞下來的數(shù)據(jù),但是如果要使用 Element.getAttribute() 則只有當(dāng) inheritAttrs 為 true 的時候才可以,因為此時在 DOM 上才會渲染這些屬性。

與 Vue 2 的 template /> 只能有一個根節(jié)點(diǎn)不同, Vue 3 允許多個根節(jié)點(diǎn),多個根節(jié)點(diǎn)的情況下,無法直接繼承這些 attrs 屬性(在 inheritAttrs: true 的情況也下無法默認(rèn)繼承),需要在子組件 Child.vue 里通過 v-bind 綁定到要繼承在節(jié)點(diǎn)上。

可以通過 Vue 實(shí)例屬性 $attrs 或者從 setup 函數(shù)里把 attrs return 出來使用

<!-- Child.vue -->
<template>
  <!-- 默認(rèn)不會繼承屬性 -->
  <div class="child">不會繼承</div>

  <!-- 綁定后可繼承, `$attrs` 是一個 Vue 提供的實(shí)例屬性 -->
  <div class="child" v-bind="$attrs">使用 $attrs 繼承</div>

  <!-- 綁定后可繼承, `attrs` 是從 `setup``return` 出來的變量 -->
  <div class="child" v-bind="attrs">使用 attrs 繼承</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'

export default defineComponent({
  setup(props, { attrs }) {

    return {
      attrs,
    }
  },
})
</script>

綁定 emits
注:這一小節(jié)的步驟是在 Father.vue 里操作。

如果父組件 Father.vue 需要獲取子組件 Child.vue 的數(shù)據(jù)更新情況,可以由子組件通過 emits 進(jìn)行通知,下面這個更新用戶年齡的例子可以學(xué)習(xí)如何給子組件綁定 emit 事件。

事件的邏輯是由父組件決定的,因此需要在父組件 Father.vue 的 script /> 里先聲明數(shù)據(jù)變量和一個更新函數(shù),并且這個更新函數(shù)通常會有一個入?yún)⒆鳛閿?shù)據(jù)的新值接收。

在本例子里,父組件聲明了一個 updateAge 方法,它接受一個入?yún)?newAge ,代表新的年齡數(shù)據(jù),這個入?yún)⒌闹祵⒂勺咏M件 Child.vue 在觸發(fā) emits 時傳入。

因為還需要在 template /> 部分綁定給子組件,所以請記得 return 出來。

// Father.vue
import { defineComponent, reactive } from 'vue'
import Child from '@cp/Child.vue'

interface Member {
  id: number
  name: string
  age: number
}

export default defineComponent({
  components: {
    Child,
  },
  setup() {
    const userInfo: Member = reactive({
      id: 1,
      name: 'Petter',
      age: 0,
    })

    /**
     * 聲明一個更新年齡的方法
     * @param newAge - 新的年齡,由子組件觸發(fā) emits 時傳遞
     */
    function updateAge(newAge: number) {
      userInfo.age = newAge
    }

    return {
      userInfo,
      updateAge,
    }
  },
})

再看 Father.vue 的 template /> 部分,和 Click 事件使用 @click 一樣,自定義的 emits 事件也是通過 v-on 或者是 @ 來綁定:

<!-- Father.vue -->
<template>
  <Child @update-age="updateAge" />
</template>

和 props 一樣,官方文檔也推薦將 camelCase 風(fēng)格(小駝峰)命名的函數(shù),在綁定時使用 kebab-case 風(fēng)格(短橫線),例如使用 update-age 代替 updateAge 傳遞。

接收并調(diào)用 emits
注:這一小節(jié)的步驟是在 Child.vue 里操作。

和 props 一樣,可以指定是一個數(shù)組,把要接收的 emit 事件名稱寫進(jìn)去:

// Child.vue
export default defineComponent({
  emits: ['update-age'],
})

和 props 不同,通常情況下 emits 這樣配置就足夠使用了。

接下來如果子組件需要更新數(shù)據(jù)并通知父組件,可以使用 setup 第二個參數(shù) context 里的 emit 方法觸發(fā):

// Child.vue
export default defineComponent({
  emits: ['update-age'],
  setup(props, { emit }) {
    // 通知父組件將年齡設(shè)置為 `2`
    emit('update-age', 2)
  },
})

emit 方法最少要傳遞一個參數(shù):事件名稱。

事件名稱是指父組件 Father.vue 綁定事件時 @update-age=“updateAge” 里的 update-age ,如果改成 @hello=“updateAge” ,那么事件名稱就需要使用 hello ,一般情況下事件名稱和更新函數(shù)的名稱會保持一致,方便維護(hù)。

對于需要更新數(shù)據(jù)的情況, emit 還支持傳遞更多的參數(shù),對應(yīng)更新函數(shù)里的入?yún)?,所以可以看到上面例子里?emit(‘update-age’, 2) 有第二個參數(shù),傳遞了一個 2 的數(shù)值,就是作為父組件 updateAge 的入?yún)?newAge 傳遞。

如果需要通信的數(shù)據(jù)很多,建議第二個入?yún)⑹褂靡粋€對象來管理數(shù)據(jù),例如父組件調(diào)整為:

// Father.vue
function updateInfo({ name, age }: Member) {
  // 當(dāng) `name` 變化時更新 `name` 的值
  if (name && name !== userInfo.name) {
    userInfo.name = name
  }

  // 當(dāng) `age` 變化并且新值在正確的范圍內(nèi)時,更新 `age` 的值
  if (age > 0 && age !== userInfo.age) {
    userInfo.age = age
  }
}

子組件在傳遞新數(shù)據(jù)時,就應(yīng)該使用對象的形式傳遞:

// Child.vue
emit('update-info', {
  name: 'Tom',
  age: 18,
})

這對于更新表單等數(shù)據(jù)量較多的場景非常好用。

接收 emits 時做一些校驗

注:這一小節(jié)的步驟是在 Child.vue 里操作。

和 props 一樣,子組件在接收 emits 時也可以對這些事件做一些驗證,這個時候就需要將 emits 配置為對象,然后把事件名稱作為 key , value 則對應(yīng)為一個用來校驗的方法。

還是用回上文那個更新年齡的方法,如果需要增加一個條件:當(dāng)達(dá)到成年人的年齡時才會更新父組件的數(shù)據(jù),那么就可以將 emits 調(diào)整為:

// Child.vue
export default defineComponent({
  emits: {
    // 需要校驗
    'update-age': (age: number) => {
      // 寫一些條件攔截,返回 `false` 表示驗證不通過
      if (age < 18) {
        console.log('未成年人不允許參與')
        return false
      }

      // 通過則返回 `true`
      return true
    },

    // 一些無需校驗的,設(shè)置為 `null` 即可
    'update-name': null,
  },
})

接下來如果提交 emit(‘update-age’, 2) ,因為不滿足驗證條件,瀏覽器控制臺將會出現(xiàn)一段 [Vue warn]: Invalid event arguments: event validation failed for event “update-age”. 這樣的警告信息。

v-model / emits
相對于 props / emits 這一對通信方案,使用 v-model 的方式更為簡單:

1.在 Father.vue ,通過 v-model 向 Child.vue 傳值

2.Child.vue 通過自身設(shè)定的 emits 向 Father.vue 通知數(shù)據(jù)更新

v-model 的用法和 props 非常相似,但是很多操作上更為簡化,但操作簡單帶來的 “副作用” ,就是功能上也沒有 props 那么多。

綁定 v-model
注:這一小節(jié)的步驟是在 Father.vue 里操作

和下發(fā) props 的方式類似,都是在子組件上綁定 Father.vue 定義好的數(shù)據(jù),這是綁定一個數(shù)據(jù)的例子:

<!-- Father.vue -->
<template>
  <Child v-model:username="userInfo.name" />
</template>

和 Vue 2 不同, Vue 3 可以直接綁定 v-model ,而無需在子組件指定 model 選項 ,并且 Vue 3 的 v-model 需要使用英文冒號 : 指定要綁定的屬性名,同時也支持綁定多個 v-model 。

如果要綁定多個數(shù)據(jù),寫多個 v-model 即可:

<!-- Father.vue -->
<template>
  <Child
    v-model:uid="userInfo.id"
    v-model:username="userInfo.name"
    v-model:age="userInfo.age"
  />
</template>

看到這里應(yīng)該能明白了,一個 v-model 其實(shí)就是一個 prop ,它支持的數(shù)據(jù)類型和 prop 是一樣的,所以子組件在接收數(shù)據(jù)的時候,完全按照 props 去定義就可以了。

點(diǎn)擊回顧:接收 props ,了解在 Child.vue 如何接收 props,以及相關(guān)的 props 類型限制等部分內(nèi)容。

配置 emits
注:這一小節(jié)的步驟是在 Child.vue 里操作。

雖然 v-model 的配置和 props 相似,但是為什么出這么兩個相似的東西?自然是為了簡化一些開發(fā)上的操作。

使用 props / emits ,如果要更新父組件的數(shù)據(jù),還需要在父組件聲明一個更新函數(shù)并綁定事件給子組件,才能夠更新。

而使用 v-model / emits ,無需在父組件聲明更新函數(shù),只需要在子組件 Child.vue 里通過 update: 前綴加上 v-model 的屬性名這樣的格式,即可直接定義一個更新事件。

// Child.vue
export default defineComponent({
  props: {
    uid: Number,
    username: String,
    age: Number,
  },
  // 注意這里的 `update:` 前綴
  emits: ['update:uid', 'update:username', 'update:age'],
})

這里的 update 后面的屬性名,支持駝峰寫法,這一部分和 Vue 2 的使用是相同的。

在配置 emits 時,也可以對數(shù)據(jù)更新做一些校驗,配置方式和講解 props / emits 時 接收 emits 時做一些校驗 這一小節(jié)的操作是一樣的。

在 Child.vue 配置好 emits 之后,就可以在 setup 里直接操作數(shù)據(jù)的更新了:

// Child.vue
export default defineComponent({
  setup(props, { emit }) {
    // 2s 后更新用戶名
    setTimeout(() => {
      emit('update:username', 'Tom')
    }, 2000)
  },
})

子組件通過調(diào)用 emit(‘update:xxx’) 即可讓父組件更新對應(yīng)的數(shù)據(jù)。

ref / emits
在學(xué)習(xí) 響應(yīng)式 API 之 ref 的時候,已講解過 ref 是可以用在 DOM 元素與子組件 上面,所以也可以使用 ref 配合 emits 完成父子組件的通信。

父組件操作子組件
注:這一小節(jié)的步驟是在 Father.vue 里操作。

父組件可以給子組件綁定 ref 屬性,然后通過 Ref 變量操作子組件的數(shù)據(jù)或者調(diào)用子組件里面的方法。

先在 template /> 處給子組件標(biāo)簽綁定 ref 屬性:

<!-- Father.vue -->
<template>
  <Child ref="child" />
</template>

然后在 script /> 部分定義好對應(yīng)的變量名稱 child (記得要 return 出來哦),即可通過該變量操作子組件上的變量或方法:

// Father.vue
import { defineComponent, onMounted, ref } from 'vue'
import Child from '@cp/Child.vue'

export default defineComponent({
  components: {
    Child,
  },
  setup() {
    // 給子組件定義一個 `ref` 變量
    const child = ref<typeof Child>()

    // 請保證視圖渲染完畢后再執(zhí)行操作
    onMounted(async () => {
      // 執(zhí)行子組件里面的 AJAX 請求函數(shù)
      await child.value!.queryList()

      // 顯示子組件里面的彈窗
      child.value!.isShowDialog = true
    })

    // 必須 `return` 出去才可以給到 `<template />` 使用
    return {
      child,
    }
  },
})

需要注意的是,在子組件 Child.vue 里,變量和方法也需要在 setup 里 return 出來才可以被父組件調(diào)用到。

子組件通知父組件
子組件如果想主動向父組件通訊,也需要使用 emits ,詳細(xì)的配置方法可見:綁定 emits

爺孫組件通信
顧名思義,爺孫組件是比 父子組件通信 要更深層次的引用關(guān)系(也有稱之為 “隔代組件” )。

C 組件被引入到 B 組件里, B 組件又被引入到 A 組件里渲染,此時 A 是 C 的爺爺級別(可能還有更多層級關(guān)系),它們之間的關(guān)系可以假設(shè)如下:

Grandfather.vue
└─Son.vue
  └─Grandson.vue

可以看到 Grandson.vue 并非直接掛載在 Grandfather.vue 下面,他們之間還隔著至少一個 Son.vue (在實(shí)際業(yè)務(wù)中可能存在更多層級),如果使用 props ,只能一級組件一級組件傳遞下去,就太繁瑣了。

因此需要更直接的通信方式來解決這種問題,這一 Part 就是講一講 C 和 A 之間的數(shù)據(jù)傳遞,常用的方法有:
Vue3 組件之間的通信
因為上下級的關(guān)系的一致性,爺孫組件通信的方案也適用于 父子組件通信 ,只需要把爺孫關(guān)系換成父子關(guān)系即可,為了方便閱讀,下面的爺組件統(tǒng)一叫 Grandfather.vue,子組件統(tǒng)一叫 Grandson.vue 。

provide / inject
這個通信方式也是有兩部分:

1.Grandfather.vue 通過 provide 向?qū)O組件 Grandson.vue 提供數(shù)據(jù)和方法
2.Grandson.vue 通過 inject 注入爺爺組件 Grandfather.vue 的數(shù)據(jù)和方法

無論組件層次結(jié)構(gòu)有多深,發(fā)起 provide 的組件都可以作為其所有下級組件的依賴提供者。

Vue 3 的這一部分內(nèi)容對比 Vue 2 來說變化很大,但使用起來其實(shí)也很簡單,開發(fā)者學(xué)到這里不用慌,它們之間也有相同的地方:

1.爺組件不需要知道哪些子組件使用它 provide 的數(shù)據(jù)
2.子組件不需要知道 inject 的數(shù)據(jù)來自哪里

另外要切記一點(diǎn)就是: provide 和 inject 綁定并不是可響應(yīng)的,這是刻意為之的,除非傳入了一個可偵聽的對象。

發(fā)起 provide
注:這一小節(jié)的步驟是在 Grandfather.vue 里操作。

先來回顧一下 Vue 2 的用法:

export default {
  // 在 `data` 選項里定義好數(shù)據(jù)
  data() {
    return {
      tags: ['中餐', '粵菜', '燒臘'],
    }
  },
  // 在 `provide` 選項里添加要提供的數(shù)據(jù)
  provide() {
    return {
      tags: this.tags,
    }
  },
}

舊版的 provide 用法和 data 類似,都是配置為一個返回對象的函數(shù),而 Vue 3 的新版 provide ,和 Vue 2 的用法區(qū)別比較大。

在 Vue 3 , provide 需要導(dǎo)入并在 setup 里啟用,并且現(xiàn)在是一個全新的方法,每次要 provide 一個數(shù)據(jù)的時候,就要單獨(dú)調(diào)用一次。

provide 的 TS 類型如下:

// `provide` API 本身的類型
function provide<T>(key: InjectionKey<T> | string, value: T): void

// 入?yún)?`key` 的其中一種類型
interface InjectionKey<T> extends Symbol {}

每次調(diào)用 provide 的時候都需要傳入兩個參數(shù):

參數(shù) 說明
key 數(shù)據(jù)的名稱
value 數(shù)據(jù)的值

其中 key 一般使用 string 類型就可以滿足大部分業(yè)務(wù)場景,如果有特殊的需要(例如開發(fā)插件時可以避免和用戶的業(yè)務(wù)沖突),可以使用 InjectionKey 類型,這是一個繼承自 Symbol 的泛型:

import type { InjectionKey } from 'vue'
const key = Symbol() as InjectionKey<string>

還需要注意的是, provide 不是響應(yīng)式的,如果要使其具備響應(yīng)性,需要傳入響應(yīng)式數(shù)據(jù),詳見:響應(yīng)性數(shù)據(jù)的傳遞與接收 。

下面來試試在爺組件 Grandfather.vue 里創(chuàng)建數(shù)據(jù) provide 下去:

// Grandfather.vue
import { defineComponent, provide, ref } from 'vue'

export default defineComponent({
  setup() {
    // 聲明一個響應(yīng)性變量并 provide 其自身
    // 孫組件獲取后可以保持響應(yīng)性
    const msg = ref('Hello World!')
    provide('msg', msg)

    // 只 provide 響應(yīng)式變量的值
    // 孫組件獲取后只會得到當(dāng)前的值
    provide('msgValue', msg.value)

    // 聲明一個方法并 provide
    function printMsg() {
      console.log(msg.value)
    }
    provide('printMsg', printMsg)
  },
})

接收 inject

注:這一小節(jié)的步驟是在 Grandson.vue 里操作。

也是先回顧一下在 Vue 2 里的用法,和接收 props 類似:

export default {
  // 通過 `inject` 選項獲取
  inject: ['tags'],
  mounted() {
    console.log(this.tags)
  },
}

Vue 3 的新版 inject 和 Vue 2 的用法區(qū)別也是比較大,在 Vue 3 , inject 和 provide 一樣,也是需要先導(dǎo)入然后在 setup 里啟用,也是一個全新的方法,每次要 inject 一個數(shù)據(jù)的時候,也是要單獨(dú)調(diào)用一次。

另外還有一個特殊情況需要注意,當(dāng) Grandson.vue 的父級、爺級組件都 provide 了相同名字的數(shù)據(jù)下來,那么在 inject 的時候,會優(yōu)先選擇離它更近的組件的數(shù)據(jù)。

根據(jù)不同的場景, inject 可以接受不同數(shù)量的入?yún)ⅲ雲(yún)㈩愋鸵哺鞑幌嗤?/p>

默認(rèn)用法
默認(rèn)情況下, inject API 的 TS 類型如下:

function inject<T>(key: InjectionKey<T> | string): T | undefined

每次調(diào)用時只需要傳入一個參數(shù):

參數(shù) 類型 說明
key string 與 provide 相對應(yīng)的數(shù)據(jù)名稱

接下來看看如何在孫組件里 inject 爺組件 provide 下來的數(shù)據(jù):

// Grandson.vue
import { defineComponent, inject } from 'vue'
import type { Ref } from 'vue'

export default defineComponent({
  setup() {
    // 獲取響應(yīng)式變量
    const msg = inject<Ref<string>>('msg')
    console.log(msg!.value)

    // 獲取普通的字符串
    const msgValue = inject<string>('msgValue')
    console.log(msgValue)

    // 獲取函數(shù)
    const printMsg = inject<() => void>('printMsg')
    if (typeof printMsg === 'function') {
      printMsg()
    }
  },
})

可以看到在每個 inject 都使用尖括號 <> 添加了相應(yīng)的 TS 類型,并且在調(diào)用變量的時候都進(jìn)行了判斷,這是因為默認(rèn)的情況下, inject 除了返回指定類型的數(shù)據(jù)之外,還默認(rèn)帶上 undefined 作為可能的值。

如果明確數(shù)據(jù)不會是 undefined ,也可以在后面添加 as 關(guān)鍵字指定其 TS 類型,這樣 TypeScript 就不再因為可能出現(xiàn) undefined 而提示代碼有問題。

// Grandson.vue
import { defineComponent, inject } from 'vue'
import type { Ref } from 'vue'

export default defineComponent({
  setup() {
    // 獲取響應(yīng)式變量
    const msg = inject('msg') as Ref<string>
    console.log(msg.value)

    // 獲取普通的字符串
    const msgValue = inject('msgValue') as string
    console.log(msgValue)

    // 獲取函數(shù)
    const printMsg = inject('printMsg') as () => void
    printMsg()
  },
})

設(shè)置默認(rèn)值
inject API 還支持設(shè)置默認(rèn)值,可以接受更多的參數(shù)。

默認(rèn)情況下,只需要傳入第二個參數(shù)指定默認(rèn)值即可,此時它的 TS 類型如下,

function inject<T>(key: InjectionKey<T> | string, defaultValue: T): T

對于不可控的情況,建議在 inject 時添加一個兜底的默認(rèn)值,防止程序報錯:

// Grandson.vue
import { defineComponent, inject, ref } from 'vue'
import type { Ref } from 'vue'

export default defineComponent({
  setup() {
    // 獲取響應(yīng)式變量
    const msg = inject<Ref<string>>('msg', ref('Hello'))
    console.log(msg.value)

    // 獲取普通的字符串
    const msgValue = inject<string>('msgValue', 'Hello')
    console.log(msgValue)

    // 獲取函數(shù)
    const printMsg = inject<() => void>('printMsg', () => {
      console.log('Hello')
    })
    printMsg()
  },
})

需要注意的是, inject 的什么類型的數(shù)據(jù),其默認(rèn)值也需要保持相同的類型。

工廠函數(shù)選項
inject API 在第二個 TS 類型的基礎(chǔ)上,還有第三個 TS 類型,可以傳入第三個參數(shù):

function inject<T>(
  key: InjectionKey<T> | string,
  defaultValue: () => T,
  treatDefaultAsFactory?: false
): T

當(dāng)?shù)诙€參數(shù)是一個工廠函數(shù),那么可以添加第三個值,將其設(shè)置為 true ,此時默認(rèn)值一定會是其 return 的值。

在 Grandson.vue 里新增一個 inject ,接收一個不存在的函數(shù)名,并提供一個工廠函數(shù)作為默認(rèn)值:

// Grandson.vue
import { defineComponent, inject } from 'vue'

interface Food {
  name: string
  count: number
}

export default defineComponent({
  setup() {
    // 獲取工廠函數(shù)
    const getFood = inject<() => Food>('nonexistentFunction', () => {
      return {
        name: 'Pizza',
        count: 1,
      }
    })
    console.log(typeof getFood) // function

    const food = getFood()
    console.log(food) // {name: 'Pizza', count: 1}
  },
})

此時因為第三個參數(shù)默認(rèn)為 Falsy 值,所以可以得到一個函數(shù)作為默認(rèn)值,并可以調(diào)用該函數(shù)獲得一個 Food 對象。

如果將第三個參數(shù)傳入為 true ,再運(yùn)行程序則會在 const food = getFood() 這一行報錯:

// Grandson.vue
import { defineComponent, inject } from 'vue'

interface Food {
  name: string
  count: number
}

export default defineComponent({
  setup() {
    // 獲取工廠函數(shù)
    const getFood = inject<() => Food>(
      'nonexistentFunction',
      () => {
        return {
          name: 'Pizza',
          count: 1,
        }
      },
      true
    )
    console.log(typeof getFood) // object

    // 此時下面的代碼無法運(yùn)行
    // 報錯 Uncaught (in promise) TypeError: getMsg is not a function
    const food = getFood()
    console.log(food)
  },
})

因為此時第三個入?yún)⒏嬷?inject ,默認(rèn)值是一個工廠函數(shù),因此默認(rèn)值不再是函數(shù)本身,而是函數(shù)的返回值,所以 typeof getFood 得到的不再是一個 function 而是一個 object 。

這個參數(shù)對于需要通過工廠函數(shù)返回數(shù)據(jù)的情況非常有用!

兄弟組件通信
兄弟組件是指兩個組件都掛載在同一個 Father.vue 下,但兩個組件之間并沒有什么直接的關(guān)聯(lián),先看看它們的關(guān)系:

Father.vue
├─Brother.vue
└─LittleBrother.vue

這種層級關(guān)系下,如果組件之間要進(jìn)行通信,目前通常有這兩類選擇:

【不推薦】先把數(shù)據(jù)傳給 Father.vue ,再使用 父子組件通信 方案處理
【推薦】借助 全局組件通信 的方案達(dá)到目的
下面的內(nèi)容將進(jìn)入全局通信的講解。

全局組件通信

全局組件通信是指項目下兩個任意組件,不管是否有直接關(guān)聯(lián)(例如父子關(guān)系、爺孫關(guān)系)都可以直接進(jìn)行交流的通信方案。

舉個例子,像下面這種項目結(jié)構(gòu), B2.vue 可以采用全局通信方案直接向 D2.vue 發(fā)起交流,而無需經(jīng)過它們各自的父組件。

A.vue
├─B1.vue
├───C1.vue
├─────D1.vue
├─────D2.vue
├───C2.vue
├─────D3.vue
└─B2.vue

常用的方法有:
Vue3 組件之間的通信
EventBus
EventBus 通常被稱之為 “全局事件總線” ,是用在全局范圍內(nèi)通信的一個常用方案,在 Vue 2 時期該方案非常流行,其特點(diǎn)就是 “簡單” 、 “靈活” 、 “輕量級” 。

回顧 Vue 2
在 Vue 2 ,使用 EventBus 無需導(dǎo)入第三方插件,可以在項目下的 libs 文件夾里,創(chuàng)建一個名為 eventBus.ts 的文件,導(dǎo)出一個新的 Vue 實(shí)例即可。

// src/libs/eventBus.ts
import Vue from 'vue'
export default new Vue()

上面短短兩句代碼已完成了一個 EventBus 的創(chuàng)建,接下來就可以開始進(jìn)行通信。

先在負(fù)責(zé)接收事件的組件里,利用 Vue 的生命周期,通過 eventBus. o n 添加事件偵聽,通過 e v e n t B u s . on 添加事件偵聽,通過 eventBus. on添加事件偵聽,通過eventBus.off 移除事件偵聽。

import eventBus from '@libs/eventBus'

export default {
  mounted() {
    // 在組件創(chuàng)建時,添加一個名為 `hello` 的事件偵聽
    eventBus.$on('hello', () => {
      console.log('Hello World')
    })
  },
  beforeDestroy() {
    // 在組件銷毀前,通過 `hello` 這個名稱移除該事件偵聽
    eventBus.$off('hello')
  },
}

然后在另外一個組件里通過 eventBus.$emit 觸發(fā)事件偵聽。

import eventBus from './eventBus'

export default {
  methods: {
    sayHello() {
      // 觸發(fā)名為 `hello` 的事件
      eventBus.$emit('hello')
    },
  },
}

這樣一個簡單的全局方案就完成了。

了解 Vue 3
Vue 3 應(yīng)用實(shí)例不再實(shí)現(xiàn)事件觸發(fā)接口,因此移除了 $on 、 $off 和 $once 這幾個事件 API ,無法像 Vue 2 一樣利用 Vue 實(shí)例創(chuàng)建 EventBus 。

根據(jù)官方文檔在 事件 API 遷移策略 的推薦,可以使用 mitt 或者 tiny-emitter 等第三方插件實(shí)現(xiàn) EventBus 。

創(chuàng)建 Vue 3 的 EventBus
這里以 mitt 為例,示范如何創(chuàng)建一個 Vue 3 的 EventBus ,首先需要安裝它。

npm i mitt

然后在 src/libs 文件夾下,創(chuàng)建一個名為 eventBus.ts 的文件,文件內(nèi)容和 Vue 2 的寫法其實(shí)是一樣的,只不過是把 Vue 實(shí)例換成了 mitt 實(shí)例。

// src/libs/eventBus.ts
import mitt from 'mitt'
export default mitt()

接下來就可以定義通信的相關(guān)事件了,常用的 API 和參數(shù)如下:
方法名稱 作用:
on 注冊一個偵聽事件,用于接收數(shù)據(jù)
emit 調(diào)用方法發(fā)起數(shù)據(jù)傳遞
off 用來移除偵聽事件

on 的參數(shù):
Vue3 組件之間的通信
這里的 handler 建議使用具名函數(shù),因為匿名函數(shù)無法銷毀。

emit 的參數(shù):
Vue3 組件之間的通信
off 的參數(shù):
Vue3 組件之間的通信

更多的 API 可以查閱 插件的官方文檔 ,在了解了最基本的用法之后,來開始配置一對組件通信。

創(chuàng)建和移除偵聽事件
在需要暴露交流事件的組件里,通過 on 配置好接收方法,同時為了避免路由切換過程中造成事件多次被綁定,從而引起多次觸發(fā),需要在適當(dāng)?shù)臅r機(jī) off 掉:

import { defineComponent, onBeforeUnmount } from 'vue'
import eventBus from '@libs/eventBus'

export default defineComponent({
  setup() {
    // 聲明一個打招呼的方法
    function sayHi(msg = 'Hello World!') {
      console.log(msg)
    }

    // 啟用偵聽
    eventBus.on('sayHi', sayHi)

    // 在組件卸載之前移除偵聽
    onBeforeUnmount(() => {
      eventBus.off('sayHi', sayHi)
    })
  },
})

關(guān)于銷毀的時機(jī),可以參考 組件的生命周期 。

調(diào)用偵聽事件
在需要調(diào)用交流事件的組件里,通過 emit 進(jìn)行調(diào)用:

import { defineComponent } from 'vue'
import eventBus from '@libs/eventBus'

export default defineComponent({
  setup() {
    // 調(diào)用打招呼事件,傳入消息內(nèi)容
    eventBus.emit('sayHi', 'Hello')
  },
})

舊項目升級 EventBus
在 Vue 3 的 EventBus 里,可以看到它的 API 和舊版是非常接近的,只是去掉了 $ 符號。

如果要對舊的項目進(jìn)行升級改造,由于原來都是使用了 $on 、 $emit 等舊的 API ,一個一個組件去修改成新的 API 容易遺漏或者全局替換出錯。

因此可以在創(chuàng)建 eventBus.ts 的時候,通過自定義一個 eventBus 對象來掛載 mitt 的 API 。

在 eventBus.ts 里,改成以下代碼:

// src/libs/eventBus.ts
import mitt from 'mitt'

// 初始化一個 mitt 實(shí)例
const emitter = mitt()

// 在導(dǎo)出時使用舊的 API 名稱去調(diào)用 mitt 的 API
export default {
  $on: (...args) => emitter.on(...args),
  $emit: (...args) => emitter.emit(...args),
  $off: (...args) => emitter.off(...args),
}

這樣在組件里就可以繼續(xù)使用 eventBus. o n 、 e v e n t B u s . on 、eventBus. on、eventBus.emit 等舊 API ,不會影響舊項目的升級使用。

Reative State

在 Vue 3 里,使用響應(yīng)式的 reative API 也可以實(shí)現(xiàn)一個小型的狀態(tài)共享庫,如果運(yùn)用在一個簡單的 H5 活動頁面這樣小需求里,完全可以滿足使用。

創(chuàng)建狀態(tài)中心
首先在 src 目錄下創(chuàng)建一個 state 文件夾,并添加一個 index.ts 文件,寫入以下代碼

// src/state/index.ts
import { reactive } from 'vue'

// 如果有多個不同業(yè)務(wù)的內(nèi)部狀態(tài)共享
// 使用具名導(dǎo)出更容易維護(hù)
export const state = reactive({
  // 設(shè)置一個屬性并賦予初始值
  message: 'Hello World',

  // 添加一個更新數(shù)據(jù)的方法
  setMessage(msg: string) {
    this.message = msg
  },
})

這就完成了一個簡單的 Reactive State 響應(yīng)式狀態(tài)中心的創(chuàng)建。

設(shè)定狀態(tài)更新邏輯
接下來在一個組件 Child.vue 的 script /> 里添加以下代碼,分別進(jìn)行了以下操作:
1.打印初始值
2.對 state 里的數(shù)據(jù)啟用偵聽器
3.使用 state 里的方法更新數(shù)據(jù)
4.直接更新 state 的數(shù)據(jù)

// Child.vue
import { defineComponent, watch } from 'vue'
import { state } from '@/state'

export default defineComponent({
  setup() {
    console.log(state.message)
    // Hello World

    // 因為是響應(yīng)式數(shù)據(jù),所以可以偵聽數(shù)據(jù)變化
    watch(
      () => state.message,
      (val) => {
        console.log('Message 發(fā)生變化:', val)
      }
    )

    setTimeout(() => {
      state.setMessage('Hello Hello')
      // Message 發(fā)生變化: Hello Hello
    }, 1000)

    setTimeout(() => {
      state.message = 'Hi Hi'
      // Message 發(fā)生變化: Hi Hi
    }, 2000)
  },
})

觀察全局狀態(tài)變化
繼續(xù)在另外一個組件 Father.vue 里寫入以下代碼,導(dǎo)入 state 并在 template /> 渲染其中的數(shù)據(jù):

<!-- Father.vue -->
<template>
  <div>{{ state.message }}</div>
  <Child />
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import Child from '@cp/Child.vue'
import { state } from '@/state'

export default defineComponent({
  components: {
    Child,
  },
  setup() {
    return {
      state,
    }
  },
})
</script>

可以觀察到當(dāng) Child.vue 里的定時器執(zhí)行時, Father.vue 的視圖也會同步得到更新。

一個無需額外插件即可實(shí)現(xiàn)的狀態(tài)中心就這么完成了!

Vuex
Vuex 是 Vue 生態(tài)里面非常重要的一個成員,運(yùn)用于狀態(tài)管理模式。

它也是一個全局的通信方案,對比 EventBus,Vuex 的功能更多,更靈活,但對應(yīng)的學(xué)習(xí)成本和體積也相對較大,通常大型項目才會用上 Vuex 。

在了解之前
摘自 Vuex 倉庫 README 文檔的一段官方提示:
意思是 Pinia 已經(jīng)成為 Vue 生態(tài)最新的官方狀態(tài)管理庫,不僅適用于 Vue 3 ,也支持 Vue 2 ,而 Vuex 將進(jìn)入維護(hù)狀態(tài),不再增加新功能, Vue 官方強(qiáng)烈建議在新項目中使用 Pinia 。

Vuex 的目錄結(jié)構(gòu)
在 Vue 3 里使用 Vuex ,需要選擇 4.x 版本,也是當(dāng)前的 @latest 標(biāo)簽對應(yīng)的版本,請先安裝它。

npm i vuex

接下來按照下面的目錄結(jié)構(gòu)創(chuàng)建對應(yīng)的目錄與文件:

src
│ # Vuex 的目錄
├─store
├───index.ts
└─main.ts

一般情況下一個 index.ts 足矣,它是 Vuex 的入口文件,如果的項目比較龐大,可以在 store 目錄下創(chuàng)建一個命名為 modules 的文件夾,使用 Vuex Modules 的方式導(dǎo)入到 index.ts 里去注冊。

回顧 Vue 2
在 Vue 2 ,需要先分別導(dǎo)入 vue 和 vuex,使用 use 方法啟用 Vuex 后,通過 new Vuex.Store(…) 的方式進(jìn)行初始化。

// src/store/index.ts
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {},
  mutations: {},
  actions: {},
  modules: {},
})

之后在組件里就可以通過 this.$store 操作 Vuex 上的方法了。

export default {
  mounted() {
    // 通過 `this.$store` 操作 Vuex
    this.$store.commit('increment')
    console.log(this.$store.state.count)
  },
}

了解 Vue 3
Vue 3 需要從 Vuex 里導(dǎo)入 createStore 創(chuàng)建實(shí)例:

// src/store/index.ts
import { createStore } from 'vuex'

export default createStore({
  state: {},
  mutations: {},
  actions: {},
  modules: {},
})

之后在 src/main.ts 里啟用 Vuex :

// src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'

createApp(App)
  .use(store) // 啟用 Vuex
  .mount('#app')

Vue 3 在組件里使用 Vuex 的方式和 Vue 2 有所不同,需要像使用路由那樣通過一個組合式 API useStore 啟用。

import { defineComponent } from 'vue'
import { useStore } from 'vuex'

export default defineComponent({
  setup() {
    // 需要創(chuàng)建一個 store 變量
    const store = useStore()

    // 再使用 store 去操作 Vuex 的 API
    // ...
  },
})

Vuex 的配置
除了初始化方式有一定的改變, Vuex 在 Vue 3 的其他配置和 Vue 2 是一樣的。

由于現(xiàn)在在 Vue 3 里已經(jīng)更推薦使用 Pinia , Vuex 已處于維護(hù)狀態(tài),因此關(guān)于 Vuex 的使用將不展開更多的介紹,有需要的開發(fā)者可以查看 Vuex 官網(wǎng)的 使用指南 了解更多。文章來源地址http://www.zghlxwxcb.cn/news/detail-402162.html

到了這里,關(guān)于Vue3 組件之間的通信的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • vue組件之間通信方式

    一、全局事件總線 范圍 :任意組件間 步驟 :1、創(chuàng)建事件總線 第一種方式:通過自定義事件總線方式 局部引用 第二種方式:通過原型綁定 main.js 局部引用 解綁事件 二、props和$emit 范圍 :父子組件間 父組件 子組件 三、Vuex(狀態(tài)管理) 范圍 :多個組件之間共享狀態(tài),可以

    2024年03月10日
    瀏覽(20)
  • Vue兄弟組件之間的通信:

    Vue兄弟組件之間的通信:

    思路: 通過中間人父組件進(jìn)行通信; 子組件先傳給父組件,然后父組件再傳給另一個子組件;? 結(jié)果: ? 注意: console.log(res.json())的結(jié)果是promise對象; 圖示: 要通過res接收res.json()結(jié)果才是data數(shù)據(jù); ?結(jié)果: ? 子組件傳給父組件的data,是一個臨時變量,如果父組件想用,

    2024年02月11日
    瀏覽(25)
  • vue 組件之間通信的方式

    1.父向子版? 父組件設(shè)置自定義屬性 子組件props接收 2.子向父版 父組件設(shè)置自定義方法并綁定接收的方法 子組件觸發(fā)方法 ?3.全局事件總線?? 4.Vuex 用這個的話首先要裝包或者創(chuàng)建工程的時候選擇這個選項手腳架會給你裝好 5.路由 抽象一點(diǎn)說路由也算通信方式的一種吧 這種

    2024年01月18日
    瀏覽(21)
  • 淺談Vue組件之間的通信

    父子組件通信 : 父組件向子組件傳遞數(shù)據(jù) :可以通過 props 屬性向子組件傳遞數(shù)據(jù)。 子組件向父組件傳遞數(shù)據(jù) :可以通過 $emit 方法觸發(fā)一個自定義事件,并在父組件中監(jiān)聽這個事件。 在父組件中: 兄弟組件通信 : 可以使用共同的父組件作為中介,父組件通過 props 向子組

    2024年02月22日
    瀏覽(20)
  • VUE 父子組件、兄弟組件 之間通信 最強(qiáng)詳解

    VUE 父子組件、兄弟組件 之間通信 最強(qiáng)詳解

    目錄 1. 父組件 調(diào)用 子組件 內(nèi)參數(shù)/方法 1.1 通過 ref 調(diào)用/獲取 子組件內(nèi)參數(shù)/方法 2. 子組件 調(diào)用 父組件 內(nèi)參數(shù)/方法 2.1 通過?emit 調(diào)用 父組件方法 2.2 通過?props?調(diào)用 父組件方法/參數(shù) 2.3 通過 this.$parent 調(diào)用 父組件方法/參數(shù) 3. 兄弟組件 通信 3.1 通過?bus 進(jìn)行 兄弟組件 通信

    2024年02月05日
    瀏覽(96)
  • vue3組件之間雙向綁定

    Vue3中組件的雙向綁定統(tǒng)一使用 v-model 進(jìn)行處理,并且可以和多個數(shù)據(jù)進(jìn)行綁定,例如 v-model:foo、v-model:bar。 v-model 等價于 :model-value=\\\"someValue\\\" 和 @update:model-value=\\\"someValue = $event\\\" v-model:foo 等價于 :foo=\\\"someValue\\\" 和 @update:foo=\\\"someValue = $event\\\" 父子組件之間雙向綁定 子組件可以結(jié)合 i

    2024年02月11日
    瀏覽(23)
  • vue組件之間的通信都有哪些?

    vue組件之間的通信都有哪些?

    vue組件之間的通信都有哪些? 父子組件通信: Props:父組件通過props將數(shù)據(jù)傳遞給子組件,子組件通過props接收父組件傳遞的數(shù)據(jù)。 Events:子組件通過$emit觸發(fā)事件,并將數(shù)據(jù)傳遞給父組件,父組件通過監(jiān)聽子組件的事件來接收數(shù)據(jù)。 兄弟組件通信: 共同的父組件作為中介:

    2024年02月06日
    瀏覽(19)
  • 07-Vue技術(shù)棧之(組件之間的通信方式)

    07-Vue技術(shù)棧之(組件之間的通信方式)

    前言: 組件之間通信的方式有很多種,比如 props 、 自定義事件 、 全局事件總線 、 消息訂閱與發(fā)布 、 父鏈與子組件索引 、 插槽 、 Vuex 等都可以實(shí)現(xiàn)組件之間的通信。在這里我將介紹以下三種通信方式。 它是一種組件間通信的方式,適用于: 子組件 === 父組件 使用場景

    2024年02月07日
    瀏覽(15)
  • AI生成--Vue組件之間通信方式有哪些

    Vue組件之間通信方式有以下幾種: 父子組件通信:父組件可以通過props傳遞數(shù)據(jù)給子組件,子組件通過$emit觸發(fā)事件通知父組件。 兄弟組件通信:可以通過共同的父組件作為中介,兄弟組件通過 e m i t 和 emit和 e mi t 和 on觸發(fā)和監(jiān)聽事件實(shí)現(xiàn)通信。 跨級組件通信:可以使用p

    2024年02月08日
    瀏覽(16)
  • vue2和vue3 子組件父組件之間的傳值方法

    在組件化開發(fā)的過程中難免會遇見 子組件和父組件之間的通訊那么這里講關(guān)于vue2和vue3不同的通訊方式 先看一下vue2 父組件向子組件傳遞參數(shù) 父組件通過 : 語法 其實(shí)就是v-bind 來傳遞參數(shù) 子組件通過 props 來獲取父組件傳遞的方法 億點(diǎn)小知識:子組件接收到數(shù)據(jù)之后,不能直接

    2024年02月09日
    瀏覽(22)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包