組件之間除了保持獨立之外,還需要相互通信,本章將介紹幾種通信的方式。
## 一、直接訪問
  Vue提供了三個實例屬性,可直接訪問父組件、子組件和根實例,如下所列。
  (1)$parent:父組件。
  (2)$root:根實例,如果沒有父實例,那么讀取的將是自身。
  (3)$children:直接子組件,無法獲取隔代的子組件,并且不保證組件的順序,也非響應式。
  下面用一個示例來演示它們的用法,首先創建兩個父子關系的組件parent和child;接著初始化根實例vm,掛載的\<div>元素包含parent組件;最后為根實例和parent組件的數據對象添加name屬性。
~~~html
<div id="container">
<parent></parent>
</div>
<script>
Vue.component("child", {
template: '<p>子組件</p>',
mounted: function() {
this.$parent.name; //"parent"
this.$root.name; //"root"
}
});
Vue.component("parent", {
data: function() {
return {
name: "parent"
};
},
template: '<child></child>'
});
var vm = new Vue({
el: "#container",
data: {
name: "root"
}
});
vm.$children; //[VueComponent]
</script>
~~~
  當執行vm.$children時,得到的是一個子組件數組。在child組件的mounted鉤子中調用了實例的$parent和$root的name屬性,其值分別是“parent”和“root”。
  大部分情況下,應當避免直接修改組件的內部,因為這么做不僅讓父子組件緊密耦合,而且還難以追蹤是誰發起的變更。
## 二、ref和$refs
  如果要直接訪問子元素或子組件,那么除了使用上文的$children屬性之外,還能通過ref特性配合$refs屬性實現。
  DOM元素或組件可通過聲明ref特性來指定一個索引標識符,即注冊引用信息。而父組件的$refs屬性則記錄了聲明過ref特性的子元素和子組件,它的值是一個對象,其鍵就是ref特性的值。下面是一個簡單的例子,注冊了父組件parent和子組件child,并且為child組件和\<input>元素分別聲明了ref特性。
~~~js
Vue.component("child", {
template: '<input ref="txt" />',
mounted: function() {
this.$refs; //{txt: input}
}
});
Vue.component("parent", {
template: '<child ref="child"></child>',
mounted: function() {
this.$refs; //{child: VueComponent}
}
});
~~~
  在兩個組件的mounted鉤子中,讀取了各自實例的$refs屬性。如果要在parent組件中讀取child組件的$refs屬性,那么可以像下面這樣。
~~~js
this.$refs.child.$refs
~~~
  注意,$refs不是響應式的,并且在渲染到頁面之前是無法訪問的,即不能在mounted之前的鉤子中使用。
  當ref特性與v-for指令配合時,引用的將是一個數組,如下所示。
~~~js
Vue.component("child", {
data: function() {
return {
names: ["strick", "freedom"]
};
},
template: `<div>
<input v-for="item in names" ref="txt" />
</div>`,
mounted: function() {
this.$refs; //{txt: [input, input]}
}
});
~~~
## 三、自定義事件
  組件支持自定義事件,并且能在子組件中觸發該事件,從而實現組件之間的通信。假設有兩個父子關系的組件parent和child,在child組件上聲明了自定義的dot事件,而在\<button>元素上添加了click事件,它們接收的事件處理程序都叫add,如下所示。
~~~js
Vue.component("child", {
template: '<button @click="add">提交</button>',
methods: {
add: function() {
this.$emit("dot", 1, 2);
}
}
});
Vue.component("parent", {
template: '<child @dot="add"></child>',
methods: {
add: function(left, right) {
console.log(left, right); //1 2
}
}
});
~~~
  Vue提供的實例方法$emit(),它的第一個參數是要觸發的事件名稱,其余參數都將回傳給該事件的處理程序。在子組件child的add()方法中向$emit()傳遞了三個參數(“dot”、1和2),父組件parent中的add()方法能接收從子組件傳遞過來的兩個數值(1和2)。
  注意,自定義的事件名稱不要用駝峰的命名方式,因為它沒有等價的連字符分隔式的名稱,例如下面的addNumber和add-number是兩個事件。
~~~html
<child @addNumber="handle"></child>
<!-- 不同 -->
<child @add-number="handle"></child>
~~~
  在DOM模板中,由于事件名稱會被自動轉換為小寫,因此像下面這樣調用addNumber事件將會失敗。但在字符串模板中不會受其影響,依然能調用成功。
~~~js
this.$emit("addNumber");
~~~
**1)v-model**
  組件也支持v-model指令,但需要做些配置。默認情況下,組件的v-model只監聽value特性的變化以及input事件。如果要定制,那么可以使用model選項,并且需要在props中添加要監聽的特性。下面注冊一個checkbox組件,并讓它的v-model指令關聯模板內的復選框的checked特性和change事件。
~~~js
Vue.component("checkbox", {
model: {
prop: "checked",
event: "change"
},
props: {
checked: Boolean
},
template: '<input type="checkbox" :checked="checked" @change="dot" />',
methods: {
dot: function(e) {
console.log(e.target.checked);
}
}
});
~~~
  在將v-model作用于checkbox組件上后(如下所示),每次點擊渲染出的復選框,就會在控制臺輸出當前的選中狀態。
