当前位置:首页 > 技术文章 > 正文内容

Vue3开发极简入门(15.1):emits补完-结合v-model

zonemu22小时前技术文章1

之前代码是通过按钮触发emit,如果希望输入框里的内容在输入之后也能同步到父组件,就可以结合v-model的update事件来操作,具体如下。

Son2.vue:

<template>
    <div class='son2'>
        <h1>子组件2</h1>
        上报司机:{{ driverName }}<br />
        <input type="text" :value="driverName" @input="handleInput($event)" placeholder="输入司机姓名" />
    </div>
</template>

<script lang='ts' setup name='Son2'>
import { ref } from 'vue';
const driverName = ref('')
const props = defineProps(['driverName']);
const emit = defineEmits(['update:driverName']);

const handleInput = (event: Event) => {
    const target = event.target as HTMLInputElement;
    driverName.value = target.value
    emit('update:driverName', target.value);
};
</script>

<style scoped>
.son2 {
    background-color: rgb(85, 193, 236);
    padding: 10px;
    margin-top: 10px;
    box-shadow: 0 0 10px black;
    border-radius: 10px;
    width: 90%;
    margin: auto;
}
</style>

父组件修改:

<template>
    <div class="father">
        <h1>父组件</h1>
        司机:{{ driverName }}<br />
        装货地:北京,卸货地:海口,发车时间:{{ departTime }}
        <Son @set-depart-time="setDepartTime" />
        <!--如果子组件传多个属性,可以直接在后面加,例如 v-model:dirverId="driverId"-->
        <Son2 v-model:driverName="driverName" />


    </div>
</template>
<script lang='ts' setup name='Father'>
import { ref } from 'vue';
import Son from './Son.vue';
import Son2 from './Son2.vue';

const departTime = ref('待定')
const driverName = ref('无')

function setDepartTime(val: string) {
    departTime.value = val
}
</script>
<style scoped>
.father {
    background-color: darkseagreen;
    box-shadow: 0 0 10px black;
    border-radius: 10px;
    height: 100%;
}
</style>

整个流程,就是子组件的输入框绑定了输入回调函数handleInput,然后触发update事件,而父组件的v-model会监听此事件,并自动更新绑定的数据。子组件需要通过defineProps来接收父组件传递的值。

如果大家搜网上的资料,代码中的driverName大多是写成modelValue。modelValue适用1个属性,如果传递多个属性给父组件,例如司机姓名、司机身份证号等,就可以用文中的写法。

高版本的(3.4+),有比较简单的写法,就是defineModel语法糖,其本质就是自动生成defineProps、defineEmits。

Son2.vue修改如下:

<template>
    <div class='son2'>
        <h1>子组件2</h1>
        <label>
            司机ID:
            <input type="number" v-model="driverId">
        </label>
        <label>
            司机姓名:
            <input v-model="driverName">
        </label>
    </div>
</template>

<script lang='ts' setup name='Son2'>
import { ref } from 'vue';

const driverId = defineModel('driverId', {
    type: Number, default: 0, required: true, set(value: number) { // 数字输入校验
        return isNaN(value) ? 0 : Number(value);
    }
})
const driverName = defineModel('driverName')
</script>

<style scoped>
.son2 {
    background-color: rgb(85, 193, 236);
    padding: 10px;
    margin-top: 10px;
    box-shadow: 0 0 10px black;
    border-radius: 10px;
    width: 90%;
    margin: auto;
}
</style>

父组件修改:

<template>
    <div class="father">
        <h1>父组件</h1>
        司机:{{ driverName }}<br />
        司机ID:{{ driverId }}<br />
        装货地:北京,卸货地:海口,发车时间:{{ departTime }}
        <Son @set-depart-time="setDepartTime" />
        <Son2 v-model:driverName="driverName" v-model:driver-id="driverId" />
    </div>
</template>
<script lang='ts' setup name='Father'>
import { ref } from 'vue';
import Son from './Son.vue';
import Son2 from './Son2.vue';

const departTime = ref('待定')
const driverName = ref('无')
const driverId = ref(0)

function setDepartTime(val: string) {
    departTime.value = val
}
</script>
<style scoped>
.father {
    background-color: darkseagreen;
    box-shadow: 0 0 10px black;
    border-radius: 10px;
    height: 100%;
}
</style>

请注意看看父子组件driverId和driverName写法的不同,我是故意这么写的:

  • 子组件定义driverId的写法,比较全,包含了类型定义、默认值、是否必填、校验&转换。
  • 父组件关于driverId的写法,“driverId”是父组件自己的,而driver-id是子组件defineModel('driverId')的那个dirverId。这一点我忘了在props一节中说明:可以使用驼峰形式(driverName用的就是),但是Vue官网上说为了和HTML attribute对齐,通常会将其写为kebab-case(短横线)形式。实际工作中,看公司自己的规范写吧。
  • TypeScript对类型要求严格,可以写作const driverName = defineModel<string>('driverName')

相关文章

宽带客户收费管理系统--维修版(宽带售后服务)

宽带客户收费管理系统--维修版headerfooter《宽带客户收费管理系统——维修版》是一款适合宽带运营商使用的管理系统。软件主要包括以下功能:1.主要功能包括用户开户、收费录入、工单登记、故障处理...

7种超轻量级的Linux发行版,能够帮助你找到适合自己的操作系统

Linux是一种非常受欢迎的开源操作系统,而且有许多版本可以选择。有时候,你需要一种超轻量级的Linux发行版,它可以在资源有限的设备上运行,并且能够快速启动。本文将介绍7种超轻量级的Linux发行版...

Win+Ubuntu缝合怪:第三方开发者推出“Wubuntu”Linux发行版

IT之家 2 月 26 日消息,一位第三方开发者推出了一款名为“Wubuntu”的缝合怪 Linux 发行版,系统本身基于 Ubuntu,但界面为微软 Windows 11 风格,甚至存在微软 Win...

据说是可以替代 Windows 的 5个 Linux 发行版

现如今有数以千计的 Linux 发行版可供您使用,然而人们却无法选择一个完美的操作系统来替代 Windows。 使用 Windows 时,傻瓜都能操作自如,同样的方法却不适用于 Linux。在这里,您...

Vue3 如何实现父子组件传值?(vue父子组件传值props)

在Vue 3中,要实现父子组件传值效果主要通过props和emit两种机制来实现,下面我们就来详细介绍一下这两种机制。父组件向子组件传值propsprops是Vue组件的一种机制,主要的作用就是实现从...

2024前端面试真题之—VUE篇(前端面试题vuex)

添加图片注释,不超过 140 字(可选)1.vue的生命周期有哪些及每个生命周期做了什么? beforeCreate是new Vue()之后触发的第一个钩子,在当前阶段data、methods、com...