事件名
与组件和prop一样,事件名提供了自动的大小写转换。如果用驼峰命名的子组件中触发一个事件,你将可以在父组件中添加一个kebabcase(短横线分割命名)的监听器。
- <my-component @my-event="doSomething"></my-component>
- this.$emit('myEvent')
与props命名一样,当你使用DOM模板时,我们建议使用kebabcase事件监听器。如果你使用的是字符串模板,这个限制就不适用。
定义自定义事件
可以通过emits选项在组件上定义已发出的事件。
- app.component('custom-form', {
- emits: ['inFocus', 'submit']
- })
当在emits选项中定义了原生事件(如click)时,将使用组件中的事件替代原生事件侦听器。
验证抛出的事件
与props类型验证类似,如果使用对象语法而不是数组语法,则可以验证它。
要添加验证,将为事件分配一个函数,该函数接收传递给$emit调用的参数,并返回一个布尔值以指示事件是否有效。
- app.component('custom-form', {
- emits: {
- // 没有验证
- click: null,
- // 验证submit 事件
- submit: ({ email, password }) => {
- if (email && password) {
- return true
- } else {
- console.warn('Invalid submit event payload!')
- return false
- }
- }
- },
- methods: {
- submitForm() {
- this.$emit('submit', { email, password })
- }
- }
- })
v-model事件
默认情况下,组件上的v-model使用modelValue作为props和update:modelValue做完事件。我们可以通过向v-model传递参数来修改这些名称:
- <my-component v-model:title="bookTitle"></my-component>
在本例中,子组件将需要一个 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)">
- `
- })
多个v-model绑定
通过利用特定prop和事件为目标的能力,正如我们之前在v-model参数中所学的那样,我们现在可以在单个组件实例上创建多个v-model绑定。
每个v-model将同步到不同的prop,而不需要在组件中添加额外的选项。
- <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)">
- `
- })
处理v-model修饰词
在2.X中,我们对组件v-model上的.trim等修饰符提供了硬编码支持。但是,如果组件可以支持自定义修饰符,则会更有用。
在3.X中,添加到组件v-model的修饰符将通过modelModifiers prop提供给组件。
v-model有内置的修饰符——.trim,.number和.lazy。但是,在某些情况下,你可能还需要添加自己的自定义修饰符。
我们做个实例:将提供的字符串第一个字母大写。
- <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 对象键并编写一个处理器来更改发出的值。在下面的代码中,每当<input/> 元素触发 input 事件时,我们都将字符串大写。
- <div id="app">
- <my-component v-model.capitalize="myText"></my-component>
- {{ myText }}
- </div>
- const app = Vue.createApp({
- data() {
- return {
- myText: ''
- }
- }
- })
- app.component('my-component', {
- props: {
- modelValue: String,
- modelModifiers: {
- default: () => ({})
- }
- },
- emits: ['update:modelValue'],
- 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)
- }
- },
- template: `<input
- type="text"
- :value="modelValue"
- @input="emitValue">`
- })
- app.mount('#app')
对于带参数的 v-model 绑定,生成的 prop 名称将为 arg + "Modifiers":
- <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 }
- }
- })