vue3学习记录-v-model
1.疑问
像那种原生标签,例如input、textarea 及 select上使用v-model,会创建双向数据绑定。那像那种自定义的组件v-model是怎么实现双向绑定的呢。
2 用法
2.1底层原理
一个名为 modelValue 的 prop,本地 ref 的值与其同步;
一个名为 update:modelValue 的事件,当本地 ref 的值发生变更时触发。
//父组件
<script setup>
import A from './components/A.vue';
import { ref } from 'vue';
const countModel = ref(0);
</script>
<template>
<div class="container">
<p>countModel:{{ countModel }}</p>
<A v-model="countModel"></A>
<B v-model="countModel1"></B>
</div>
</template>
//子组件
<template>
<input type="text" :value="modelValue" @input="inputChange">
</template>
<script setup>
defineProps({
modelValue:String
})
const inputChange =(e) =>{
console.log(e.target.value)
emit('update:modelValue',e.target.value)
}
const emit = defineEmits(['update:modelValue'])
</script>
其实还是把组件向下传的值,子组件接受绑定在input、textarea 及 select上,改变时再emit出来,父组件接收后又再改变自己的值。
父组件中的 v-model=“foo” 将被编译为:
<A
:modelValue=“countModel”
@update:modelValue=“$event => (countModel= $event)”
/>
2.2 多个v-model
Vue 3 允许在一个组件上使用多个 v-model
<!-- CustomForm.vue -->
<script setup>
defineProps(['firstName', 'lastName'])
defineEmits(['update:firstName', 'update:lastName'])
</script>
<template>
<input
:value="firstName"
@input="$emit('update:firstName', $event.target.value)"
/>
<input
:value="lastName"
@input="$emit('update:lastName', $event.target.value)"
/>
</template>
//父组件
<script setup>
import CustomForm from './components/CustomForm.vue';
import { ref } from 'vue';
const firstName = ref('')
const lastName = ref('')
</script>
<template>
<div class="container">
<CustomForm
v-model:firstName="firstName"
v-model:lastName="lastName"
/>
<p>全名:{{ firstName }} {{ lastName }}</p>
</div>
</template>
2.3 defineModel()
从 Vue 3.4 开始,推荐的实现方式是使用 defineModel() 宏:
<!-- Child.vue -->
<script setup>
const model = defineModel()
function update() {
model.value++
}
</script>
<template>
<div>
<div>Parent bound v-model is: {{ model }}</div>
<input type="text" v-model="model">
<button @click="update">Increment</button>
</div>
</template>
defineModel的写法input绑定值用的是v-model,单个或则多个v-model和底层原理类似的写法
2.4 自定义修饰符
Vue 3 还允许我们为 v-model 创建自定义修饰符。自定义一个capitalize实现首字母大写.
<script setup>
import B from './components/B.vue';
import { ref } from 'vue';
const countModel = ref('');
</script>
<template>
<div class="container">
<B v-model.capitalize="countModel"></B>
</div>
</template>
<template>
<input type="text" :value="modelValue" @input="inputChange">
</template>
<script setup>
import { ref, reactive} from 'vue'
const props = defineProps({
modelValue:String,
modelModifiers:{default: ()=> {}}
})
const inputChange =(e) =>{
let value = e.target.value
if (props.modelModifiers.capitalize) {
value = value.charAt(0).toUpperCase() + value.slice(1)
}
emit('update:modelValue',value)
}
const emit = defineEmits(['update:modelValue'])
</script>
3.4之后的写法
<!-- Child.vue -->
<script setup>
const [model, modifiers] = defineModel({
set(val){
if(modifiers.capitalize){
return val.charAt(0).toUpperCase() + val.slice(1)
}
return val
}
})
</script>
<template>
<div>Parent bound v-model is: {{ model }}</div>
<input type="text" v-model="model">
</template>