1. 程式人生 > >vue學習筆記(九)vue-cli中的元件通訊

vue學習筆記(九)vue-cli中的元件通訊

前言

在上一篇部落格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專案的格式進行講解其它的知識