1 v-model

1.1 理解 v-model

v-model 是 vue3 中的一个内置指令,很多表单元素都可以使用这个属性,如 input、checkbox 等,咱可以在自定义组件中实现 v-model。v-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 组件实现逻辑比较简单:

  • template 中放置两个输入框 el-input,分别对应 姓 和 名 两个字段;
  • 定义两个变量 innerFamilyName 和 innerFirstName 绑定两个输入框的值;
  • 在 props 定义 modeValue 属性,接收父组件传递过来的 PersonName 类型的对象;
  • 使用 watch 深度监听 modelValue,当其属性值有变化时,重新赋值给上面绑定输入框的两个变量;
  • 当两个输入框触发 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,运行效果完全一致。

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

到此这篇关于Vue3 SFC 和 TSX 方式自定义组件实现 v-model的文章就介绍到这了,更多相关Vue3 自定义组件v-model内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

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

  1. vue3获取当前路由地址

    本文详细讲解了vue3获取当前路由地址的方法,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  2. 十分钟带你快速上手Vue3过渡动画

    在开发中我们想要给一个组件的显示和消失添加某种过渡动画,可以很好的增加用户体验,下面这篇文章主要给大家介绍了关于如何快速上手Vue3过渡动画的相关资料,需要的朋友可以参考下

  3. 用vue3封装一个符合思维且简单实用的弹出层

    最近新项目中需要一个弹窗组件,所以我就做了一个,下面这篇文章主要给大家介绍了关于如何利用vue3封装一个符合思维且简单实用的弹出层,文中通过实例代码介绍的非常详细,需要的朋友可以参考下

  4. 使用Vite+Vue3+Vant全家桶快速构建项目步骤详解

    这篇文章主要为大家介绍了使用Vite+Vue3+Vant全家桶快速构建项目步骤详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  5. vue3中$attrs的变化与inheritAttrs的使用详解

    $attrs现在包括class和style属性。 也就是说在vue3中$listeners不存在了,vue2中$listeners是单独存在的,在vue3 $attrs包括class和style属性, vue2中 $attrs 不包含class和style属性,这篇文章主要介绍了vue3中$attrs的变化与inheritAttrs的使用 ,需要的朋友可以参考下

  6. vue3中proxy的基本用法说明

    这篇文章主要介绍了vue3中proxy的基本用法说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  7. 如何利用vue3实现一个俄罗斯方块

    俄罗斯方块这个游戏相信大家都玩过,下面这篇文章主要给大家介绍了关于如何利用vue3实现一个俄罗斯方块的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下

  8. Vue3 携手 TypeScript 搭建完整项目结构

    TypeScript 是JS的一个超级,主要提供了类型系统和对ES6的支持,使用 TypeScript 可以增加代码的可读性和可维护性,在 react 和 vue 社区中也越来越多人开始使用TypeScript,这篇文章主要介绍了Vue3 携手 TypeScript 搭建完整项目结构,需要的朋友可以参考下

  9. vue3中defineComponent 的作用详解

    这篇文章主要介绍了vue3中defineComponent 的作用,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  10. 对Vue3中reactive的深入理解

    这篇文章主要介绍了对Vue3中reactive的深入理解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部