Vue 組件之間數(shù)據(jù)傳遞的幾種方式:
- 父組件向子組件傳遞數(shù)據(jù)章办,使用props屬性批狐;子組件向父組件中傳遞數(shù)據(jù),在子組件中使用$emit派發(fā)事件鸳谜,父組件中使用v-on
監(jiān)聽事件盅惜;缺點(diǎn):組件嵌套層次多的話并巍,傳遞數(shù)據(jù)比較麻煩休偶。
- 父組件向子組件傳遞數(shù)據(jù)章办,使用props屬性批狐;子組件向父組件中傳遞數(shù)據(jù),在子組件中使用$emit派發(fā)事件鸳谜,父組件中使用v-on
- 祖先組件通過依賴注入(inject / provide)的方式,向其所有子孫后代傳遞數(shù)據(jù)懒棉;缺點(diǎn):無法監(jiān)聽數(shù)據(jù)修改的來源,不支持響應(yīng)式览绿。
- 通過屬性parent / $children /
ref,訪問根組件穗慕、父級(jí)組件饿敲、子組件中的數(shù)據(jù);缺點(diǎn):要求組件之間要有傳遞性逛绵。
- 通過屬性parent / $children /
- 通過事件總線(event
bus)的方式怀各,可以實(shí)現(xiàn)任意兩個(gè)組件間進(jìn)行數(shù)據(jù)傳遞;缺點(diǎn):不支持響應(yīng)式术浪,這個(gè)概念是vue1.0版本中的瓢对,現(xiàn)在已經(jīng)廢棄。
- 通過事件總線(event
- 通過 VueJs 的狀態(tài)管理模式 Vuex胰苏,實(shí)現(xiàn)多個(gè)組件進(jìn)行數(shù)據(jù)共享硕蛹,推薦使用這種方式進(jìn)行項(xiàng)目中各組件間的數(shù)據(jù)傳遞。
下面詳細(xì)介紹數(shù)據(jù)傳遞的幾種方式:
1.props/$emit
prop 是在組件上注冊(cè)的一些自定義的 attribute硕并。就像下面的 :sub-num 法焰。
<div :sub-num="num"></div>
1.1 父組件向子組件中傳遞數(shù)據(jù)
1、一個(gè)組件默認(rèn)可以擁有任意數(shù)量的 prop倔毙,任何值都可以傳遞給任何 prop埃仪。
2、當(dāng)一個(gè)值傳遞給一個(gè) prop attribute 的時(shí)候陕赃,它就變成了那個(gè)組件實(shí)例的一個(gè)屬性(例如下面的 subNum)卵蛉,通過屬性名,我們就能夠在組件實(shí)例中訪問這個(gè)值么库。
父組件向子組件中傳遞數(shù)據(jù)傻丝,可以在子組件中通過設(shè)置props屬性來接收傳遞過來的數(shù)據(jù)。
<div id="app">
<div>{{num}}</div>
<!-- 將父組件中的num诉儒,傳遞給子組件中的sub-num -->
<blog-count :sub-num="num" :sub-user="user"></blog-count>
</div>
<script>
const blogCount={
//子組件中通過props屬性接收父組件傳遞過來的數(shù)據(jù)
props:["subNum","subUser"],
template:`<div>
<p>這是從父組件傳進(jìn)來的數(shù)字:{{subNum}}</p>
<p>這是從父組件傳進(jìn)來的對(duì)象:{{subUser.name}}-{{subUser.age}}</p>
</div>`,
}
var vm=new Vue({
el:"#app",
data:{
num:2,
user:{
name:"zhangsan",
age:18
}
},
components:{
blogCount
}
})
</script>
1.2 子組件向父組件傳遞數(shù)據(jù)
子組件向父組件傳遞數(shù)據(jù)桑滩,通過 $emit派發(fā)事件,父組件中通過 v-on 接收該事件允睹,拿到傳遞的數(shù)據(jù)运准。
語法:$emit(eventName,data)缭受,第一個(gè)參數(shù)為事件名稱胁澳,需要跟父組件中 v-on 監(jiān)聽的事件名稱一致;第二個(gè)參數(shù)為要傳遞的數(shù)據(jù)米者。
<div id="app">
<div>{{num}}</div>
<!-- 通過 v-on 監(jiān)聽事件-->
<blog-count @countchange="changeHandle"></blog-count>
</div>
<script>
const blogCount={
template:`<button @click="clickHandle">點(diǎn)擊接收子組件傳遞過來的數(shù)據(jù)</button>`,
data(){
return {num:6}
},
methods: {
clickHandle(){
//使用 $emit派發(fā)事件
this.$emit("countchange",this.num);
}
}
}
var vm=new Vue({
el:"#app",
data:{
num:0
},
methods: {
changeHandle(data){
this.num=data;
}
},
components:{
blogCount
}
})
</script>
1.3 .sync 修飾符
如果使用 update:myPropName 的模式觸發(fā)事件韭畸,上面的代碼可以寫成下面這樣:
<div id="app">
<div>{{num}}</div>
<blog-count :num="num" @update:countchange="num=$event"></blog-count>
<!--最終可以簡(jiǎn)寫為-->
<!-- <blog-count :countchange.sync="num"></blog-count> -->
</div>
<script>
const blogCount={
template:`<button @click="$emit('update:countchange',num)">點(diǎn)擊接收子組件傳遞過來的數(shù)據(jù)</button>`,
data(){
return {num:6}
}
})
var vm=new Vue({
el:"#app",
data:{num:0}
}
</script>
提取出組件的代碼為:
<blog-count :num="num" @update:countchange="num=$event"></blog-count>```
為了方便起見宇智,我們?yōu)檫@種模式提供一個(gè)縮寫,即 .sync 修飾符:
```javascript
<blog-count :countchange.sync="num"></blog-count>
子組件向父組件傳遞數(shù)據(jù)胰丁,也可以通過使用 .sync 修飾符來完成随橘。
2. 依賴注入 provide inject
- 這對(duì)選項(xiàng)是2.2.0版本新增的。需要一起使用锦庸,它允許一個(gè)祖先組件向其所有子孫后代注入一個(gè)依賴机蔗,不論組件層次有多深,并在起上下游關(guān)系成立的時(shí)間里始終生效甘萧。
- 主要解決了跨級(jí)組件間的通信問題萝嘁。
- 在祖先組件中增加屬性 provide,它的屬性值是一個(gè)對(duì)象或返回一個(gè)對(duì)象的函數(shù)扬卷。該對(duì)象包含了給子組件要傳遞的數(shù)據(jù)牙言。
- 在子組件中增加屬性 inject ,用來接收數(shù)據(jù)怪得,它的選項(xiàng)是一個(gè)字符串?dāng)?shù)組咱枉,或一個(gè)對(duì)象。
<div id="app">
<div>{{num}}</div>
<blog-count></blog-count>
</div>
<script>
const blogCount={
//子組件中使用inject屬性來接收數(shù)據(jù)
inject:["num"],
template:`<div>{{num}}</div>`
}
var vm=new Vue({
el:"#app",
data:{
num:10
},
//父組件中使用provide屬性存放要傳遞的數(shù)據(jù)
provide:function(){
return {
num:this.num
}
},
components:{
blogCount
}
})
</script>
依賴注入 provide inject徒恋,這種方式的缺點(diǎn):
- 祖先組件不需要知道哪些后代組件使用它提供的屬性庞钢。
- 后代組件不需要知道被注入的屬性來自哪里。
- 會(huì)將應(yīng)用程序中的組件與它們當(dāng)前的組織方式耦合起來因谎,使重構(gòu)變得更加困難基括。
- 所提供的屬性是非響應(yīng)式的。
3. parent / $children / ref
- 通過 $root 屬性訪問根實(shí)例 new Vue()财岔。
- 通過$parent 屬性訪問父組件的實(shí)例风皿。
- 通過children 并不保證順序匠璧,也不是響應(yīng)式的桐款。
- 通過 r e f s 屬 性 訪 問 子 組 件 中 的 數(shù) 據(jù) , 子 組 件 標(biāo) 簽 上 加 r e f 的 屬 性 夷恍。 例 如 在 子 組 件 的 d o m 元 素 上 增 加 屬 性 r e f = " a b c " 魔眨, 就 可 以 使 用 t h i s . refs 屬性訪問子組件中的數(shù)據(jù),子組件標(biāo)簽上加 ref 的屬性酿雪。例如在子組件的dom元素上增加屬性 ref = "abc"遏暴,就可以使用this.refs屬性訪問子組件中的數(shù)據(jù),子組件標(biāo)簽上加ref的屬性指黎。例如在子組件的dom元素上增加屬性ref="abc"朋凉,就可以使用this.refs.abc 拿到這個(gè)子組件的實(shí)例。
- ref醋安,如果在普通的 DOM 元素上使用杂彭,引用指向的就是 DOM 元素墓毒;如果用在子組件上,引用就指向組件實(shí)例亲怠。
- $refs 只會(huì)在組件渲染完成之后生效所计,并且它們不是響應(yīng)式的。
<div id="app">
<blog-count></blog-count>
</div>
<script>
const blogItem={
template:`<div>{{$root.num}}-{{$parent.num}}</div>`,
data(){
return {
num:3
}
},
mounted() {
//訪問根實(shí)例中的數(shù)據(jù)
console.log("Vue.num:"+this.$root.num);
//訪問父級(jí)組件中的數(shù)據(jù)
console.log("blogCount.num:"+this.$parent.num);
//調(diào)用父級(jí)組件中的方法
this.$parent.start()
},
}
const blogCount={
template:`<div><blogItem ref="refItem"></blogItem></div>`,
data(){
return {num:6}
},
components:{
blogItem
},
methods: {
start(){
console.log("blogCount start...");
console.log(this.$children[0].num)
}
},
mounted() {
//訪問子組件的實(shí)例
console.log(this.$refs.refItem.num);
},
}
var vm=new Vue({
el:"#app",
data:{
num:0
},
components:{
blogCount
}
})
</script>
4. event bus 事件總線
事件的觸發(fā)器团秽,vue 1.0版本使用比較多主胧,現(xiàn)在已經(jīng)不用。
這種方法可以看作是通過一個(gè)空的實(shí)例 new Vue()作為事件總線(事件中心)徙垫,用它來派發(fā)和監(jiān)聽事件,可以實(shí)現(xiàn)任何組件間的通信放棒,包括父子姻报、兄弟、跨級(jí)间螟。缺點(diǎn):這種傳遞數(shù)據(jù)的方式不是響應(yīng)式吴旋。
<div id="app">
<div>{{num}}</div>
<blog-count></blog-count>
<button @click="clickHandle">send</button>
</div>
<script>
//創(chuàng)建一個(gè)空的vue實(shí)例
const eventbus=new Vue();
//子組件
const blogCount={
data(){
return {num:1}
},
template:`<div>{{num}}</div>`,
mounted() {
//監(jiān)聽事件
eventbus.$on("message",(msg)=>{
this.num=msg;
})
}
}
var vm=new Vue({
el:"#app",
data:{
num:10
},
components:{
blogCount
},
methods: {
clickHandle(){
//派發(fā)事件
eventbus.$emit('message',this.num)
}
}
})
</script>
5. vuex
Vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開發(fā)的狀態(tài)管理模式。它的狀態(tài)存儲(chǔ)是響應(yīng)式的厢破。采用集中式存儲(chǔ)管理應(yīng)用的所有組件的狀態(tài)荣瑟,也就是說,對(duì)數(shù)據(jù)的所有操作都要在vuex中進(jìn)行摩泪。
5.1 vuex 原理
vuex 實(shí)現(xiàn)了一個(gè)單向數(shù)據(jù)流笆焰,在全局擁有一個(gè) State 用來存放數(shù)據(jù),當(dāng)組件用同步的方式更改 State 中的數(shù)據(jù)時(shí)见坑,必須通過 Mutation 進(jìn)行嚷掠。當(dāng)使用異步方式(例如 ajax請(qǐng)求)修改數(shù)據(jù),必須先經(jīng)過 Actions 荞驴,再由 Actions 經(jīng)過 Mutation來操作不皆。
[圖片上傳失敗...(image-f4a68b-1650376415186)]
5.2 store
每一個(gè) Vuex 應(yīng)用的核心就是 store(倉庫)⌒苈ィ“store”基本上就是一個(gè)容器霹娄,它包含著你的應(yīng)用中大部分的狀態(tài) (state)。
const store = new Vuex.Store({
state: {
//相當(dāng)于自定義組件中的data
},
getters:{
//相當(dāng)于自定義組件中的computed
},
mutations: {
//相當(dāng)于自定義組件中的methods鲫骗,只能做同步的操作
//對(duì)state中的數(shù)據(jù)進(jìn)行修改
},
actions: {
//異步操作犬耻,例如ajax請(qǐng)求
//使用commit 觸發(fā) mutations
}
})
5.3 vuex的核心概念
5.3.1 State
- State相當(dāng)于自定義組件中的data,用來存放數(shù)據(jù)执泰,頁面中所有的數(shù)據(jù)都是從該對(duì)象中進(jìn)行讀取香追。
- 在組件中使用 store.state / this.$store.state 來讀取vuex中的數(shù)據(jù)。
//創(chuàng)建 vuex 實(shí)例
const store = new Vuex.Store({
state: {
count:3
}
}
//創(chuàng)建 vue 實(shí)例
const app = new Vue({
el: '#app',
store,
components: { Counter },
template: `<div class="app"><counter></counter></div>`
})
//自定義組件
const Counter = {
template: `<div>{{ count }}</div>`,
computed: {
count () {
return this.$store.state.count
}
}
}
5.3.2 getter
- getter 相當(dāng)于自定義組件中的computed坦胶,getter 的返回值會(huì)根據(jù)它的依賴被緩存起來透典,且只有當(dāng)它的依賴值發(fā)生了改變才會(huì)被重新計(jì)算晴楔。
- Getter 接受 state 作為其第一個(gè)參數(shù),也可以接受其他 getter 作為第二個(gè)參數(shù)峭咒。
- 可以使用 store.getters / this.$store.getters 訪問這些值税弃。
const store = new Vuex.Store({
state: {
sourceList:[],
pageNo:1,
pageSize:5,
},
getters: {
dataList:(state)=>{
//計(jì)算分頁后的數(shù)據(jù)
let start=(state.pageNo-1)*state.pageSize;
let end=start+state.pageSize;
let result=state.sourceList.slice(start,end);
return result;
},
pages:(state,getters)=>{
//計(jì)算頁碼的范圍
return Math.ceil(getters.dataList.length/state.pageSize);
}
}
})
5.3.3 Mutation
- mutation 相當(dāng)于自定義組件中的methods。
- mutation是更改 Vuex 的 State 中數(shù)據(jù)的唯一方法凑队。
- 通過 store.commit(type,data)調(diào)用 mutation则果,第一個(gè)參數(shù)為事件類型,需要和mutation中函數(shù)名稱一致漩氨;第二個(gè)參數(shù)為要傳遞的參數(shù)西壮。
- mutation中的函數(shù)接受 state 作為其第一個(gè)參數(shù)。
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
increment (state) {
// 變更狀態(tài)
state.count++
}
}
})
const vm = new Vue(){
methods:{
change(){
store.commit("increment");
}
}
5.3.4 Action
- action 主要用來操作所有的異步請(qǐng)求叫惊。
- action 不能直接對(duì)State 中的數(shù)據(jù)進(jìn)行操作款青,只能通過commit(type,data) 方法調(diào)用 mutation。
- action 函數(shù)接受一個(gè)與 store 實(shí)例具有相同方法和屬性的 context 對(duì)象霍狰,因此你可以調(diào)用 context.commit 提交一個(gè) mutation抡草,或者通過 context.state 和 context.getters 來獲取 state 和 getters。
- 通過 store.dispatch(type)方法觸發(fā)action蔗坯,參數(shù)為事件類型康震,需要和action中函數(shù)名稱一致。
const store = new Vuex.Store({
state: {
dataList:[]
},
mutations: {
render(state,data){
state.dataList=data;
},
},
actions: {
getData({commit}){
fetch("./data.json").then((res)=>res.json()).then((res)=>{
commit("render",res.data);
})
**加粗樣式** }
}
})
const vm = new Vue(){
created(){
store.dispatch("getData");
}
}
總結(jié):
父組件和子組件間通信:
- 父向子傳遞數(shù)據(jù)是通過props宾濒,子向父?jìng)鬟f數(shù)據(jù)是通過event($emit)腿短;
- 通過父鏈/子鏈進(jìn)行數(shù)據(jù)傳遞(children);
- 通過 ref 也可以訪問組件實(shí)例绘梦;
- 依賴注入:provide / inject答姥;
兄弟組件間通信: - event bus
- Vuex
跨級(jí)組件間通信: - event bus;
- Vuex谚咬;
- 依賴注入:provide / inject鹦付;