日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > vue >内容正文

vue

Vue实现组件间通信的七种方式

發(fā)布時間:2023/12/29 vue 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Vue实现组件间通信的七种方式 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1.?props / $emit

父組件通過props的方式向子組件傳遞數(shù)據(jù),而通過$emit?子組件可以向父組件通信:

  • 父傳子:父組件通過import引入子組件,并注冊,在子組件標(biāo)簽上添加要傳遞的屬性,子組 件通過props接收,接收有兩種形式一是通過數(shù)組形式[‘要接收的屬性’ ],二是通過對象形式{ }
  • 子傳父:父組件向子組件傳遞事件方法,子組件通過$emit觸發(fā)事件,回調(diào)給父組件

props的特點:

  • props只能是父組件向子組件進(jìn)行傳值,props使得父子組件之間形成一個單向的下行綁定。子組件的數(shù)據(jù)會隨著父組件的更新而響應(yīng)式更新;但是子組件無法引起父組件的數(shù)據(jù)更新。
  • props可以顯示定義一個或一個以上的數(shù)據(jù),對于接收的數(shù)據(jù),可以是各種數(shù)據(jù)類型,同樣也可以是傳遞一個對象或函數(shù)。
  • props屬性名規(guī)則:若在props中使用駝峰形式,模板中標(biāo)簽需要使用短橫線的形式來書寫。

?代碼示例:

父傳子(prop的用法)

父組件:

<template><div id="father"><son :msg="msg" :fn="myFunc"></son></div> </template><script> import son from "./son.vue"; export default {name: "father",components: {son},data() {msg: "我是父組件";},methods: {myFunc() {console.log("我是父組件的方法");}} }; </script>

子組件:

<template><div id="son"><p>{{msg}}</p><button @click="fn">按鈕</button></div> </template> <script> export default {name: "son",props: ["msg", "fn"] }; </script>

子傳父($emit的用法)

$emit 綁定一個自定義事件,當(dāng)這個事件被執(zhí)行的時候就會將參數(shù)傳遞給父組件,而父組件通過v-on監(jiān)聽并接收參數(shù)

父組件:

<template><div id="father"><son :arrList="arrList" @changeIndex="changeIndex"></son><p>{{currentIndex}}</p></div> </template><script> import son from './son.vue' export default {name: 'father',components: { son},data() {return {currentIndex: -1,arrList: ['龍族', '繪梨衣', '前端','后端']}},methods: {changeIndex(index) {this.currentIndex = index}} } </script>

子組件:

