Bind a single attribute
Basic binding
Custom componentsCustomInput
Give an example
<script setup> const txt = ref(''); </script> <template> <CustomInput v-model="txt" /> </template>
v-model
Will be expanded into the following form
<CustomInput :modelValue="txt" @update:modelValue="newValue => txt = newValue" />
<CustomInput>
There are two things that need to be done inside the component:
- Make internal native
<input>
Elementalvalue
attribute bind tomodelValue
prop - When native
input
When the event is triggered, trigger a new value.update:modelValue
Custom events
Here is the corresponding code:
<script setup> const props = defineProps({ 'modelValue': String, }) const emit = defineEmits(["update:modelValue"]) </script> <template> <input :value="modelValue" @input="$emit('update:modelValue', $)" /> </template>
Some people think this writing method is too cumbersome, which will make the tag code longer
Another implementation within the componentv-model
The way is to use a writable with both getter and settercomputed
Attributes
computed binding
usecomputed
When attributes,get
The method needs to be returnedmodelValue
prop, andset
The method needs to trigger the corresponding event
<script setup> const value = computed({ get() { return }, set(value) { emit("update:modelValue", value) } }) </script> <template> <input v-model="value" /> </template>
This writing method can simplify the properties in the tag and have clear logic
A single attribute can be usedv-model
It's easy to do it, what if multiple attributes require two-way binding?
🚀 v-model binds multiple attributes
By default,v-model
All are used on componentsmodelValue
As a prop, andupdate:modelValue
As the corresponding event
But we can givev-model
Specify a parameter to change these names:
<template> <CustomInput v-model:first-name="first" v-model:last-name="last" /> </template>
Similarly, it can be bound in two ways, justprop
From the originalmodelValue
It becomes the passed parameter name, and the corresponding event also becomesupdate: parameter name
<script setup> const props = defineProps({ firstName: String, lastName: String, }) // Use in computedconst emit = defineEmits(['update:firstName', 'update:lastName']) </script> <template> <input type="text" :value="firstName" @input="$emit('update:firstName', $)" /> <input type="text" :value="lastName" @input="$emit('update:lastName', $)" /> </template>
🚩 Bind the object
In a complex component, if multiple fields require two-way binding, it will be a bit complicated if the method shown above is used.
Introducing two ways to bind objects from two directions
Define parent componentsearchBar
For a complex form component
<script setup> import { ref } from "vue" const modelValue = ref({ keyword: "123", selectValue: "", options: [ { label: "all", value: "" }, { label: "a1", value: "1" }, { label: "a2", value: "2" }, ] }) </script> <template> <searchBar v-model="modelValue" /> </template>
Then insearchBar
In the component, we receivemodelValue
And define the type asObject
<template> <div> <!-- <input type="text" v-model=""> Two-way binding can be achieved --> <input type="text" :value="" @input="handleKeywordChange" > <select v-model=""> <option v-for="o in " :key="" :value=""> {{ }} </option> </select> </div> </template> <script lang="ts" setup> const props = defineProps({ modelValue: { type: Object, default: () => ({}) } }) const emit = defineEmits(["update:modelValue"]); // Take input as an exampleconst handleKeywordChange=(val)=>{ emit("update:modelValue",{ ..., keyword: }) } </script>
If you pass in an object, as described in the comments
<input type="text" v-model="">
Although two-way binding can be performed directly, this will destroySingle data flow
and aboveemit
The same thing as the event is triggered, but the passed data becomes an object
Although using emit can trigger two-way binding, it is too cumbersome. Here is a more elegant writing method, which can be said to be a strange trick --computed + prxoy
If usingcomputed
Bind, you might write this kind of code
<template> <input type="text" v-model=""> </template> <script lang="ts" setup> const model = computed({ get() { return }, set(value) { // (value) // found no print emit("update:modelValue", { ..., keyword: value }) } }) <script>
But when you enter, you will find that it is not triggered.setter
, becausecomputed
Will be a first-level proxy, and the proxy object has not been modified
If you want to triggersetter
, as shown below:
// Only in this way will change = { keyword:"asdfad" }
This method cannot triggersetter
, it cannot be bound in two directions. What should I do?
existgetter
Return oneAgent object!existgetter
Return oneAgent object!existgetter
Return oneAgent object!
becauseproxy
The proxy object is consistent with the proxy object attributes, so we useproxy
Package original object
Sov-model
The object bound to the proxy is after the proxy. If the attributes of the proxy object change, the proxy object will be triggered.set
Method, at this time we can triggeremit
const model = computed({ get() { return new Proxy(, { set(obj, name, val) { emit("update:modelValue", { ...obj, [name]: val }) return true } }) }, set(value) { emit("update:modelValue", { ..., keyword: value }) } })
Modifier
We knowv-model
There are some built-in modifiers, such as.trim
,.number
and.lazy
。
In some scenarios, we may want a custom componentv-model
Supports custom modifiers.
Let's create a custom modifiercapitalize
, it will automaticallyv-model
The first letter of the string value bound to be converted to capitalization:
<CustomInput ="txt" />
We addedcapitalize
Modifier, it will be automatically passed toprop
InmodelModifiers
middle
<script setup> const props = defineProps({ modelValue: String, modelModifiers: { default: () => ({}) } }) const emitValue = (e) => { let value = ; // Use modifier if () { value = (0).toUpperCase() + (1) } emit('update:modelValue', value) } </script> <template> <input :value="modelValue" @input="emitValue" /> </template>
Summarize
existvue
, we can usev-model
The instructions are very convenient for two-way binding, and can complete many interesting functions with modifiers.
The above is a detailed explanation of the usage of v-model in vue3. For more information about the usage of vue3 v-model, please follow my other related articles!