1 v-model

1.1 理解 v-model

v-model 是 vue3 中的一个内置指令,很多表单元素都可以使用这个属性,如 inputcheckbox 等,咱可以在自定义组件中实现 v-modelv-model 本质上是一个语法糖:

  • 绑定父组件传递过来的 modelValue 属性;
  • 值改变时向父组件发出事件 update:modelValue

1.2 案例描述

理解了 v-model 的本质,咱可以分别使用 SFC(.vue 文件)和 TSX(.tsx)方式定义一个组件 person-name ,使该组件可以使用 v-model

person-name 包括两个输入框,分别是“姓”(familyName)和“名”(firstName)两个字段,v-model 传递的数据格式为:

{ familyName: '张', firstName: '三' }

首先定义该类型 person-name-type.ts

export interface PersonName {
/** 姓 */
familyName?: string;
/** 名 */
firstName?: string;
}

1.3 编写样式

编写 person-name.scss 样式文件,后面再两个组件中分别引入:

.person-name {
.el-form-item {
width: 200px;
}
}

2 编写组件

2.1 实现思路

person-name 组件实现逻辑比较简单:

  1. template 中放置两个输入框 el-input,分别对应 两个字段;
  2. 定义两个变量 innerFamilyNameinnerFirstName 绑定两个输入框的值;
  3. props 定义 modeValue 属性,接收父组件传递过来的 PersonName 类型的对象;
  4. 使用 watch 深度监听 modelValue,当其属性值有变化时,重新赋值给上面绑定输入框的两个变量;
  5. 当两个输入框触发 input 事件时,通过 update:modelValue 事件通知父组件,从而实现 v-model

2.2 SFC(.vue)中的实现

创建组件文件 person-name-sfc.vue

<template>
<div class="person-name">
<el-form-item label="姓">
<el-input v-model="innerFamilyName" @input="onInput"></el-input>
</el-form-item>
<el-form-item label="名">
<el-input v-model="innerFirstName" @input="onInput"></el-input>
</el-form-item>
</div>
</template> <script lang="ts" setup name="person-name-sfc">
import { PropType, ref, watch } from 'vue'
import { PersonName } from './person-name-type' const props = defineProps({
modelValue: {
type: Object as PropType<PersonName>,
required: true,
default: () => ({})
}
}) const emits = defineEmits(['update:modelValue']) const innerFamilyName = ref('')
const innerFirstName = ref('') watch(() => props.modelValue, (newVal) => {
innerFamilyName.value = newVal?.familyName || ''
innerFirstName.value = newVal?.firstName || ''
}, {
deep: true,
immediate: true
}) const onInput = () => {
emits('update:modelValue', {
familyName: innerFamilyName.value,
firstName: innerFirstName.value
})
}
</script> <style scoped lang="scss">
@import "./person-name";
</style>

2.3 TSX(.tsx)中的实现

创建组件文件 person-name-tsx.tsx

import { defineComponent, PropType, ref, watch } from 'vue'
import { PersonName } from './person-name-type'
import './person-name.scss' export default defineComponent({
name: 'person-name-tsx',
props: {
modelValue: {
type: Object as PropType<PersonName>,
required: true,
default: () => ({})
}
},
emits: ['update:modelValue'],
setup (props, context) {
const innerFamilyName = ref(props.modelValue.familyName)
const innerFirstName = ref(props.modelValue.firstName) const onInput = () => {
context.emit('update:modelValue', {
familyName: innerFamilyName.value,
firstName: innerFirstName.value
})
} watch(() => props.modelValue, (newVal) => {
innerFamilyName.value = newVal?.familyName || ''
innerFirstName.value = newVal?.firstName || ''
}, {
deep: true,
immediate: true
}) return () => (
<div class="person-name">
<el-form-item label="姓">
<el-input vModel={innerFamilyName.value} onInput={onInput}/>
</el-form-item>
<el-form-item label="名">
<el-input vModel={innerFirstName.value} onInput={onInput}/>
</el-form-item>
</div>
)
}
})

3 使用组件

创建父组件 demo-v-model.vue,在里面使用上面定义的两个组件:

<template>
<div>
<person-name-sfc v-model="personName1"></person-name-sfc>
<el-button @click="onResetClick1">reset</el-button>
<div>{{personName1}}</div>
</div>
<el-divider />
<div>
<person-name-tsx v-model="personName2"></person-name-tsx>
<el-button @click="onResetClick2">reset</el-button>
<div>{{personName2}}</div>
</div>
</template> <script lang="ts" setup>
import PersonNameSfc from '@/components/model/person-name-sfc.vue'
import { ref } from 'vue'
import { PersonName } from '@/components/model/person-name-type'
import PersonNameTsx from '@/components/model/person-name-tsx' const defaultPersonName = { familyName: '张', firstName: '三' } const personName1 = ref<PersonName>({ ...defaultPersonName })
const personName2 = ref<PersonName>({ ...defaultPersonName }) const onResetClick1 = () => {
personName1.value = { ...defaultPersonName }
}
const onResetClick2 = () => {
personName2.value = { ...defaultPersonName }
}
</script>

运行效果如下:

上面部分使用 .vue 编写的组件,下面部分使用 .tsx 编写的组件,两者独立绑定 v-model,运行效果完全一致。

  1. 子组件可以接收到父组件传递的初始值;
  2. 子组件值改变时会通知到父组件;
  3. 父组件改变值时,子组件会响应变更。

