vue中自定义组件v-model的用法
前言
面试官:
你讲了你封装了不少组件,那自定义组件中有用过v-model吗,知道他的实现过程吗,那v-model的修饰符,比如常用的input输入框中v-model.trim是如何实现的吗。
我:
用过(其实不怎么用,只知道个大概,平常封装组件直接传值props这样的)就是相当于在子组件里面定义value值,它会有个默认的emit事件input进行回调来对父组件数据进行更新。自定义的修饰符没用过,如果需要处理数据,一般会采用事件来对数据再进一层处理
面试官:
那如果我是单选,多选种类的怎么更新呢
我:
应该差不多吧
面试官:
也是value吗,如果是的话,单选多选使用时不会冲突吗
我:
那,这,不知道 然后就一阵沉默结束
面试官:
那,这,一阵沉默后说你等通知吧
vue2中自定义组件 v-model 的实现
我们来看下官网的说法
- 我们根据 api 来测试一下,在子组件里面使用 input 输入框定义 value ,用默认的回调方式更新
**父组件:**
<template>
<div class="v-model">
父组件的值 <span>{{ inputValue }}</span>
<myChildren v-model="value"></myChildren>
</div>
</template>
<script>
import myChildren from "./children.vue"
export default{
name:'Parent-level',
components:{
myChildren
},
data(){
return{
value:'父组件初始值'
}
}
}
</script>
**子组件:**
<template>
<div class="v-model-children">
子组件的值
<input type="text" :value="value" @input="(e)=>{$emit('input',e.target.value)}" class="input">
</div>
</template>
<script>
export default{
name:'children-input',
props:{
value:{
type:String,
default:''
}
},
}
</script>
那如果我们改下 props 中接收的 value 为其他字段呢,还能父子数据同步吗。结果是虽然子组件更新父组件能更新,但是父组件的初始值子组件是拿不到的。 那我们换个方式来进行子组件初始值更新,在data里面定义一个数据,监听父组件传过来的值,有值更新后对data里面定义的值进行更新
*子组件*
<template>
<div class="v-model-children">
子组件的值
<input type="text" :value="inputValue" @input="(e)=>{$emit('input',e.target.value)}" class="input">
</div>
</template>
<script>
export default{
name:'children-input',
props:{
value:{
type:String,
default:''
}
},
data(){
return{
inputValue:''
}
},
watch:{
value: {
handler(newval) {
this.inputValue=newval
},
immediate: true
}
},
}
</script>
结果是可行,但多此一举,多写了几行代码,少摸了一会鱼。
- 我们来看下其他类型的 model 绑定
*父组件*
<template>
<div class="v-model">
<span>父组件的值{{ value }}</span>
<myChildren v-model="value"></myChildren>
</div>
</template>
<script>
import myChildren from "./index-children.vue"
export default{
name:'Parent-level',
components:{
myChildren
},
data(){
return{
value:false,
}
},
}
</script>
*子组件*
<template>
<div class="v-model-children">
子组件的值
<select name="fruit" :checked="checked" v-on:change="$emit('input', $event.target.value)">>
<option value="apple">apple</option>
<option value="pear">pear</option>
<option value="watermelon">watermelon</option>
<option value="banana">banana</option>
</select>
</div>
</template>
<script>
export default{
name:'children-input',
model:{
prop:'checked',
event:'change'
},
props:{
checked:{
type:String,
default:''
},
},
}
</script>
我们把子组件里面的 model 设置注释掉,则父组件初始值就不会同步更新到子组件。 假如想使用自定义的 prop 和事件,我们把这个 model 设置为我们自己需要的,就可以实现自定义组件的 v-model 。
.sync修饰符
假如我们一个 Model 弹窗,希望实现一个数据双向绑定的效果,我们也可以使用 .sync
修饰符来处理。可以这样来理解,.sync 起到父组件数据实时更新到子组件的作用,但是需要搭配特定的 update 回调才起作用。
*父组件*
<template>
<div class="v-model">
<span>父组件</span>
<button @click="()=>visible=true">显示子组件</button>
<myChildren :visible.sync="visible"></myChildren>
</div>
</template>
<script>
import myChildren from "./index-children.vue"
export default{
name:'Parent-level',
components:{
myChildren
},
data(){
return{
visible:false,
}
}
}
</script>
*子组件*
<template>
<div class="v-model-children" v-if="visible">
显示子组件
<button @click="()=>$emit('update:visible',false)"> 移除子组件</button>
</div>
</template>
<script>
export default{
name:'children-input',
props:{
visible:{
type:Boolean,
default:false
},
}
}
</script>
总结一下:
总得来说相比于我们平常封装的组件,少了一个子组件中 props 的重新取值,和父组件的更新回调。但是它也是有不足的地方,一个自定义组件只有一个v-model 。.sync
的数据双向绑定需要搭配固定的 update
回调才能进行实时更新
vue3中自定义组件 v-model 的实现
我们先来看下官网的用法
默认情况下,组件上的
v-model 使用
modelValue 作为 prop 和
update:modelValue 作为事件。我们可以通过向
v-model 传递参数来修改这些名称:
我们先用代码实现一下
*父组件*
<template>
<div class="wrapper">
父组件:{{value }}
<HelloWorld v-model="value"/>
等价于 <!-- <HelloWorld v-model:model-value="value"/> -->
</div>
</template>
<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue'
import { ref } from 'vue';
const value=ref('父级xxx')
</script>
*子组件*
<template>
<div class="greetings">
<span>子组件: </span>{{ modelValue }}
<button @click="()=>$emit('update:modelValue','子级xxx')">更新子组件</button>
</div>
</template>
<script setup lang="ts">
defineProps({
modelValue:{
type:String,
default:''
}
})
defineEmits(['update:modelValue'])
</script>
有没有很眼熟,和 vue2 中 .sync
方式差不多,都是通过 update 进行回调更新。算是 vue2 中 v-model
与 .sync
实现方式的结合体。
那如果我们想不使用modeValue ,使用自定义的prop呢?
我们把子组件中 modelValue 都替换为 myModel ,先不改动父组件测试一下,发现父组件无法更新了。我们来修改一下父组件的绑定属性改为 v-model:my-model="value" 就可以实现父子组件同步更新了
vue3可以定义多个model
*父组件*
<template>
<div class="wrapper">
父组件:{{value }}
<br>
父组件2:{{value2 }}
<HelloWorld v-model:my-model="value" v-model:my-model2="value2"/>
</div>
</template>
<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue'
import { ref } from 'vue';
const value=ref('父级xxx')
const value2=ref('父级xxx2')
</script>
*子组件*
<template>
<div class="greetings">
<div>
<span>子组件: </span>{{ myModel }}
<button @click="()=>$emit('update:myModel','子级xxx')">更新子组件</button>
</div>
<div>
<span>子组件2: </span>{{ myModel2 }}
<button @click="()=>$emit('update:myModel2','子级xxx2')">更新子组件2</button>
</div>
</div>
</template>
<script setup lang="ts">
defineProps({
myModel:{
type:String,
default:''
},
myModel2:{
type:String,
default:''
}
})
defineEmits(['update:myModel','update:myModel2'])
</script>
看起来和定义一个 v-model 没什么区别,就是就是多定义了一组父子级数据而已
那vue3中v-model修饰符是如何使用的呢?
在 3.x 中,添加到组件
v-model
的修饰符将通过modelModifiers
prop 提供给组件
意思就是如果我们使用修饰符,需要在定义 prop 的时候进行修饰符的定义,我们用代码来实现一下
*父组件*
<template>
<div class="wrapper">
父组件:{{value }}
<br>
<HelloWorld v-model:my-model.capitalize="value"/>
</div>
</template>
<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue'
import { ref } from 'vue';
const value=ref('fujishjux')
</script>
*子组件*
<template>
<div class="greetings">
<span>子组件: </span>{{ myModel }}
<input type="text"
:value="myModel"
@input="inputChange">
</div>
</template>
<script setup lang="ts">
const props:any=defineProps({
myModel:{
type:String,
default:'',
},
myModelModifiers:{
default: () => ({})
}
})
const emit=defineEmits(['update:myModel'])
const inputChange=(e:any)=>{
let value = e.target.value
// console.log(props.myModelModifiers.capitalize)
if(props.myModelModifiers.capitalize){
value = value.charAt(0).toUpperCase() + value.slice(1)
}
emit('update:myModel',value)
}
</script>
我们在 prop 后进行了一个修饰符操作的定义,当父组件添加了修饰符,在子组件中就能知道需要对数据进行处理!
有个点需要注意一下,就是修饰符的定义就是我们定义的 prop + Modifiers,否则就会无效
结语
到这里自定义 v-model 已经聊完了,虽然这是一个很小的点,但是对我们开发中也很有帮助。我是南岸月明
致力于用最简洁的话聊清楚一个个知识点,共同进步是我目标!
转载自:https://juejin.cn/post/7205561335554310204