首頁 >頭條 >乾貨分享:Vue3組件通訊的7種方式!

乾貨分享:Vue3組件通訊的7種方式!

青灯夜游
青灯夜游轉載
2022-02-16 10:20:322684瀏覽

元件(Component)是 Vue 最核心的功能,是可重複使用的vue實例;但元件實例的作用域是相互獨立的,也就是說不同元件間的資料是無法直接互相引用的。那麼,如何將組件間的資料關聯起來呢?如何進行通信傳遞數據呢?以下這篇文章就跟大家分享七種組件通訊方式,希望對大家有幫助!

乾貨分享:Vue3組件通訊的7種方式!

本篇文章是全部採用的<script setup></script>這個組合式API寫法,相對於選項式來說,組合式API這種寫法比較自由,具體可以參考Vue文檔對兩種方式的描述。

註:php中文網路上班也開始教授最新版本的vue課程了,有興趣的朋友可以了解學習。

本篇文章將介紹如下七種元件通訊方式:

  • props
  • emit
  • v-model
  • refs
  • provide/inject
  • eventBus
  • vuex/pinia(狀態管理工具)

開始搞事情~

舉一個栗子

俗話說的好,學習不寫demo,那就是耍流氓~

本篇文章將圍繞下面這個demo,如下圖所示:

乾貨分享:Vue3組件通訊的7種方式!

上圖中,列表輸入框分別是父子元件,根據不同傳值方式,可能誰是父元件誰是子組件會有所調整。

1、Props方式

Props方式是Vue中最常見的一種父傳子的一種方式,使用也比較簡單。 【相關推薦:vue.js影片教學

根據上面的demo,我們將資料以及對資料的操作定義在父元件,子元件只做清單的一個渲染;

父元件程式碼如下:

<template>
  <!-- 子组件 -->
  <child-components :list="list"></child-components>
  <!-- 父组件 -->
  <div class="child-wrap input-group">
    <input
      v-model="value"
      type="text"
      class="form-control"
      placeholder="请输入"
    />
    <div class="input-group-append">
      <button @click="handleAdd" class="btn btn-primary" type="button">
        添加
      </button>
    </div>
  </div>
