30. [组件]Vue子组件调用父组件方法、传值和校验
前面我们讲了单项数据流的概念,这节学习一下子组件如何通过事件向父组件传递参数,打破单项数据流的限制。在单项数据流中,我们用了计数器Counter
这个例子做了个小例子,帮助大家理解。我们先来复习一下什么是单项数据流。
通过计数器的编写,本节我们的学习目标如下:
- 子组件调用父组件事件的编写方法
- 子组件向父组件事件中传递参数的方法
- 子组件传递参数时,如何通过
emits
进行校验
直接开始我们的学习吧。
编写计数器案例
新建一个文件Demo30.html
文件,代码如下。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Demo30</title> <script src="https://cdn.bootcdn.net/ajax/libs/vue/3.0.2/vue.global.js"></script> </head> <body> <div id="app"></div> </body> <script> const app = Vue.createApp({ data() { return { counter: 0 } }, template: ` <h2>mybj123.com</h2> <counter :counter="counter"/> ` }) app.component('Counter', { props: ['counter'], template: ` {{counter}}<button @click="this.counter+=1">增加数量</button> ` }) const vm = app.mount("#app") </script> </html>
上面的代码,当我们在浏览器中点击增加时,是不能增加counter
的值的,这就是 Vue单向数据流
的限制。但是有时候,我们就是想在子组件里改变父组件传递过来的值,怎么办呢?
子组件调用父组件事件
这时候就需要子组件调用父组件的事件,从而改变父组件里的值。我们先在父组件里编写一个方法,叫做handleAddCounter
。这个方法就作一件事,每执行一次,数据项里的counter
加 1。
methods: { handleAddCounter() { this.counter += 1 } },
父组件有了这个方法,就可以改变counter
数据行的值了,有方法后,现在问题就变成了,如何在子组件中调用这个方法了。
这时候可以先在子组件
的模板template
中编写一个click
事件。
{{counter}}<button @click="handleClick">增加数量</button>
子组件调用的并不是父组件中的方法,而是子组件中的方法。如果想调用父组件中的handleAddConter
方法,这时候可以在子组件中新建一个方法handleClick
,然后用$emit
调用父组件的响应事件add
。
具体代码如下:
app.component('Counter', { props: ['counter'], methods: { handleClick() { this.$emit('add') } }, template: ` {{counter}}<button @click="handleClick">增加数量</button> ` })
这时候的add
是什么呢?add
就是响应事件,在父组件的模板template
中,添加一个add
响应事件,然后响应事件再调用方法handleAdCounter
。
父组件里的模板:
template: ` <h2>mybj123.com</h2> <counter :counter="counter" @add="handleAddCounter"/> `
这时候可以到浏览器看一下结果,你会发现当点击增加按钮的时候,数据项中的counter
值,已经可以增加了。只是在控制台会打印出警告。
警告的意思你调用的add
方法,并没有用emits
进行声明。
app.component('Counter', { props: ['counter'], emits: ['add'], methods: { handleClick() { this.$emit('add') } }, })
声明后,控制台中的警告会消失。这也是 Vue 对子组件
调用父组件时的一种约束,就是调用前需要声明,否则就会报出警告。
子组件向父组件传递参数
当我们不是每次想加 1 的时候,比如这个值是子组件
决定的,比如是2
吧。这时候子组件需要向父组件传值,也是可以做到的,你可以在子组件中这样编写。
methods: { handleClick() { this.$emit('add', 2) } },
然后在父组件中接受这个参数param
(这个参数的名字你可以随便起),为了看的方便,在控制台进行打印。
methods: { handleAddCounter(param) { console.log(param) this.counter += param } },
这时候子组件的参数就传递给了父组件,并且可以使用了。当然你还有更好的选择,就是把所有业务逻辑都放在子组件中,然后把结果传递给父组件。我平时更喜欢用这种方式,比如代码可以写成下面的样子。 业务逻辑写在子组件里:
methods: { handleClick() { this.$emit('add', this.counter + 3) } },
父组件直接接受结果就可以了:
methods: { handleAddCounter(param) { console.log(param) this.counter = param } },
对传递值的校验
在子组件向父组件传递值的时候,还可以开启校验功能。校验是通过emits
这个选项来声明的。比如现在我们要求传递到add
中的值,不大于 20。如果大于 20 就进行警告。
emits: { add: (value) => { return value < 20 ? true : false } },
最终效果如下:
我这里的业务逻辑很简,你完全可以根据你的业务逻辑来编写验证过程。
为了方便大家学习,附上全部代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Demo30</title> <script src="https://cdn.bootcdn.net/ajax/libs/vue/3.0.2/vue.global.js"></script> </head> <body> <div id="app"></div> </body> <script> const app = Vue.createApp({ data() { return { counter: 0 } }, methods: { handleAddCounter(param) { console.log(param) this.counter = param } }, template: ` <h2>mybj123.com</h2> <counter :counter="counter" @add="handleAddCounter" /> ` }) app.component('Counter', { props: ['counter'], emits: { add: (value) => { return value < 20 ? true : false } }, methods:{ handleClick(){ this.$emit('add', this.counter + 3) } }, template: ` {{counter}}<button @click="handleClick">增加数量</button> ` }) const vm = app.mount("#app") </script> </html>
以上这就是本节学习的内容了,我们主要讲解了组件间,子组件调用父组件的方法和传递参数的操作。小伙伴们学习后一定要动手练习,只有动手练习才能发现问题,才能真正学会。
码云笔记 » 30. [组件]Vue子组件调用父组件方法、传值和校验