正文如下
目前
setup sugar
已经进行了定稿,而
vue3 + setup sugar + TS
的写法看起来很香,所以我大胆尝试了下,期间发现一些小问题,分享下我的经验,如有问题,欢迎斧正。
前期准备
-
使用
vue-cli
创建一个 vue3 + TS 的项目
-
vscode
禁用
Vetur
,下载
Volar
什么是 setup sugar
在单文件组件(SFC)中引入一个新的
<script>
类型 setup。它向模板公开了所有的顶层绑定。
未使用
setup sugar
<template>
<Foo :count="count" @click="inc" />
</template>
<script>
import Foo from './Foo.vue'
import { ref } from 'vue'
export default {
setup() {
const count = ref(1)
const inc = () => { count.value++ }
return {
count,
</script>
使用了
setup sugar
<template>
<Foo :count="count" @click="inc" />
</template>
<script setup>
// 导入的组件也可直接可用于模板(指令同理,同样会被自动注册)
import Foo from './Foo.vue'
import { ref } from 'vue'
// 书写组合式 api 就像在正常的 setup 中一般,但是不需要进行手动地进行 return
const count = ref(0)
const inc = () => { count.value++ }
</script>
你可以在
github.com/vuejs/rfcs/…
[4]
以及
github.com/vuejs/rfcs/…
[5]
看到有关
setup sugar
和
ref sugar
有关更多的讨论。个人不喜欢
ref sugar
,个人认为
.value
的写法比较好理解,结合
Volar
的帮助提示,已经没有多少的心智负担。
vue3 组合式写法是否会产生更多问题
目前网络上很多人反应使用组合式 api 反而显得代码更加乱了。那么从
vue2
的
options api
到
vue3
的
composition api
写法,究竟会获得什么好处呢?
-
逻辑耦合度更高:在
options api
中如何一个功能我们需要用到
data
+
method
+
watch
...等更多 api,一段代码无法合并在一起,我们在阅读一段逻辑需要进行反复上下移动进行观看。而
composition api
就解决了这个问题。
-
功能抽离:得益于函数式编程,一个功能逻辑我们可以封装到一个 hook 中,我们直接导入hook,运行方法,即可。
缺点:从
options api
切换到
composition api
最大的问题无异于最大的问题就是没有强制的代码分区,如果书写的人没有很好的代码习惯,那么后续的人将会看的十分难受。目前我是这么解决的:
-
自我代码分区并且尽量抽离方法(写好注释),分区如下:
-
-
相关引入
-
-
响应式数据、props、emit 定义
-
-
生命周期以及 watch 书写
-
-
方法定义
-
-
方法、属性暴露
-
组件抽离:将页面拆成两个文件夹,一个为
views
,一个为
components
。views 和 components 文件夹下有各自的文件。views 文件夹中为页面入口,掌管数据,而 components 则为页面中一些组件抽离。如果是公共组件,再抽离到 components 文件夹下其他位置。
-
hook 抽离:尽可能将逻辑抽离,并不一定要进行复用。
setup 衍生出的新的 api
define 编译器宏(compiler macros )
以
define
开头的 api 都为编译器宏(compiler macros )api,只能在
<script setup>
中使用。它们不需要被导入,并且在处理
<script setup>
时被编译掉。
注意:
define
类 api 必须直接在 setup 中外层进行使用,你无法将其放在方法中。
注意:
define
类 api 虽然不用导入,但是这一点和 TS 兼容不太好,如果不引入会提示
undefined
,如果进行了引入,会有
warning
提示。
注意:
define
类 api虽然目前都可以使用 TS 类型声明,但是你无法导入一个 interface 或者 type 进行类型声明(直接在文件中声明是可以的),因为这样会报错。猜测这一点是和
define
编译器宏有关,可能后期会被修复。
-
defineProps
:这个 api 很好理解,就是定义 props 相关信息。
基础用法:
defineProps({
name: {
type: String,
required: false,
default: 'Petter',
userInfo: Object,
tags: Array,
})
使用 TS 类型声明:
const props = defineProps<{
foo: string
bar?: number
}>()
注:两个写法不可以一起进行使用,也就是一个
defineProps
不能既使用 TS 类型声明,也使用基础用法。
-
withDefaults
:这个方法并非属于编译器宏(compiler macros )api,但是这个 api 由
defineProps
衍生而出。在 TS 类型声明下无法进行设置默认值,这个 api 主要是为了解决这个场景。
withDefaults(defineProps<{
size?: number
labels?: string[]
}>(), {
size: 3,
labels: () => ['default label']
})
-
defineEmits
:这个 api 也很好理解,就是定义 emits 相关信息。不过使用和以前有点不一样。
基础使用:
// 声明
const emits = defineEmits(['change', 'delete'])
// 使用
emits('change')
TS声明类型:
// 声明
const emit = defineEmits<{ (e: 'change', id: number): void (e: 'update', value: string): void }>()
// 使用
emits('change',1)
-
defineExpose
:在传统的 Vue 组件中,所有暴露在模板上的东西都隐含地暴露在组件实例上,也就是父组件可以通过ref 或者子链可以全量获取到子组件所有的属性、方法。大多数时候,这种全量暴露是过度的,而 vue3 setup 中必须进行手动暴露。
const a = 1
const b = ref(2)
defineExpose({ a, b, })
注意:目前发现
defineExpose
暴露出去的属性以及方法都是
unknown
类型,如果有修正类型的方法,欢迎评论区补充。
hook api
注:useContext API 被弃用,取而代之的是更加细分的 api。
-
useAttrs
:见名知意,这是用来获取 attrs 数据,但是这和 vue2 不同,里面包含了
class
、
属性
、
方法
。
-
在 vue2 中封装组件透传属性、方法你可能这么写:
<component v-bind='$attrs',v-on='$listeners'></component>
vue3 里删除了 $listeners,新写法:
<template>
<component v-bind='attrs'></component>
</template>
<srcipt setup lang='ts'>
const attrs = useAttrs();
<script>
-
useCSSModule
:CSS Modules 是一种 CSS 的模块化和组合系统。vue-loader 集成 CSS Modules,可以作为模拟 scoped CSS。允许在单个文件组件的
setup
中访问CSS模块。此 api 本人用的比较少,不过多做介绍。
-
useSlots
: 顾名思义,获取插槽数据。
-
useCssVars
: 此 api 暂时资料比较少。介绍
v-bind in styles
时提到过。
-
useTransitionState
: 此 api 暂时资料比较少。
-
useSSRContext
: 此 api 暂时资料比较少。
公司想做一个内部的企微H5应用,给代理人或者销售们用,主要用途有两点:
在后台维护一整套素材(图片、文章、文本、视频、语言、小程序等),可以在H5中选择素材并群发给客户、客户群、朋友圈