Có lẽ chúng ta đã quá quen thuộc với VueJS – một web framework vô cùng mạnh mẽ và “đẹp troai”.
Trong đó, một trong những tính năng không thể thiếu đó là 2-way data binding, cụ thể là sử dụng v-model.
Nếu chưa từng làm việc với vuejs thì mình sẽ giải thích một cách khái quát giúp bạn hiểu về 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 đó. Vẫn hơi khó hiểu đúng không, vậy dưới đây là một ví dụ về v-model:
<template>
<input type="text" v-model="value"/>
<div>giá trị nhập từ input: <span style="color: red">{{value}}</span></div>
</template>
<script>
export default {
data() {
return {
value: ''
}
}
}
</script>
// Input: Đây là giá trị được nhập từ input
// Output: giá trị nhập từ input: Đây là giá trị được nhập từ input
Dễ đúng không. Nhưng tùy vào dự án mà bạn cần tạo các custom input 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 để implement v-model
- Sử dụng thuộc tính computer
- Custom props và event
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á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 CustomInput.vue -->
<template>
<input type="text" v-model="model" />
</template>
<script>
export default {
props: ['modelValue'],
data() {
return {
model: this.modelValue
}
},
watch: {
model(currentValue) {
this.$emit('update:modelValue', currentValue)
}
}
}
</script>
<!-- Cách sử dụng -->
<template>
<CustomInput v-model="text" />
<div>giá trị nhập từ input: <span style="color: red">{{text}}</span></div>
</template>
<script>
import CustomInput from './components/CustomInput.vue'
export default {
components: { CustomInput },
data() {
return {
text: ''
}
}
}
</script>
2. Custom method để implement v-model
Nếu sử dụng watcher ảnh hưởng tới hiệu năng của ứng dụng. Vậy cách 2 này sẽ 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.
<!-- Tạo component CustomInput.vue -->
<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>
<script>
export default {
props: ['modelValue'],
emits: ['update:modelValue']
}
</script>
<!-- Cách sử dụng -->
<template>
<CustomInput v-model="text" />
<div>giá trị nhập từ input: <span style="color: red">{{ text }}</span></div>
</template>
<script>
import CustomInput from './components/CustomInput.vue'
export default {
components: { CustomInput },
data() {
return {
text: ''
}
}
}
</script>
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:
<!-- Tạo component CustomInput.vue -->
<template>
<input v-model="value" />
</template><script>
export default {
props: ['modelValue'],
computed: {
value: {
get() {
return this.modelValue
},
set(value) {
this.$emit('update:modelValue', value)
}
}
}
}
</script>
<!-- Cách sử dụng -->
<template>
<CustomInput v-model="text" />
<div>giá trị nhập từ input: <span style="color: red">{{ text }}</span></div>
</template>
<script>
import CustomInput from './components/CustomInput.vue'
export default {
components: { CustomInput },
data() {
return {
text: ''
}
}
}
</script>
4. Custom props và event
Vì prop và event mặc định của v-model của Vue3 là modelValue
và update:modelValue
. Tuy nhiên chúng ta có thể biến đổi tên của nó bằng cách truyền đối số cho v-model
<!-- Component cha -->
<CustomInput v-model:title="text" />
Trong trường hợp này, component con sẽ nhận một prop title
và một emit một sự kiện update:title
để cập nhật lại giá trị ở component cha
<!-- CustomInput.vue -->
<template>
<input
type="text"
:value="title"
@input="$emit('update:title', $event.target.value)"
/>
</template>
<script>
export default {
props: ['title'],
emits: ['update:title']
}
</script>
Kết luận
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.Tương tự bạn cũng có thể làm với một số type khác của input như radio, checkbox,…
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.