1.父組件向子組件通信:
總結:父組件通過props向下傳遞數據給子組件。注:組件中的數據共有三種形式:data、props、computed。
通信步驟:
1.1 在父組件中定義要傳遞的數據。
1.2 在父組件中調用子組件,並在組件上進行屬性綁定,前者自定義名稱便於子組件調用,後者是要傳遞的數據名稱。
1.3 在組件件中通過props對象進行接收。
//父組件App組件
<template>
<div id="app">
//1.2 在父組件中調用子組件,並在組件上進行屬性綁定,前者自定義名稱便於子組件調用,後者是要傳遞的數據名稱。前者childs1是自定義名稱便於子組件調用,後者childs2是要傳遞數據名
<childs :childs1="childs2"></childs>
</div>
</template>
<script>
import Childs from "./components/childs";
export default {
name: 'App',
data(){
return{
//1.1 在父組件定義數據。
childs:["Henry","Bucky","Emily"]
}
},
components:{ childs,}
}
</script>
//子組件 childs
<template>
<div class="hello">
<ul>
//遍歷傳遞過來的值childs1,然後呈現到頁面
<li v-for="child in childs1">{{child }}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Childs',
//1.3 在組件件中通過props對象進行接收。
props:{
childs1:{ //這個就是父組件中子標籤自定義名字
type:Array,
required:true
}
}
}
</script>
2.子組件向父組件通信:
總結:子組件通過$event給父組件發送消息,實際上就是子組件把自己的數據發送到父組件。通過事件形式。
通信步驟:
2.1 在子組件中定義要傳遞的數據。
2.2 在子組件中 methods 中定義一個函數,函數內部通過 .$emit(‘定義事件名稱 childData’,‘要傳遞的數據 title’)向父組件傳遞數據。
2.3 在子組件中 將這個函數綁定到點擊事件上。
2.4 在父組件中在調用的子組件上同樣進行事件綁定,與子組件名稱可以不同。
2.5 在父組件中methods 中,用這個綁定的事件去獲取數據。
//子組件childs
<template>
<childs>
//2.3 在子組件中 將這個函數綁定到點擊事件上。
<h1 @click="childData">{{title}}</h1>
</childs>
</template>
<script>
export default {
name: 'Childs',
data() {
return {
//2.1在子組件中定義要傳遞的數據。
title:"Vue.js Demo"
}
},
methods:{
changeTitle()
let _this. = this
//2.2 在子組件中 methods 中定義一個函數,函數內部通過 .$emit(‘定義事件名稱 childData’,‘要傳遞的數據 title’)向父組件傳遞數據。
_this.$emit("childData", this.title)
}
}
}
</script>
//父組件App
<template>
<div id="app">
//2.4 在父組件中在調用的子組件上同樣進行事件綁定,與子組件名稱可以不同。
<childs @titleChanged="updateTitle($event)" ></childs>
<h2>{{title}}</h2>
</div>
</template>
<script>
import Childs from "./components/childs";
export default {
name: 'App',
components:{
childs
}
data(){
return{
title: ""
}
},
methods:{
//2.5 在父組件中methods 中,用這個綁定的事件去獲取數據。
updateTitle(e){
let _this. = this
_this.title = e
}
}
}
</script>
3.跨級組件間的通信:
總結:多級組件嵌套需要傳遞數據時,通常使用的方法是通過vuex。但如果僅僅是傳遞數據,而不做中間處理,可以使用$attrs
/$listeners。
當前組件已接收的屬性指的是當前組件在props中聲明的屬性。
$attrs:表示<父組件傳遞的屬性集合>與<當前組件已接收的屬性集合>的差集,也就是說已被當前組件接收的屬性,在下面的層級中無法再獲取到$attrs的值與inheritAttrs的值無關。
inheritAttrs: 默認true,也就是說當前組件如果沒有在props中聲明的剩餘屬性會繼承到原始html元素的屬性值上,改爲false,在當前組件中props中沒有聲明的多餘屬性不會繼承到原始html元素的屬性。
$listeners是子組件通過$emit提交的所有事件集合 (由於冒泡,還包含子組件從下一層組件獲得的所有事件),和$attrs不同的是,即使當前組件處理了子組件提交的某個事件,父組件仍然能獲取到這個事件並處理,它應該是遵循了事件冒泡的原則。
使用步驟:
1. 在父級組件進行屬性綁定和事件綁定。屬性綁定用來向下級(子或孫組件)傳遞數據,事件綁定用來接收下級(孫組件)發送過來的數據
2. 在子級組件下面通過porps ,來接收父級組件傳遞過來的數據。 通過v-bind="$attrs" v-on="$listeners" 向孫級組件傳遞數據。通過事件綁定來接收孫級組件發送過來的數據。
3. 在孫級組件通過porps 接收父級組件傳遞過來的數據。定義點擊事件,通過 this.$emit('事件名稱',要發送的數據) 向上級(子級或父級)發送數據。
//父組件
<template>
<div id="App"><h2>父級組件:({{name}},{{age}}</h2>
<child
:fatherName="name"
:fatherAge="age"
@toGrandFather="grandChildValue"
@toFather="grandChildValue">
</child>
</div>
</template>
<script>
import child from "./Child"
export default {
name: "App",
components:{child},
data(){
return {
name: "小辛",
age: 27
}
},
methods:{
grandChildValue(value){
console.log("孫組件對我說:"+value)
}
}
}
</script>
//子組件child<template>
<div id="Child">
<h2>我是子組件</h2>
<p>我的父組件名叫{{fatherName}}</p>
<grandson v-bind="$attrs" v-on="$listeners" @toFather="childValue"></grandson>
</div>
</template>
<script>
import grandson from "./Grandson"
export default {
name: "Child",
components: {grandson},
// 1.默認true,也就是說當前組件如果沒有在props中聲明的剩餘屬性會繼承到原始html元素的屬性值上。2.改爲false,在當前組件中props中沒有聲明的多餘屬性不會繼承到原始html元素的屬性
inheritAttrs: false,
// 定義:當前組件已接收的屬性指的是當前組件在props中聲明的屬性
props: ["fatherName"],
methods: {
childValue(value){
console.log("子組件對我說:"+value)
}
}
}
</script>
//孫組件grandson
<template>
<div id="grandson">
<h2>我是孫組件</h2>
<p>我父組件定義的name名叫{{fatherName}},今年{{fatherAge}}歲</p>
<button @click="toGrandFather">叫爺爺</button>
<button @click="toFather">叫爸爸</button>
</div>
</template>
<script>
export default {
name: "Grandson",
props: ["fatherAge","fatherName"],
methods: {
toGrandFather(){
this.$emit("toGrandFather","App.vue,我是您孫組件")
},
toFather(){
this.$emit("toFather","Child.vue,我是您子組件")
}
}
}
</script>
4.輕量級任何組件間(父子、兄弟、跨級)的通信:
總結:通過一個空的Vue實例作爲$EventBus中央事件總線(事件中心),用它來觸發事件和監聽事件,巧妙而輕量地實現了任何組件間的通信,包括父子、兄弟、跨級。當我們的項目比較大時,可以選擇更好的狀態管理解決方案 vuex。EventBus事件不會隨着組件的關閉而自行銷燬,所以當路由切換時,EventBus事件會不停的觸發,如果數據量比較多的時候,可能會比較影響性能吧,所以需要及時銷燬所綁定的EventBus事件。在destroyed()生命週期時執行this.$EventBus.$off('事件名稱') 進行事件銷燬。
通信步驟:
3.1 首先在main.js將$EventBus綁定在vue實例上。Vue.prototype.$EventBus = new Vue()。在組件出通過this.$EventBus調用。
3.2 在任意A組件發出數據,this.$EventBus.$emit('事件名','數據');
3.3 在任意B組件接收數據,this.$EventBus.$on(‘與A組件定義的事件名保持相同',data => {});
//父組件
<template>
<div id="app">
<child-a></child-a>
<child-b></child-b>
<child-c></child-c>
<div>
<p>{{name }}</p>
<p>{{sex}}</p>
<p>{{age}}</p>
<div>
</div>
</template>
<script>
import child-a from "./components/child-a";
import child-b from "./components/child-b";
import child-c from "./components/child-c";
export default {
name: 'App',
components:{
child-a ,
child-b,
child-c
},
data(){
return {
name : '',
sex: '',
age: ''
}
},
mounted(){
let _this. = this
_this.fromDataChildB()
_this.fromDataChildC()
_this.fromDataChildA()
},
methods:{
//父組件接收來自任意子組件B的發送的數據
fromDataChildB(){
let _this. = this
_this.$EventBus.$on('sendName', (data)=>{
_this.name= data.name
})
},
//父組件接收來自任意子組件C的發送的數據
fromDataChildC(){
let _this. = this
_this.$EventBus.$on('sendSex', (data)=>{
_this.sex= data.sex
})
},
//父組件接收來自任意子組件A的發送的數據
fromDataChildA(){
let _this. = this
_this.$EventBus.$on('sendAge', (data)=>{
_this.age= data.age
})
}
},
destroyed(){
//事件銷燬
let _this =this
_this.$EventBus.$off('sendName')
_this.$EventBus.$off('sendSex')
_this.$EventBus.$off('sendAge')
}
}
</script>
//組件child-a
<template>
<div id="childA">
<div>{{age}}</div>
<button @click="toSendChildB"></button>
</div>
</template>
<script>
export default {
name: 'childA',
data(){
return {
age: '',
name : 'xiaoXin',
}
},
mounted(){
let _this. = this
_this.fromDataChildC()
},
methods:{
//接收來自統計C組件發送的數據
fromDataChildC(){
let _this. = this
_this.$EventBus.$on('sendAge', (data)=>{
_this.age= data.age
})
},
//在任意A組件發出數據,this.$EventBus.$emit('事件名','數據');
toSendChildB(){
let _this. = this
_this.$EventBus.$emit('sendName', _this.name)
}
},
destroyed(){
let _this =this
_this.$EventBus.$off('sendAge')
}
}
</script>
//組件child-b
<template>
<div id="childB">
<div>{{name}}</div>
<button @click="toSendChildC"></button>
</div>
</template>
<script>
export default {
name: 'childB',
data(){
return {
name : '',
sex: 'man',
}
},
mounted(){
let _this. = this
_this.fromDataChildA()
},
methods:{
//接收來自統計A組件發送的數據
fromDataChildA(){
let _this. = this
_this.$EventBus.$on('sendName', (data)=>{
_this.name = data.name
})
},
//在任意B組件發出數據,this.$EventBus.$emit('事件名','數據');
toSendChildC(){
let _this. = this
_this.$EventBus.$emit('sendSex', _this.sex)
}
},
destroyed(){
let _this = this
_this.$EventBus.$off('sendName')
}
}
</script>
//子組件child-c
<template>
<div id="childC">
<div>{{sex}}</div>
<button @click="toSendChildA"></button>
</div>
</template>
<script>
export default {
name: 'childC',
data(){
return {
sex: '',
age: '27'
}
},
mounted(){
let _this. = this
_this.fromDataChildB()
},
methods:{
//接收來自統計B組件發送的數據
fromDataChildB(){
let _this. = this
_this.$EventBus.$on('sendSex', (data)=>{
_this.sex= data.sex
})
},
//在任意C組件發出數據,this.$EventBus.$emit('事件名','數據');
toSendChildA(){
let _this. = this
_this.$EventBus.$emit('sendAge', _this.age)
}
},
destroyed(){
let _this = this
_this.$EventBus.$off('sendSex')
}
}
</script>
5.狀態管理器Vuex——萬能組件間通信:
總結:Vuex實現了一個單向數據流,在全局擁有一個State存放數據,如果需要對state做計算,可以在getters中進行。當組件要更改State中的數據時,必須通過Mutation進行,Mutation同時提供了訂閱者模式供外部插件調用獲取State數據的更新。而當所有異步操作(常見於調用後端接口異步獲取更新數據)或批量的同步操作需要走Action,但Action也是無法直接修改State的,還是需要通過Mutation來修改State的數據。最後,根據State的變化,渲染到視圖上。
通信步驟:
1.創建store.js 文件,與main.js文件同級。
2.安裝vuex庫,在main.js文件裏進行引入和註冊到vue實例中。
安裝:npm install --save vuex
引入:在store.js 中引入vue和vuex ,,
初始化:在store.js 中 Vue.use(vuex)
註冊:在main.js 文件引入 store.js ,並註冊到vue根實例中
import store from './store/store.js'
new Vue({
el: '#app',
store,
components: { App },
template: '<App/>'
})
3. 創建store模塊,
export const store = new Vuex.Store({ //最重要的事就是保存應用的狀態
state: { //狀態存儲,頁面狀態管理容器對象
num: 0
},
getters: {
doubleNum(state){ //對狀態進行計算,state對象讀取方法
return state.num* 2
},
},
mutations: {
increment(state){ //state狀態改變並做同步提交操做
state.num ++
},
actions: {
submitNum({commit}){ //異步提交mutation中的狀態,commit是context下的一個方法
commit('increment')
}
}
})
在組件中調用:
調用原始的狀態:this.$store.state.num
調用gettes計算後的狀態:this.$store.gettes.doubleNum
調用mutations改變後的狀態:this.$store.mutations.increment
調用actions進行異步提交狀態:this.$store.dispacth('submitNum')
Vuex與localStorage的配合:vuex 是 vue 的狀態管理器,存儲的數據是響應式的。但是並不會保存起來,刷新之後就回到了初始狀態。具體做法應該在vuex裏數據改變的時候把數據拷貝一份保存到localStorage裏面,刷新之後,如果localStorage裏有保存的數據,取出來再替換store裏的state。由於vuex裏,我們保存的狀態,都是數組,而localStorage只支持字符串,所以需要用JSON轉換。我們常用二者的結合做用戶登錄和用戶登出,以及登錄狀態保留。
vuex最好的用法是模塊化Module,將不同的的狀態單獨處理。減少彼此的耦合度。
本文如果存在錯誤之處歡迎指出。如有更好的vue.js組件間通信方式感謝指導。感謝觀看。