vue組件通訊分爲橫向和縱向。html
**縱向**vue
1. props 和 $emitnode
props:接收來自父組件的數據app
$emit:觸發事件ide
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script> // 全局組件 Vue.component('Parent', { data(){ return { msg: 'I am the data of Parent!', childToParentData: 'I am the data of Parent!', }; }, template: `<div> <p> I am the parent component!</p> <Child :childData="msg" @childHandler="handerFn"/> <p>childToParentData: {{childToParentData}}</p> </div>`, methods: { handerFn(val){ console.log(val); this.childToParentData = val; }, } }) Vue.component('Child', { data(){ return { msg: 'I am the data of Child!', inputVal: this.childData, }; }, props: ['childData'], template: `<div> <p> I am the child component!</p> <p>{{msg}}</p> <input v-model="inputVal" @input="changeVal(inputVal)" /> </div>`, methods: { changeVal(val){ // 經過 $emit 觸發,參數爲 事件名,參數 this.$emit('childHandler', val); } } }) var App = { template: `<div> <Parent /> </div>`, }; var vm = new Vue({ el: '#app', data(){ return { }; }, components: { App }, methods: { }, template: ` <App /> ` }) </script> <pre> 子組件向父組件傳值 一、自定義事件 二、子組件原生事件 三、原生事件的處理函數中經過$emit觸發自定義事件 注:子組件不能修改props中的值,不然報錯,可經過子組件本身的數據接收props中的值來解決 </pre> </body> </html>
2. $parent 和 $children函數
後代組件能夠經過$parent.$parent.$parent這種形式跨級通訊ui
父組件能夠經過$children[0].$children[0]這種形式跨級通訊,若是有多個子組件,索引很差控制this
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script> // 全局組件 Vue.component('Parent', { data(){ return { msg: 'I am the data of Parent!', grandToParent: '', }; }, template: `<div> <p> I am the parent component!</p> <input v-model="msg" @input="consoleFn"/> <p style="color: red;">{{grandToParent}}</p> <hr /> <Child/> </div>`, methods: { consoleFn(){ this.$children[0].parentMsg = this.msg; }, }, }) Vue.component('Child', { data(){ return { msg: 'I am the data of Child!', parentMsg: '', grandToChild: '', }; }, template: `<div> <p> I am the child component!</p> <p>{{msg}}</p> <button @click="consoleFn">attr</button> <p style="color: red;">{{parentMsg}}</p> <p style="color: red;">{{grandToChild}}</p> <hr /> <GrandChild /> </div>`, methods: { consoleFn(){ this.$children[0].childMsg = this.msg; }, }, }) Vue.component('GrandChild', { data(){ return { msg: 'I am the data of GrandChild!', childMsg: '', }; }, template: `<div> <p> I am the GrandChild component!</p> <p>{{msg}}</p> <button @click="consoleFn" >attr</button> <p style="color: red;">{{childMsg}}</p> <hr /> </div>`, methods: { consoleFn(){ this.$parent.grandToChild = this.msg; this.$parent.$parent.grandToParent = this.msg; }, }, }) var App = { template: `<div> <Parent /> </div>`, }; var vm = new Vue({ el: '#app', data(){ return { }; }, components: { App }, methods: { }, template: ` <App /> ` }) </script> <pre> $parent, $children, $root, $parent.$parent 非響應式,若是有多個直接子組件 </pre> </body> </html>
3. $attrs 和 $listenersspa
後代組件從$attrs獲取父組件傳給後代組件的數據component
後代組件經過$emit觸發$listeners的事件將數據傳給父組件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script> // 全局組件 Vue.component('Parent', { data(){ return { msg: 'I am the data of Parent!', childToParentData: 'I am the data of Parent!', }; }, template: `<div> <p> I am the parent component!</p> <p>childToParentData: {{childToParentData}}</p> <button @click="consoleFn">attr</button> <br /> <Child :parentMsg="msg" @childClick="parentHandler" v-bind="$attrs" v-on="$listeners"/> </div>`, // inheritAttr: false, methods: { consoleFn(){ console.log(this.$attrs); // {} console.log(this.$listeners); // {} }, parentHandler(data){ console.log(data); }, }, }) Vue.component('Child', { data(){ return { msg: 'I am the data of Child!', }; }, template: `<div> <p> I am the child component!</p> <p>{{msg}}</p> <button @click="consoleFn">attr</button> <br /> <GrandChild :childMsg="msg" @grandChildClick="childHandler" v-bind="$attrs" v-on="$listeners"/> </div>`, // inheritAttr: false, methods: { consoleFn(){ console.log(this.$attrs); // {parentMsg: } console.log(this.$listeners); //{childClick: } }, childHandler(data){ console.log(data); }, }, }) Vue.component('GrandChild', { data(){ return { msg: 'I am the data of GrandChild!', }; }, template: `<div> <p> I am the GrandChild component!</p> <p>{{msg}}</p> <button @click="consoleFn" >attr</button> <br /> </div>`, // inheritAttr: false, methods: { consoleFn(){ console.log(this.$attrs); // {parentMsg: , childMsg: } console.log(this.$listeners); //{childClick: , grandChildClick: } this.$emit('childClick', this.msg); // 若是不收集,$emit只能觸發其父級的事件 this.$emit('grandChildClick', this.msg); }, }, }) var App = { template: `<div> <Parent /> </div>`, }; var vm = new Vue({ el: '#app', data(){ return { }; }, components: { App }, methods: { }, template: ` <App /> ` }) </script> <pre> 一、$attrs收集屬性 二、$listeners收集事件 </pre> </body> </html>
4. provide 和 inject
父組件向後代組件單向傳遞數據
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script> // 全局組件 Vue.component('Parent', { data(){ return { msg: 'I am the data of Parent!', }; }, provide(){ return { parentMsg: this.msg, }; }, template: `<div> <p> I am the parent component!</p> <input v-model="msg"/> <!-- provide和inject綁定並非可響應的, 因此msg的變化不會影響後代組件中已經接收到的msg的值 --> <button @click="consoleFn">attr</button> <hr /> <Child/> </div>`, methods: { consoleFn(){ console.log(this); }, }, }) Vue.component('Child', { data(){ return { msg: 'I am the data of Child!', }; }, provide: { childMsg: 'I am the data of Child!', }, inject: ['parentMsg'], template: `<div> <p> I am the child component!</p> <p>{{msg}}</p> <button @click="consoleFn">attr</button> <p style="color: red;">{{parentMsg}}</p> <hr /> <GrandChild /> </div>`, methods: { consoleFn(){ console.log(this); }, }, }) Vue.component('GrandChild', { data(){ return { msg: 'I am the data of GrandChild!', }; }, inject: ['parentMsg', 'childMsg'], template: `<div> <p> I am the GrandChild component!</p> <p>{{msg}}</p> <button @click="consoleFn" >attr</button> <p style="color: red;">{{parentMsg}}</p> <p style="color: red;">{{childMsg}}</p> <hr /> </div>`, methods: { consoleFn(){ console.log(this); }, }, }) var App = { template: `<div> <Parent /> </div>`, }; var vm = new Vue({ el: '#app', data(){ return { }; }, components: { App }, methods: { }, template: ` <App /> ` }) </script> <pre> 單向 </pre> </body> </html>
**橫向**
1. 數據總線
用一箇中間變量保存數據
var bus = new Vue()
$on綁定事件
$emit觸發事件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script> var bus = new Vue(); // 全局組件 Vue.component('Parent', { data(){ return { msg: 'I am the data of Parent!', }; }, template: `<div> <p> I am the parent component!</p> <button @click="consoleFn">button</button> <br /> <BrotherOne /> <BrotherTwo /> </div>`, methods: { consoleFn(){ console.log(bus); }, }, }) Vue.component('BrotherOne', { data(){ return { msg: 'I am the data of BrotherOne!', fromBrother: '', }; }, template: `<div> <p> I am the BrotherOne component!</p> <p>{{msg}}</p> <input v-model="fromBrother" @input="transformData"/> <br /> </div>`, methods: { transformData(){ bus.$emit('globalBus', this.fromBrother); }, }, }) Vue.component('BrotherTwo', { data(){ return { msg: 'I am the data of BrotherTwo!', fromBrother: '', }; }, template: `<div> <p> I am the BrotherTwo component!</p> <p>{{msg}}</p> <p>fromBrother: {{fromBrother}}</p> <button @click="consoleFn" >button</button> <br /> </div>`, methods: { consoleFn(){ console.log(bus); }, }, mounted(){ bus.$on('globalBus', val => { this.fromBrother = val; }) } }) var App = { template: `<div> <Parent /> </div>`, }; var vm = new Vue({ el: '#app', data(){ return { }; }, components: { App }, methods: { }, template: ` <App /> ` }) </script> </body> </html>
var bus = {}
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <div id="app"> </div> <script src="./node_modules/vue/dist/vue.js"></script> <script> var bus = {}; // 全局組件 Vue.component('Parent', { data(){ return { msg: 'I am the data of Parent!', }; }, template: `<div> <p> I am the parent component!</p> <button @click="consoleFn">button</button> <br /> <BrotherOne /> <BrotherTwo /> </div>`, methods: { consoleFn(){ console.log(bus); }, }, }) Vue.component('BrotherOne', { data(){ return { msg: 'I am the data of BrotherOne!', fromBrother: '', }; }, template: `<div> <p> I am the BrotherOne component!</p> <p>{{msg}}</p> <input v-model="fromBrother" @input="transformData"/> <br /> </div>`, methods: { transformData(){ bus['brotherOne'] = { 'fromBrother': this.fromBrother, }; }, }, }) Vue.component('BrotherTwo', { data(){ return { msg: 'I am the data of BrotherTwo!', fromBrother: '', }; }, template: `<div> <p> I am the BrotherTwo component!</p> <p>{{msg}}</p> <p>fromBrother: {{fromBrother}}</p> <button @click="consoleFn" >button</button> <br /> </div>`, methods: { consoleFn(){ this.fromBrother = bus['brotherOne']['fromBrother']; }, }, }) var App = { template: `<div> <Parent /> </div>`, }; var vm = new Vue({ el: '#app', data(){ return { }; }, components: { App }, methods: { }, template: ` <App /> ` }) </script> </body> </html>