vue3+ts实际开发中该如何优雅书写vue3语法
double_Fly_ 人气:0vue3语法的发展
- Vue3 在早期版本( 3.0.0-beta.21 之前)中对 composition api 的支持,只能在组件选项 setup 函数中使用。
- 在 3.0.0-beta.21 版本中增加了 <script setup> 的实验特性。如果你使用了,会提示你 <script setup> 还处在实验特性阶段。
- 在 3.2.0 版本中移除<script setup> 的实验状态,从此,宣告 <script setup> 正式转正使用,成为框架稳定的特性之一。
所以我们现在直接就开始使用3.2.0之后的写法
优势
与组件选项 setup 函数对比, <script setup>
的优点:
- 更少、更简洁的代码,不需要使用 return {} 暴露变量和方法了,使用组件时不需要主动注册了;
- 更好的 Typescript 支持,使用纯 Typescript 声明 props 和抛出事件,不会再像 option api 里那么蹩脚了;
- 更好的运行时性能;
- 当然, <script setup> 也是有自己的缺点的,比如需要学习额外的 API。
Composition Api类型约束
<script setup lang="ts"> import { ref, reactive, computed } from 'vue' type User = { name: string age: number } // ref const msg1 = ref('') // 会默认约束成 string 类型,因为ts类型推导 const msg2 = ref<string>('') // 可以通过范型约束类型 const user1 = ref<User>({ name: 'tang', age: 18 }) // 范型约束 const user2 = ref({} as User) // 类型断言 // reactive const obj = reactive({}) const user3 = reactive<User>({ name: 'tang', age: 18 }) const user4 = reactive({} as User) // computed const msg3 = computed(() => msg1.value) const user5 = computed<User>(() => { return { name: 'tang', age: 18 } }) </script>
编译器宏
编译器宏(compiler macros) 有:defineProps、defineEmits、withDefaults、defineExpose 等。
编译器宏只能在 <script setup>
块中使用,不需要被导入,并且会在处理 <script setup>
块时被一同编译掉。
编译器宏必须在 <script setup>
的顶层使用,不可以在 <script setup>
的局部变量中引用
defineProps
在 <script setup>
块中是没有组件配置项的,也就是说是没有 props 选项,需要使用 defineProps 来声明 props 相关信息。defineProps 接收的对象和组件选项 props 的值一样。
我这边引用了pug 如果需要安装一下就可以直接使用 <template lang="pug">
好处可以减少代码量 层次也清楚
npm install pug
// componentA.vue 组件 <template lang="pug"> div div {{`我的名字是${name},今年${age}`}} div(v-for="item in list",:key="item.name") {{`我的名字是${item.name},今年${item.age}`}} </template> <script setup lang="ts"> interface item { name: string, age: string } const props = defineProps<{ name: string, age: string, list?: item[] // ?非必传参数 }>() </script>
// home.vue 页面 <template lang="pug"> .mainBg componentA(:name="name",:age="age", :list="list") </template> <script lang="ts" setup> import { ref } from 'vue'; import componentA from '@/components/componentA.vue'; let name = ref('') const age = ref('') const list = ref( [ { name: '张三', age: '20' }, { name: '李四', age: 18 }, { name: '王五', age: 25 }, ] ) <style lang="scss"> .mainBg { padding: 10px; } </style>
这时候是可以看到TS写法里面 name和age是没有定义默认值
页面效果
Vue3 为我们提供了 withDefaults 这个编译器宏,给 props 提供默认值
// componentA.vue 组件 <template lang="pug"> div div {{`我的名字是${name},今年${age}`}} div(v-for="item in list",:key="item.name") {{`我的名字是${item.name},今年${item.age}`}} </template> <script setup lang="ts"> interface item { name: string, age: string } interface Props { name: string, age: string, list?: item[] } const props = withDefaults(defineProps<Props>(),{ name: "小cc", age: "18", list: ()=> [] }) </script>
这边给它定义默认值之后保存 看页面发现还是没有把默认值展示出来
这是因为我们在home页面给name和age用ref赋值的时候给了 ‘ ’ 所以他把空当成了默认值就没有展示withDefaults里面给的默认值 这时候我们把name和age写成
let name = ref() const age = ref()
还有一种情况 当不给props定义默认值的时候 传参也是为空时
defineEmits
一样的,在 <script setup>
块中也是没有组件配置项 emits 的,需要使用 defineEmits 编译器宏声明 emits 相关信息。
// componentA.vue 组件 <template lang="pug"> div div {{`我的名字是${name},今年${age}`}} //- div(v-for="item in list",:key="item.name") {{`我的名字是${item.name},今年${item.age}`}} el-button(type="primary",@click="setName") 向父组件发送 name el-button(type="primary",@click="setAge") 向父组件发送 age </template> <script setup lang="ts"> interface item { name: string, age: string } interface Props { name: string, age: string, list?: item[] } const props = withDefaults(defineProps<Props>(),{ name: "小cc", age: "18", list: ()=> [] }) const emits = defineEmits<{ (e: 'changeName', value: string) : void, (e: 'changeAge', value: string) : void, }>() const setName = () => { emits('changeName', '小橙子') } const setAge = () => { emits("changeAge", "28") } </script>
// home.vue <template lang="pug"> .mainBg componentA(:name="name",:age="age", :list="list", @changeName="changeName",@changeAge="changeAge") </template> <script lang="ts" setup> import { ref } from 'vue'; import componentA from '@/components/componentA.vue'; let name = ref('') const age = ref('') const list = ref( [ { name: '张三', age: '20' }, { name: '李四', age: 18 }, { name: '王五', age: 25 }, ] ) const changeName = (val: string) => { name.value = val } const changeAge = (val: string) => { age.value = val } <style lang="scss"> .mainBg { padding: 10px; } </style>
点击后
defineExpose
在 Vue3 中,默认不会暴露任何在 <script setup>
中声明的绑定,即不能通过模板 ref 获取到组件实例声明的绑定。
Vue3 提供了 defineExpose 编译器宏,可以显式地暴露需要暴露的组件中声明的变量和方法。
这个情况的场景父组件需要直接调用子组件内部的方法或者修改子组件里的值时,需要将方法或值通过defineExpose暴露才能操作
// componentB.vue <template lang="pug"> div h1 组件B h1 {{msg}} </template> <script setup lang="ts"> import {ref} from 'vue' const msg = ref('今天天气不怎么好') const changeMsg = (v: string) => { msg.value = v } // 对外暴露的属性 需要用ref 调用子组件方法是需要把方法暴露出去 defineExpose({ msg, changeMsg, }) </script>
<template lang="pug"> .mainBg el-button(type="primary",@click="handleChangeMsg") 组件B componentB(ref="root") </template> <script lang="ts" setup> import { ref } from 'vue'; import componentB from '@/components/componentB.vue'; const root = ref<any>(null) const handleChangeMsg = () => { root.value.changeMsg("果然 下雨了") } </script> <style lang="scss"> .mainBg { padding: 10px; } </style>
如果把defineExpose注释掉
由于没有把这个方法暴露出来 导致找不到这个方法 changeMsg is not a function
总结
加载全部内容