likes
comments
collection
share

父子组件间通过事件通信

作者站长头像
站长
· 阅读数 47

子组件通知父组件修改父组件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"/>

备注

  1. 使用this.$emit('addOne')向外触发事件的时候,事件的名称要使用驼峰式
  2. 但是在监听事件的时候要使用横线连接的方式命名<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需要满几个条件。

  1. 子组件接收数据的时候名字必须叫modelValue,即props:[modelValue],子组件中就可以直接使用modelValue
  2. 子组件通过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
评论
请登录