首先 vue
組件化的一個(gè)框架。
既然是組件化。
那么一定存在組件和組件之間傳值的問(wèn)題
在討論組件和組件怎么傳值的問(wèn)題之前,
可以先看看組件與組價(jià)之間有三種關(guān)系。
- 父->子
- 子->父
- 平行組件之間傳值.
1. 父子組件間傳值.
一個(gè)父組件里面包含了一個(gè)子組件,需要把父組件的數(shù)據(jù)傳遞給子組件以便于子組件顯示.
數(shù)據(jù)流動(dòng)方向:父組件數(shù)據(jù)
-> 子組件
子組件利用
綁定屬性
的方式綁定父組件的數(shù)據(jù)屬性,從而獲取父組件的值.
Vue.component('pview',{
template:`<div>
<input type="text" v-model='message'>
<!-- 這里使用 v-bind 表達(dá)式綁定父容器的數(shù)據(jù)屬性 -->
<cview :msg="message"></civew>
</div>`,
data:function(){
return {
message:'message in parentView'
}
}
})
Vue.component('cview',{
template:`<p>從父組件獲取到的值:{{msg}}</p>`,
props:['msg'] // 子組件需要使用 props來(lái)接收
})
html
<div id='app'>
<pview></pview>
<selfview outter-Data='這是普通擴(kuò)展屬性'></selfview>
</div>
結(jié)果:
上述demo
中,在子組件的頂級(jí)利用 v-bind:
表達(dá)式綁定父組件的 data
屬性.并在子組件內(nèi)部使用 props
屬性來(lái)接收這個(gè)msg
,即可在子組件內(nèi)部使用{{msg}}
or this.msg
了.
補(bǔ)充:
我們可以在子組件標(biāo)簽里使用
v-bind:msg = 父組件數(shù)據(jù)屬性
,并子子組件內(nèi)搭配props:['msg']
來(lái)獲取到從父組件傳遞過(guò)來(lái)的屬性數(shù)據(jù).
子組件擴(kuò)展屬性
這里的子組件擴(kuò)展屬性和父組件就沒有關(guān)系了,完全是子組件自己的數(shù)據(jù)行為.
數(shù)據(jù)流動(dòng)方向:子組件擴(kuò)展屬性
-> 子組件
Vue.component('selfview', {
template:`<button @click="on_click"> {{outterData}} -- {{innerData}}</button>`,
props:['outterData'], // 屬性擴(kuò)展都需要些在這里. *** 注意,擴(kuò)展屬性寫的是 outter-Data ,這里寫的是 outterData .
data:function() {
return {
innerData:'這是組件自己內(nèi)部的數(shù)據(jù)屬性字段'
}
}
})
<!-- 注意,這里不是使用的:outter-Data 而是普通的 outter-Data -->
<selfview outter-Data='這是普通擴(kuò)展屬性'></selfview>
html
<div id='app'>
<pview></pview>
<selfview outter-Data='這是普通擴(kuò)展屬性'></selfview>
</div>
結(jié)果:
總結(jié):
- 在子組件頂級(jí)標(biāo)簽里可以使用
:msg='父組件屬性'(v-bind:不要忘記冒號(hào))
&props['msg']
的方式拿到父組件屬性數(shù)據(jù). - 也可以完全擴(kuò)展一個(gè)屬性自己的數(shù)據(jù)屬性
msg='自己的擴(kuò)展的屬性值'
&props:['msg']
子組件可以通過(guò)擴(kuò)展屬性綁定
:msg='parentMSG'
&props:['msg']
的方式給從父組件那里獲取到值.
子組件往父組件傳值
子組件通過(guò) 屬性
的方式從父組件獲取數(shù)據(jù).
當(dāng)子組件需要向父組件傳遞數(shù)據(jù)(數(shù)據(jù)流向:子組件
-> 父組件
) ,一般是通過(guò)事件
來(lái)實(shí)現(xiàn).
Vue.component('pview',{
template:`<div>
<h3>我是父組件</h3>從子組件傳遞過(guò)來(lái)的值:{{dataFromCview}}
<cview @send-data-to-pview="showDataFromCView"></cview>
</div>`,
data:function() {
return {
dataFromCview:''
}
},
methods:{
// 父組件提供事件響應(yīng)函數(shù),并利用第一個(gè)參數(shù)data獲取子組件傳遞過(guò)來(lái)的數(shù)據(jù)
showDataFromCView(data) {
this.dataFromCview = data
}
}
})
Vue.component('cview',{
template:`<div>
<input type='text' v-model='name'/>
<button @click='on_click'>傳值</button>
</div>`,
data:function(){
return {
name:''
}
},
methods:{
on_click(){
// 定義了一個(gè)事件,觸發(fā)這個(gè)事件的響應(yīng)函數(shù)是綁定了父組件的showDataFromCview方法,并將子組件的 this.name 屬性以參數(shù)的形式傳遞回去.
this.$emit('send-data-to-pview',this.name)
}
}
})
html
<div id='app'>
<pview></pview>
</div>
結(jié)果:
總結(jié):
子組件從父組件傳遞值的時(shí)候,是利用
自定義事件指向父組件的某個(gè)方法
,并在子組件內(nèi)部觸發(fā)這個(gè)自定義事件,間接的觸發(fā)定義在父組件身上的方法,在利用參數(shù)
的形式將數(shù)據(jù)從子組件傳遞到父組件身上去 .
補(bǔ)充:
當(dāng)然,子組件定義的事件,不光可以綁定和觸發(fā)父組件的方法,也可以直接修改父組件的屬性值.
子組件定義一個(gè) on_change_pview_data_pro
事件,在觸發(fā)這個(gè) on_change_pview_data_pro
事件時(shí),直接修改父組件的 name
屬性.
Vue.component('pview',{
template:`<div style='border:1px solid black'>
<h3>我是父組件</h3>
<p>從子組件傳遞過(guò)來(lái)的值:{{dataFromCview}}</p>
<p>子組件通過(guò)事件直接修改父組件的name屬性:{{name}}</p>
<cview @send-data-to-pview="showDataFromCView" @on_change_pview_data_pro="name='通過(guò)事件常量傳值'"></cview>
</div>`,
data:function() {
return {
dataFromCview:'',
name: '這是name默認(rèn)值'
}
},
methods:{
showDataFromCView(data) {
this.dataFromCview = data
}
}
})
Vue.component('cview',{
template:`<div style='border:1px solid red;margin:5px;'>
<p>我是子組件</p>
<input type='text' v-model='name'/>
<button @click='on_click'>傳值</button><br>
<button @click='on_change_pview_data_pro'>通過(guò)事件直接修改父組件的屬性值</button>
</div>`,
data:function(){
return {
name:''
}
},
methods:{
on_click(){
// 定義了一個(gè)事件,觸發(fā)這個(gè)事件的響應(yīng)函數(shù)是綁定了父組件的showDataFromCview方法,并將子組件的 this.name 屬性以參數(shù)的形式傳遞回去.
this.$emit('send-data-to-pview',this.name)
},
on_change_pview_data_pro() {
// 子組件直接觸發(fā)事件,沒有傳遞參數(shù),因?yàn)闆]有綁定事件響應(yīng)函數(shù)(父組件的某個(gè)方法)
// 而是直接修改父組件的某個(gè)數(shù)據(jù)屬性(name)的值為常量(通過(guò)事件常量傳值)
// @on_change_pview_data_pro="name='通過(guò)事件常量傳值'"
this.$emit('on_change_pview_data_pro')
}
}
})
html
<div id='app'>
<pview></pview>
</div>
結(jié)果
兩個(gè)平行的組價(jià)之間傳遞消息
首先回顧父子間數(shù)據(jù)如何傳遞的:
-
數(shù)據(jù)流從
父組件 --- >子組件
通過(guò) 屬性- 子組件利用屬性
:msg='pmsg'
& 'props:['msg']' 拿到父組件的數(shù)據(jù)屬性. - 子組件也可以自定義
msg='abc'
&props:['msg']
來(lái)擴(kuò)展自己的自定義屬性.
- 子組件利用屬性
-
數(shù)據(jù)流從
子組件 --- > 父組件
通過(guò) 事件- 子組件通過(guò)非常正統(tǒng)的
子組件事件
&父組件事件響應(yīng)方法
的方式來(lái)傳遞數(shù)據(jù)- 子組件在定義一個(gè)自定義事件,
@send-data-to-pview='showDataFromCView'
,給此事件綁定一個(gè)父組件的事件響應(yīng)函數(shù)
. - 子組件在內(nèi)部觸發(fā)這個(gè)自定義事件,并通過(guò)第二個(gè)參數(shù)將數(shù)據(jù)傳遞到父組件事件響應(yīng)方法里.
- 子組件在定義一個(gè)自定義事件,
// 子組件事件綁定父組件事件響應(yīng)函數(shù) <cview @send-data-to-pview="showDataFromCView" ></civew> // 子組件觸發(fā)這個(gè)事件 & 傳遞參數(shù) on_click(){ this.$emit('send-data-to-pview',this.name) }, // 父組件提供事件響應(yīng)方法,并接受參數(shù) showDataFromCView(data) { this.dataFromCview = data }
- 子組件通過(guò)非常正統(tǒng)的
+ 子組件事件直接修改父組件的數(shù)據(jù)屬性值/
```JavaScript
// 注意,這里的 name 是父組件的屬性
<cview @on_change_pview_data_pro="name='通過(guò)事件常量傳值'"></cview>
```
也就是說(shuō),到目前為止,父子組件間傳遞數(shù)據(jù).
+ 父 --> 子,利用`屬性`
+ 子 --> 父,利用`事件`.
而**平行的兩個(gè)組件之間**,是里用`事件`來(lái)傳遞值的.
**場(chǎng)景**
一個(gè) **talker** 用來(lái)說(shuō)一些話.
一個(gè) **listener** 用來(lái)聽 **talker**說(shuō)的這些話.
```JavaScript
let Event = new Vue()
Vue.component('talker',{
template:`<div>
talker Says: <input type='text' @keyup='isSaying' v-model='content' />
</div>`,
data:function(){
return {
content:'我還什么都沒說(shuō)'
}
},
methods:{
isSaying() {
// Event 通過(guò) $emit,直接發(fā)送一個(gè) event-talker-saying 的事件.
// 并傳出這個(gè) this.content 數(shù)據(jù).
Event.$emit('event-talker-saying',this.content)
}
}
})
Vue.component('listener',{
template:`<div>
<span>i heard talker says:</span>
<span style='font-weight:800;font-size:30px'>{{talkerSay}}</span>
</div>`,
data:function(){
return {
talkerSay:''
}
},
// 事件監(jiān)聽
// 當(dāng)組件加載到 DOM 中去時(shí) ,綁定并監(jiān)聽這個(gè)事件
mounted() {
Event.$on('event-talker-saying',(content)=>{
this.talkerSay = content
})
},
})
html
<div id='app'>
<talker></talker>
<listener></listener>
</div>
它倆是平級(jí)的.
結(jié)果
主要步驟:
- 使用
new Vue()
構(gòu)造函數(shù),獲取一個(gè)沒有作用域的全局vue
事件實(shí)例.Event -
talker
組件在合適的時(shí)機(jī),使用Event觸發(fā)事件event-talker-saying
,并傳遞參數(shù).
isSaying() {
// Event 通過(guò) $emit,直接發(fā)送一個(gè) event-talker-saying 的事件.
// 并傳出這個(gè) this.content 數(shù)據(jù).
Event.$emit('event-talker-saying',this.content)
}
-
listener
在合適的時(shí)機(jī)(onmounted()),訂閱事件,并在二個(gè)參數(shù)箭頭函數(shù)里,拿到觸發(fā)事件帶過(guò)來(lái)的數(shù)據(jù).
// 事件監(jiān)聽
// 當(dāng)組件加載到 DOM 中去時(shí) ,綁定并監(jiān)聽這個(gè)事件
mounted() {
Event.$on('event-talker-saying',(content)=>{
this.talkerSay = content
})
},
// 補(bǔ)充一點(diǎn),由于this作用域的問(wèn)題,在這里推薦使用箭頭函數(shù).
最后總結(jié):
- 數(shù)據(jù)傳遞方向
-
父 -> 子 利用屬性!!!****屬性!!!****屬性!!!
-
子組件身上利用屬性
綁定父組件屬性
:msg='pmg'
自己的擴(kuò)展屬性
msg='hellworld'
別忘了子組件內(nèi)部的
props:['msg']
-
-
子 -> 父 利用事件!!!****事件!!!****事件!!!
-
子組件身上自己訂閱自定義事件
事件可以綁定父組件的某個(gè)方法作為事件響應(yīng)函數(shù).
事件也可可以直接以常量的方式修改父組件數(shù)據(jù)屬性的值.
-
事件定義了,需要觸發(fā).
- 子組件在合適的時(shí)機(jī)里,去觸發(fā)這個(gè)事件.
this.$emit('event-name',param)
- 子組件在合適的時(shí)機(jī)里,去觸發(fā)這個(gè)事件.
-
-
A -> B 平級(jí)的兩個(gè)組件使用 事件!!!****事件!!!****事件!!!
- 需要傳遞數(shù)據(jù)的一方,利用一個(gè)全局的事件對(duì)象
let Event = new Vue()
,來(lái)觸發(fā)一個(gè)事件,并傳遞事件數(shù)據(jù).
- 需要傳遞數(shù)據(jù)的一方,利用一個(gè)全局的事件對(duì)象
-
Event.$emit('event-talker-saying',this.content)
- 需要接受數(shù)據(jù)的這一方,則在一個(gè)合適的時(shí)機(jī),監(jiān)聽此事件,并根據(jù)第二個(gè)箭頭匿名函數(shù)拿到事件傳遞過(guò)來(lái)的數(shù)據(jù).
Event.$on('event-talker-saying',(content)=>{
this.talkerSay = content
})