父子组件间通过事件通信
子组件通知父组件修改父组件data中的数据
子组件通知父组件,让父组件修改data中定义的数据
自定义事件实现子父子组件通信
const app = Vue.createApp({
data() {
return {
count: 1
}
},
methods:{
handleAddOne() {
this.count += 1
}
},
template:`
<div>
<counter :count="count" @add-one="handleAddOne"/>
</div>
`
})
app.component('counter',{
props:["count"],
methods:{
handleClick() {
this.$emit('addOne')
}
},
template:`
<div @click="handleClick">{{count}}</div>
`
})
const vm = app.mount('#root')
如上面的例子,由于vue中单项数据流,子组件不允许直接修改父组件传递过来的数据,因此子组件需要告诉父组件修改父组件中data中数据count
子组件如何通知父组件去修改数据呢?
子组件通过this.$emit('addOne')
向外触发事件,父组件就能自动的监听到这个事件
父组件在调用子组件的地方使用 @add-one 监听并绑定父组件自己的事件处理方法handleAddOne <counter @add-one="handleAddOne"/>
备注
- 使用
this.$emit('addOne')
向外触发事件的时候,事件的名称要使用驼峰式- 但是在监听事件的时候要使用横线连接的方式命名
<counter @add-one="handleAddOne"/>
总结
子组件通过
this.$emint('event')
向外触发事件, 父组件通过在子组件上自定义这个子组件触发的事件@event
,实现父子组件的通信,尤其是子组件向父组件传信息
父组件接收子组件传递过来的数据
上面的例子,只是子组件“通知”父组件修改父组件data中的数据,实现简单的子组件和父组件之间的通信
但是子组件还可以传递数据给父组件
const app = Vue.createApp({
data() {
return {
count: 1
}
},
methods:{
handleAdd(param) {
this.count += param
}
},
template:`
<div>
<counter :count="count" @add="handleAdd"/>
</div>
`
})
app.component('counter',{
props:["count"],
methods:{
handleClick() {
this.$emit('add',2)
}
},
template:`
<div @click="handleClick">{{count}}</div>
`
})
const vm = app.mount('#root')
如上面例子所示,子组件通过this.$emit
向外触发事件的同时,后面还能跟一个传递给父组件的参数this.$emit('add',2)
父组件通过在子组件上@add
监听这个事件,监听事件的方法handleAdd
就可以获取到这个参数
这样每次点击count,就由之前的每次只能加1,变成可以增加2了。当然this.$emit('add',2)
,不只是可以传一个参数2,还可以传给多的参数。
优化一下吧
实际上计算的这步可以在子组件中完成
const app = Vue.createApp({
data() {
return {
count: 1
}
},
methods:{
handleAdd(newCount) {
this.count = newCount
}
},
template:`
<div>
<counter :count="count" @add="handleAdd"/>
</div>
`
})
app.component('counter',{
props:["count"],
methods:{
handleClick() {
this.$emit('add',this.count + 2)
}
},
template:`
<div @click="handleClick">{{count}}</div>
`
})
const vm = app.mount('#root')
子组件在接收到父组件传递过来的数据count
后,在使用this.$emit
向外触发事件的时候,可以把计算过的count传给父组件,父组件拿到计算过的cout替换当前的count
标记子组件向外触发了哪些事件
如果子组件向外触发事件,那么我们可以在创建组件的地方使用emits:['event']
的方式,让我们一眼就能看出子组件向外触发了什么事件。否则如果子组件中很多的方法,都向外触发了事件,我们还要逐行的看代码去梳理向外触发了多少个事件,比较麻烦
const app = Vue.createApp({
data() {
return {
count: 1
}
},
methods:{
handleAdd(newCount) {
this.count = newCount
}
},
template:`
<div>
<counter :count="count" @add="handleAdd"/>
</div>
`
})
app.component('counter',{
props:["count"],
emits:['add'],
methods:{
handleClick() {
this.$emit('add',this.count + 2)
}
},
template:`
<div @click="handleClick">{{count}}</div>
`
})
const vm = app.mount('#root')
使用
emits:['event']
标记子组件向外触发了哪些事件,有助于代码管理和阅读
当然emits
不仅限于数组还可以是对象
这样可以校验/过滤子组件向父组件传递的参数
例如,每次校验父组件向外传递的数据count小于于0,才同意子组件向父组件传递数据,否则就给出警告
const app = Vue.createApp({
data() {
return {
count: 1
}
},
methods:{
handleAdd(newCount) {
this.count = newCount
}
},
template:`
<div>
<counter :count="count" @add="handleAdd"/>
</div>
`
})
app.component('counter',{
props:["count"],
emits: {
add: (count) => {
if(count < 0) {
return true
}
return false
}
},
methods:{
handleClick() {
this.$emit('add',this.count + 2)
}
},
template:`
<div @click="handleClick">{{count}}</div>
`
})
const vm = app.mount('#root')
通过v-model简化代码
为什么想到了v-model?
const app = Vue.createApp({
data() {
return {
count: 1,
text: 'hello world'
}
},
methods:{
handleAdd(newCount) {
this.count = newCount
}
},
template:`
<div>
<input v-model="text"/>
<counter :count="count" @add="handleAdd"/>
</div>
`
})
app.component('counter',{
props:["count"],
emits:["add"],
methods:{
handleClick() {
this.$emit('add',this.count + 2)
}
},
template:`
<div @click="handleClick">{{count}}</div>
`
})
const vm = app.mount('#root')
上面的例子的过程是: 父组件向子组件传递cout数据,子组件触发事件,再去改变父组件中的数据,它很类似于v-model
input输入框中的内容和data中的变量text做了数据的双向绑定,数据text改变,input中的值就发生变化。input触发事件的时候,也会改变text中的数据
之前的例子中,子组件中接收一个数据count,当count发生改变的时候,子组件counter展示的内容会变。同样当子组件counter向外触发事件的时候,也会改变data中的count
咦!好像还真是这样,那么怎么使用v-model来实现之前的代码呢?
接受vue的语法糖吧
const app = Vue.createApp({
data() {
return {
count: 1,
}
},
methods:{
handleAdd(newCount) {
this.count = newCount
}
},
template:`
<div>
<counter v-model="count"/>
</div>
`
})
app.component('counter',{
props:['modelValue'],
methods:{
handleClick() {
this.$emit('update:modelValue',this.modelValue + 2)
}
},
template:`
<div @click="handleClick">{{modelValue}}</div>
`
})
const vm = app.mount('#root')
备注
通过
v-model
将父组件中data的数据count传递给子组件子组件如果想要使用父组件传递过来的数据count需要满几个条件。
- 子组件接收数据的时候名字必须叫
modelValue
,即props:[modelValue]
,子组件中就可以直接使用modelValue
了- 子组件通过
this.emit
向外触发事件的时候,这个事件的名字必须是update: modelValue
注意
handleClick() { this.$emit('update:modelValue',this.modelValue + 2) }
使用
this.$emit
向外触发事件,并传递参数this.modelValue + 2
后,父组件自动感知到这个触发的事件后,并接收到这个参数
会用参数
this.modelValue + 2
自动的替换掉使用v-model
绑定的值cout<counter v-model="count"/>
父子组件存在双向绑定的时候使用
换个名字吧!!
如果不想使用modelValue
接收父组件传递过来的数据
我们可以给个别名,比如叫app,那么就该改成:
const app = Vue.createApp({
data() {
return {
count: 1,
}
},
methods:{
handleAdd(newCount) {
this.count = newCount
}
},
template:`
<div>
<counter v-model:app="count"/>
</div>
`
})
app.component('counter',{
props:['app'],
methods:{
handleClick() {
this.$emit('update:app',this.app + 2)
}
},
template:`
<div @click="handleClick">{{app}}</div>
`
})
const vm = app.mount('#root')
因此,如果父子组间存在双向绑定的关系的时候,就可以将之前复杂的代码,简写成使用v-model
这样简化代码
转载自:https://juejin.cn/post/7237828040280375352