1 modelo v
1.1 Entendiendo el modelo v
v-model es una instrucción integrada en vue3. Muchos elementos de formulario pueden usar este atributo, como input , checkbox , etc. Podemos implementar v-model en componentes personalizados . v-model es esencialmente un azúcar sintáctico:
- Enlace el atributo modelValue pasado por el componente principal ;
- Emita el evento update:modelValue al componente principal cuando cambie el valor .
1.2 Descripción del caso
Después de comprender la esencia de v-model , podemos usar SFC (archivo .vue) y TSX (.tsx) para definir un nombre de persona del componente para que el componente pueda usar v-model .
person-name incluye dos cuadros de entrada, a saber, "apellido" ( familyName ) y "first name" ( firstName ), el formato de datos pasado por v-model es:
{ familyName: '张', firstName: '三' }
Primero defina el tipo person-name-type.ts :
export interface PersonName {
/** 姓 */
familyName?: string;
/** 名 */
firstName?: string;
}
1.3 Estilos de escritura
Escriba el archivo de estilo person-name.scss e impórtelo en los dos componentes más adelante:
.person-name {
.el-form-item {
width: 200px;
}
}
2 Escribir componentes
2.1 Ideas de implementación
La lógica de implementación del componente nombre-persona es relativamente simple:
- Coloque dos casillas de entrada el-input en la plantilla , correspondientes a los dos campos de apellido y nombre respectivamente ;
- Defina dos variables innerFamilyName e innerFirstName para vincular los valores de los dos cuadros de entrada;
- Defina el atributo modeValue en props para recibir el objeto de tipo PersonName pasado por el componente principal ;
- Use watch para monitorear modelValue en profundidad , y cuando cambie el valor de su atributo, reasígnelo a las dos variables vinculadas al cuadro de entrada anterior;
- Cuando los dos cuadros de entrada activan el evento de entrada , se notifica al componente principal a través del evento update:modelValue para implementar v-model .
2.2 Implementación en SFC (.vue)
Cree el archivo de componente 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 Implementación en TSX (.tsx)
Cree el archivo de componente 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 Uso de componentes
Cree el componente principal demo-v-model.vue y use los dos componentes definidos anteriormente:
<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>
El efecto de ejecución es el siguiente:
La parte superior usa los componentes escritos en .vue, y la parte inferior usa los componentes escritos en .tsx. Los dos están vinculados al modelo v de forma independiente , y el efecto de la operación es exactamente el mismo.
- Los componentes secundarios pueden recibir el valor inicial pasado por el componente principal;
- Cuando cambie el valor del componente secundario, se lo notificará al componente principal;
- Cuando el componente principal cambia su valor, el componente secundario responde al cambio.