閱讀時間預估:8分鐘
元件之間通訊是Vue中最常用,最基礎的部分,通常元件之前的通訊分為以下幾種:
- 1.父元件給子元件傳遞值,傳遞事件
- 2.子元件給父元件傳遞值,傳遞事件
- 3.兄弟元件之間傳遞值,傳遞事件
方法一、props $emit v-on
1.父元件給子元件傳值
父元件A通過props向子元件B通訊
接下來我們通過一個例子來加深以上理解:
自定義一個Son.vue子元件,引入到父元件中 在父元件中定義一個資料
<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來定義父元件傳值的值型別,是否是必須以及預設值
<script>
export default {
components: {
},
data () {
return {
};
},
computed: {
},
methods: {
},
props: {
user: { //這個就是父元件中子標籤自定義名字
type: Array,
required: true,
default: []
}
},
}
</script>
複製程式碼
然後在適當的位置將父元件傳遞過來的資料進行渲染
<template>
<div>
<ul>
<li v-for="(item,index) in user"
:key="index">姓名:{{item}}</li>
</ul>
</div>
</template>
複製程式碼
瀏覽器開啟會顯示user裡面的值.
總結:父元件通過props向下傳遞資料給子元件。注:元件中的資料共有三種形式:data、props、computed
2.子元件向父元件傳值(通過自定義事件形式)
核心點
-
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>
複製程式碼
方法四: 釋出訂閱模式
- 1.通過
npm install pubsub-js --save
的方式引入pubsub庫 - 2.建立
event-type.js
定義Symbol型別的資料並匯出
// event-types.js
export const MY_TOPIC = Symbol('MY_TOPIC')
複製程式碼
- 3.在需要釋出(傳遞事件)的地方引入
pubsub
和event=type.js
,並且通過以下方式釋出事件
import PubSub from 'pubsub'
import { MY_TOPIC } from './event-types.js'
PubSub.publish(MY_TOPIC, 'world');
複製程式碼
- 4.在需要訂閱(接受事件)的地方引入
pubsub
和event=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官方推薦的一種解決元件中通訊的完美解決方案,也是在專案開發中必用的方案:
認真看完本篇後對照思維導圖可以在腦海裡回顧一遍哦,對此塊的知識點你會有更深的認識和理解.
如果我的分享對面前的這位大俠有所啟發,請不要吝嗇手中大拇指,以程式設計師最高禮遇點贊✨ 評論加分享的方式鼓勵我持續分享,也歡迎各位大佬勘誤,提出寶貴意見.
關注公眾號回覆:學習 領取前端最新最全學習資料,也可以進群和大佬一起學習交流
猛戳 我的前端進階Blog