Chào mừng đến với Cafedev! Trong bài viết này, chúng ta sẽ khám phá về Vuejs với Component v-model – một tính năng quan trọng cho việc tạo và quản lý hai chiều dữ liệu giữa các thành phần trong ứng dụng Vue. Với Component v-model, bạn có thể dễ dàng thực hiện việc truyền dữ liệu giữa các thành phần con và cha một cách linh hoạt và hiệu quả. Hãy cùng tìm hiểu cách sử dụng và triển khai tính năng này trong ứng dụng của bạn!

1. Cách sử dụng Cơ bản

v-model có thể được sử dụng trên một component để thực hiện một liên kết hai chiều.
Bắt đầu từ Vue 3.4, cách tiếp cận được khuyến nghị để đạt được điều này là sử dụng macro defineModel():

<!-- Child.vue -->
<script setup>
const model = defineModel()

function update() {
  model.value++
}
</script>

  <div>parent bound v-model is: {{ model }}</div>

Cha sau đó có thể ràng buộc một giá trị với v-model:

<!-- Parent.vue -->
<Child v-model="countModel" />


Giá trị được trả về bởi defineModel() là một ref. Nó có thể được truy cập và biến đổi như bất kỳ ref nào khác, ngoại trừ việc nó hoạt động như một liên kết hai chiều giữa một giá trị cha mẹ và một giá trị cục bộ:
.value của nó được đồng bộ hóa với giá trị được ràng buộc bởi v-model của cha;
– Khi nó bị biến đổi bởi con, nó cũng gây ra việc cập nhật giá trị được ràng buộc của cha.

Điều này có nghĩa là bạn cũng có thể ràng buộc ref này với một phần tử nhập native bằng v-model, làm cho việc bọc các phần tử nhập native trở nên dễ dàng trong khi vẫn cung cấp cách sử dụng v-model tương tự:

<script setup>
const model = defineModel()
</script>

  <input v-model="model" />


Ví dụ Playground

1.1 Định nghĩa

defineModel là một macro tiện ích. Trình biên dịch mở rộng nó thành như sau:
– Một prop có tên modelValue, mà giá trị của ref cục bộ được đồng bộ với;
– Một sự kiện có tên update:modelValue, được phát ra khi giá trị của ref cục bộ bị biến đổi.
Đây là cách bạn sẽ triển khai cùng một component con được hiển thị trước 3.4:

<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>

  <input
    :value="props.modelValue"
    @input="emit('update:modelValue', $event.target.value)"
  />


Sau đó, v-model=”modelValue” trong thành phần cha sẽ được biên dịch thành:

<!-- Parent.vue -->
<Child
  :modelValue="foo"
  @update:modelValue="$event => (foo = $event)"
/>

Như bạn có thể thấy, nó khá nhiều từ. Tuy nhiên, hiểu được điều gì đang xảy ra bên trong là hữu ích.
Bởi vì defineModel khai báo một prop, bạn có thể khai báo các tùy chọn prop cơ bản bằng cách truyền nó vào defineModel:

// making the v-model required
const model = defineModel({ required: true })

// providing a default value
const model = defineModel({ default: 0 })


Cảnh báo: Nếu bạn có một giá trị mặc định cho prop defineModel và bạn không cung cấp bất kỳ giá trị nào cho prop này từ component cha, điều này có thể gây ra sự không đồng bộ giữa các component cha và con. Trong ví dụ dưới đây, myRef của cha là không xác định, nhưng model của con là 1:

// child component:
const model = defineModel({ default: 1 })

// parent component:
const myRef = ref()

<Child v-model="myRef"></Child>

2. Đối số của v-model

v-model trên một component cũng có thể chấp nhận một đối số:

<MyComponent v-model:title="bookTitle" />


Trong component con, chúng ta có thể hỗ trợ đối số tương ứng bằng cách truyền một chuỗi cho defineModel() làm đối số đầu tiên của nó:

<!-- MyComponent.vue -->
<script setup>
const title = defineModel('title')
</script>
<template>
  <input type="text" v-model="title" />
</template>


Thử nghiệm trong Playground
Nếu các tùy chọn prop cũng cần thiết, chúng nên được truyền sau tên model:

const title = defineModel('title', { required: true })

3. Multiple v-model bindings

Bằng cách tận dụng khả năng nhắm đến một prop và sự kiện cụ thể như chúng ta đã học trước đó với các đối số của v-model, bây giờ chúng ta có thể tạo nhiều ràng buộc v-model trên một thể hiện 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 phải có các tùy chọn bổ sung trong thành phần:

<UserName
  v-model:first-name="first"
  v-model:last-name="last"
/>
<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>

Try it in the Playground

4. Xử lý các modifier của v-model


Khi chúng ta đang học về các ràng buộc đầu vào biểu mẫu, chúng ta đã thấy rằng v-model có các modifier 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 ràng buộc v-model trên thành phần đầu vào tùy chỉnh của bạn hỗ trợ các modifier tùy chỉnh.

Hãy tạo một ví dụ về modifier tùy chỉnh, capitalize, mà chuyển đổi chữ cái đầu tiên của chuỗi được cung cấp bởi ràng buộc v-model:

<MyComponent v-model.capitalize="myText" />

Các Modifier được thêm vào một v-model của thành phần có thể được truy cập trong thành phần con bằng cách phân giải giá trị trả về từ defineModel() như sau:

<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 modifier, 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ị trên get / set của tham chiếu mô hình và nên trả về một giá trị được biến đổi. Đây là cách chúng ta có thể sử dụng tùy chọn set để triển khai modifier capitalize:

<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>

Try it in the Playground

Modifiers cho v-model với đối số

Dưới đây là một ví dụ khác về việc sử dụng các modifier với nhiều v-model có các đối số khác nhau:

<UserName
  v-model:first-name.capitalize="first"
  v-model:last-name.uppercase="last"
/>
<script setup>
const [firstName, firstNameModifiers] = defineModel('firstName')
const [lastName, lastNameModifiers] = defineModel('lastName')

console.log(firstNameModifiers) // { capitalize: true }
console.log(lastNameModifiers) // { uppercase: true }
</script>

Trên đây là những thông tin hữu ích về Vuejs with Component v-model mà chúng tôi muốn chia sẻ trên Cafedev. Hi vọng rằng bạn đã có cái nhìn tổng quan và sâu sắc hơn về cách sử dụng và triển khai tính năng này trong ứng dụng Vue của mình. Hãy tiếp tục khám phá và áp dụng những kiến thức mới này vào dự án của bạn để tạo ra những trải nghiệm người dùng tốt hơn và mã nguồn dễ bảo trì hơn. Cảm ơn bạn đã đọc bài viết trên Cafedev!

Tham khảo thêm: MIỄN PHÍ 100% | Series tự học Vuejs từ cơ bản tới nâng cao

Các nguồn kiến thức MIỄN PHÍ VÔ GIÁ từ cafedev tại đây

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của CafeDev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!