首先 vue
组件化的一个框架。
既然是组件化。
那么一定存在组件和组件之间传值的问题
在讨论组件和组件怎么传值的问题之前,
可以先看看组件与组价之间有三种关系。
- 父->子
- 子->父
- 平行组件之间传值.
1. 父子组件间传值.
一个父组件里面包含了一个子组件,需要把父组件的数据传递给子组件以便于子组件显示.
数据流动方向:父组件数据
-> 子组件
子组件利用
绑定属性
的方式绑定父组件的数据属性,从而获取父组件的值.
Vue.component('pview',{
template:`<div>
<input type="text" v-model='message'>
<!-- 这里使用 v-bind 表达式绑定父容器的数据属性 -->
<cview :msg="message"></civew>
</div>`,
data:function(){
return {
message:'message in parentView'
}
}
})
Vue.component('cview',{
template:`<p>从父组件获取到的值:{{msg}}</p>`,
props:['msg'] // 子组件需要使用 props来接收
})
html
<div id='app'>
<pview></pview>
<selfview outter-Data='这是普通扩展属性'></selfview>
</div>
结果:
父->子传值.gif上述demo
中,在子组件的顶级利用 v-bind:
表达式绑定父组件的 data
属性.并在子组件内部使用 props
属性来接收这个msg
,即可在子组件内部使用{{msg}}
or this.msg
了.
补充:
我们可以在子组件标签里使用
v-bind:msg = 父组件数据属性
,并子子组件内搭配props:['msg']
来获取到从父组件传递过来的属性数据.
子组件扩展属性
这里的子组件扩展属性和父组件就没有关系了,完全是子组件自己的数据行为.
数据流动方向:子组件扩展属性
-> 子组件
Vue.component('selfview', {
template:`<button @click="on_click"> {{outterData}} -- {{innerData}}</button>`,
props:['outterData'], // 属性扩展都需要些在这里. *** 注意,扩展属性写的是 outter-Data ,这里写的是 outterData .
data:function() {
return {
innerData:'这是组件自己内部的数据属性字段'
}
}
})
<!-- 注意,这里不是使用的:outter-Data 而是普通的 outter-Data -->
<selfview outter-Data='这是普通扩展属性'></selfview>
html
<div id='app'>
<pview></pview>
<selfview outter-Data='这是普通扩展属性'></selfview>
</div>
结果:
子组件自己的普通扩展属性,注意命名方式总结:
- 在子组件顶级标签里可以使用
:msg='父组件属性'(v-bind:不要忘记冒号)
&props['msg']
的方式拿到父组件属性数据. - 也可以完全扩展一个属性自己的数据属性
msg='自己的扩展的属性值'
&props:['msg']
子组件可以通过扩展属性绑定
:msg='parentMSG'
&props:['msg']
的方式给从父组件那里获取到值.
子组件往父组件传值
子组件通过 属性
的方式从父组件获取数据.
当子组件需要向父组件传递数据(数据流向:子组件
-> 父组件
) ,一般是通过事件
来实现.
Vue.component('pview',{
template:`<div>
<h3>我是父组件</h3>从子组件传递过来的值:{{dataFromCview}}
<cview @send-data-to-pview="showDataFromCView"></cview>
</div>`,
data:function() {
return {
dataFromCview:''
}
},
methods:{
// 父组件提供事件响应函数,并利用第一个参数data获取子组件传递过来的数据
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(){
// 定义了一个事件,触发这个事件的响应函数是绑定了父组件的showDataFromCview方法,并将子组件的 this.name 属性以参数的形式传递回去.
this.$emit('send-data-to-pview',this.name)
}
}
})
html
<div id='app'>
<pview></pview>
</div>
结果:
子->父传值.gif总结:
子组件从父组件传递值的时候,是利用
自定义事件指向父组件的某个方法
,并在子组件内部触发这个自定义事件,间接的触发定义在父组件身上的方法,在利用参数
的形式将数据从子组件传递到父组件身上去 .
补充:
当然,子组件定义的事件,不光可以绑定和触发父组件的方法,也可以直接修改父组件的属性值.
子组件定义一个 on_change_pview_data_pro
事件,在触发这个 on_change_pview_data_pro
事件时,直接修改父组件的 name
属性.
Vue.component('pview',{
template:`<div style='border:1px solid black'>
<h3>我是父组件</h3>
<p>从子组件传递过来的值:{{dataFromCview}}</p>
<p>子组件通过事件直接修改父组件的name属性:{{name}}</p>
<cview @send-data-to-pview="showDataFromCView" @on_change_pview_data_pro="name='通过事件常量传值'"></cview>
</div>`,
data:function() {
return {
dataFromCview:'',
name: '这是name默认值'
}
},
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'>通过事件直接修改父组件的属性值</button>
</div>`,
data:function(){
return {
name:''
}
},
methods:{
on_click(){
// 定义了一个事件,触发这个事件的响应函数是绑定了父组件的showDataFromCview方法,并将子组件的 this.name 属性以参数的形式传递回去.
this.$emit('send-data-to-pview',this.name)
},
on_change_pview_data_pro() {
// 子组件直接触发事件,没有传递参数,因为没有绑定事件响应函数(父组件的某个方法)
// 而是直接修改父组件的某个数据属性(name)的值为常量(通过事件常量传值)
// @on_change_pview_data_pro="name='通过事件常量传值'"
this.$emit('on_change_pview_data_pro')
}
}
})
html
<div id='app'>
<pview></pview>
</div>
结果
子->父传值-直接在事件里修改父组件的属性值.gif两个平行的组价之间传递消息
首先回顾父子间数据如何传递的:
-
数据流从
父组件 --- >子组件
通过 属性- 子组件利用属性
:msg='pmsg'
& 'props:['msg']' 拿到父组件的数据属性. - 子组件也可以自定义
msg='abc'
&props:['msg']
来扩展自己的自定义属性.
- 子组件利用属性
-
数据流从
子组件 --- > 父组件
通过 事件- 子组件通过非常正统的
子组件事件
&父组件事件响应方法
的方式来传递数据- 子组件在定义一个自定义事件,
@send-data-to-pview='showDataFromCView'
,给此事件绑定一个父组件的事件响应函数
. - 子组件在内部触发这个自定义事件,并通过第二个参数将数据传递到父组件事件响应方法里.
- 子组件在定义一个自定义事件,
// 子组件事件绑定父组件事件响应函数 <cview @send-data-to-pview="showDataFromCView" ></civew> // 子组件触发这个事件 & 传递参数 on_click(){ this.$emit('send-data-to-pview',this.name) }, // 父组件提供事件响应方法,并接受参数 showDataFromCView(data) { this.dataFromCview = data }
- 子组件通过非常正统的
+ 子组件事件直接修改父组件的数据属性值/
```JavaScript
// 注意,这里的 name 是父组件的属性
<cview @on_change_pview_data_pro="name='通过事件常量传值'"></cview>
```
也就是说,到目前为止,父子组件间传递数据.
+ 父 --> 子,利用`属性`
+ 子 --> 父,利用`事件`.
而**平行的两个组件之间**,是里用`事件`来传递值的.
**场景**
一个 **talker** 用来说一些话.
一个 **listener** 用来听 **talker**说的这些话.
```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:'我还什么都没说'
}
},
methods:{
isSaying() {
// Event 通过 $emit,直接发送一个 event-talker-saying 的事件.
// 并传出这个 this.content 数据.
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:''
}
},
// 事件监听
// 当组件加载到 DOM 中去时 ,绑定并监听这个事件
mounted() {
Event.$on('event-talker-saying',(content)=>{
this.talkerSay = content
})
},
})
html
<div id='app'>
<talker></talker>
<listener></listener>
</div>
它俩是平级的.
结果
平级组件间传值.gif主要步骤:
- 使用
new Vue()
构造函数,获取一个没有作用域的全局vue
事件实例.Event -
talker
组件在合适的时机,使用Event触发事件event-talker-saying
,并传递参数.
isSaying() {
// Event 通过 $emit,直接发送一个 event-talker-saying 的事件.
// 并传出这个 this.content 数据.
Event.$emit('event-talker-saying',this.content)
}
-
listener
在合适的时机(onmounted()),订阅事件,并在二个参数箭头函数里,拿到触发事件带过来的数据.
// 事件监听
// 当组件加载到 DOM 中去时 ,绑定并监听这个事件
mounted() {
Event.$on('event-talker-saying',(content)=>{
this.talkerSay = content
})
},
// 补充一点,由于this作用域的问题,在这里推荐使用箭头函数.
最后总结:
- 数据传递方向
-
父 -> 子 利用属性!!!****属性!!!****属性!!!
-
子组件身上利用属性
-
绑定父组件属性
:msg='pmg'
-
自己的扩展属性
msg='hellworld'
-
别忘了子组件内部的
props:['msg']
-
-
-
子 -> 父 利用事件!!!****事件!!!****事件!!!
-
子组件身上自己订阅自定义事件
-
事件可以绑定父组件的某个方法作为事件响应函数.
-
事件也可可以直接以常量的方式修改父组件数据属性的值.
-
-
事件定义了,需要触发.
- 子组件在合适的时机里,去触发这个事件.
this.$emit('event-name',param)
- 子组件在合适的时机里,去触发这个事件.
-
-
A -> B 平级的两个组件使用 事件!!!****事件!!!****事件!!!
- 需要传递数据的一方,利用一个全局的事件对象
let Event = new Vue()
,来触发一个事件,并传递事件数据.
- 需要传递数据的一方,利用一个全局的事件对象
-
Event.$emit('event-talker-saying',this.content)
- 需要接受数据的这一方,则在一个合适的时机,监听此事件,并根据第二个箭头匿名函数拿到事件传递过来的数据.
Event.$on('event-talker-saying',(content)=>{
this.talkerSay = content
})
网友评论