<template><div><div v-for="(item, index) in arrList" :key="index" @click="emitIndex(index)">{{item}}</div></div> </template><script> export default {props: ['arrList'],methods: {emitIndex(index) {this.$emit('changeIndex', index) // 觸發(fā)父組件的方法,并傳遞參數(shù)index}} } </script>

2.ref / $refs

ref:這個屬性用在子組件上,它的引用就指向了該子組件的實例,可以通過實例來訪問組件的數(shù)據(jù)和方法;如果在普通的 DOM 元素上使用,引用指向的就是 DOM元素。

父組件:

<template><child ref="child"></component-a> </template> <script>import child from './child.vue'export default {components: { child },mounted () {console.log(this.$refs.child.name); // mySonthis.$refs.child.sayHello(); // Hello father!}} </script>

子組件:

<template><div id="app"></div> </template> <script> export default {name:'child',data () {return {name: 'mySon'}},methods: {sayHello () {console.log('Hello father!')}} } </script>

3.eventBus(事件總線)

其原理就是:事件訂閱發(fā)布,eventBus?又稱為事件總線,在vue中可以使用它來作為溝通橋梁的概念, 就像是所有組件共用相同的事件中心,可以向該中心注冊發(fā)送事件或接收事件, 所以組件都可以通知其他組件。

使用步驟如下:

(1)創(chuàng)建事件中心管理組件之間的通信

// event-bus.jsimport Vue from 'vue' export const EventBus = new Vue()

(2)發(fā)送事件 假設(shè)有兩個兄弟組件firstCom和secondCom:

firstCom和secondCom的父組件:

<template><div><first-com></first-com><second-com></second-com></div> </template><script> import firstCom from './firstCom.vue' import secondCom from './secondCom.vue' export default {components: { firstCom, secondCom } } </script>

在firstCom組件中發(fā)送事件:

<template><div><button @click="add">點擊增加</button> </div> </template><script> import {EventBus} from './event-bus.js' // 引入事件中心export default {data(){return{num:0}},methods:{add(){EventBus.$emit('addition', {num:this.num++})}} } </script>

(3)接收事件

在secondCom組件中接收事件:

<template><div>求和: {{count}}</div> </template><script> import { EventBus } from './event-bus.js' export default {data() {return {count: 0}},mounted() {EventBus.$on('addition', param => {this.count = this.count + param.num;})} } </script>

在上述代碼中,這就相當(dāng)于將num值存貯在了事件總線中,在其他組件中可以直接訪問。事件總線就相當(dāng)于一個橋梁,不用組件通過它來通信。雖然看起來比較簡單,但是這種方法也有不變之處,如果項目過大,使用這種方式進(jìn)行通信,后期維護起來會很困難。

4.Vuex

Vuex 是一個專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。它采用集中式存儲管理應(yīng)用的所有組件的狀態(tài),并以相應(yīng)的規(guī)則保證狀態(tài)以一種可預(yù)測的方式發(fā)生變化.

Vuex 解決了多個視圖依賴于同一狀態(tài)和來自不同視圖的行為需要變更同一狀態(tài)的問題,將開發(fā)者的精力聚焦于數(shù)據(jù)的更新而不是數(shù)據(jù)在組件之間的傳遞上

Vuex各個模塊:

  • state:用于數(shù)據(jù)的存儲,是store中的唯一數(shù)據(jù)源
  • getters:如vue中的計算屬性一樣,基于state數(shù)據(jù)的二次包裝,常用于數(shù)據(jù)的篩選和多個數(shù)據(jù)的相關(guān)性計算
  • mutations:類似函數(shù),改變state數(shù)據(jù)的唯一途徑,且不能用于處理異步事件
  • actions:類似于mutation,用于提交mutation來改變狀態(tài),而不直接變更狀態(tài),可以包含任意異步操作
  • modules:類似于命名空間,用于項目中將各個模塊的狀態(tài)分開定義和操作,便于維護

Vuex使用步驟:

(1)這里我們先新建 store文件夾, 對Vuex進(jìn)行一些封裝處理

在 store 文件夾下添加 index.js 文件

// index.js// 自動掛載指定目錄下的store import Vue from 'vue' import Vuex from 'vuex'Vue.use(Vuex)let modules = {}// @/store/module 目錄下的文件自動掛載為 store 模塊 const subModuleList = require.context('@/store/modules', false, /.js$/) subModuleList.keys().forEach(subRouter => {const moduleName = subRouter.substring(2, subRouter.length - 3)modules[moduleName] = subModuleList(subRouter).default }) //也可自己手動掛載(自行選擇)export default new Vuex.Store({state: {},mutations: {},actions: {},modules })

(2)在 store 文件夾下添加?module?文件夾,在module文件夾再新建?user.js?文件

// user.jsimport user from '@/utils/user.js' import userApi from '@/apis/user' import { OPEN_ACCOUNT_STAGE, STAGE_STATUS } from '@/constant'let getUserPromise = nullexport default {namespaced: true,state() {return {userInfo: null, // 用戶信息isLogined: !!user.getToken(), // 是否已經(jīng)登錄}},mutations: {// 更新用戶信息updateUser(state, payload) {state.isLogined = !!payloadstate.userInfo = payload},},actions: {// 獲取當(dāng)前用戶信息getUserInfo(context, payload) {//相關(guān)代碼},// 登出logout(context, payload = {}) {// 是否手動退出const { manual } = payloadif (manual) {await userApi.postLogout()}user.clearToken()context.commit('updateUser', null)},} }

(3)然后在項目的?main.js?文件中引入

import Vue from 'vue' import App from '@/app.vue' import { router } from '@/router' import store from '@/store/index'const vue = new Vue({el: '#app',name: 'root',router,store,render: h => h(App), })

(4)封裝很愉快結(jié)束了了,然后就正常操作即可

this.$store.state.user.isLogined this.$store.state.user.userInfo this.$store.commit('user/updateUser', {})await this.$store.dispatch('user/logout', { manual: true })

5.$attrs與 $listeners

現(xiàn)在我們來討論另一種情況:如果我們給出的組件關(guān)系圖中A組件與D組件是隔代關(guān)系, 那它們之前進(jìn)行通信有哪些方式呢?

  • 使用props綁定來進(jìn)行一級一級的信息傳遞, 如果D組件中狀態(tài)改變需要傳遞數(shù)據(jù)給A, 使用事件系統(tǒng)一級級往上傳遞
  • 使用eventBus,這種情況下還是比較適合使用, 但是碰到多人合作開發(fā)時, 代碼維護性較低, 可讀性也低
  • 使用Vuex來進(jìn)行數(shù)據(jù)管理, 但是如果僅僅是傳遞數(shù)據(jù), 而不做中間處理,使用Vuex處理感覺有點大材小用了.
  • 所以就有了 $attrs / $listeners ,通常配合 inheritAttrs 一起使用。

    inheritAttrs

    默認(rèn)情況下父作用域的不被認(rèn)作 props 的 attribute 綁定 (attribute bindings) 將會“回退”且作為普通的 HTML attribute 應(yīng)用在子組件的根元素上。當(dāng)撰寫包裹一個目標(biāo)元素或另一個組件的組件時,這可能不會總是符合預(yù)期行為。

    通過設(shè)置 inheritAttrs 到 false,這些默認(rèn)行為將會被去掉。而通過實例 property $attrs 可以讓這些 attribute 生效,且可以通過 v-bind 顯性的綁定到非根元素上。

    注意:這個選項不影響 class 和 style 綁定,Vue對class和style做了特殊處理

    簡單來說就是

    • inheritAttrs:true 時繼承除props之外的所有屬性
    • inheritAttrs:false 只繼承class 和 style屬性
    • $attrs:包含了父作用域中不被認(rèn)為 (且不預(yù)期為) props 的特性綁定 (class 和 style 除外),并且可以通過 v-bind="$attrs" 傳入內(nèi)部組件。當(dāng)一個組件沒有聲明任何 props 時,它包含所有父作用域的綁定 (class 和 style 除外)。
    • $listeners:包含了父作用域中的 (不含 .native 修飾符) v-on 事件監(jiān)聽器。它可以通過 v-on="$listeners" 傳入內(nèi)部組件。它是一個對象,里面包含了作用在這個組件上的所有事件監(jiān)聽器,相當(dāng)于子組件繼承了父組件的事件。

    代碼示例:

    父組件:

    <template><child :name="name" :age="age" :infoObj="infoObj" @updateInfo="updateInfo" @delInfo="delInfo" /> </template> <script>import Child from '../components/child.vue'export default {name: 'father',components: { Child },data () {return {name: '繪梨衣',age: 22,infoObj: {from: '河北',job: 'superman',hobby: ['reading', 'writing', 'eating']}}},methods: {updateInfo() {console.log('update info');},delInfo() {console.log('delete info');}}} </script>

    ?兒子組件:

    <template><!-- 通過 $listeners 將父作用域中的事件,傳入 grandSon 組件,使其可以獲取到 father 中的事件 --><grand-son :height="height" :weight="weight" @addInfo="addInfo" v-bind="$attrs" v-on="$listeners" /> </template> <script>import GrandSon from '../components/grandSon.vue'export default {name: 'child',components: { GrandSon },props: ['name'],data() {return {height: '170cm',weight: '55kg'};},created() {console.log(this.$attrs); // 結(jié)果:age, infoObj, 因為父組件共傳來name, age, infoObj三個值,由//于name被 props接收了,所以只有age, infoObj屬性console.log(this.$listeners); // updateInfo: f, delInfo: f},methods: {addInfo () {console.log('add info')}}} </script>

    孫子組件:

    <template><div>{{ $attrs }} --- {{ $listeners }}<div> </template> <script>export default {props: ['weight'],created() {console.log(this.$attrs); // age, infoObj, height console.log(this.$listeners) // updateInfo: f, delInfo: f, addInfo: fthis.$emit('updateInfo') // 可以觸發(fā) father 組件中的updateInfo函數(shù)}} </script>

    6.$parent / $children

    • 使用$parent可以讓組件訪問父組件的實例(訪問的是上一級父組件的屬性和方法)。
    • 使用 $children 可以讓組件訪問子組件的實例,但是, $children 并不能保證順序,并且訪問的數(shù)據(jù)也不是響應(yīng)式的。

    注意:

    • 通過 $parent 訪問到的是上一級父組件的實例,可以使用 $root 來訪問根組件的實例
    • 在組件中使用$children拿到的是所有的子組件的實例,它是一個數(shù)組,并且是無序的
    • 在根組件 #app 上拿 $parent 得到的是 new Vue()的實例,在這實例上再拿 $parent 得到的是undefined,而在最底層的子組件拿 $children 是個空數(shù)組
    • $children 的值是數(shù)組,而 $parent是個對象

    用法:

    子組件:

    <template><div><span>{{message}}</span><p>父組件的值為: {{parentVal}}</p></div> </template><script> export default {data() {return {message: 'Vue'}},computed:{parentVal(){return this.$parent.msg;}} } </script>

    父組件:

    <template><div class="app"><div>{{msg}}</div><child></child><button @click="change">點擊改變子組件值</button></div> </template><script> import child from './child.vue' export default {components: { child },data() {return {msg: 'Hello'}},methods: {change() {// 獲取到子組件this.$children[0].message = 'JavaScript'}} } </script>

    7.依賴注入(provide / inject)

    這種方式就是vue中依賴注入,該方法用于 父子組件之間 的通信。當(dāng)然這里所說的父子不一定是真正的父子,也可以是祖孫組件,在層數(shù)很深的情況下,可以使用這種方式來進(jìn)行傳值。就不用一層一層的傳遞數(shù)據(jù)了。

    provide和inject是vue提供的兩個鉤子,和data、methods是同級的。并且provide的書寫形式和data一樣。

    • provide 鉤子用來發(fā)送數(shù)據(jù)或方法
    • inject鉤子用來接收數(shù)據(jù)或方法

    注意: 依賴注入所提供的屬性是非響應(yīng)式的。

    用法:

    父組件:

    provide() { return { num: this.num }; }

    子組件:

    inject: ['num']

    還有另一種寫法,這種寫法可以訪問父組件中的所有屬性:

    provide() {return {app: this}; } data() {return {num: 111}; }inject: ['app'] console.log(this.app.num)

    總結(jié)

    1.父子組件間通信

    • 子組件通過 props 屬性來接受父組件的數(shù)據(jù),然后父組件在子組件上注冊監(jiān)聽事件,子組件通過 emit 觸發(fā)事件來向父組件發(fā)送數(shù)據(jù)。
    • 通過 ref 屬性給子組件設(shè)置一個名字。父組件通過 $refs 組件名來獲得子組件,子組件通過 $parent 獲得父組件,這樣也可以實現(xiàn)通信。
    • 使用 provide/inject,在父組件中通過 provide提供變量,在子組件中通過 inject 來將變量注入到組件中。不論子組件有多深,只要調(diào)用了 inject 那么就可以注入 provide中的數(shù)據(jù)

    2.跨代組件間通信

    跨代組件間通信其實就是多層的父子組件通信,同樣可以使用上述父子組件間通信的方法,只不過需要多層通信會比較麻煩。

    3.兄弟組件間通信

    通過 $parent + $refs 以父組件為中間人來獲取到兄弟組件,也可以進(jìn)行通信。

    4.任意組件間通信

    使用 eventBus ,其實就是創(chuàng)建一個事件中心,相當(dāng)于中轉(zhuǎn)站,可以用它來傳遞事件和接收事件。它的本質(zhì)是通過創(chuàng)建一個空的 Vue 實例來作為消息傳遞的對象,通信的組件引入這個實例,通信的組件通過在這個實例上監(jiān)聽和觸發(fā)事件,來實現(xiàn)消息的傳遞。

    總結(jié)

    以上是生活随笔為你收集整理的Vue实现组件间通信的七种方式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。