ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、视频、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 自定义事件 > 本章节需要掌握组件基础 > emit我译成发射,觉得发射这个词比较形象的将子组件事件发射出来的一个动作。 ### **事件名** 像组件和`props`,事件名也会进行自动转换,如果你在子组件里发射一个驼峰命名的事件,你就可以在父组件中添加一个短横线分隔的监听: ~~~ this.$emit('myEvent') ~~~ ~~~html <my-component @my-event="doSomething"></my-component> ~~~ 因为有`props`情形存在,模板内DOM议使用短横线分隔命名方式。如果你使用字符串模板,则不存在这个限制。 ### **自定义事件定义** > [Vue School自定义事件视频教程](https://vueschool.io/lessons/defining-custom-events-emits?friend=vuejs) 自定义事件发射(请子组件传递到父组件)可以通过`emits`选项: ~~~ app.component('custom-form', { emits: ['inFocus', 'submit'] }) ~~~ 当在`emits`中定义了一个原生事件(如`click`)时,组件事件将会代替原生事件监听。 >提示 > 推荐定义所有已发射的事件,以便记录组件是如何工作的 ### **验证已射事件** 同`prop`类型验证一样,一个已发射事件如果通过对象语法而不是数组语法,也可以被验证。 添加一个验证,事件会分配一个函数来接收参数,并传递给`$emit`调用,返回一个布尔值来确认事件是否有效。 ~~~ app.component('custom-form', { emits: { // 无验证 click: null, // 验证提交事件 submit: ({ email, password }) => { if (email && password) { return true } else { console.warn('不合法的 submit 事件加载!') return false } } }, methods: { submitForm() { this.$emit('submit', { email, password }) } } }) ~~~ ## `v-model`参数 默认组件的`v-model`使用`modelValue`作为prop和`update:modelValue`作为事件。我们可以传递一个参数给`v-model`修改这些名称: ~~~html <my-component v-model:title="bookTitle"></my-component> ~~~ ~~~ app.component('my-component', { props: { title: String }, emits: ['update:title'], template: ` <input type="text" :value="title" @input="$emit('update:title', $event.target.value)"> ` }) ~~~ 在这个案例中,子组件会同步接收`title`prop,发射`update:title`事件: ~~~ app.component('my-component', { props: { title: String }, emits: ['update:title'], template: ` <input type="text" :value="title" @input="$emit('update:title', $event.target.value)"> ` }) ~~~ ~~~html <my-component v-model:title="bookTitle"></my-component> ~~~ ## 多`v-model`绑定 正如前面所学习`v-model`参数,我们可以为同一个组件实例添加多个v-model参数。 每个`v-model`可以与不同的`prop`相同步,组件不需要额外的选项: ~~~html <user-name v-model:first-name="firstName" v-model:last-name="lastName" ></user-name> ~~~ ~~~ app.component('user-name', { props: { firstName: String, lastName: String }, emits: ['update:firstName', 'update:lastName'], template: ` <input type="text" :value="firstName" @input="$emit('update:firstName', $event.target.value)"> <input type="text" :value="lastName" @input="$emit('update:lastName', $event.target.value)"> ` }) ~~~ 我们来写一个完整点的例子,实现一个区号-座机输入组件,结果如下图: ![](https://img.kancloud.cn/ca/d2/cad22c4ead3c2a452d7b499eefa74f8d_404x194.png) 代码如下: ~~~html <!DOCTYPE html> <html lang="en-US"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>component v-model</title> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="app"> <tel-input v-model:tel-number="telNumber" v-model:area-number="areaNumber"></tel-input> <p> {{areaNumber}}-{{telNumber}} </p> </div> </body> <script type="text/javascript"> const data_and_methods = { data() { return { telNumber: '', areaNumber: '' } }, methods: { } } const app = Vue.createApp(data_and_methods) app.component('tel-input',{ props: { areaNumber:String, telNumber:String }, emits: ['update:areaNumber','update:telNumber'], template: ` <input placeholder="区号" type="number" class="area-number" :value="areaNumber" @input="$emit('update:areaNumber',$event.target.value)" /> - <input placeholder="座机号码" type="number" class="tel-number" :value="telNumber" @input="$emit('update:telNumber',$event.target.value)" /> ` }) app.mount("#app") </script> <style type="text/css"> .area-number {width:60px;} </style> </html> ~~~ ## 处理`v-model`修饰符 在前面我们学习输入绑定时,`v-model`有一些内置的修饰符如`.trim`,`.number`,`.lazy`等。有些情形,你也想增加一些自定义的修饰符。 让我们来创建一个`capitalize`修饰符,使用`v-model`绑定将输入首字母转换为大写。 组件`v-model`修饰符通过`modelModifers`prop提供给组件。下面的例子,我们创建了一个含有默认为空对象 的`modelModifiers`prop组件。 注意在组件`created`生命周期勾子触发器中,`modelModifiers`prop包含`capitalize`且值是`true` - 当它被设置在`v-model`绑定`v-model.capitalize="myText"`。 ~~~html <my-component v-model.capitalize="myText"></my-component> ~~~ ~~~ app.component('my-component', { props: { modelValue: String, modelModifiers: { default: () => ({}) } }, emits: ['update:modelValue'], template: ` <input type="text" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)"> `, created() { console.log(this.modelModifiers) // { capitalize: true } } }) ~~~ 现在我们设置好了prop,我们检测`modelModifiers`对象的键,然后通过方法处理要发射出去的值。下面我们来把输入框的首字母转换为大写: ~~~html <!DOCTYPE html> <html lang="en-US"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>component v-model modifiers</title> <script src="https://unpkg.com/vue@next"></script> </head> <body> <div id="app"> <my-component v-model.capitalize="myText"></my-component> <p>{{ myText }}</p> </div> </body> <script type="text/javascript"> const data_and_methods = { data() { return { myText: '' } } } const app = Vue.createApp(data_and_methods) app.component('my-component',{ props: { modelValue: String, modelModifiers: { default: () => ({}) } }, emits: ['update:modelValue'], template: ` <input type="text" :value="modelValue" @input="emitValue" /> `, methods: { emitValue(e){ let value = e.target.value if(this.modelModifiers.capitalize){ value = value.charAt(0).toUpperCase() + value.slice(1) } this.$emit('update:modelValue',value) } }, created() { console.log(this.modelModifiers) } }) app.mount("#app") </script> </html> ~~~ `v-model`绑定参数,生成的prop名将会是`arg+"modelModifiers"`: ~~~html <my-component v-model:description.capitalize="myText"></my-component> ~~~ ~~~ app.component('my-component', { props: ['description', 'descriptionModifiers'], emits: ['update:description'], template: ` <input type="text" :value="description" @input="$emit('update:description', $event.target.value)"> `, created() { console.log(this.descriptionModifiers) // { capitalize: true } } }) ~~~