~~~html
<div id="container">
<checkbox v-model="current"></checkbox>
</div>
<script>
var vm = new Vue({
el: "#container",
data: {
current: true
}
});
</script>
~~~
*****
> 原文出處:
[博客園-Vue躬行記](https://www.cnblogs.com/strick/category/1512864.html)
[知乎專欄-Vue躬行記](https://zhuanlan.zhihu.com/pwvue)
已建立一個微信前端交流群,如要進群,請先加微信號freedom20180706或掃描下面的二維碼,請求中需注明“看云加群”,在通過請求后就會把你拉進來。還搜集整理了一套[面試資料](https://github.com/pwstrick/daily),歡迎瀏覽。

推薦一款前端監控腳本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不僅能監控前端的錯誤、通信、打印等行為,還能計算各類性能參數,包括 FMP、LCP、FP 等。
- ES6
- 1、let和const
- 2、擴展運算符和剩余參數
- 3、解構
- 4、模板字面量
- 5、對象字面量的擴展
- 6、Symbol
- 7、代碼模塊化
- 8、數字
- 9、字符串
- 10、正則表達式
- 11、對象
- 12、數組
- 13、類型化數組
- 14、函數
- 15、箭頭函數和尾調用優化
- 16、Set
- 17、Map
- 18、迭代器
- 19、生成器
- 20、類
- 21、類的繼承
- 22、Promise
- 23、Promise的靜態方法和應用
- 24、代理和反射
- HTML
- 1、SVG
- 2、WebRTC基礎實踐
- 3、WebRTC視頻通話
- 4、Web音視頻基礎
- CSS進階
- 1、CSS基礎拾遺
- 2、偽類和偽元素
- 3、CSS屬性拾遺
- 4、浮動形狀
- 5、漸變
- 6、濾鏡
- 7、合成
- 8、裁剪和遮罩
- 9、網格布局
- 10、CSS方法論
- 11、管理后臺響應式改造
- React
- 1、函數式編程
- 2、JSX
- 3、組件
- 4、生命周期
- 5、React和DOM
- 6、事件
- 7、表單
- 8、樣式
- 9、組件通信
- 10、高階組件
- 11、Redux基礎
- 12、Redux中間件
- 13、React Router
- 14、測試框架
- 15、React Hooks
- 16、React源碼分析
- 利器
- 1、npm
- 2、Babel
- 3、webpack基礎
- 4、webpack進階
- 5、Git
- 6、Fiddler
- 7、自制腳手架
- 8、VSCode插件研發
- 9、WebView中的頁面調試方法
- Vue.js
- 1、數據綁定
- 2、指令
- 3、樣式和表單
- 4、組件
- 5、組件通信
- 6、內容分發
- 7、渲染函數和JSX
- 8、Vue Router
- 9、Vuex
- TypeScript
- 1、數據類型
- 2、接口
- 3、類
- 4、泛型
- 5、類型兼容性
- 6、高級類型
- 7、命名空間
- 8、裝飾器
- Node.js
- 1、Buffer、流和EventEmitter
- 2、文件系統和網絡
- 3、命令行工具
- 4、自建前端監控系統
- 5、定時任務的調試
- 6、自制短鏈系統
- 7、定時任務的進化史
- 8、通用接口
- 9、微前端實踐
- 10、接口日志查詢
- 11、E2E測試
- 12、BFF
- 13、MySQL歸檔
- 14、壓力測試
- 15、活動規則引擎
- 16、活動配置化
- 17、UmiJS版本升級
- 18、半吊子的可視化搭建系統
- 19、KOA源碼分析(上)
- 20、KOA源碼分析(下)
- 21、花10分鐘入門Node.js
- 22、Node環境升級日志
- 23、Worker threads
- 24、低代碼
- 25、Web自動化測試
- 26、接口攔截和頁面回放實驗
- 27、接口管理
- 28、Cypress自動化測試實踐
- 29、基于Electron的開播助手
- Node.js精進
- 1、模塊化
- 2、異步編程
- 3、流
- 4、事件觸發器
- 5、HTTP
- 6、文件
- 7、日志
- 8、錯誤處理
- 9、性能監控(上)
- 10、性能監控(下)
- 11、Socket.IO
- 12、ElasticSearch
- 監控系統
- 1、SDK
- 2、存儲和分析
- 3、性能監控
- 4、內存泄漏
- 5、小程序
- 6、較長的白屏時間
- 7、頁面奔潰
- 8、shin-monitor源碼分析
- 前端性能精進
- 1、優化方法論之測量
- 2、優化方法論之分析
- 3、瀏覽器之圖像
- 4、瀏覽器之呈現
- 5、瀏覽器之JavaScript
- 6、網絡
- 7、構建
- 前端體驗優化
- 1、概述
- 2、基建
- 3、后端
- 4、數據
- 5、后臺
- Web優化
- 1、CSS優化
- 2、JavaScript優化
- 3、圖像和網絡
- 4、用戶體驗和工具
- 5、網站優化
- 6、優化閉環實踐
- 數據結構與算法
- 1、鏈表
- 2、棧、隊列、散列表和位運算
- 3、二叉樹
- 4、二分查找
- 5、回溯算法
- 6、貪心算法
- 7、分治算法
- 8、動態規劃
- 程序員之路
- 大學
- 2011年
- 2012年
- 2013年
- 2014年
- 項目反思
- 前端基礎學習分享
- 2015年
- 再一次項目反思
- 然并卵
- PC網站CSS分享
- 2016年
- 制造自己的榫卯
- PrimusUI
- 2017年
- 工匠精神
- 2018年
- 2019年
- 前端學習之路分享
- 2020年
- 2021年
- 2022年
- 2023年
- 2024年
- 日志
- 2020