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

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

之前代码是通过按钮触发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')

相关文章

最美 Linux 发行版之争还在继续,Elementary OS 0.3 发布 0.3 Freya 更新

对于个人终端消费者而言,Linux 发行版们依然希望通过 UI 革新来吸引他们的注意。除了 Ubuntu 这样综合能力强的选手,偏重界面的发行版里,前有 OpenSUSE,后有 Linux Mint,...

细数5款国外热门Linux发行版(linux发行版排名网站)

Linux系统已经与我们的生活息息相关,当你用Android手机浏览这篇文章时,你就已经在使用Linux系统。当然作为编程开发最热门的系统,他还有很多专注于开发使用的版本。Fedora热门入门推荐,一...

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

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

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

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

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

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

Vue3,父组件子组件传值,provide(提供)和inject(注入)传值

父组件向子组件传值父子组件传递数据时,通常使用的是props和emit,父向子传递使用props,子向父传递使用emit。子组件接收3种方式// 1、简单接收 props:["title...