vue3.x組件間通信趾徽,實用小技巧都在這里

本想簡單寫寫,沒想到說清楚已經變成了一篇很長的帖子翰守,歡迎當筆記搜藏起來孵奶。

props / emits 父子組件通信

props一般負責向子組件傳遞數(shù)據(jù)
下面是一個簡單的例子,父組件向子組件傳遞了一個title潦俺,子組件負責顯示title。

// child-component.vue
<template>
  <h2>{{ title }}</h2>
</template>

<script>
  export default {
    name: "child-component",
    props: ['title'] //可以注冊多個prop
  }
</script>

// 父組件中,使用子組件
<ChildComponent :title="'這是傳遞的Title'"></ChildComponent>

emits主要用于監(jiān)聽子組件事件
開發(fā)過程中子組件可能需要與父級組件進行溝通事示,這時我們就需要用到emits早像。下面是一個簡單的例子,點擊子組件按鈕時肖爵,改變了父組件顯示的信息卢鹦。

// child-component.vue
<button @click="$emit('textChange', '子組件被點擊了')">點我</button>

// 父組件中,使用子組件
<template>
  <div>
    <div>{{ msg }}</div>
    <ChildComponent @textChange="msg = $event"></ChildComponent>
  </div>
</template>

<script>
  import ChildComponent from "./child-component"
  export default {
    components: {
      ChildComponent
    },
    data() {
      return {
        msg: 'test msg!'
      }
    }
  }
</script>

prop 類型劝堪、驗證以及默認值
這三塊內容在官網篇幅還挺長的冀自,感覺上重點卻不多,我們上面注冊props的時候使用的數(shù)組秒啦,如:["title"]熬粗,其實實際開發(fā)過程中,為了傳值的清晰余境,我們用的都是對象驻呐,此外我們會指定其類型,驗證規(guī)則芳来,以及給出默認值含末,三者都是可選的,看下面的例子:

export default {
  props: {
    // 基礎的類型檢查 (`null` 和 `undefined` 會通過任何類型驗證)
    propA: Number,
    // 多個可能的類型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 帶有默認值的數(shù)字
    propD: {
      type: Number,
      default: 100
    },
    // 帶有默認值的對象
    propE: {
      type: Object,
      // 對象或數(shù)組默認值必須從一個工廠函數(shù)獲取
      default() {
        return { message: 'hello' }
      }
    },
    // 自定義驗證函數(shù)
    propF: {
      validator(value) {
        // 這個值必須匹配下列字符串中的一個
        return ['success', 'warning', 'danger'].includes(value)
      }
    },
    // 具有默認值的函數(shù)
    propG: {
      type: Function,
      // 與對象或數(shù)組默認值不同即舌,這不是一個工廠函數(shù) —— 這是一個用作默認值的函數(shù)
      default() {
        return 'Default function'
      }
    }
  }
}

注意:
所有的 prop 都使得其父子 prop 之間形成了一個單向下行綁定:父級 prop 的更新會向下流動到子組件中佣盒,但是反過來則不行。這樣會防止從子組件意外變更父級組件的狀態(tài)顽聂,從而導致你的應用的數(shù)據(jù)流向難以理解肥惭。

另外,每次父級組件發(fā)生變更時芜飘,子組件中所有的 prop 都將會刷新為最新的值务豺。這意味著你不應該在一個子組件內部改變 prop。如果你這樣做了嗦明,Vue 會在瀏覽器的控制臺中發(fā)出警告笼沥。
但是,如果prop傳遞的是一個對象或者數(shù)組娶牌,我們是可以改變其內部的數(shù)據(jù)的奔浅,同時這個改變會變更對象或數(shù)組本身,從而影響到其所在父組件的狀態(tài)诗良。

vue3的新選項emits
vue 3 提供了一個 emits 選項汹桦,和現(xiàn)有的 props 選項類似。這個選項可以用來定義一個組件可以向其父組件觸發(fā)的事件鉴裹。emits 選項中列出的事件不會從組件的根元素繼承舞骆,也將從$attrs property中移除钥弯。

emits 可以是數(shù)組或對象,從組件觸發(fā)自定義事件督禽,emits 可以是簡單的數(shù)組脆霎,也可以是對象,后者允許配置事件驗證(因為返回false也依舊會繼續(xù)調用事件狈惫,所以作者本人沒理解驗證這塊睛蛛,有知道的小伙伴歡迎留言)。使用如下:

emits: {
  // 沒有驗證函數(shù)
  click: null,

  // 帶有驗證函數(shù)
  submit: payload => {
    if (payload.email && payload.password) {
      return true
    } else {
      return false // 返回false事件依舊會繼續(xù)被調用
    }
  }
}

因為不聲明emits也可以使$emit來調用傳遞的事件胧谈,所以看似用處不大忆肾,但聲明首先可以使代碼清晰,可以一眼看到向其父組件透傳的事件菱肖。同時需要向其父組件透傳原生事件(如:@ckick)的組件來說客冈,不聲明會導致事件被觸發(fā)兩次,而聲明可以避免這類問題蔑滓。

provide / inject 多層嵌套組件通信

使用場景:
1郊酒、多層嵌套組件傳值
2、父子組件相互尋找比較麻煩键袱,如slot

多層嵌套組件通信

簡單示例:

// 父組件 提供對象
provide: {
  user: 'John Doe'
}

// 子組件燎窘,接收對象
inject: ['user'],
created() {
  console.log(`Injected property: ${this.user}`) // > 注入 property: John Doe
}

訪問組件實例 property(用this),我們需要將 provide 轉換為返回對象的函數(shù)

// 父組件
data() {
  return {
    userName: 'test name',
  }
},
provide() {
  return {
    user: this.userName
  }
}

響應性注意這里傳遞的是值蹄咖,并不是響應式的褐健,官網建議分配一個組合式 API computed property:

// 來自官網的建議
todoLength: Vue.computed(() => this.todos.length)

個人建議直接傳遞一個對象過去,利用指針傳遞來實現(xiàn)響應式澜汤。(簡單粗暴)如果非要了解可以關注后續(xù)再寫文章中關于 reactive provide/inject 的信息

$attrs / $parent / $refs 能抓到貓就是好老鼠系列

$attrs 包含了父作用域中不作為組件 props 或 emits 的 attribute 綁定和事件蚜迅。當一個組件沒有聲明任何 prop 時,這里會包含所有父作用域的綁定俊抵,并且可以通過 v-bind="$attrs" 傳入內部組件——這在創(chuàng)建高階的組件時會非常有用谁不。
示例:

// 父組件中
<ChildComponent title="123" titleProp="456"></ChildComponent>

// 子組件中
props: ['titleProp'],
created() {
  console.log(this.$attrs.title); // 123
  console.log(this.$attrs.titleProp); // undefined
  
  console.log(this.title); // undefined
  console.log(this.titleProp); // 123
}

$parent 這是父實例,如果當前實例有的話徽诲。簡單粗暴拿著實例各種用刹帕。

$refs 一個對象,持有注冊過ref的所有 DOM 元素和組件實例谎替。父組件使用其可以輕易的獲取子組件偷溺,并各種使用。

eventBus 事件總線vue3不支持了

在絕大多數(shù)情況下钱贯,不鼓勵使用全局的事件總線在組件之間進行通信挫掏。雖然在短期內往往是最簡單的解決方案,但從長期來看秩命,它維護起來總是令人頭疼尉共。
如果非得要用褒傅,可以使用一些外部第三方庫,例如 mitttiny-emitter

// eventBus.js
import emitter from 'tiny-emitter/instance'

export default {
  $on: (...args) => emitter.on(...args),
  $once: (...args) => emitter.once(...args),
  $off: (...args) => emitter.off(...args),
  $emit: (...args) => emitter.emit(...args),
}

vuex 和 自定義共享對象

vuex 輕松獲取響應式的全局數(shù)據(jù)袄友。

業(yè)務獨立的組件通信更推薦的做法是自定義一個js對象樊卓,用js對象來保存共享數(shù)據(jù)和函數(shù)。export是一個對象的話杠河,import之后訪問的是同一個對象,其可以方便的提供數(shù)據(jù)共享和函數(shù)調用浇辜。此外券敌,如果想要不同的對象可以export一個工廠函數(shù)。

總結

  • props / emits 應該是父子組件之間溝通的首選柳洋。兄弟節(jié)點可以通過它們的父節(jié)點通信待诅。
  • provide / inject 允許一個組件與它的插槽內容進行通信。這對于總是一起使用的緊密耦合的組件非常有用熊镣。
  • provide / inject 也能夠用于組件之間的遠距離通信卑雁。它可以幫助避免“prop 逐級透傳”,即 prop 需要通過許多層級的組件傳遞下去绪囱,但這些組件本身可能并不需要那些 prop测蹲。
  • prop 逐級透傳也可以通過重構以使用插槽來避免。如果一個中間組件不需要某些 prop鬼吵,那么表明它可能存在關注點分離的問題扣甲。在該類組件中使用 slot 可以允許父節(jié)點直接為它創(chuàng)建內容,因此 prop 可以被直接傳遞而不需要中間組件的參與齿椅。
  • 全局狀態(tài)管理琉挖,比如 Vuex
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市涣脚,隨后出現(xiàn)的幾起案子示辈,更是在濱河造成了極大的恐慌,老刑警劉巖遣蚀,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件矾麻,死亡現(xiàn)場離奇詭異,居然都是意外死亡妙同,警方通過查閱死者的電腦和手機射富,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粥帚,“玉大人胰耗,你說我怎么就攤上這事∶⑽校” “怎么了柴灯?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵卖漫,是天一觀的道長。 經常有香客問我赠群,道長羊始,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任查描,我火速辦了婚禮突委,結果婚禮上,老公的妹妹穿的比我還像新娘冬三。我一直安慰自己匀油,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布勾笆。 她就那樣靜靜地躺著敌蚜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪窝爪。 梳的紋絲不亂的頭發(fā)上弛车,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音蒲每,去河邊找鬼纷跛。 笑死,一個胖子當著我的面吹牛邀杏,可吹牛的內容都是我干的忽舟。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼淮阐,長吁一口氣:“原來是場噩夢啊……” “哼叮阅!你這毒婦竟也來了?” 一聲冷哼從身側響起泣特,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤浩姥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后状您,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體勒叠,經...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年膏孟,在試婚紗的時候發(fā)現(xiàn)自己被綠了眯分。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡柒桑,死狀恐怖弊决,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤飘诗,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布与倡,位于F島的核電站,受9級特大地震影響昆稿,放射性物質發(fā)生泄漏纺座。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一溉潭、第九天 我趴在偏房一處隱蔽的房頂上張望净响。 院中可真熱鬧,春花似錦喳瓣、人聲如沸别惦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至氯庆,卻和暖如春蹭秋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背堤撵。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工仁讨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人实昨。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓洞豁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親荒给。 傳聞我的和親對象是個殘疾皇子丈挟,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內容