v-model implementation in Vue.js 3
In Vue3, alias for v-model, e.g.:
<Comp v-model="vv">
is prop modelValue
+ event @update:modelValue
:
<Comp :modelValue="vv" @update:modelValue="vv = $event">
So, to create v-model in vue, you just need to read from reactive modelValue property in the component and emit event named "@update:modelValue". Check example below to understand how to do it.
Example
Create file MyInp.vue
:
<template> | |
<div class="inpwrap"> | |
<div class="lbl" :class="modelValue || inpFoc ? 'fill' : ''"> | |
{{ label }} | |
</div> | |
<input | |
class="inp" | |
:value="modelValue" | |
@input="onInput" | |
@focus='inpFoc = true' | |
@blur='inpFoc = false' | |
/> | |
</div> | |
</template> | |
<script> | |
export default { | |
props: { | |
modelValue: String, | |
label: String, | |
}, | |
data() { | |
return { | |
inpFoc: false, | |
} | |
}, | |
methods: { | |
onInput(event) { | |
this.$emit('update:modelValue', event.target.value) | |
} | |
}, | |
} | |
</script> | |
| |
<style scoped> | |
.inpwrap { | |
width: 200px; | |
margin-top: 30px; | |
position: relative; | |
margin-left: calc(50% - 100px); | |
} | |
.lbl { | |
position: absolute; | |
top: 10px; | |
left: 10px; | |
pointer-events: none; | |
transition: 0.3s; | |
} | |
.lbl.fill { | |
top: -8px; | |
left: 5px; | |
font-size: 14px; | |
background-color: white; | |
padding: 0 5px | |
} | |
.inp { | |
width: 100%; | |
box-sizing: border-box; | |
padding: 10px; | |
border: 1px solid #333; | |
border-radius: 10px; | |
} | |
</style> |
To connect file use:
<template> | |
<div> | |
<div>Hello, dear {{ name }} {{surname}}</div> | |
<MyInp label="Name" v-model="name"></MyInp> | |
<MyInp label="Surname" v-model="surname"></MyInp> | |
</div> | |
</template> | |
<script> | |
import MyInp from './components/MyInp.vue' | |
export default { | |
components: { | |
MyInp | |
}, | |
data() { | |
return { | |
name: '', | |
surname: '', | |
} | |
}, | |
} | |
</script> |