问题: 使用第三方 vue3-tel-input电话组件时,通过v-model绑定具有初始值的电话变量,但input框内显示的初始值为空?
排查过程:
- 将 v-model绑定改为 :value绑定后,电话变量初始值竟然能够显示
- 在vue3-tel-input组件上绑定有自定义的 input 事件
- vue3-tel-input组件的子组件,暴露了 value属性和
e m i t ( ′ i n p u t ′ , v a l u e , t h i s . p h o n e O b j e c t , t h i s . emit('input', value, this.phoneObject, this. emit(′input′,value,this.phoneObject,this.refs.input) 的触发事件,
以触发父类通过 @input绑定的方法逻辑。 - 查看 vue3-tel-input子组件源码,并没有定义 modelValue属性和 @update:modelValue触发事件。
知识点解析:
- v-model 为vue语法糖,绑定在
<input>
和组件
上编译后的等价展开不同。- 绑定在
<input>
元素,编译后,为 :value和 @input的组合。@input提供了默认实现。 - 绑定在组件上,编译后,为 :modelValue和 @update:modelValue事件。@update:modelValue提供了默认实现。
- 绑定在
********************绑定在<input>上*************************
编译前:
<input v-model="formModel.phoneNumber" />
编译后:
<input
:value="formModel.phoneNumber"
@input="formModel.phoneNumber = $event.target.value"
/>
********************绑定在组件上*************************
编译前:
<vue-tel-input v-model="value">
编译后:
<vue-tel-input
:modelValue="formModel.phoneNumber"
@update:modelValue="newValue => formModel.phoneNumber = newValue"
/>
- 属性绑定的变量,值只会单向传递,例如通过 :value和 :modelValue,如果没有额外的触发事件,即子组件中值的变化不会影响到父组件通过 :value和 :modelValue绑定变量的值。
解决方案:
- 方案一: 使用v-model绑定。优点在于简单,通过默认的input触发事件可以实现双向数据绑定,也可以自定义input事件;
缺点在于,vue3-tel-input子组件内没有modelValue属性,没有默认实现默认值渲染。适合于没有默认值的场景。 - 方案二: 通过 :value 和自定义 input事件进行变量绑定和数据更新操作逻辑。由于组件内已经暴露 value属性,所以能够实现默认值渲染,也可以自定义input事件逻辑,灵活性高,适合有默认值的场景。
拓展
封装组件,v-model绑定变量,通过在子组件中,暴露 modelValue属性和 update:modelValue触发事件实现双向数据绑定。
-----------------父组件-------------------------
<script setup>
import {reactive} from "vue";
import SonItem from "@/views/SonItem.vue";
let formModel = reactive({
value: 'Hello World'
})
</script>
<template>
<div class="about">
<h4>Parent {{formModel.value}}</h4>
<SonItem v-model="formModel.value"></SonItem>
</div>
</template>
-----------------子组件-------------------------
<template>
<input type="text" :value="props.modelValue" @input="$emit('update:modelValue', $event.target.value)">
</template>
<script setup>
let props = defineProps({
modelValue:{
type: String
}
});
</script>