前言
最近的一个项目从熟悉的vue2.x版本直接转向了vue3.2版本,最初的时候及其不习惯,而且文档比较少,但是在一阵子探索之后,发现用vue3 + script setup语法糖 + hook真的是特别舒适,下面讲一下开发的实践方式和一些注意点,官方文档随便看的东西我就多说啦
实践探索
组件的引入
首先是组件的引入无须注册,引入就可以直接使用。
下面的示例代码可以看到我在模板中使用组件时的是大驼峰命名,这是因为在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需要使用默认值就得用withDefaults
api,下面是官方的例子
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>()
还以一点是,官方文档说defineProps
和defineEmits
这两个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是函数,我们可以清晰的看到变量的来源,编写也很方便。
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就可以了。
注意点
defineProps
和defineEmits
这两个api都是只能在<script setup>
中使用的,可千万别在hook中定义了噢(别忘我咋知道的)
总结
使用Vue3 进行开发对于js的要求确实是有所提升,最初我也是因为vue3对ts的支持比较好才去学习,但是在使用后发现确实相比vue2在vue3中可以写出更加清晰直观的代码,这对于团队的协作开发来说是大有好处的!
我是新人oil希望我的文章对你有帮助噢!