阅读 2583

Vue3 <script setup>语法糖+ts+Hook实践探索

前言

最近的一个项目从熟悉的vue2.x版本直接转向了vue3.2版本,最初的时候及其不习惯,而且文档比较少,但是在一阵子探索之后,发现用vue3 + script setup语法糖 + hook真的是特别舒适,下面讲一下开发的实践方式和一些注意点,官方文档随便看的东西我就多说啦

Vue script setup官方文档

实践探索

组件的引入

首先是组件的引入无须注册,引入就可以直接使用

下面的示例代码可以看到我在模板中使用组件时的是大驼峰命名,这是因为在vscode中对一些代码提示工具比较友好,也是vue的风格指南中所倡导的,最初我在开发时写的是横杠命名但是遇到了eslint的报错,提示使用了未引入的组件,应该是新特性代码检查工具还不太兼容吧

<template>     <LeftBar></LeftBar> </template> <script setup lang="ts"> import LeftBar from "./components/LeftBar/index.vue" </script> 复制代码

模板中变量引用

在最初vue3版本推出的时候去使用感觉一个一个变量去return简直麻烦到爆炸,但现在 script setup中定义的变量都会自动return出去,这一点对于开发体验来说简直爽到飞起,但是这一点也对开发者的能力提高了要求,不能胡乱定义一些变量了。

<template>     <div>{{a}}</div> </template> <script setup lang="ts"> const a:string = "我是a" </script> 复制代码

组件参数、方法的定义

现在的组件定义参数需要使用 defineProps api,定义方法使用defineEmits api,使用在defineProps 中定义的参数在模板中使用的时候不需要写props,具体使用方式如下

<template>     <div>{{a}}</div> </template> <script setup> import {  defineEmits,defineProps,onMounted } from "vue" const props = defineProps({     a:{         type:String,         default:'我是a'     } }) const emit = defineEmits(['funcA']) onMounted(   ()=>console.log(props.a)   emit('funcA') ) </script> 复制代码

在ts中我们还可以直接通过类型声明定义props或emits,直接在defineProps方法泛型传入类型就声明,defineEmits也是同理,中下面用项目中的一个例子

<script setup>     const props = defineProps<{       handle: "add" | "update"       parentId: number | null       flag: boolean       isDir: boolean     }>() </script> 复制代码

如果props需要使用默认值就得用withDefaultsapi,下面是官方的例子

interface Props {   msg?: string   labels?: string[] } const props = withDefaults(defineProps<Props>(), {   msg: 'hello',   labels: () => ['one', 'two'] }) 复制代码

注意点

在上面的代码中我们可以看到,如果使用TS的话可以直接传入类型进行参数声明,我们可能会去将参数的类型给抽离出来以重复利用,但是如果在 defineProps 使用外部引入的interface或者type会报错的,它提醒我们要使用字面量类型,当前在github上vue的issue已经有这个问题了,目前还没解决,期待早日完善,目前的方法就是类型只能写在当前的vue文件中

//下面的代码会报错,type argument passed to defineProps() must be a literal type import type { PropsType } from "./type" const props = defineProps<PropsType>() 复制代码

还以一点是,官方文档说definePropsdefineEmits这两个api现在不需要引入就可以直接在<script setup>中使用了,但是在实际开发中代码提示还是会报方法未定义的问题,这个也是只能先引入着,等后期兼容好了再修改

使用获取ref元素或子组件注册引用信息

在vue3中,想要实现vue2中$ref获取子组件数据的方式如下代码

<template>     <ComponentA ref='aRef'>{{a}}</ComponentA> </template> <script setup> import ComponentA from "./ComponentA/index.vue" import {ref,onMounted} from "vue" const a = ref() onMounted(()=>{     console.log(a) }) </script> 复制代码

在实际使用中你会发现你拿不到组件的数据,因为在子组件中script setup 默认不暴露任何数据,如果需要用到子组件的值你需要使用 defineExpose api

<script setup lang="ts"> //AComponents子组件 import {defineExpose} from "vue" const formData = {a:1,b:2} defineExpose({   formData, }) </script> 复制代码

在ts中使用的时候,你可能需要获取子组件的类型,你可以使用InstanceType<typeof 组件名称> 来获取组件的类型,以传入ref泛型

<a-component  ref="aRef"> </a-component> <script setup lang="ts"> import AComponents from "./xxx" const aRef = ref<InstanceType<typeof AComponents>>() </script> 复制代码

Hook介绍

在最初写vue3.x版本的时候,也许有很多人和我一样在组件中把全部业务代码一把梭,然后写的又臭又乱,还贼多引入,还想着vue2不比这舒服多了。但是在了解了Hook之后才发现,vue3相比vue2最爽的地方就是这了!

前言万语不如放实例,先看一下我在项目中的使用方式,下面是我的一个单页面组件目录和入口文件代码,可以看到业务代码非常的少,主要就是归功于Hook,Hook类似于vue2的mixin,都是用于业务代码的抽离,但是mixin的副作用就是引用的多了变量的来源就不清晰了,而且还会有变量名重复的问题。而hook是函数,我们可以清晰的看到变量的来源,编写也很方便。

image.png

Hook就是例如下面的代码,这里是一个叫useState的hook,用于创建页面所需要的变量,它写在单独的一个文件中,并放在与组件入口文件同级的hook文件夹里

import { useStore } from "@/store" import { ref, watch, computed } from "vue-demi" function useState() {   const store = useStore()   const editorRef = ref()   const content = computed({     get() {       return store.state.markdown.content     },     set(val: string) {       store.commit("markdown/changeContent", val)     },   })   return { editorRef, content } } export default useState 复制代码

入口文件 index.vue,在入口文件中我引入了很多个hook,它们依赖我使用useState这个hook创建的变量

<!-- index.vue --> <template>   <div class="flex w-full h-full">     <v-md-editor       v-model="content"       :mode="store.state.editor.editMode"       :includeLevel="[1, 2, 3, 4]"       height="calc(100vh - 60px)"       :disabled-menus="[]"       @upload-image="uploadImg"       ref="editorRef"       id="editor"     ></v-md-editor>   </div> </template> <script setup lang="ts"> import { useStore } from "@/store/index" import useState from "./hooks/useState" import useSaveDoc from "./hooks/useSaveDoc" import useUpload from "./hooks/useUpload" const store = useStore() const { editorRef, content } = useState() useSaveDoc() const { uploadImg } = useUpload(editorRef) </script> 复制代码

那么如果组件中要增加更多的方法要怎么做呢,只需要写更多hook就OK啦,使用hook可以将我们的逻辑上相关联的数据和方法抽离出来单独维护,需要增加功能的时候只需要在hook中修改代码或者添加hook就可以了。

注意点

definePropsdefineEmits这两个api都是只能在<script setup> 中使用的,可千万别在hook中定义了噢(别忘我咋知道的)

总结

使用Vue3 进行开发对于js的要求确实是有所提升,最初我也是因为vue3对ts的支持比较好才去学习,但是在使用后发现确实相比vue2在vue3中可以写出更加清晰直观的代码,这对于团队的协作开发来说是大有好处的!

我是新人oil希望我的文章对你有帮助噢!


作者:oil欧哟
链接:https://juejin.cn/post/7015587671019880478

文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