本文小編為大家詳細介紹“vue指令如何實現(xiàn)組件通信”,內(nèi)容詳細,步驟清晰,細節(jié)處理妥當,希望這篇“vue指令如何實現(xiàn)組件通信”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。
創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供東西湖網(wǎng)站建設、東西湖做網(wǎng)站、東西湖網(wǎng)站設計、東西湖網(wǎng)站制作等企業(yè)網(wǎng)站建設、網(wǎng)頁設計與制作、東西湖企業(yè)網(wǎng)站模板建站服務,十載東西湖做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡服務。
vue指令實現(xiàn)組件通信的方法:1、父組件通過“props”的方式向子組件傳遞數(shù)據(jù),而通過“$emit”子組件可以向父組件通信;2、通過“ref/$refs”屬性實現(xiàn)組件通信;3、通過eventBus事件總線實現(xiàn)組件通信;4、使用Vuex實現(xiàn)組件通信;5、通過“$attrs”與“$listeners”實現(xiàn)組件通信等。
Vue實現(xiàn)組件間通信的七種方式
父組件通過props
的方式向子組件傳遞數(shù)據(jù),而通過$emit
子組件可以向父組件通信:
父傳子:父組件通過import引入子組件,并注冊,在子組件標簽上添加要傳遞的屬性,子組 件通過props接收,接收有兩種形式一是通過數(shù)組形式[‘要接收的屬性’ ],二是通過對象形式{ }
子傳父:父組件向子組件傳遞事件方法,子組件通過
$emit
觸發(fā)事件,回調(diào)給父組件
props的特點:
props只能是父組件向子組件進行傳值,props使得父子組件之間形成一個單向的下行綁定。子組件的數(shù)據(jù)會隨著父組件的更新而響應式更新;但是子組件無法引起父組件的數(shù)據(jù)更新。
props可以顯示定義一個或一個以上的數(shù)據(jù),對于接收的數(shù)據(jù),可以是各種數(shù)據(jù)類型,同樣也可以是傳遞一個對象或函數(shù)。
props屬性名規(guī)則:若在props中使用駝峰形式,模板中標簽需要使用短橫線的形式來書寫。
代碼示例:
父組件:
<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 綁定一個自定義事件,當這個事件被執(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>
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); // mySon
this.$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>
其原理就是:事件訂閱發(fā)布,eventBus
又稱為事件總線,在vue中可以使用它來作為溝通橋梁的概念, 就像是所有組件共用相同的事件中心,可以向該中心注冊發(fā)送事件或接收事件, 所以組件都可以通知其他組件。
使用步驟如下:
// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()
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>
在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>
在上述代碼中,這就相當于將num值存貯在了事件總線中,在其他組件中可以直接訪問。事件總線就相當于一個橋梁,不用組件通過它來通信。雖然看起來比較簡單,但是這種方法也有不變之處,如果項目過大,使用這種方式進行通信,后期維護起來會很困難。
Vuex 是一個專為 Vue.js 應用程序開發(fā)的狀態(tài)管理模式。它采用集中式存儲管理應用的所有組件的狀態(tài),并以相應的規(guī)則保證狀態(tài)以一種可預測的方式發(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ù)的相關性計算
mutations:類似函數(shù),改變state數(shù)據(jù)的唯一途徑,且不能用于處理異步事件
actions:類似于mutation,用于提交mutation來改變狀態(tài),而不直接變更狀態(tài),可以包含任意異步操作
modules:類似于命名空間,用于項目中將各個模塊的狀態(tài)分開定義和操作,便于維護
Vuex使用步驟:
(1)這里我們先新建 store文件夾, 對Vuex進行一些封裝處理
在 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.js
import user from '@/utils/user.js'
import userApi from '@/apis/user'
import { OPEN_ACCOUNT_STAGE, STAGE_STATUS } from '@/constant'
let getUserPromise = null
export default {
namespaced: true,
state() {
return {
userInfo: null, // 用戶信息
isLogined: !!user.getToken(), // 是否已經(jīng)登錄
}
},
mutations: {
// 更新用戶信息
updateUser(state, payload) {
state.isLogined = !!payload
state.userInfo = payload
},
},
actions: {
// 獲取當前用戶信息
getUserInfo(context, payload) {
//相關代碼
},
// 登出
logout(context, payload = {}) {
// 是否手動退出
const { manual } = payload
if (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 })
現(xiàn)在我們來討論另一種情況:如果我們給出的組件關系圖中A組件與D組件是隔代關系, 那它們之前進行通信有哪些方式呢?
使用props綁定來進行一級一級的信息傳遞, 如果D組件中狀態(tài)改變需要傳遞數(shù)據(jù)給A, 使用事件系統(tǒng)一級級往上傳遞
使用eventBus,這種情況下還是比較適合使用, 但是碰到多人合作開發(fā)時, 代碼維護性較低, 可讀性也低
使用Vuex來進行數(shù)據(jù)管理, 但是如果僅僅是傳遞數(shù)據(jù), 而不做中間處理,使用Vuex處理感覺有點大材小用了.
所以就有了 $attrs / $listeners ,通常配合 inheritAttrs 一起使用。
默認情況下父作用域的不被認作 props 的 attribute 綁定 (attribute bindings) 將會“回退”且作為普通的 HTML attribute 應用在子組件的根元素上。當撰寫包裹一個目標元素或另一個組件的組件時,這可能不會總是符合預期行為。
通過設置 inheritAttrs 到 false,這些默認行為將會被去掉。而通過實例 property $attrs 可以讓這些 attribute 生效,且可以通過 v-bind 顯性的綁定到非根元素上。
注意:這個選項不影響 class 和 style 綁定,Vue對class和style做了特殊處理
簡單來說就是
inheritAttrs:true 時繼承除props之外的所有屬性
inheritAttrs:false 只繼承class 和 style屬性
$attrs:包含了父作用域中不被認為 (且不預期為) props 的特性綁定 (class 和 style 除外),并且可以通過 v-bind="$attrs" 傳入內(nèi)部組件。當一個組件沒有聲明任何 props 時,它包含所有父作用域的綁定 (class 和 style 除外)。
$listeners:包含了父作用域中的 (不含 .native 修飾符) v-on 事件監(jiān)聽器。它可以通過 v-on="$listeners" 傳入內(nèi)部組件。它是一個對象,里面包含了作用在這個組件上的所有事件監(jiān)聽器,相當于子組件繼承了父組件的事件。
代碼示例:
父組件:
<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: f
this.$emit('updateInfo')
// 可以觸發(fā) father 組件中的updateInfo函數(shù)
}
}
</script>
使用$parent可以讓組件訪問父組件的實例(訪問的是上一級父組件的屬性和方法)。
使用 $children 可以讓組件訪問子組件的實例,但是, $children 并不能保證順序,并且訪問的數(shù)據(jù)也不是響應式的。
注意:
通過 $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>
這種方式就是vue中依賴注入,該方法用于 父子組件之間的通信。當然這里所說的父子不一定是真正的父子,也可以是祖孫組件,在層數(shù)很深的情況下,可以使用這種方式來進行傳值。就不用一層一層的傳遞數(shù)據(jù)了。
provide和inject是vue提供的兩個鉤子,和data、methods是同級的。并且provide的書寫形式和data一樣。
provide 鉤子用來發(fā)送數(shù)據(jù)或方法
inject鉤子用來接收數(shù)據(jù)或方法
注意: 依賴注入所提供的屬性是非響應式的。
用法:
父組件:
provide() {
return {
num: this.num
};
}
子組件:
inject: ['num']
還有另一種寫法,這種寫法可以訪問父組件中的所有屬性:
provide() {
return {
app: this
};
}
data() {
return {
num: 111
};
}
inject: ['app']
console.log(this.app.num)
讀到這里,這篇“vue指令如何實現(xiàn)組件通信”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內(nèi)容的文章,歡迎關注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
本文題目:vue指令如何實現(xiàn)組件通信
當前地址:http://www.2m8n56k.cn/article40/pshsho.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供面包屑導航、網(wǎng)站制作、網(wǎng)站策劃、商城網(wǎng)站、動態(tài)網(wǎng)站、外貿(mào)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:[email protected]。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)