前言
在上一篇博客vue學習筆記(八)組件校驗&通信中,我們學會了vue中組件的校驗和父組件向子組件傳遞信息以及子組件通知父組件(父子組件通信),上一篇博客也提到那是對組件內容的剛剛開始,而本章博客將會重點的講解vue-cli中的組件通信,畢竟這在以后的開發內容中是非常普遍使用的。那么一起來看看本篇博客需要學習的知識點吧!
本章目標
-
學會使用vue-cli中父組件向子組件傳遞信息
-
學會使用vue-cli中子組件向父組件傳遞信息
-
學會使用vue-cli中非父子組件傳遞信息
vue-cli中的父組件向子組件傳遞信息
既然提到要使用vue-cli實現組件通信,那么肯定要有vue-cli的環境,沒有搭建vue-cli環境的園友可以參考這篇博客使用webstorm搭建vue-cli項目,這篇博客講解的非常透徹,大家可以先將環境搭建好,然后再來看這篇博客,假設我們項目搭建好了,項目目錄結構如下
(1)創建兩個組件父組件和子組件
我們需要在src/components/parent/創建兩個組件ParentComponent.vue和ChildComponent.vue,創建好之后目錄如下
(2)分別在對應的組件中編寫代碼
ParentComponent.vue
<template> <div> <h1>{{title}}</h1> <!--注意:每個組件注冊必須有一個根元素--> <Child :message="message"></Child> </div> </template> <script> import Child from './ChildComponent' export default { name: "ParentComponent", data() { return { title:'這是父組件', message: '我是父組件' } }, components:{ Child } } </script> <style scoped> </style>
首先在父組件中定義兩個數據title和message,message是要傳遞給子組件的信息,第二步導入子組件和注冊子組件,第三步將需要傳遞的信息綁定到組件上。
總結
- 定義數據
- 導入組件和注冊組件
- 數據綁定到組件上
ChildComponent.vue
<template> <div> <!--注意每個組件注冊必須有一個根元素--> <h1>{{title}}</h1> <span>父組件傳遞過來的消息是:{{message}}</span> </div> </template> <script> export default { name: "ChildComponent", props:['message'], //使用props接收父組件傳遞的信息 data(){ return{ title:'這是子組件', } } } </script> <style scoped> </style>
在子組件中我們使用props來接收父組件傳遞過來的信息,然后進行渲染數據就可以了。
index.vue
import Vue from 'vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' import Hi from '@/components/Test/Hi' import parent from '@/components/parent/ParentComponent' Vue.use(Router) export default new Router({ routes: [ { path:'/', component:parent, name:parent } ] })
結果:
講到這里使用vue-cli實現父組件向子組件傳遞信息我就講解完了,接下來實現子組件向父組件傳遞信息。
vue-cli中的子組件向父組件傳遞信息
學會了父組件向子組件傳遞信息,接下來就要學習子組件向父組件傳遞信息,同樣我們還是使用如上的兩個組件,更新之后的代碼
ParentComponent.vue
<template> <div> <h1>{{title}}</h1> <!--注意:每個組件注冊必須有一個根元素--> <Child :message="message" @send="getChildMsg"></Child> <h1>來自子組件的消息:{{childMsg}}</h1> </div> </template> <script> import Child from './ChildComponent' export default { name: "ParentComponent", data() { return { title:'這是父組件', message: '我是父組件', childMsg:'' } }, components:{ Child }, methods:{ getChildMsg(data){ this.childMsg=data; } } } </script> <style scoped> </style>
父組件中我們重新定義了一個新的屬性(childMsg)來接收子組件傳遞過來的消息,可以知道子組件向父組件傳遞的事件是send,然后調用send來接收子組件傳遞過來的數據
ChildComponent.vue
<template> <div> <!--注意每個組件注冊必須有一個根元素--> <h1>{{title}}</h1> <span>父組件傳遞過來的消息是:{{message}}</span> <input type="button" value="向父組件傳遞信息" @click="sendMsgToParent"> </div> </template> <script> export default { name: "ChildComponent", props:['message'], //使用props接收父組件傳遞的信息 data(){ return{ title:'這是子組件', fromChildMsg:'我是來自子組件的消息', } }, methods:{ sendMsgToParent(){ this.$emit('send',this.fromChildMsg); } } } </script> <style scoped> </style>
子組件中也是重新定義了一個新的屬性(fromChildMsg),這個屬性是需要傳遞給父組件的,然后通過按鈕的點擊事件使用this.$emit()將事件名稱和數據傳遞給父組件,父組件注冊send方法之后就可以接收到子組件傳遞過來的消息了
結果:
講到這里父組件向子組件傳遞信息和子組件向父組件傳遞消息就全部講解完了,可以說是講解的非常詳細,每一步我寫的都是非常清楚
總結:
- 父組件向子組件傳遞信息通過props
- 子組件向父組件傳遞信息通過this.$emit(‘事件名稱’,值1,值2,....)
vue-cli中的非父子組件傳遞信息
在組件通信中除了有父組件向子組件傳遞信息和子組件向父組件傳遞信息,還有非父子組件通信,同樣我也會講解的非常詳細。
(1)新建目錄用於非父子組件通信
在src/components新建other目錄和兩個組件分別:BrotherComponent.vue,SisterComponent.vue,以及在src/assets下創建一個event.js文件,創建之后的目錄如下
(2)event.js充當總線
event.js這個文件中我們只創建了一個新的Vue實例,以后它就承擔起了組件之間通信的用來充當總線橋梁了,也就是中央事件總線,為的就是將BrotherComponent.vue和SisterComponent.vue聯系起來。
event.js
//方式一 import Vue from 'Vue' export default new Vue /*方式二 let bus=new Vue export default bus */
BrotherComponent.vue
<template> <div> <h1>兄弟組件</h1> <input type="button" @click="sendMsg" value="向姐妹組件傳遞信息"> <sister></sister> </div> </template> <script> //導入總線 import bus from '../../assets/event' //導入姐妹組件 import sister from './SisterComponent' export default { name: "BrotherComponent", data(){ return{ tips:'I am your brother' } }, components:{ sister //注冊界面組件 }, methods:{ sendMsg(){ bus.$emit('send',this.tips); } } } </script> <style scoped> </style>
在這個組件中首先是導入的總線和姐妹組件,然后注冊了姐妹組件,我們在響應點擊事件的sendMsg函數中用$emit觸發了一個自定義的send事件,並傳遞了一個字符串參數,
這個參數就是需要傳遞個姐妹組件的值。$emit實例方法觸發當前實例(這里的當前實例就是bus)上的事件,附加參數都會傳給監聽器回調
SisterComponent.vue
<template> <div> <h1>姐妹組件</h1> <span>{{msg}}</span> </div> </template> <script> import bus from '../../assets/event' export default { name: "SisterComponent", data(){ return{ msg:'' } }, methods:{ getMsg(){ bus.$on('send',data=>{ this.msg=data; }) } }, mounted(){ this.getMsg(); } } </script> <style scoped> </style>
在這個組件中,我們在mounted中,監聽了send,並把傳遞過來的字符串參數傳遞給了$on監聽器的回調函數,mounted:是一個Vue生命周期中的鈎子函數,簡單點說就類似於jquery的ready,Vue會在文檔加載完畢后調用mounted函數,$on:監聽當前實例上的自定義事件(此處當前實例為bus)。事件可以由$emit觸發,回調函數會接收所有傳入事件觸發函數($emit)的額外參數
index.js
import Vue from 'vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' import Hi from '@/components/Test/Hi' import parent from '@/components/parent/ParentComponent' import brother from '@/components/other/BrotherComponent' Vue.use(Router) export default new Router({ routes: [ { path:'/', component:brother, name:brother } ] })
結果
總結:
- 創建一個事件總線,例如示例中event.js,用它作為通信橋梁
- 在需要傳值的組件中用bus.$emit觸發一個自定義事件,並傳遞參數
- 在需要接收數據的組件中用bus.$on監聽自定義事件,並在回調函數中處理傳遞過來的參數
講到這里組件基本通信方式的已經講解完成了,之后等學習了更高級的內容之后再補充新的組件通信的方式,一共講解了三種通信方式,分別是父組件向子組件傳遞信息,子組件向父組件傳遞信息,非父子組件傳遞信息。內容不多講解的也十分詳細,那么為了鞏固組件的知識下面也會講解一些示例。
綜合練習
普通版任務清單
這個版本的任務清單在上一篇博客中已經講解過了,為什么在這里又要重新提到呢?博主覺得上一篇博客沒有講解的很詳細,而且本篇博客也是還有其它版本的任務清單,所以將這兩個結合起來,學習起來也比較方便。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>普通版任務清單</title> </head> <body> <div id="app"> <input type="text" v-model="newTask" @keyup.enter="addNew" placeholder="請輸入你要完成的任務"/> <todo-item v-for="(item,index) of tasks" :title='item' :index="index" @remove="removeItem"></todo-item> </div> <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> let vm=new Vue({ el:'#app', data:{ newTask:'', tasks:['看一場電影','讀一本書','請朋友吃一頓飯'], }, methods:{ addNew(){ this.tasks.unshift(this.newTask);//向任務清單的最前面添加任務 this.newTask=''; //清空文本框中的內容 }, removeItem(index){ if(confirm('你確定要刪除嗎?')){ this.tasks.splice(index); } } }, computed:{ }, components:{ 'todoItem':{ props:['title',"index"], template:'<li><span>{{title}}</span><button @click="sendMsg(index)">X</button></li>', methods:{ sendMsg(index){ console.log(index); this.$emit('remove',index); } } } } }) </script> </body> </html>
步驟分析:
- 1.定義好要添加的任務(newTask)和全部的任務清單(tasks),按下enter鍵的時候向任務清單添加一條任務,
- 2.定義好任務列表清單組件,然后將任務列表和索引傳遞進去
- 3.定義好子組件通知父組件的事件this.$emite('remove',index)
- 4.父組件接收到子組件通知的事件和下標索引,然后做出相應的處理
vue-cli版任務清單
普通版的任務清單我們就結束了,接下來需要實現的是vue-cli中的任務清單,這個任務清單和普通版的沒有多大區別,只不過是換了一種寫法,原理還是沒有改變的(換湯不換葯),那么跟隨我一起來瞧瞧吧!
1.新建目錄和組件
在src/components下新建taks目錄和ParentComponent.vue和ChildComponent.vue兩個組件,建立之后的目錄如下
2.對應的組件中編寫代碼
ParentComponent.vue
<template> <div> <h1>這是父組件</h1> <input type="text" v-model="newTask" @keyup.enter="addNew" placeholder="請輸入你要添加的任務"> <child v-for="(item,index) of tasks" :item="item" :index="index" @remove="removeItem" :key="index"></child> </div> </template> <script> import Child from './ChildComponent' export default { name: "ParentComponent", components:{ Child //注冊子組件 }, data(){ return{ newTask:'', tasks:['買一本書','看一場電影','寫一篇博客'], } }, methods:{ addNew(){ this.tasks.unshift(this.newTask); this.newTask=""; }, removeItem(index){ //刪除任務 if(confirm('你確定要刪除嗎?')){ this.tasks.splice(index); } } } } </script> <style scoped> </style>
- 父組件中首先導入子組件和注冊子組件,然后定義要添加的任務清單(newTask)和全部的任務清單列表(tasks),輸入框中addNew方法是當我們按下enter鍵時向tasks添加一條新的任務清單。
- 注冊好子組件之后,將任務清單項和每一條任務清單項的索引傳遞給子組件。
- 父組件接收子組件通知的方法(remove),然后對任務清單做出相應的處理。
ChildComponent.vue
<template> <div> <li>{{item}}<button @click="sendMsg(index)">X</button></li> </div> </template> <script> export default { name: "ChildComponent", props:['item','index'], data(){ return{ } }, methods:{ sendMsg(index){ this.$emit('remove',index); } } } </script> <style scoped> </style>
- 在子組件中,首先使用props接收父組件傳遞過來的兩個參數item,index。
- 定義一個通知父組件的方法,告訴父組件需要刪除那個任務清單。
index.js
import Vue from 'vue' import Router from 'vue-router' import parent from '@/components/task/ParentComponent' Vue.use(Router) export default new Router({ routes: [ { path:'/', component:parent, name:parent } ] })
vue-cli版本的任務清單我們也就完成了,總之換湯不換葯,還是那句老話,父組件向子組件傳遞信息使用props,子組件向父組件傳遞信息使用this.$emit('事件名稱',值1,值2,...)
普通版蜀國交稅
這個案例和之前的也差不多,原理還是一樣的,那么一起來看看吧!
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>普通版蜀國交稅</title> </head> <body> <div id="app"> <h2>{{name}}</h2> <h3>總數:{{total}}</h3> <me-tax @tax="undateTotal" name="趙雲" :unit="unit"></me-tax> <me-tax @tax="undateTotal" name="馬超" :unit="unit"></me-tax> <me-tax @tax="undateTotal" name="張飛" :unit="unit"></me-tax> <me-tax @tax="undateTotal" name="關羽" :unit="unit"></me-tax> <me-tax @tax="undateTotal" name="黃忠" :unit="unit"></me-tax> <h3>{{msg}}</h3> </div> <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> Vue.component('me-tax',{ template:'<button @click="upTax">{{money}}</button>', data(){ return{ money:0, } }, props:['name','unit'], methods:{ upTax(){ this.money+=this.unit; //稅收總和 this.$emit('tax',{name:this.name,money:this.money});// 通知父組件 } } }) let vm=new Vue({ el:'#app', data:{ name:'蜀國交稅', total:0, unit:10, //每次交稅的量 msg:'' }, methods:{ undateTotal(obj){ this.total+=this.unit; this.msg=obj.name+"交稅成功,已交稅"+obj.money; } }, computed:{ } }) </script> </body> </html>
結果
思路分析:
- 父組件中定義好交稅的總和(total)和每次交稅的數量(unit)
- 定義好子組件,接收父組件傳遞過來的兩個參數name和unit,定義一個計算自己交稅的總量和通知父組件的方法tax
- 父組件接收到子組件的通知之后,計算所交稅的總和,並顯示那位蜀將交的稅收
vue-cli版蜀國交稅
vue-cli版的蜀國交稅的話,我們同樣按照步驟進行,一步一步來解析
(1)新建目錄和定義六個組件
在src/components新建money目錄和UnitTotalComponent.vue,UnitComponentA.vue,UnitComponentB.vue,UnitComponentC.vue,UnitComponentD.vue,UnitComponentE.vue六個組件,目錄結構如下
在這里我們將組件拆分了,上面是復制同樣的組件,而這里是一個文件對應一個組件
(2)在對應的組件中編寫代碼
UnitTotalComponent.vue
<template> <div> <h1>{{name}}</h1> <h3>總交稅:{{total}}</h3> <A title="張飛" :unit="unit" @tax="updateTotal"></A> <B title="關羽" :unit="unit" @tax="updateTotal"></B> <C title="馬超" :unit="unit" @tax="updateTotal"></C> <D title="趙雲" :unit="unit" @tax="updateTotal"></D> <E title="黃忠" :unit="unit" @tax="updateTotal"></E> <h3>{{msg}}</h3> </div> </template> <script> //導入相應的組件 import A from './UnitComponentA' import B from './UnitComponentB' import C from './UnitComponentC' import D from './UnitComponentD' import E from './UnitComponentE' export default { name: "UnitTotalComponent", data(){ return{ name:'蜀國交稅', total:0, unit:10, //每次交稅的量 msg:'' } }, components:{ //注冊組件 A, B, C, D, E }, methods:{ updateTotal(obj){ this.total+=this.unit; this.msg=obj.name+'交稅成功,已交稅'+obj.money; } } } </script> <style scoped> </style>
- UnitTotalComponent組件中首先導入了五個組件以及注冊了這五個組件
- 定義需要傳遞的數數據(每次交稅的量unit)
- 根據每個子組件通知的方法將所交的稅計算總和,並顯示哪位蜀將
UnitComponentA.vue
<template> <div> <button @click="upTax">{{money}}</button> </div> </template> <script> export default { name: "UnitComponentA", props:['title','unit'], methods:{ upTax(){ this.money+=this.unit; this.$emit('tax',{name:this.title,money:this.money}); } }, data(){ return{ money:0, } } } </script> <style scoped> </style>
- UnitComponentA組件接收父組件傳遞過來的兩個屬性title和unit
- 定義好通知父組件的方法tax,將參數和方法傳過去
UnitComponentB.vue
<template> <div> <button @click="upTax">{{money}}</button> </div> </template> <script> export default { name: "UnitComponentB", props:['title','unit'], methods:{ upTax(){ this.money+=this.unit; this.$emit('tax',{name:this.title,money:this.money}); } }, data(){ return{ money:0, } } } </script> <style scoped> </style>
- UnitComponentB組件接收父組件傳遞過來的兩個屬性title和unit
- 定義好通知父組件的方法tax,將參數和方法傳過去
UnitComponentC.vue
<template> <div> <button @click="upTax">{{money}}</button> </div> </template> <script> export default { name: "UnitComponentC", props:['title','unit'], methods:{ upTax(){ this.money+=this.unit; this.$emit('tax',{name:this.title,money:this.money}); } }, data(){ return{ money:0, } } } </script> <style scoped> </style>
- UnitComponentC組件接收父組件傳遞過來的兩個屬性title和unit
- 定義好通知父組件的方法tax,將參數和方法傳過去
UnitComponentD.vue
<template> <div> <button @click="upTax">{{money}}</button> </div> </template> <script> export default { name: "UnitComponentD", props:['title','unit'], methods:{ upTax(){ this.money+=this.unit; this.$emit('tax',{name:this.title,money:this.money}); } }, data(){ return{ money:0, } } } </script> <style scoped> </style>
- UnitComponentD組件接收父組件傳遞過來的兩個屬性title和unit
- 定義好通知父組件的方法tax,將參數和方法傳過去
UnitComponentE.vue
<template> <div> <button @click="upTax">{{money}}</button> </div> </template> <script> export default { name: "UnitComponentE", props:['title','unit'], methods:{ upTax(){ this.money+=this.unit; this.$emit('tax',{name:this.title,money:this.money}); } }, data(){ return{ money:0, } } } </script> <style scoped> </style>
- UnitComponentE組件接收父組件傳遞過來的兩個屬性title和unit
- 定義好通知父組件的方法tax,將參數和方法傳過去
index.js
import Vue from 'vue' import Router from 'vue-router' import total from '@/components/money/UnitTotalComponent' Vue.use(Router) export default new Router({ routes: [ { path:'/', component:total, name:total } ] })
結果
vue的組件通信到這里就要告一段落了,該講解的知識點也講解完成了,反正這篇博客你反復去看總會有收獲的。學習起來並不難,任務清單和蜀國交稅這兩個案例將所學的組件通信結合了起來,學習起來也非常方便。
總結
本篇博客主要講解了三個知識點,父組件向子組件傳遞信息,子組件向父組件傳遞信息,非父子組件通信,父組件向子組件傳遞信息主要是通過props進行數據傳遞,子組件向父組件傳遞信息主要是通過this.$emit('事件名',值1,值2,...),非父子組件通信,先建立中央通信總線,傳遞數據的一方使用bus.$emit(),接收數據的一方使用bus.$on(),本篇博客已經將組件通信這一方面的知識講解的非常透徹,后期所有的博客幾乎都會圍繞vue-cli項目的格式進行講解其它的知識點。