Vue從甜小白到皮大佬系列(六) 組件通訊

閱讀時間預估:8分鐘前端

組件之間通訊是Vue中最經常使用,最基礎的部分,一般組件以前的通訊分爲如下幾種:vue

  • 1.父組件給子組件傳遞值,傳遞事件
  • 2.子組件給父組件傳遞值,傳遞事件
  • 3.兄弟組件之間傳遞值,傳遞事件

方法1、props $emit v-on

1.父組件給子組件傳值

父組件A經過props向子組件B通訊git

接下來咱們經過一個例子來加深以上理解:程序員

自定義一個Son.vue子組件,引入到父組件中 在父組件中定義一個數據github

<template>
    <div id="app">
        <!-- 前者自定義名稱便於子組件調用,後者要傳遞數據名 -->
        <son v-bind:user="user"></son>  
    </div>
</template>
複製代碼
<script>
import Son from './components/Son'

export default {
    name: 'app',
    components: {
        Son,
    },
    data () {
        return { // 父組件定義數據,傳遞給子組件
            user: ["james", "alice", "joho"]
        }
    },
  }
</script>
    
複製代碼

子組件中經過prop來定義父組件傳值的值類型,是不是必須以及默認值vuex

<script>
export default {
    components: {

    },
    data () {
        return {

        };
    },
    computed: {

    },
    methods: {
    },
    props: {
        user: { //這個就是父組件中子標籤自定義名字
            type: Array,
            required: true,
            default: []
        }
    },
}
</script>
複製代碼

而後在適當的位置將父組件傳遞過來的數據進行渲染npm

<template>
    <div>
        <ul>
            <li v-for="(item,index) in user"
                :key="index">姓名:{{item}}</li>
        </ul>

    </div>
</template>
複製代碼

瀏覽器打開會顯示user裏面的值.瀏覽器

總結:父組件經過props向下傳遞數據給子組件。注:組件中的數據共有三種形式:data、props、computedbash

2.子組件向父組件傳值(經過自定義事件形式)

核心點app

  • 1.子組件使用this.$emit('fn',param)向父組件傳值

  • 2.父組件經過v-on:fn="fn"來接受子組件傳遞過來的值

子組件中:

子組件包含一個點擊事件

// 定義一個點擊事件
 <son v-bind:user="user"
             @titleChange="changeTitle">
</son>
複製代碼

在點擊事件中經過this.$emit()來傳遞事件

<script>
//import x from ''
export default {
    components: {

    },
    data () {
        return {
            title: '我是子組件',
            toParentData: '我是子組件傳遞的數據'
        };
    },
    computed: {

    },
    methods: {
        btnClick () {
            this.$emit('titleChange', this.toParentData);
        }
    },
    }
</script>

複製代碼

父組件中: 經過v-on來接受子組件發出的事件名稱:titleChange而且和本身的changeTitle事件綁定

<template>
    <div id="app">
        <!-- 前者自定義名稱便於子組件調用,後者要傳遞數據名 -->
        <son v-bind:user="user"
             v-on:titleChange="changeTitle"></son>
        <p>{{msg}}</p>
    </div>
</template>
複製代碼

實現changeTitle方法,改變data中的msg數據

<script>
import Son from './components/Son'

export default {
    name: 'app',
    components: {
        Son,
    },
    data () {
        return {
            user: ["james", "alice", "joho"],
            msg: '我是父組件顯示的內容'
        }
    },
    methods: {
        changeTitle (title) {
            this.msg = title;
        }
    }
}
</script>
複製代碼

總結:子組件經過events給父組件發送消息,實際上就是子組件把本身的數據發送到父組件。

方法二 中央事件總線 Bus 進行通訊

發現了一個問題,若是孫子組件給爺爺組件傳值,經過props或者$emit方式是一件很痛苦的事情,須要經過中間的爸爸來作銜接,這樣通訊顯然會使得組件耦合,同時兄弟組件間的通訊props,$emit也實現不了?那麼問題來了,如何解決呢?

這裏介紹中央事件總線的方式,名字高大上其實就是抽一個公共Vue實例媒介來管理,須要通訊的組件都引入Bus,以後經過分別觸發和監聽 Bus 事件,進而實現組件之間的通訊和參數傳遞.

  • 1.首先建 Vue 實例做爲總線:
// Bus.js
import Vue from 'vue'
export default new Vue;
複製代碼
  • 2.須要通訊的組件都引入 Bus.js,使用 $emit發送信息:
// ComponentA.vue
<template>
  <div>
    <b>組件A:</b><button @click="handleBus">傳遞數值給須要的組件</button>
  </div>
</template>

<script>
  import Bus from './bus.js' 
  export default {
    methods: {
      handleBus () {
        Bus.$emit('someBusMessage','來自ComponentA的數據')
      }
    }
  }
</script>
複製代碼
  • 3.須要組件A信息的就使用$on來監聽:
// ComponentB.vue
<template>
  <div>
    <b>組件B:</b><button @click="handleBus">接收組件A的信息</button>
    <p>{{message}}</p>
  </div>
</template>

<script>
  import Bus from './bus.js' 
  export default {
    data() {
      return {
        message: ''
      }
    },
    created () {
      let that = this // 保存當前對象的做用域this
      Bus.$on('someBusMessage',function (data) {
        that.message = data
      })
    },
    beforeDestroy () {
      // 手動銷燬 $on 事件,防止屢次觸發
      Bus.$off('someBusMessage', this.someBusMessage)
    }
  }
</script>
複製代碼

中央總線優勢:能夠解耦組件,方便兄弟間通訊

方法三 $parent / $children & $refs

  • $parent / $children:指定已建立的實例,在二者之間創建父子關係。子實例能夠用 this.$parent 訪問父實例,子實例被推入父實例的 $children 中。

  • $refs:一個對象,持有註冊過 ref特性的全部 DOM 元素和組件實例。ref 被用來給元素或子組件註冊引用信息。引用信息將會註冊在父組件的 $refs 對象上。

  • 若是在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;若是用在子組件上,引用就指向組件。

父組件

<template>
    <div id="app">
        <!-- 前者自定義名稱便於子組件調用,後者要傳遞數據名 -->
        <p>{{msg}}</p>
        <child-one ref="childOne"></child-one>
        <child-two ref="childTwo"></child-two>
        <button @click="oneContent">顯示child-one傳過來的數據</button>
        <button @click="twoOneContent">顯示hild-two傳過來的數據</button>

    </div>
</template>

<script>
// 引入子組件
import ChildOne from './components/ChildOne'
import ChildTwo from './components/ChildTwo'
export default {
    name: 'app',
    components: {
        ChildOne,
        ChildTwo
    },
    data () {
        return {
            msg: '我是父組件',
            content: 'James' //子組件要用的數據
        }
    },
    methods: {
        // button 的事件響應 
        oneContent () {
            const childOne = this.$refs.childOne;
            this.msg = childOne.msg;
        },
        twoOneContent () {
            // 經過$refs取到childTwo
            const childTwo = this.$refs.childTwo;
            this.msg = childTwo.msg;
        }
    },
}
</script>
複製代碼

子組件1

<template>
    <div>
        <p>{{title}} 個人父組件是{{content}}</p>
    </div>
</template>

<script>
//import x from ''
export default {
    components: {
    },
    data () {
        return {
            content: '',
            title: '我是子組件 childOne',
            msg: '我只子組件childOne hello ereryOne'
        };
    },
    mounted () {
        // 從父組件裏取contet的數據
        this.content = this.$parent.content;
    },
}
</script>
複製代碼

子組件2:

<template>
    <div>
        <p>{{title}} 個人父組件是{{content}}</p>
    </div>
</template>

<script>
//import x from ''
export default {
    data () {
        return {
            content: '',
            title: '我是子組件 childTwo',
            msg: '我是子組件childTwo hello ereryOne'
        };
    },
    mounted () {
        // 加載父組件content的內容
        this.content = this.$parent.content;
    },
}
</script>
複製代碼

方法四: 發佈訂閱模式

官方GitHub

  • 1.經過npm i pubsub --save的方式引入pubsub庫
  • 2.建立event-type.js定義Symbol類型的數據並導出
// event-types.js
export const MY_TOPIC = Symbol('MY_TOPIC')
複製代碼
  • 3.在須要發佈(傳遞事件)的地方引入pubsubevent=type.js,而且經過如下方式發佈事件
import PubSub from 'pubsub'
import { MY_TOPIC } from './event-types.js'
PubSub.publish(MY_TOPIC, 'world');

複製代碼
  • 4.在須要訂閱(接受事件)的地方引入pubsubevent=type.js,而且經過如下方式接受事件
import PubSub from 'pubsub'
import { MY_TOPIC } from './event-types.js'
PubSub.subscribe(MY_TOPIC, function (msg, data) {
	console.log(data)
});
複製代碼

方法五 Vuex

官方傳送門

Vuex 是Vue官方推薦的一種解決組件中通訊的完美解決方案,也是在項目開發中必用的方案:

點我學習Vuex

認真看完本篇後對照思惟導圖能夠在腦海裏回顧一遍哦,對此塊的知識點你會有更深的認識和理解.

Vue組件思惟導圖

若是個人分享對面前的這位大俠有所啓發,請不要吝嗇手中大拇指,以程序員最高禮遇點贊✨ 評論加分享的方式鼓勵我持續分享,也歡迎各位大佬勘誤,提出寶貴意見.

關注公衆號回覆:學習 領取前端最新最全學習資料,也能夠進羣和大佬一塊兒學習交流

猛戳 個人前端進階Blog
相關文章
相關標籤/搜索