VueJS – Cách tự implement v-model cho một component

0
Dịch vụ dạy kèm gia sư lập trình

Có lẽ chúng ta đã quá quen thuộc với VueJS – một web framework vô cùng mạnh mẽ và “đẹp trai”.

Trong đó, một trong những tính năng mà rất nhiều người dùng đó là 2-way data binding, cụ thể là sử dụng v-model.

Đây là một cách thức mà bạn hay dùng cho các form nhập liệu. Khi mà giá trị của các biến vừa dùng để hiển thị trên input, đồng thời khi người dùng nhập thì nó cũng tự động lưu vào biến đó. Nhưng có lẽ thuộc tính v-model thường có sẵn trong các component của VueJS, hoặc thư viện bên thứ 3, rất ít khi bạn tự tạo.

Tùy vào dự án bạn đang xây dựng, bạn có thể tự tạo các custom component mà trong đó cần phải xử lý 2-way data binding. Dưới đây là một số cách mà bạn có thể tự implement v-model:

  • Watcher một biến local
  • Custom method
  • Sử dụng thuộc tính computer
  • Custom props và event (VueJS 2) – giống như cách Angular đang làm
  • Cuối cùng là sử dụng .sync modifier

Bài viết này, mình sẽ hướng dẫn cụ thể cách implement v-model theo những phương pháp trên.

1. Watcher một biến local

Đây có lẽ là cách mọi người hay nghĩ tới nhất khi cần implement v-model cho component của mình.

Cách thực hiện đơn giản nhất là gồm những bước sau:

  • chúng ta khai báo một props,
  • sau đó tạo một biến observable trong data() và khởi tạo giá trị là giá trị của props đã khai báo trước đó
  • Cuối cùng là sử dụng event để thông báo cho component cha, mục đích là để update giá trị props từ bên ngoài component.

Nói thì có vẻ trừu tượng vậy thôi, nhưng nhìn code là bạn sẽ thấy nó đơn giản như nào.

<!— Tạo component BaseInput.vue -->
<template>
  <input type="text" v-model="model" />
</template>

<script>
  export default {
    props: {
      value: {
        type: String,
        default: ''
      }
    },
    data() {
      return {
        model: this.value
      }
    },
    watch: {
      model(currentValue) {
        this.$emit('input', currentValue)
      }
    }
  }
</script>

<!—Cách sử dụng -->
<BaseInput v-model="text" />

2. Custom method để implement v-model

Có thể bạn đã nghe ở đâu đó bàn luận rằng sử dụng nhiều watcher sẽ ảnh hưởng tới hiệu năng của ứng dụng. Kể ra thì cũng có lý.

Vậy thì cách thứ 2 này sẽ không sử dụng watch nữa, mà tận dụng event @input có sẵn của input native, và tạo một custom method trong component của chúng ta.

Chúng ta sẽ truyền giá trị của input tới component cha thông qua emit một event, mục đích cũng là để có thể cập nhật props từ bên ngoài component.

Trong trường hợp này, chúng ta hoàn toàn không sử dụng thuộc tính v-model của native input, mà sử dụng thuộc tính value.

<!—Định nghĩa component BaseInput.vue -->
<template>
  <input type="text" :value="value" @input="onInput" />
</template>

<script>
  export default {
    props: {
      value: {
        type: String,
        default: ''
      }
    },
    methods: {
      onInput(event) {
        this.$emit('input', event.target.value)
      }
    }
  }
</script>

<!—Cách sử dụng -->
<BaseInput v-model="text" />
Lưu ý: Đối với Vue3, thuộc tính value được đổi tên thành modelValue và tên của event input được đổi thành update:modelValue

3. Sử dụng thuộc tính computer

Một cách khác nữa để implement v-model trong một custom component đó là sử dụng getter và setter của computed.

Bạn có thể định nghĩa một thuộc tính computed, sau đó:

  • Implement một getter để trả về value của thuộc tính đó.
  • Một setter để emit một input event tới component cha

Cụ thể cách viết code như sau:

<!—Khai báo component BaseInput.vue -->
<template>
  <input type="text" v-model="model" />
</template>

<script>
  export default {
    props: {
      value: {
        type: String,
        default: ''
      }
    },
    computed: {
      model: {
        get() {
          return this.value
        },
        set(value) {
          this.$emit('input', value)
        }
      }
    }
  }
</script>

<!—Cách sử dụng -->
<BaseInput v-model="text" />

4. Custom props và event

Lại một cách nữa để cho bạn lựa chọn khi cần implement v-model cho component yêu dấu của mình.

Nghiên cứu đến phần này, thực sự mình liên tưởng tới cơ chế 2-way data binding của Angular. Khá là tương đồng. Hay là hai framework này nó học hỏi nhau nhỉ?

Trong các giải pháp implement v-model ở trên, tên của props luôn là value, còn tên của event luôn là input. Đây đều là cấu hình mặc định trong cách implement v-model trong custom component của bạn.

Tất nhiên, bạn thích thì có thể thay đổi. Phải có sự linh động ở đây chứ. Ai lại fix cứng thế bao giờ, đúng không?

Để làm được điều đó, bạn cần đặt tên thuộc tính model, và khai báo trong component biết props và event mà bạn đã thay đổi.

Vào việc luôn nhỉ!

<!—Khai báo component BaseInput.vue -->
<template>
  <input type="text" :value="text"  @input="onInput" />
</template>

<script>
  export default {
    model: {
      prop: 'text',
      event: 'update'
    },
    props: {
      text: {
        type: String,
        default: ''
      }
    },
    methods: {
      onInput(event) {
        this.$emit('update', event.target.value)
      }
    }
  }
</script>

<!—Cách sử dụng -->
<BaseInput v-model="text" />

Tạm kết

Trên đây là một số cách để bạn implement v-model trong một component tùy chỉnh mà bạn tự tạo. Bạn thích và hay sử dụng cách nào nhất?

Tải mã nguồn minh họa của các cách trên:

VueJS với ưu điểm nhanh, gọn, nhẹ và tùy biến cao, nên mình nghĩ ngoài những cách trên, sẽ còn nhiều cách khác nữa.

Bạn còn nghĩ ra cách nào khác để implement v-model cho component nữa không? Để lại ý kiến bình luận bên dưới nhé. Mình cũng đang đón chờ đây.

💥 Đọc thêm bài viết rất hay khác về VueJS:

Nguồn tham khảo: Pablo Veiga blog

Dịch vụ phát triển ứng dụng mobile giá rẻ - chất lượng
Bài trướcCách tạo lớp Presenter trong MVP độc lập với Android Application Class
Bài tiếp theo⚽ AFF Cup 2022 – Link xem trực tiếp các trận đấu Việt Nam
Sơn Dương
Tên đầy đủ là Dương Anh Sơn. Tốt nghiệp ĐH Bách Khoa Hà Nội. Mình bắt đầu nghiệp coder khi mà ra trường chẳng xin được việc đúng chuyên ngành. Mình tin rằng chỉ có chia sẻ kiến thức mới là cách học tập nhanh nhất. Các bạn góp ý bài viết của mình bằng cách comment bên dưới nhé !

Bình luận. Cùng nhau thảo luận nhé!

avatar
  Theo dõi bình luận  
Thông báo