方式主要包括:
- ==父組件=>子組件 | 單向數(shù)據(jù)流涧尿,props==
- ==子組件=>父組件 | 觀(guān)察者模式翁涤,即vue的自定義事件 on==
- ==非父子組件通信 | 中介者模式,即 中央事件總線(xiàn) bus==
- ==父子組件通信 | 父鏈和子鏈==
- vuex 等狀態(tài)管理庫(kù)(略)
1 父組件=>子組件扔涧,props的兩個(gè)主要用法
- 子組件把 props 的值枯夜,作為初始值(data中)保存起來(lái)湖雹,從而和父級(jí)解綁
- 子組件需要二次處理 props 值,這時(shí),應(yīng)將其作為【計(jì)算屬性】保存起來(lái)
將prop用于子組件的data
- 定義一個(gè)本地的 data 屬性并將這個(gè) prop 用作其初始值
props: ['initialCounter'],
data: function () {
return {
counter: this.initialCounter
}
}
- 用 prop 的值來(lái)定義一個(gè)計(jì)算屬性
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
prop 是單向數(shù)據(jù)流
- 所有的 prop 都使得其父子 prop 之間形成了一個(gè)==單向下行綁定==
父級(jí) prop 的更新會(huì)向下流動(dòng)到子組件中,但是反過(guò)來(lái)則不行 - ==不要在子組件中改變 prop==
props傳值:父組件=>子組件
//靜態(tài)傳值
<blog-post name="zhangkai"></blog-post>
//動(dòng)態(tài)傳值
<blog-post :name="zhangkai"></blog-post>
<blog-post :num="42"></blog-post>
<blog-post :ifSale="false"></blog-post>
<blog-post :list="[1,2,3]"></blog-post>
<blog-post :person="{name:'zhangkai',age:19}"></blog-post>
<blog-post :person="person.name"></blog-post>
//不帶參數(shù)的 v-bind,post={id:1,title:"title"}
<blog-post v-bind="post"></blog-post>
//等價(jià)于
<blog-post
v-bind:id="post.id"
v-bind:title="post.title"
></blog-post>
prop檢驗(yàn)
詳細(xì)章節(jié)見(jiàn)
- <a >vue prop傳值default屬性如何使用</a>
- <a >vue prop傳值類(lèi)型檢驗(yàn)</a>
2 子組件=>父組件
- 原理:【觀(guān)察者模式】 + 【vue自定義事件】
- 子組件用 $emit 方法觸發(fā)事件楞遏,第一個(gè)參數(shù)是自定義事件名勒奇,后續(xù)參數(shù)都是要傳遞的數(shù)據(jù)
- 父組件用 v-on 定義的方法監(jiān)聽(tīng)子組件的事件
- 注意劈彪,add 和 reduce 是兩個(gè)自定義事件痘括,用來(lái)監(jiān)聽(tīng)子組件的 $emit 事件
//vue模板
<template>
<div class="wrap">
<!--注意屠凶,add 和 reduce 是兩個(gè)自定義事件,用來(lái)監(jiān)聽(tīng)子組件的 $emit 事件-->
<MyComponent v-on:add="handleTotal" v-on:reduce="handleTotal"/>
{{total}}
</div>
</template>
//vue script
var MyComponent = {
template:
"<div>\
<button @click='handleAdd'>+1</button>\
<button @click='handleReduce'>-1</button>\
</div>",
data() {
return {
sum: 0
};
},
methods: {
handleAdd() {
this.sum++;
this.$emit("add", this.sum);
},
handleReduce() {
this.sum--;
this.$emit("reduce", this.sum);
}
}
};
export default {
components: {
MyComponent
},
data() {
return {
total: 0
};
},
methods: {
handleTotal(total) {
this.total = total;
}
}
};
3 非父子組件通信 bus
- 使用【中央事件總線(xiàn) bus】
- bus 其實(shí)就是一個(gè)空的Vue實(shí)例,充當(dāng)中介者的作用
- bus 通過(guò) on 來(lái)監(jiān)聽(tīng)獲取,這兩個(gè)方法的第一個(gè)參數(shù)必需是同一個(gè)消息名稱(chēng)
- bus 對(duì)象中,可以添加 data、methods呵晚、computed 等信息
- 協(xié)同開(kāi)發(fā)中劣纲,向 bus 對(duì)象添加一些共享的信息,是非常有用的
- 比如劫瞳,token、用戶(hù)昵稱(chēng)伺绽、郵箱信息等,只需初始化時(shí)讓 bus獲取一次,所有組件就都可以使用了
//vue模板
<template>
<div class="wrap">
<componentA/>
<br>
{{msg}}
</div>
</template>
<script>
//vue script
import Vue from "vue";
const bus = new Vue({
data: {
name: "",
passport: ""
}
}); //一個(gè)空的Vue實(shí)例歌殃,做為【中央事件總線(xiàn)】
const componentA = {
template: "<button @click='handleEvent'>傳遞事件</button>",
methods: {
handleEvent() {
bus.name = "gs";
bus.$emit("on-msg", "componentA content");
}
}
};
export default {
components: {
componentA
},
data() {
return {
msg: ""
};
},
mounted() {
const that = this;
bus.$on("on-msg", msg => {
console.log(bus.name);
that.msg = msg;
});
}
};
4 父子組件通信 父鏈和子鏈
- 在子組件中,this.$parent 可以訪(fǎng)問(wèn)父組件實(shí)例
- 在父組件中朵你,this.children 可以訪(fǎng)問(wèn)子組件實(shí)例
- 該方法可以向上向上無(wú)限遞歸抡医,直到遇見(jiàn)根組件和葉子組件
- 給子組件添加一個(gè) ref 屬性,可以幫助父組件快速找到子組件(調(diào)用方法 this.$refs.comA.msg,實(shí)際上 react 也有這樣的方法)宙刘,但不建議使用 ref
- 注意衙猪,在 mounted階段時(shí) this.$refs 才會(huì)綁定茫船,在 created 階段尚未綁定
- 另外,$refs 不是一個(gè)響性式的屬性
//注意高每,this.$children 一般為數(shù)組
this.$children[0].age
//使用 ref 屬性,可以更容易找到子組件
//<componentA ref="ageCom"/>
this.$refs.ageCom.age;
注意事項(xiàng):
不要在子組件中修改 props 的值
- props 是對(duì)象或數(shù)組時(shí)带欢,由于是引用類(lèi)型逗宜,在子組件中修改,會(huì)影響到父組件
重要空骚!Prop 的大小寫(xiě) (camelCase vs kebab-case)
- 聲明一個(gè)vue組件纺讲,如果使用駝峰命名法,在使用時(shí)府怯,需要轉(zhuǎn)換成短橫線(xiàn)分隔命名
- 因?yàn)槿绻晦D(zhuǎn)刻诊,html解析時(shí),會(huì)將大寫(xiě)字母小寫(xiě)化牺丙,這樣變量即為undefined
- 如下则涯,props 一般是一個(gè)數(shù)組,也可以是一個(gè)對(duì)象(對(duì)象類(lèi)型檢測(cè))
//聲明一個(gè)組件
Vue.component('blog-post', {
// 在 JavaScript 中是 camelCase 的
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
})
//使用組件
<blog-post post-title="hello!"></blog-post>