</template>
<script setup>
import { ref } from &#39;vue&#39;
import ChildComponents from &#39;./child.vue&#39;
const list = ref([&#39;JavaScript&#39;, &#39;HTML&#39;, &#39;CSS&#39;])
const value = ref(&#39;&#39;)
// add 触发后的事件处理函数
const handleAdd = () => {
  list.value.push(value.value)
  value.value = &#39;&#39;
}
</script>

子元件只需要對父元件傳遞的值進行渲染即可,程式碼如下:

<template>
  <ul class="parent list-group">
    <li class="list-group-item" v-for="i in props.list" :key="i">{{ i }}</li>
  </ul>
</template>
<script setup>
import { defineProps } from &#39;vue&#39;
const props = defineProps({
  list: {
    type: Array,
    default: () => [],
  },
})
</script>

2、emit方式

emit方式也是Vue中最常見的元件通訊方式,該方式用於子傳父

#根據上面的demo,我們將清單定義在父元件,子元件只需要傳遞新增的值。

子元件程式碼如下:

<template>
  <div class="child-wrap input-group">
    <input
      v-model="value"
      type="text"
      class="form-control"
      placeholder="请输入"
    />
    <div class="input-group-append">
      <button @click="handleSubmit" class="btn btn-primary" type="button">
        添加
      </button>
    </div>
  </div>
</template>
<script setup>
import { ref, defineEmits } from &#39;vue&#39;
const value = ref(&#39;&#39;)
const emits = defineEmits([&#39;add&#39;])
const handleSubmit = () => {
  emits(&#39;add&#39;, value.value)
  value.value = &#39;&#39;
}
</script>

在子元件中點選【新增】按鈕後,emit一個自訂事件,並將新增的值作為參數傳遞。

父元件程式碼如下:

<template>
  <!-- 父组件 -->
  <ul class="parent list-group">
    <li class="list-group-item" v-for="i in list" :key="i">{{ i }}</li>
  </ul>
  <!-- 子组件 -->
  <child-components @add="handleAdd"></child-components>
</template>
<script setup>
import { ref } from &#39;vue&#39;
import ChildComponents from &#39;./child.vue&#39;
const list = ref([&#39;JavaScript&#39;, &#39;HTML&#39;, &#39;CSS&#39;])
// add 触发后的事件处理函数
const handleAdd = value => {
  list.value.push(value)
}
</script>

在父元件中只需要監聽子元件自訂的事件,然後執行對應的新增操作。

3、v-model方式

v-model是Vue中一個比較出色的語法糖,就例如下面這段程式碼

<ChildComponent v-model:title="pageTitle" />

就是下面這段程式碼的簡寫狀況

<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />

v-model確實簡單了不少,現在我們就來看上面那個demo,如何用v-model實作。

子元件

<template>
  <div class="child-wrap input-group">
    <input
      v-model="value"
      type="text"
      class="form-control"
      placeholder="请输入"
    />
    <div class="input-group-append">
      <button @click="handleAdd" class="btn btn-primary" type="button">
        添加
      </button>
    </div>
  </div>
</template>
<script setup>
import { ref, defineEmits, defineProps } from &#39;vue&#39;
const value = ref(&#39;&#39;)
const props = defineProps({
  list: {
    type: Array,
    default: () => [],
  },
})
const emits = defineEmits([&#39;update:list&#39;])
// 添加操作
const handleAdd = () => {
  const arr = props.list
  arr.push(value.value)
  emits(&#39;update:list&#39;, arr)
  value.value = &#39;&#39;
}
</script>

在子元件中我們先定義propsemits,然後在加入完成之後emit指定事件。

註:update:*是Vue中的固定寫法,*表示props中的某個屬性名稱。

父元件中使用就比較簡單,程式碼如下:

<template>
  <!-- 父组件 -->
  <ul class="parent list-group">
    <li class="list-group-item" v-for="i in list" :key="i">{{ i }}</li>
  </ul>
  <!-- 子组件 -->
  <child-components v-model:list="list"></child-components>
</template>
<script setup>
import { ref } from &#39;vue&#39;
import ChildComponents from &#39;./child.vue&#39;
const list = ref([&#39;JavaScript&#39;, &#39;HTML&#39;, &#39;CSS&#39;])
</script>

4、refs方式

在使用選項式API時,我們可以透過 this.$refs.name的方式取得指定元素或元件,但是在組合式API中就無法使用哪一種方式取得。如果我們想要透過ref的方式取得元件或元素,需要定義一個同名的Ref對象,在元件掛載後就可以存取了。

範例程式碼如下:

<template>
  <ul class="parent list-group">
    <li class="list-group-item" v-for="i in childRefs?.list" :key="i">
      {{ i }}
    </li>
  </ul>
  <!-- 子组件 ref的值与<script>中的保持一致 -->
  <child-components ref="childRefs"></child-components>
  <!-- 父组件 -->
</template>
<script setup>
import { ref } from &#39;vue&#39;
import ChildComponents from &#39;./child.vue&#39;
const childRefs = ref(null)
</script>

子元件程式碼如下:

<template>
  <div class="child-wrap input-group">
    <input
      v-model="value"
      type="text"
      class="form-control"
      placeholder="请输入"
    />
    <div class="input-group-append">
      <button @click="handleAdd" class="btn btn-primary" type="button">
        添加
      </button>
    </div>
  </div>
</template>
<script setup>
import { ref, defineExpose } from &#39;vue&#39;
const list = ref([&#39;JavaScript&#39;, &#39;HTML&#39;, &#39;CSS&#39;])
const value = ref(&#39;&#39;)
// add 触发后的事件处理函数
const handleAdd = () => {
  list.value.push(value.value)
  value.value = &#39;&#39;
}
defineExpose({ list })
</script>

setup元件預設是關閉的,也即透過範本ref 取得到的元件的公開實例,不會暴露任何在**<script setup></script>中宣告的綁定。如果需要公開需要透過****defineExpose**** API暴露**。

5、provide/inject方式

provideinject是Vue中提供的一對API,該API可以實現父元件向子元件傳遞數據,無論層級有多深,都可以透過這對API實現。範例程式碼如下所示:

父元件

<template>
  <!-- 子组件 -->
  <child-components></child-components>
  <!-- 父组件 -->
  <div class="child-wrap input-group">
    <input
      v-model="value"
      type="text"
      class="form-control"
      placeholder="请输入"
    />
    <div class="input-group-append">
      <button @click="handleAdd" class="btn btn-primary" type="button">
        添加
      </button>
    </div>
  </div>
</template>
<script setup>
import { ref, provide } from &#39;vue&#39;
import ChildComponents from &#39;./child.vue&#39;
const list = ref([&#39;JavaScript&#39;, &#39;HTML&#39;, &#39;CSS&#39;])
const value = ref(&#39;&#39;)
// 向子组件提供数据
provide(&#39;list&#39;, list.value)
// add 触发后的事件处理函数
const handleAdd = () => {
  list.value.push(value.value)
  value.value = &#39;&#39;
}
</script>

子元件

<template>
  <ul class="parent list-group">
    <li class="list-group-item" v-for="i in list" :key="i">{{ i }}</li>
  </ul>
</template>
<script setup>
import { inject } from &#39;vue&#39;
// 接受父组件提供的数据
const list = inject(&#39;list&#39;)
</script>

值得注意的是使用provide進行資料傳遞時,盡量readonly進行資料的包裝,避免子元件修改父級傳遞過去的資料

6、事件匯流排

Vue3中移除了事件總線,但可以藉助於第三方工具來完成,Vue官方推薦mitttiny-emitter;

在大多數情況下不推薦使用全局事件總線的方式來實現組件通信,雖然比較簡單粗暴,但是長久來說維護事件總線是一個大難題,所以這裡就不展開講解了,具體可以閱讀具體工具的文檔

7、狀態管理工具

VuexPinia是Vue3中的狀態管理工具,使用這兩個工具可以輕鬆實現元件通信,由於這兩個工具功能比較強大,這裡就不做展示了,具體可以查閱文檔

#寫在最後

本篇文章到這就結束了,總的來說比較簡單,沒有什麼複雜內容。

如果這篇文章對你來說有點作用,歡迎按讚、留言、收藏,避免在需要的時候找不到。

如果文中有錯誤,歡迎指正~

原文網址:https://juejin.cn/post/7062740057018335245

作者:一碗週

(學習影片分享:web前端教學

陳述:
本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除