I. Giới thiệu
Hello everyone ✌️, bài viết này mình muốn chia sẻ các thông tin và chức năng mới của phiên bản Vue 3.3
-
<script setup>
+ TypeScript- Imported and Complex Types Support in Macros
- Generic Components
- More Ergonomic defineEmits
- Typed Slots with defineSlots
-
Tính năng thử nghiệm
- Reactive Props Destructure
- defineModel
-
Các tính năng đáng chú ý khác
- defineOptions
- Better Getter Support with toRef and toValue
- JSX Import Source Support
II. Nội dung
Phiên bản này tập trung vào các cải tiến về trải nghiệm cho các lập trình viên, cụ thể là SFC <script setup>
+ Typescript.
Cùng với phiên bản v1.6 của Vue Language Tools (trước đây gọi là Volar) đã giải quyết được nhiều điểm khó khăn tồn tại từ lâu khi sử dụng Vue với TypeScript.
Dependency Updates
- volar / vue-tsc@^1.6.4
- vite@^4.3.5
- @vitejs/plugin-vue@^4.2.0
- vue-loader@^17.1.0 (if using webpack or vue-cli)
<script setup>
+ TypeScript
1. Imported and Complex Types Support in Macros
Ở các version < 3.3, các kiểu dữ liệu được định nghĩa cho defineProps hay defineEmits chỉ giới hạn ở các kiểu dữ liệu cục bộ...
// Hoạt động bình thường
<script setup lang="ts">
interface Props { title: string } defineProps<Props>()
</script>
// Xảy ra lỗi
<script setup lang="ts">
import type { Props } from './foo' defineProps<Props>()
</script>
Hạn chế này đã được giải quyết ở version 3.3
<script setup lang="ts">
import type { Props } from './foo' // imported + intersection type
defineProps<Props & { extraProp?: string }>()
</script>
2. Generic Components
Các Components ở phiên bản mới sử dụng <script setup>
đã có thể thêm generic type
thông qua attribute
generic :
Simple T
<script setup lang="ts" generic="T"> defineProps<{ list: T[], modelValue?: T }> defineEmits<{ (e: `update:ModelValue`, a: T): void }>() </script>
Extend types...
<script setup lang="ts" generic="T extends string | number, U extends Item"> import type { Item } from './types'
defineProps<{ id: T list: U[]
}>() </script>
3. More Ergonomic defineEmits
Từ phiên bản v3.3, đã có thêm cách khai báo kiểu dữ liệu cho tham số của defineEmits
một cách thuận tiện hơn như sau.
// BEFORE
const emit = defineEmits<{ (e: 'foo', title: string): void (e: 'bar', id: number, ...rest: any[]): void
}>()
// AFTER
const emit = defineEmits<{ foo: [title: string] bar: [id: number, ...rest: any[]]
}>()
4. Typed Slots with defineSlots
Trong Vue v3.3 defineSlots
là một phương thức được sử dụng để định nghĩa các nội dung (slot) cần được chèn vào Component trong Vue Composition API
.
<script setup lang="ts">
defineSlots<{ default?: (props: { msg: string }) => any item?: (props: { id: number }) => any
}>()
</script>
Tính năng thử nghiệm
1. Reactive Props Destructure
Tính năng này cung cấp cách khai báo giá trị mặc định cho props một cách thuận tiện hơn.
<script setup>
import { watchEffect } from 'vue' const { msg = 'hello' } = defineProps(['msg']) watchEffect(() => { // accessing `msg` in watchers and computed getters // tracks it as a dependency, just like accessing `props.msg` console.log(`msg is: ${msg}`)
})
</script> <template>{{ msg }}</template>
2. defineModel
Đây là một tính năng mình thấy rất hay ở phiên bản lần này.
Ở các phiên bản trước, Vue hỗ trợ two-way binding
với v-model
bằng cách khai báo prop
và emit
để nhận và update cho giá trị đó.
<!-- BEFORE -->
<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
console.log(props.modelValue) function onInput(e) { emit('update:modelValue', e.target.value)
}
</script> <template> <input :value="modelValue" @input="onInput" />
</template>
Nhưng từ version 3.3, chúng ta chỉ cần sử dụng defineModel
defineModel
sẽ tự động đăng ký một prop
và trả về một tham chiếu có thể thay đổi, cập nhật trực tiếp.
<!-- AFTER -->
<script setup>
const modelValue = defineModel()
console.log(modelValue.value)
</script> <template> <input v-model="modelValue" />
</template>
Các tính năng đáng chú ý khác
Bên cạnh các tính năng mới được giới thiệu ở trên, thì ở phiên bản này tác giả cũng có những thay đổi và cập nhật cho những tính năng đã xuất hiện ở các phiên bản trước.
1. defineOptions
defineOptions cho phép bạn tùy chỉnh các option của Component một cách tường minh và linh hoạt hơn.
import { defineOptions } from 'vue'; const MyComponent = defineOptions({ name: 'MyComponent', props: { message: String }, data() { return { counter: 0 }; }, methods: { increment() { this.counter++; } }, template: ` <div> <p>{{ message }}</p> <button @click="increment">Increment</button> <p>Counter: {{ counter }}</p> </div> `
});
2. Cập nhật toRef
và toValue
toRef
đã được cải tiến để chuẩn hóa các giá trị, getters, refs thành refs
// equivalent to ref(1)
toRef(1) // e.g: Ref<number>
// creates a readonly ref that calls the getter on .value access
toRef(() => props.foo)
// returns existing refs as-is
toRef(existingRef)
Bạn có thể sử dụng toRef
để cập nhật lại sự thay đổi giá trị gần tương tự như computed
.
Chức năng toValue
trong Vue được sử dụng để lấy giá trị hiện tại của một thuộc tính đang theo dõi. Nó có thể được sử dụng trên bất kỳ thuộc tính nào, bao gồm cả thuộc tính được tạo bằng ref hoặc computed.
toValue(1) // --> 1
toValue(ref(1)) // --> 1
toValue(() => 1) // --> 1
toValue
có thể sử dụng để thay thế cho unRef
const myRef = ref(0);
console.log(toValue(myRef)); // 0 myRef.value = 1;
console.log(toValue(myRef)); // 1
III. Tổng kết
Đây là những thông tính năng mới về phiên bản VueJS v3.3. Cảm ơn các bạn đã theo dõi bài viết của mình nhé.