前言
在上一篇
的文章中,我们了解了vue组件Non-Props属性
,今天我们继续深入了解一下vue组件中的父子组件之间通信
。
回顾
在前面的几篇文章中,我们知道组件之间传值的时候,可以通过父组件调用子组件标签,然后在子组件标签上用动态传参的方法传递给子组件,但是子组件没办法去修改父组件的值,因为子组件接收到的值是只读
的。
<script> const app = Vue.createApp({ data(){ return { count: 1 } }, template: ` <div> <counter :count="count" /> </div> ` }); app.component('counter', { props: ['count'], methods: { handleClick(){ this.count += 1 } }, template: ` <div @click="handleClick">{{count}}</div> ` }) const vm = app.mount('#root'); </script> 复制代码
[Vue warn]: Attempting to mutate prop "count". Props are readonly.
今天的文章中我们将详细讲解一下父子组件如何通过事件方法进行通信。
$emit
$emit
:子组件触发父组件事件的方法 当子组件中无法完成的一些事件操作时,可
- 以通过
$emit
方法通知父组件去完成。下面我们就来改造一下上面的代码。
handleClick(){ this.$emit('addOne') } 复制代码
this.$emit()
:这个方法时一个固定的写法,也是vue提供的事件,意思就是我要向外部触发一个事件,传入事件名称即可。
既然子组件要通知父组件触发一个事件,那么父组件就得接收到子组件传递过来的事件。
const app = Vue.createApp({ data(){ return { count: 1 } }, methods: { handleAddOne(){ this.count += 1 } }, template: ` <div> <counter :count="count" @add-one="handleAddOne" /> </div> ` }); 复制代码
- 父组件中可以在子组件标签上通过
v-on
指令(简写@
)接收子组件触发的事件。
- 子组件触发事件是采用
驼峰
形式去写方法名,父组件接收的时候需要改成-
接收方法名。
- 父组件接收到子组件传递过来的方法之后,就可以触发父组件内部方法了
传参
通过上面的代码我们看到父子组件之间通过事件已经可以进行通信了,但是我们只是触发了事件而已,当我们需要在子组件里面传递参数要咋整呢?
- 子组件触发的事件中,调用
$emit
方法时,除了定义方法名之外,后面还可以直接携带参数。
handleClick(){ this.$emit('add', 2) } 复制代码
- 父组件触发的事件中,可以直接在方法中接收子组件传递过来的参数。
const app = Vue.createApp({ data(){ return { count: 1 } }, methods: { handleAddOne(param){ this.count += param } }, template: ` <div> <counter :count="count" @add="handleAddOne" /> </div> ` }); 复制代码
$emit
方法后面携带的参数可以是多个。
// 子组件中的事件 handleClick(){ this.$emit('add', 2, 3) } // 父组件中的事件 handleAddOne(param1, param2){ this.count += param2 } 复制代码
$emit
方法后面携带的参数也可以直接进行计算。
// 子组件中的事件 handleClick(){ this.$emit('add', this.count + 4) } // 父组件中的事件 handleAddOne(count){ this.count = count } 复制代码
emits
emits
:校验对外触发的方法名
app.component('counter', { props: ['count'], emits: ['add'], methods: { handleClick(){ this.$emit('add', this.count + 4) } }, template: ` <div @click="handleClick">{{count}}</div> ` }) 复制代码
在子组件中可以定义emits
来校验$emit
中的方法名,如果一致则可以触发成功。
emits: ['minus'], 复制代码
如果我们将子组件中的emits
定义的值和$emit
中的方法名不一致,则会在浏览器控制台中进行提示。
[Vue warn]: Component emitted event "add" but it is neither declared in the
emits option nor as an "onAdd" prop.
除了在emits
中使用数组定义方法名之外,还可以通过对象的方式进行校验。
emits: { add: (count) => { if(count < 0){ return true } return false } }, 复制代码
- 在
emits
对象中可以监听$emit
中的方法名,触发一个事件的时候可以获取到$emit
中传递的参数值。
当监听对象中校验不通过时,也会在浏览器控制台中进行提示。
[Vue warn]: Invalid event arguments: event validation failed for event "add".
v-model
在以前的文章中,我们知道v-model
指令是做双向数据绑定的,其实它也可以做父子组件通信的指令。
<script> const app = Vue.createApp({ data(){ return { count: 1 } }, template: ` <div> <counter v-model="count" /> </div> ` }); app.component('counter', { props: ['modelValue'], methods: { handleClick(){ this.$emit('update:modelValue', this.modelValue + 5) } }, template: ` <div @click="handleClick">{{modelValue}}</div> ` }) const vm = app.mount('#root'); </script> 复制代码
- 父组件中调用子组件标签时,可以直接使用
v-model
指令进行传值。
- 子组件中通过
props
接收父组件中的参数modelValue
。
$emit
方法中,直接通过update:modelValue
的事件就可以对父组件的值进行修改了。
modelValue
是默认写法,不可以随意更改。
但是有些时候,我们需要自定义父组件传递给子组件的参数名称要怎么做呢?
<script> const app = Vue.createApp({ data(){ return { count: 1 } }, template: ` <div> <counter v-model:count="count" /> </div> ` }); app.component('counter', { props: ['count'], methods: { handleClick(){ this.$emit('update:count', this.count + 6) } }, template: ` <div @click="handleClick">{{count}}</div> ` }) const vm = app.mount('#root'); </script> 复制代码
- 直接在父组件中的子组件标签上使用
v-model:xxx
的方式进行自定义名称即可。
- 子组件就接收自定义的名称进行渲染和操作。
总结
本篇文章主要讲解了vue中的父子组件之间通过事件通信的方法:$emit
、v-model
,也讲解了在进行通信时可以传递参数,也可以对传递的方法和参数进行校验。