Vue3 SFC 和 TSX 方式自定义组件实现 v-model的更多相关文章

  1. Vue3 SFC 和 TSX 方式调用子组件中的函数

    在开发中会遇到这样的需求:获取子组件的引用,并调用子组件中定义的方法.如封装了一个表单组件,在父组件中需要调用这个表单组件的引用,并调用这个表单组件的校验表单函数或重置表单函数.要实现这个功能,首先要 ...

  2. vue3系列:vue3.0自定义全局弹层V3Layer|vue3.x pc桌面端弹窗组件

    基于Vue3.0开发PC桌面端自定义对话框组件V3Layer. 前两天有分享一个vue3.0移动端弹出层组件,今天分享的是最新开发的vue3.0版pc端弹窗组件. V3Layer 一款使用vue3.0 ...

  3. Vue自定义组件以及组件通信的几种方式

    本帖子来源:小贤笔记 功能 组件 (Component) 是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素,Vue.js 的编译器为它 ...

  4. vue3.x自定义组件双向数据绑定v-model

    vue2.x 语法 在 2.x 中,在组件上使用 v-model 相当于绑定 value prop 并触发 input 事件: <ChildComponent v-model="pag ...

  5. vue 相邻自定义组件渲染错误正确的打开方式

    话不多说看问题: 当封装自定义组件时例如(自定义下拉列表)两个相同的组件在多次v-if变化时偶尔会发生渲染错误,明明赋值正确但是组建中的ajax方法可能返回的数据乱掉,或者其他神逻辑错误. 经过查询发 ...

  6. form-create 3.0 版本发布,好用的Vue3版本动态表单生成组件

    form-create 是一个可以通过 JSON 生成具有动态渲染.数据收集.验证和提交功能的表单生成组件.支持2个UI框架,并且支持生成任何 Vue 组件.内置20种常用表单组件和自定义组件,再复杂 ...

  7. Android开发之自定义组件和接口回调

    说到自定义控件不得不提的就是接口回调,在Android开发中接口回调用的还是蛮多的.在这篇博客开始的时候呢,我想聊一下iOS的自定义控件.在iOS中自定义控件的思路是继承自UIView, 在UIVie ...

  8. Android自定义组件

    [参考的原文地址] http://blog.csdn.net/l1028386804/article/details/47101387效果图: 实现方式: 一:自定义一个含有EditText和Butt ...

  9. HTML5 UI框架Kendo UI Web中如何创建自定义组件(二)

    在前面的文章<HTML5 UI框架Kendo UI Web自定义组件(一)>中,对在Kendo UI Web中如何创建自定义组件作出了一些基础讲解,下面将继续前面的内容. 使用一个数据源 ...

随机推荐

  1. Chapter 02 - Let's Get Started(C#篇)

    详细解释,书上有哈.直接上代码和结果. Xcode下的自定义类 (通过new file-> cocoa class创建,保持和书中名字一样RandomController),自定义的fields ...

  2. 设置Windows Server 2022、Win10、Win11自动登录的简单方法-OK

    这里介绍自己从使用 Windows Server 2003 到 Windows Server 2022 一直都在使用的自动登录系统的方法,屡试不爽.网上讨论的方法太繁琐,所以共享出来,供大家参考.该方 ...

  3. 使用CSS实现多种Noise噪点效果

    声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 背景 在插画中添加噪点肌理可以营造出一种自然的氛围.噪点肌理可以用于塑造阴影.高 ...

  4. kali下安装Nessus

    Kali安装Nessus 说明 Nessus是一款基于插件的系统漏洞扫描和分析软件 一.安装 1.下载安装包 https://www.tenable.com/downloads/nessus 查看ka ...

  5. [CF1527D] MEX Tree (lca)

    题面 给你一棵 n n n 个结点的树,对于所有的 k ∈ [ 0 , n ] k\in[0,n] k∈[0,n] ,求出 M E X = k {\rm MEX}=k MEX=k 的路径数量. 一条路 ...

  6. 蕞短鹭(artskjid) (⭐通信题/模拟⭐)

    文章目录 题面(过于冗长,主要是对通信题的一些解释) 题解 1.通信题什么意思 2.此题题解 CODE 实现 题面(过于冗长,主要是对通信题的一些解释) 题解 1.通信题什么意思 并不是两个程序同时跑 ...

  7. JDK 自带的服务发现框架 ServiceLoader 好用吗?

    请点赞关注,你的支持对我意义重大. Hi,我是小彭.本文已收录到 Github · AndroidFamily 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,关注公众号 [彭旭锐] ...

  8. 在 Windows 搭建 SVN 服务

    以下内容为本人的学习笔记,如需要转载,请声明原文链接微信公众号「englyf」https://www.cnblogs.com/englyf/p/16671311.html 最近公司给配了台新电脑,配置 ...

  9. C#:winform窗体 实现类似QQ的窗体在桌面边缘停靠和隐藏

    设计思路:1.使用定时器(Timer)来监控鼠标位置和窗体位置,并实现窗体的停靠和隐藏2.当鼠标拖动窗体时,窗体才有可能根据自身位置决定是否停靠3.如果窗体四周没有接触到屏幕边缘则不会停靠4.如果窗体 ...

  10. ES6之前,JS的继承

    继承的概念 谈到继承,就不得不谈到类和对象的概念. 类是抽象的,它是拥有共同的属性和行为的抽象实体. 对象是具体的,它除了拥有类共同的属性和行为之外,可能还会有一些独特的属性和行为. 打个比方: 人类 ...