父子組件通信
1餐禁、父子組件通過prop傳遞數(shù)據(jù)
父組件可以將一條數(shù)據(jù)傳遞給子組件血久,這條數(shù)據(jù)可以是動態(tài)的,父組件的數(shù)據(jù)更改的時候帮非,子組件接收的也會變化氧吐。
子組件被動的接收父組件的數(shù)據(jù),子組件不要再更改這條數(shù)據(jù)了。
組件實例的作用域是孤立的,父組件不能直接使用子組件的數(shù)據(jù)末盔,子組件也不能直接使用父組件的數(shù)據(jù)筑舅。
父組件在調用子組件的時候給子組件傳遞數(shù)據(jù):
<template id="father">
<div class="father">
<p>我是父組件,這是我的fMsg:{{fMsg}}</p>
<input type = "text" v-model = "fMsg">
<hr>
<son msg = "你好"></son>
</div>
</template>
父組件給子組件傳遞數(shù)據(jù)的時候庄岖,子組件需要利用props的屬性來確定自己的預期數(shù)據(jù)豁翎,如果兒子沒有通過props屬性接受傳遞過來的數(shù)據(jù),則數(shù)據(jù)會以自定義屬性的方式隅忿,放在兒子最外層的根元素上面心剥。
子組件通過props來接受父組件傳遞過來的數(shù)據(jù),并且通過{{msg}}使用
components:{
son:{
template:"<div>我是son子組件背桐!這是父組件傳遞給我的msg:{{msg}}</div>",
//接收父組件傳遞來的屬性 msg
props:["msg"]
}
}
2优烧、父組件通過v-bind指令傳遞自身變量給子組件
我們可以用 v-bind 來動態(tài)地將 prop 綁定到父組件的數(shù)據(jù)。每當父組件的數(shù)據(jù)變化時链峭,該變化也會傳導給子組件畦娄。
<template id="father">
<div class="father">
<p>我是父組件,這是我的fMsg:{{fMsg}}</p>
<input type = "text" v-model = "fMsg">
<hr>
<!-- <son msg = "你好"></son> -->
<son :msg = "fMsg"></son>
</div>
</template>
如果如果父組件傳遞屬性給子組件的時候鍵名有'-'
<son :f-msg = "fMsg"></son>
子組件接收、使用的時候寫成小駝峰的模式
components:{
son:{
template:"<div>我是son子組件熙卡!這是父組件傳遞給我的msg:{{fMsg}}</div>",
//接收父組件傳遞來的屬性 msg
props:["fMsg"]
}
}
3杖刷、prop驗證傳遞過來的數(shù)據(jù)
我們可以為組件的 prop 指定驗證規(guī)則。如果傳入的數(shù)據(jù)不符合要求驳癌,Vue 會發(fā)出警告滑燃。這對于開發(fā)給他人使用的組件非常有用
驗證主要分為:類型驗證、必傳驗證颓鲜、默認值設置表窘、自定義驗證
類型驗證
// 類型驗證
// num:Number //父組件傳遞過來的num必須是Number類型
// 添加多個類型
num: [Number,String],
規(guī)定傳遞過來的數(shù)值類型必須是number,否則系統(tǒng)會報錯
必傳驗證
規(guī)定父組件必須給子組件傳遞該值
//必傳驗證
// num:{
// required: true
// }
默認值設置
當父組件不給子組件傳遞該值的時候甜滨,給子組件設定一個默認值
// 默認值設置
// num:{
// default:100
// }
自定義驗證
//自定義驗證
num:{
validator(val){
return val > 100
}
}
規(guī)定傳遞過來的數(shù)值必須要大于100乐严,否則系統(tǒng)會報錯
4、父子組件依靠應用類型的地址傳遞共享數(shù)據(jù)
單向數(shù)據(jù)流
Prop 是單向綁定的:當父組件的屬性變化時衣摩,將傳遞給子組件昂验,但是反過來不會。這是為了防止子組件無意間修改了父組件的狀態(tài)昭娩,來避免應用的數(shù)據(jù)流變得難以理解凛篙。
<template id="father">
<div class="father">
<input type = "text" v-model = "message">
<hr>
<son :message = "message"></son>
</div>
</template>
<template id = "son">
<div>
<p>這是子組件</p>
<input type = "text" v-model = "message"></input>
</div>
</template>
另外黍匾,每次父組件更新時栏渺,子組件的所有 prop 都會更新為最新值。這意味著你不應該在子組件內部改變 prop锐涯。如果你這么做了,Vue 會在控制臺給出警告纹腌。
所以如果我們想實現(xiàn)父子間的數(shù)據(jù)共享,依靠的就是應用類型的地址傳遞升薯,應將message寫成對象的形式莱褒,傳遞的時候將對象傳遞給子組件广凸,子組件引用的時候使用對象的value值。
<template id="father">
<div class="father">
<input type = "text" v-model = "message.value">
<hr>
<!-- 傳遞的時候將對象傳遞給子組件 -->
<son :message = "message"></son>
</div>
</template>
<template id = "son">
<div>
<p>這是子組件</p>
<!-- 引用的時候使用對象的value值 -->
<input type = "text" v-model = "message.value"></input>
</div>
</template>
這時候更改父組件的value值谅海,子組件的數(shù)據(jù)同步更改,子組件修改value值的時候也同步修改了父組件的數(shù)據(jù)扭吁。這是因為不管是子組件還是父組件,我們操作的都是同一個對象侥袜,父組件直接把引用類型的地址傳遞給子組件,子組件沒有直接修改對象枫吧,只是更改了里面的屬性值。
父組件如果將一個引用類型的動態(tài)數(shù)據(jù)傳遞給子組件的時候由蘑,數(shù)據(jù)會變成雙向控制的,子組件改數(shù)據(jù)的時候父組件也能接收到數(shù)據(jù)變化,因為子組件改的時候不是在改數(shù)據(jù)(地址)尼酿,而是在改數(shù)據(jù)里的內容,也就是說引用類型數(shù)據(jù)的地址始終沒有變化裳擎,不算改父組件數(shù)據(jù)。
注意:在 JavaScript 中對象和數(shù)組是引用類型鹿响,指向同一個內存空間,如果 prop 是一個對象或數(shù)組惶我,在子組件內部改變它會影響父組件的狀態(tài)。 message:{val:""}
5、viewmodel關系鏈
在組件間可以用過ref形成ref鏈捧挺,組件還擁有一個關系鏈($parent),通過這兩種鏈;理論來說闽烙,任意的兩個組件都可以互相訪問,互相進行通信黑竞。
$parent:父組件
$children:子組件
$root:根組件
當子組件在set方法中修改父組件傳遞過來的值時,系統(tǒng)會報錯摊溶,因為子組件不能修改父組件的數(shù)據(jù)。
Vue.component("bbb",{
template:"#bbb",
props:["msg"],
computed:{
/* ownMessage(){
return this.msg;
} */
ownMessage:{
get(){
return this.msg;
},
set(val){
this.msg = val //系統(tǒng)報錯:子組件不能更改父組件傳遞的數(shù)據(jù)
}
}
}
})
所以這時候要使用$parent莫换,讓父組件自己更改自己的數(shù)據(jù)
set(val){
// this.msg = val //系統(tǒng)報錯:子組件不能更改父組件傳遞的數(shù)據(jù)
// console.log(this)
// 相當于父組件自己更改了msg數(shù)據(jù)
this.$parent.msg = val;
}
6、父組件通過ref標記獲取子組件的數(shù)據(jù)
父組件在調用子組件的時候使用ref做標記
<template id="aaa">
<div>
<button @click = "get">點擊獲取bbb數(shù)據(jù)</button>
<!-- 組件間不僅可以用過$root/$parent/$children來獲取對應關系的組件坷剧,父組件還可以主動的通過ref為子組件做標記 -->
<bbb ref = "b"></bbb>
</div>
</template>
父組件的this屬性上有$refs標記,通過refs標記拿到子組件
// 通過ref標記更改子組件的數(shù)據(jù)
// this.$refs.b.message = "哈哈"
組件間不僅可以用過$parent/children/root來獲取對應關系的組件惫企,父組件還可以主動的通過ref為子組件做標記 也可以給dom做標記陵叽,也會形成ref鏈,也可以交互.
<button ref="btn" @click="get">get</button>
<bbb ref="b></bbb>
注意多個子組件標記的是同一個鍵名巩掺,獲取到的應該是一個數(shù)組
<bbb ref = "b" v-for = "(item,index) in 3" :key = "index"></bbb>
// 通過下標修改對應的數(shù)值
this.$refs.b[0].message = "哈哈"
運行效果:
子父組件通信
1、子組件通過父組件傳遞的方法來更改父組件的數(shù)據(jù)
父組件可以將更改自身數(shù)據(jù)的方法傳遞給子組件研儒,子組件調用這個方法的時候,就可以給父組件傳遞數(shù)據(jù)端朵,父組件被動的接收子組件的數(shù)據(jù)。
子組件聲明一條自身的msg
Vue.component("son",{
template:"#son",
// 子組件接收父組件傳遞過來的方法
props:["change"],
data(){
return{
msg:"我是子組件"
}
}
})
父組件先聲明一條自己的數(shù)據(jù)
data(){
return{
// 父組件先聲明一條自己的數(shù)據(jù)
parentMsg:""
}
}
再寫一個可以更改自身數(shù)據(jù)的方法
methods:{
// 寫一個可以更改自身數(shù)據(jù)的方法
change(msg){
this.parentMsg = msg
}
}
將寫好的change方法傳遞給子組件
<template id="father">
<div>
<p>這是父組件</p>
<p>子組件傳遞過來的值是:{{parentMsg}}</p>
<hr>
<!-- 調用子組件的時候冲呢,將更改自身數(shù)據(jù)的方法傳遞給子組件 -->
<son :change = "change"></son>
</div>
</template>
子組件通過props接收父組件傳遞過來的change方法
props:["change"]
給p標簽添加點擊事件,點擊即觸發(fā)change方法碗硬,同時將自身的msg傳遞給父組件瓤湘,相當于父組件的change方法被執(zhí)行砌创。
<template id="son">
<div>
<p>子組件說:{{msg}}</p>
<p @click = "change(msg)">點擊我觸發(fā)父親的change方法</p>
</div>
</template>
父組件可以在頁面中渲染子組件傳遞過來的數(shù)據(jù)
<p>子組件傳遞過來的值是:{{parentMsg}}</p>
運行效果:
2、通過自定義事件實現(xiàn)子父通信
每一個組件或者實例都會有自定義事件住涉,和觸發(fā)事件的能力信柿,父組件給子組件綁定一個自定義事件醒第,這個事件的處理程序卻是父組件的一個方法,當子組件觸發(fā)這個事件的時候稠曼,相當于父組件的方法被執(zhí)行。
父組件想獲取子組件的數(shù)據(jù)時,在調用子組件的時候給子組件綁定一個自定義事件change-event
<template id="father">
<div>
<p>這是父組件</p>
<p>子組件傳遞過來的值是:{{parentMsg}}</p>
<hr>
<!-- 給子組件綁定一個自定義事件 -->
<son @change-event = "change"></son>
</div>
</template>
在子組件中定義一個點擊事件漠吻,點擊p標簽執(zhí)行changeWord方法
<p @click = "changeWord">點擊我觸發(fā)父親的change方法</p>
在方法中編寫changeWord方法,通過this.$emit來觸發(fā)綁定在自己身上的自定義事件途乃,第一個參數(shù)為事件名稱change-event,第二個參數(shù)為觸發(fā)這個函數(shù)的時候給他傳遞的數(shù)值:自身的msg耍共。
methods:{
changeWord(){
//觸發(fā)自身綁定的change事件
this.$emit("change-event",this.msg)//第一個參數(shù)為觸發(fā)事件的名字,第二個參數(shù)為觸發(fā)這個函數(shù)的時候給他傳遞的數(shù)值
}
}
一旦觸發(fā)綁定在自身上的自定義事件试读,相當于父組件的change方法被執(zhí)行。
兄弟組件通信
1鹏往、通過viewmodel關系鏈
定義哥哥組件,給哥哥組件添加一個點擊事件伊履,點擊觸發(fā)hitLittle方法
<template id = "big-brother">
<div>
<p>我是哥哥</p>
<button @click = "hitLittle">打弟弟</button>
</div>
</template>
定義弟弟組件,給弟弟組件添加一個p標簽唐瀑,由crying數(shù)據(jù)控制其顯示與隱藏
<template id="little-brother">
<div>
<p>我是弟弟</p>
<p v-if = "crying">嗚嗚嗚</p>
</div>
</template>
在弟弟組件的data中聲明crying數(shù)據(jù),默認為false
Vue.component("little-brother",{
template:"#little-brother",
data(){
return{
crying:false
}
}
})
在哥哥組件的methods中定義hitLittle方法哄辣,通過viewmodel關系鏈更改弟弟組件中的crying方法
Vue.component("big-brother",{
template:"#big-brother",
methods:{
hitLittle(){
//在兄弟組件之間的通信,可以采用關系鏈和ref鏈去使用力穗,解決兄弟之間通信問題。
this.$parent.$children[1].crying = true;//讓littel改變自身的crying狀態(tài)
}
}
})
運行效果:
2当窗、viewmodel關系鏈+ref鏈
在弟弟組件中添加ref標記
<little-brother ref = "little"></little-brother>
在哥哥組件的hitLittle方法中通過viewmodel和ref鏈配合使用更改弟弟組件中的crying數(shù)據(jù)
hitLittle(){
//在兄弟組件之間的通信,可以采用關系鏈和ref鏈去使用崖面,解決兄弟之間通信問題。
// this.$parent.$children[1].crying = true;//讓littel改變自身的crying狀態(tài)
//viewmodel鏈和ref鏈配合使用
this.$parent.$refs.little.crying = true;
}
3巫员、eventbus事件總線
創(chuàng)建一個空的實例
var angle = new Vue();
弟弟組件自己定義一個更改自身狀態(tài)的方法
methods:{
cry(){
this.crying = true
}
}
在mounted生命周期函數(shù)中綁定一個自定義事件,第一個參數(shù)為自定義事件名简识,第二個函數(shù)為需要處理的函數(shù)
mounted(){
// 綁定一個自定義事件救军,第一個參數(shù)為自定義事件名,第二個函數(shù)為需要處理的函數(shù)
angle.$on("hit-little",this.cry)
}
在哥哥組件中觸發(fā)自定義事件
hitLittle(){
//觸發(fā)little-brother組件的hit-little事件
angle.$emit("hit-little")
}
4唱遭、vuex狀態(tài)管理
vuex是vue提供的一個全局的狀態(tài)管理工具,主要處理項目中多組件間狀態(tài)共享拷泽。
Vuex是vue官方的一款狀態(tài)管理工具,什么是狀態(tài)呢司致?我們在前端開發(fā)中有一個概念:數(shù)據(jù)驅動,頁面中任意的顯示不同脂矫,都應該有一條數(shù)據(jù)來控制,而這條數(shù)據(jù)又叫做state霉晕,狀態(tài)。
在vue中牺堰。組件間進行數(shù)據(jù)傳遞、通信很頻繁伟葫,而父子組件和非父子組件的通信功能也比較完善,但是筏养,唯一困難的就是多組件間的數(shù)據(jù)共享,這個問題由vuex來處理
(1)創(chuàng)建store
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
(2)設置state
state就是一個純對象渐溶,上面有一些狀態(tài)掛載
state: {
num:0,
name:"list"
}
(3)在根實例里配置store
這樣,我們就可以在任意的組件中通過this.$store來使用關于store的api
import store from './store/index'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
(4)在Home組件中使用state
computed:{
...mapState({
num:state=>state.num
})
},
(5)使用mutations更改state
mutations也是一個純對象掌猛,里面包含很多更改state 的方法,這些方法的形參接收到state荔茬,在函數(shù)體里更改竹海,這時,組件用到的數(shù)據(jù)也會更改斋配,實現(xiàn)響應式灌闺。
mutations: {
changeNum(state){
state.num++
}
}
(6)在組件中調用mutations方法,更改組件中的state坏瞄。
//使用vuex提供的mapMutations幫助我們在組件中調用mutations方法
...mapMutations(["changeNum"]),
//給按鈕添加點擊事件
<button @click = "changeNum">點擊更改num值</button>
運行效果: