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>
本站声明:
1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/294606.html