Appearance
Component v-model
Sử dụng Cơ Bản
v-model
có thể được sử dụng trên một thành phần để thực hiện một liên kết hai chiều.
Bắt đầu từ Vue 3.4, phương pháp khuyến nghị để đạt được điều này là sử dụng macro defineModel()
:
vue
<!-- Child.vue -->
<script setup>
const model = defineModel()
function update() {
model.value++
}
</script>
<template>
<div>Giá trị v-model được liên kết từ phía cha là: {{ model }}</div>
</template>
Sau đó, phía cha có thể liên kết một giá trị với v-model
:
template
<!-- Parent.vue -->
<Child v-model="count" />
Giá trị trả về bởi defineModel()
là một ref. Nó có thể được truy cập và thay đổi giống như bất kỳ ref nào khác, ngoại trừ nó hoạt động như một liên kết hai chiều giữa một giá trị phụ thuộc vào cha và một giá trị cục bộ:
.value
của nó được đồng bộ với giá trị được liên kết bởiv-model
của phần tử cha;- Khi nó được thay đổi bởi thành phần con, nó làm cho giá trị được liên kết của cha được cập nhật theo.
Điều này có nghĩa là bạn cũng có thể liên kết ref này với một phần tử nhập người dùng native thông qua v-model
, giúp bọc các phần tử nhập native một cách dễ dàng trong khi vẫn cung cấp cùng cách sử dụng v-model
:
vue
<script setup>
const model = defineModel()
</script>
<template>
<input v-model="model" />
</template>
Bên Trong
defineModel
là một macro tiện ích. Trình biên dịch mở rộng nó thành các phần sau:
- Một prop có tên là
modelValue
, giá trị của ref cục bộ được đồng bộ với nó; - Một sự kiện có tên là
update:modelValue
, được phát ra khi giá trị của ref cục bộ thay đổi.
Đây là cách bạn sẽ triển khai cùng một thành phần con được hiển thị trước phiên bản 3.4:
vue
<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>
<template>
<input
:value="props.modelValue"
@input="emit('update:modelValue', $event.target.value)"
/>
</template>
Như bạn có thể thấy, nó lớn hơn đáng kể. Tuy nhiên, hiểu được điều gì đang xảy ra phía dưới là hữu ích.
Vì defineModel
khai báo một prop, bạn có thể đặt ra các tùy chọn của prop cơ bản bằng cách chuyển nó vào defineModel
:
js
// làm cho v-model là bắt buộc
const model = defineModel({ required: true })
// cung cấp một giá trị mặc định
const model = defineModel({ default: 0 })
Đối Số của v-model
v-model
trên một thành phần cũng có thể chấp nhận một đối số:
template
<MyComponent v-model:title="bookTitle" />
Trong thành phần con, chúng ta có thể hỗ trợ đối số tương ứng bằng cách truyền một chuỗi vào defineModel()
như là đối số đầu tiên của nó:
vue
<!-- MyComponent.vue -->
<script setup>
const title = defineModel('title')
</script>
<template>
<input type="text" v-model="title" />
</template>
Nếu cũng cần các tùy chọn của prop, chúng cũng nên được truyền sau tên của mô hình:
js
const title = defineModel('title', { required: true })
Sử dụng trước 3.4
vue
<!-- MyComponent.vue -->
<script setup>
defineProps(['title'])
defineEmits(['update:title'])
</script>
<template>
<input
type="text"
:value="title"
@input="$emit('update:title', $event.target.value)"
/>
</template>
Nhiều v-model
Bindings
Bằng cách tận dụng khả năng định rõ một prop và sự kiện cụ thể như chúng ta đã học trước đó với đối số v-model
, chúng ta có thể tạo nhiều v-model
trên một thể hiện của thành phần duy nhất.
Mỗi v-model
sẽ đồng bộ với một prop khác nhau, mà không cần sử dụng thêm tùy chọn trong thành phần:
template
<UserName
v-model:first-name="first"
v-model:last-name="last"
/>
vue
<script setup>
const firstName = defineModel('firstName')
const lastName = defineModel('lastName')
</script>
<template>
<input type="text" v-model="firstName" />
<input type="text" v-model="lastName" />
</template>
Sử dụng trước 3.4
vue
<script setup>
defineProps({
firstName: String,
lastName: String
})
defineEmits(['update:firstName', 'update:lastName'])
</script>
<template>
<input
type="text"
:value="firstName"
@input="$emit('update:firstName', $event.target.value)"
/>
<input
type="text"
:value="lastName"
@input="$emit('update:lastName', $event.target.value)"
/>
</template>
Xử lý Modifiers cho v-model
Khi chúng ta đang tìm hiểu về việc kết nối đầu vào của biểu mẫu, chúng ta thấy rằng v-model
có modifiers tích hợp sẵn - .trim
, .number
và .lazy
. Trong một số trường hợp, bạn cũng có thể muốn v-model
trên thành phần input tùy chỉnh của bạn hỗ trợ các modifiers tùy chỉnh.
Hãy tạo một ví dụ về modifier tùy chỉnh, capitalize
, chuyển đổi chữ cái đầu tiên của chuỗi được cung cấp bởi v-model
:
template
<MyComponent v-model.capitalize="myText" />
Các modifiers được thêm vào v-model
của một thành phần có thể được truy cập trong thành phần con bằng cách phân rã giá trị trả về của defineModel()
như sau:
vue
<script setup>
const [model, modifiers] = defineModel()
console.log(modifiers) // { capitalize: true }
</script>
<template>
<input type="text" v-model="model" />
</template>
Để điều chỉnh điều kiện cách giá trị nên được đọc / ghi dựa trên các modifiers, chúng ta có thể truyền các tùy chọn get
và set
cho defineModel()
. Hai tùy chọn này nhận giá trị khi nhận / đặt giá trị của tham chiếu model và nên trả về giá trị đã được biến đổi. Dưới đây là cách chúng ta có thể sử dụng tùy chọn set
để triển khai modifier capitalize
:
vue
<script setup>
const [model, modifiers] = defineModel({
set(value) {
if (modifiers.capitalize) {
return value.charAt(0).toUpperCase() + value.slice(1)
}
return value
}
})
</script>
<template>
<input type="text" v-model="model" />
</template>
Sử dụng trước 3.4
vue
<script setup>
const props = defineProps({
modelValue: String,
modelModifiers: { default: () => ({}) }
})
const emit = defineEmits(['update:modelValue'])
function emitValue(e) {
let value = e.target.value
if (props.modelModifiers.capitalize) {
value = value.charAt(0).toUpperCase() + value.slice(1)
}
emit('update:modelValue', value)
}
</script>
<template>
<input type="text" :value="modelValue" @input="emitValue" />
</template>
HzMKsP+u0kLOPoZWzkx1X7j18A8s0DEY=)
Modifiers cho v-model
với tham số
Dưới đây là một ví dụ khác về việc sử dụng modifiers với nhiều v-model
với các tham số khác nhau:
template
<UserName
v-model:first-name.capitalize="first"
v-model:last-name.uppercase="last"
/>
vue
<script setup>
const [firstName, firstNameModifiers] = defineModel('firstName')
const [lastName, lastNameModifiers] = defineModel('lastName')
console.log(firstNameModifiers) // { capitalize: true }
console.log(lastNameModifiers) // { uppercase: true}
</script>
Sử dụng trước 3.4
vue
<script setup>
const props = defineProps({
firstName: String,
lastName: String,
firstNameModifiers: { default: () => ({}) },
lastNameModifiers: { default: () => ({}) }
})
defineEmits(['update:firstName', 'update:lastName'])
console.log(props.firstNameModifiers) // { capitalize: true }
console.log(props.lastNameModifiers) // { uppercase: true}
</script>