1.1props
方式:能夠是數組或對象,用於接收父組件的數據javascript
<div id="app"> <child-component :msg="message" :count="count"></child-component> <button @click="count++"> 點擊+1 </button> </div> <script> const childComponent = { props: { msg: String count: Number }, template: `<div><p>{{msg}}</p><p>{{count}}</p><div>` } new Vue({ el: '#app', data: { message:'父組件的值', count:0 }, components:{ childComponent } }) </script>
1.2 經過$parent
獲取父組件實例的方法或者屬性html
這種方式,從嚴格意義上講不是值的傳遞,而是一種 「取」 (不推薦直接經過實例進行值的獲取)vue
實例屬性
$parent
能夠得到父組件的實例,藉助實例能夠調用父實例中的方法,或者父實例上的屬性java
<div id="app"> <child-component :msg="message" :count="count"></child-component> <button @click="count++"> 點擊+1 </button> </div> <script> //子組件 const childComponent = { data:() => ({ msg:'', count:null }), methods: { handleClick(){ //調用父級實例的方法 this.$parent.parentMethods(); } } mounted () { // 獲取父級實例中的屬性 this.msg = this.$parent.message; this.count = this.$parent.count; } template: `<div><p @click="handleClick">{{msg}}</p><p>{{count}}</p><div>` } // 父級 new Vue({ el: '#app', data: { message: '父組件的值', count: 0 }, methods: { parentMethod () { console.log('我是父級的方法'); } } components: { childComponent } }) </script>
1.3 使用修飾符.sync
數組
修飾符.sync
是2.3.0+
新增,它對props
起到了一種修飾的做用,使用.sync
進行修飾的props
,意味着子組件有修改它的意圖,這種狀況下它只起到一個標註性做用,有它沒它都不會影響邏輯app
使用.sync
修改上邊的代碼:ide
// 父組件 List.vue
<template> <!-- 這裏不寫 .sync 也不會影響結果 --> <List-item :title.sync="title" @update:title="updataTitle"></List-item> </template> <script> import ListItem from "./ListItem"; export default { data() { return { title: "我是title", } }, components: { ListItem }, methods: { updataTitle(res) { this.title = res; } } } </script> // 子組件 ListItem.vue <template> <div> <button @click="handleClick">Click me</button> <div>{{title}}</div> </div> </template> <script> export default { props: { title: String, }, methods: { handleClick() { // 子組件向父組件傳值 this.$emit('update:title', '我要父組件更新 title'); } } } </script>
使用.sync
向子組件傳遞多個props
:工具
當咱們用一個對象同時設置多個prop
的時候,也能夠將這個.sync
修飾符和v-bind
配合使用:this
<text-document v-bind.sync="doc"></text-document>
這樣會把doc
對象中的每個屬性(如:title)都做爲一個獨立的prop
傳進去,而後各自添加用於更新的v-on
監聽器。spa
2.1 經過事件傳值$emit
使用:
子組件使用
$emit
發送一個自定義事件父組件使用指令
v-on
監聽子組件發送的事件
<div id="app"> <child-component @child-event="childEvent"></child-component> </div> <script> //子組件 const childComponent={ data:()=>({ msg:'點擊發送值到父組件', count:null }), methods:{ handleClick(data){ this.$emit('child-event','我是子組件傳過來的值'); } } template:`<div><p @click="handleClick">{{msg}}</p><p>{{count}}</p><div>` } // 父級 new Vue({ el:'#app', data:{ message:'父組件的值', count:0 }, methods:{ childEvent(data){ console.log("子組件傳過來的值",data); } } components:{ childComponent } }) </script>
2.2 經過$children
獲取子組件實例
同$parent
2.3 經過ref
註冊子組件引用
雖然存在prop
和事件,可是有時仍可能須要在 JavaScript 裏直接訪問一個子組件。爲了實現這樣的需求,能夠使用ref
特性爲某個子組件設置一個 ID 引用,就是一個身份標識
<div id="app"> <child-component ref="childComponent"></child-component> <button @click="getRefs"> 獲取子組件實例 </button> </div> <script> //子組件 const childComponent={ data:()=>({ msg:'點擊發送值到父組件', count:null }), template:`<div><p @click="handleClick">{{msg}}</p><p>{{count}}</p><div>` } // 父級 new Vue({ el:'#app', data:{ message:'父組件的值', count:0 }, methods:{ getRefs(){ console.log("子組件傳過來的值",this.$refs.childComponent.msg); } } components:{ childComponent } }) </script>
3.1Bus
中央事件總線
非父子組件傳值,能夠使用一個空的Vue
實例做爲中央事件總線,結合實例方法$on
,$emit
使用
注意:
註冊的
Bus
要在組件銷燬時卸載,不然會屢次掛載,形成觸發一次但多個響應的狀況。
beforeDestroy(){ this.$Bus.$off('方法名',value); }
Bus
定義方式:
1,將Bus
抽離出來,組件有須要時引入
// bus.js import Vue from 'vue'; const Bus = new Vue(); export default Bus;
2,將Bus
掛載到 Vue 根實例的原型上
import Vue from 'vue'; Vue.prototype.$bus = new Vue();
3,將Bus
注入到 Vue 根對象上
import Vue form 'vue'; const Bus = new Vue(); new Vue({ el:'#app', data:{ Bus } })
使用例子:
<div id="app"> <child-component ></child-component> <child-component-two ></child-component-two> </div> <script> Vue.prototype.$bus = new Vue(); //子組件1 const childComponent={ data:()=>({ msg:'我是子組件一', sendMsg:'我是子組件一發送的值' }), methods:{ handleClick(){ this.$Bus.$emit('sendMsg',this.sendMsg); } } template:`<div><p @click="handleClick">{{msg}}</p></p><div>` } //子組件2 const childComponentTwo={ data:()=>({ msg:'我是子組件二', brotherMsg:'' }), mounted(){ this.$Bus.$on('sendMsg',data=>{ this.brotherMsg = data; }) }, beforeDestroy(){ this.$Bus.$off('sendMsg'); } template:`<div><p @click="handleClick">{{msg}}</p><p>{{brotherMsg}}</p><div>` } // 父級 new Vue({ el:'#app', data:{}, components:{ childComponent, childComponentTwo } }) </script>
4.1$attrs
和$listeners
若是父組件 A 下面有子組件 B,組件 B 下面有組件 C,這時若是組件 A 直接想傳遞數據給 組件 C,那就行不通了!因此,這時能夠使用$attrs
和$listeners
Vue 2.4 提供了$attrs
和$listeners
來實現可以直接讓 組件 A 傳遞消息給 組件 C
// 組件A Vue.component('A', { template: ` <div> <p>this is parent component!</p> <B :messagec="messagec" :message="message" v-on:getCData="getCData" v-on:getChildData="getChildData(message)"></B> </div> `, data() { return { message: 'hello', messagec: 'hello c' //傳遞給c組件的數據 } }, methods: { // 執行B子組件觸發的事件 getChildData(val) { console.log(`這是來自B組件的數據:${val}`); }, // 執行C子組件觸發的事件 getCData(val) { console.log(`這是來自C組件的數據:${val}`); } } }); // 組件B Vue.component('B', { template: ` <div> <input type="text" v-model="mymessage" @input="passData(mymessage)"> <!-- C組件中能直接觸發 getCData 的緣由在於:B組件調用 C組件時,使用 v-on 綁定了 $listeners 屬性 --> <!-- 經過v-bind 綁定 $attrs 屬性,C組件能夠直接獲取到 A組件中傳遞下來的 props(除了 B組件中 props聲明的) --> <C v-bind="$attrs" v-on="$listeners"></C> </div> `, /** * 獲得父組件傳遞過來的數據 * 這裏的定義最好是寫成數據校驗的形式,省得獲得的數據是咱們意料以外的 * * props: { * message: { * type: String, * default: '' * } * } * */ props: ['message'], data () { return { mymessage: this.message } }, methods: { passData(val){ //觸發父組件中的事件 this.$emit('getChildData', val) } } }); // 組件C Vue.component('C', { template: ` <div> <input type="text" v-model="$attrs.messagec" @input="passCData($attrs.messagec)"> </div> `, methods: { passCData(val) { // 觸發父組件A中的事件 this.$emit('getCData',val) } } }); var app = new Vue({ el:'#app', template: ` <div> <A /> </div> ` });
4.2provide
和inject
熟悉 React 開發的同窗對 Context API 確定不會陌生吧!在 Vue 中也提供了相似的 API 用於組件之間的通訊。在父組件中經過provide
來提供屬性,而後在子組件中經過inject
來注入變量。不論子組件有多深,只要調用了inject
,那麼就能夠注入在provide
中提供的數據,而不是侷限於只能從當前父組件的prop
屬性來獲取數據,只要在父組件的生命週期內,子組件均可以調用。這和 React 中的 Context API 有沒有很類似!
// 定義 parent 組件 Vue.component('parent', { template: ` <div> <p>this is parent component!</p> <child></child> </div> `, provide: { for:'test' }, data() { return { message: 'hello' } } }); // 定義 child 組件 Vue.component('child', { template: ` <div> <input type="tet" v-model="mymessage"> </div> `, inject: ['for'], // 獲得父組件傳遞過來的數據 data(){ return { mymessage: this.for } }, }); const app = new Vue({ el: '#app', template: ` <div> <parent /> </div> ` });
上面的實例中,定義了組件parent
和組件child
,組件parent
和 組件child
是父子關係。
parent
組件中,經過provide
屬性,以對象的形式向子孫組件暴露了一些屬性child
組件中,經過inject
屬性注入了parent
組件提供的數據,實際這些經過inject
注入的屬性是掛載到 Vue 實例上的,因此在組件內部能夠經過this
來訪問注意:
官網文檔說起 provide 和 inject 主要爲高階插件 / 組件庫提供用例,並不推薦直接用於應用程序代碼中。
4.3 Vuex 狀態管理
Vuex 是狀態管理工具,實現了項目狀態的集中式管理。工具的實現借鑑了 Flux、Redux 和 The Elm Architecture 的模式和概念。固然與其餘模式不一樣的是,Vuex 是專門爲 Vue.js 設計的狀態管理庫,以利用 Vue.js 的細粒度數據響應機制來進行高效的狀態更新。