尤雨溪今年4月份的时候,在微博了发布了一条微博:
之前虽然有零零散散的了解了下相关的东西,但是体验不是很深,俗话说了解一个东西最好的方式就是用它做个东西。后面忙着工作和家庭的事情,一直没有时间入坑,这不刚有些时间,就入坑了。
开发的项目是一个小而美的博客:
技术栈:
Vue3 + TypeScript + Vite + Vue Route4
编辑器:
VSCode + Volar
我先分步分享一下自己的体会和心得,最后再说下自己整体的感受。
1. Vue3
单从Vue3来讲,这次使用给我最大的感受就是script setup语法。
Vue2是用data来定义要绑定的数据;Vue3刚出的时候使用setup函数语法,是在函数内声明相关的变量,最后return;Vue3.2引入script setup语法糖。
例如:
<script setup lang="ts">
// articleList可以直接用在模板里。
let articleList = reactive<ArticleList>([]);
// paginator可以直接用在莫办理
// 分页计算属性
const paginator = computed(() => {
return new Paginator(currentPage.value, total.value, pageSize.value);
});
</script>
这个我感觉特别好用,主要感受有:
1. 基于script标签顶层,嵌套层次少了,结构更加简单。
2. 移除了this,写起来更自然,直接定义的变量和方法在模板中都能直接访问到,写起来就感觉和直接写原生js差不多。
3. 一开始不想把组件提取的很细,可以把各个独立模块的变量、方法、监听、计算属性放在一起,后面提取起来方便很多。
1.1 嵌套层次少了
vue2是写在一个大的对象里,里面data、methods、computed等,然后里面再嵌套写很多代码。vue3使用setup函数,代码层次也很深。
现在写在基于script标签顶层,嵌套层次少了,结构更加简单。
1.2 移除this对象
移除this对象,很多代码不用写this点啥啥的,确实很自然。
不过也因为script setup移除了this对象,一些相关的方法也跟着改动了,比如:路由、组件通信写法都有点不太一样。
路由需要使用useRoute获取路由对象,后面获取参数和vue2一样:
import { useRoute } from 'vue-router';
const route = useRoute();
// route.query.cid 获取分类id
调用子组件方法方面,因为没有export default了,子组件需要通过defineExpose方法暴露出相关的变量和方法:
const addComment = (comment: Comment) => {
commentList.unshift(comment);
}
// 对外暴露 增加评论 的方法
defineExpose({
addComment
})
1.3 组件封装更方便
这点也是我感受比较深的地方,开发项目的时候一开始有时不可能封装的很细。
比如一开始我把发表评论的表单和评论列表放在一个组件。
js我是这么写的:
<script setup lang="ts">
// 前面统一写发表评论相关的代码
const comment = reactive(commentModel.initComment(props.articleId));
const tips = reactive({
type: "",
msg: "",
});
// ...还有很多相关的发表评论代码。
// 后面统一写评论列表相关的代码
const commentList = reactive<CommentList>([commentModel.initComment()]);
onMounted(() => {
// ...获取评论
});
// ...还有很多评论列表相关的代码。
</script>
后面要提取评论列表的时候,我把评论列表的模板和代码整块提取就可以了,非常方便。
如果是vue2,我就需要在methods找下评论列表相关的代码、在computed中找下相关的、在onMouted中找到相关的代码,想想都很麻烦。
1.4 script setup整体感受
script setup语法从整体来看还是比较方便的,带来的好处比坏处多。
1.5 template模板终于不需要根元素
template不用唯一根元素了,这个改动很实用。想想vue2用组件的时候,为了符合唯一根元素的语法,有时需要外围加一个无用根标签,真的很无奈。
2. TypeScript
这次使用 TypeScript,和之前使用 JavaScript 相比,我的最大体会有如下3点:
1. 强类型。
2. 类定义。
3. 泛型。
2.1 强类型
typescript最大的特性就是强类型,和之前用js不一样,每次声明一个变量,都要指明类型。
2.1.1 缺点
这个我感觉有点麻烦,对象类型需要挨个定义好每个属性,尤其是针对服务端接口返回的数据,需要一个一个定义好其中每个属性的类型。
例如下图是定义文章列表接口返回的数据类型:
这里文章的字段还比较少,如果碰到复杂点的项目,好几十个字段的,手酸。
如果是开发比较小的项目,就是杀鸡用牛头了。原来用js直接获取服务端的数据,然后页面输出下就很快了。
2.1.2 优点
但是好处也特别明显:
1. 对象变量的属性在编辑器里可以直接点出来,非常方便。
2. 查看对象有哪些字段和方法也非常方便,不用console.log了,手册也翻得少了。
3. 维护更加方便。
有时用axios发起请求的参数忘记了,扫一下axios的请求参数对象就很清晰了:
关于维护方便,这个确实没得说,强类型嘛,给一个对象增加或者减少属性、修改变量类型、修改方法参数、返回类型等,没有匹配的地方编辑器直接报了错,不容易产生修改盲区。
总体来看,我觉得好处还是大于坏处的,尤其是开发大型项目,真的是很实用。
2.2 类定义
JavaScript中ES6虽然也支持类定义,但是写起来还是感觉特别扭,和常见的面向对象编程语言还是有差别,比如像公有私有属性、抽象类等。
TypeScript中类的使用起来非常自然,因为之前有写过Java,所以上手起来很快。
这次写的项目,我基本都是定义一个一个的类来封装对应的功能,比如:文章类、评论类、分类等等,我只想表达很面向对象。
2.3 泛型
泛型我觉得是这次入坑其中最难理解的东西。JavaScript是弱类型语言,没有泛型也不需要泛型,TypeScript和Vue3中大量使用了泛型。
比如语言中的数组:
// TypeScript中数组定义
interface Array<T> {
...还有很多代码
}
Promise对象定义:
interface Promise<T> {
then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;
...还有很多代码
}
Vue3的常用的ref、reactive部分定义:
export declare function ref<T extends object>(value: T): [T] extends [Ref] ? T : Ref<UnwrapRef<T>>;
export declare function reactive<T extends object>(target: T): UnwrapNestedRefs<T>;
都大量使用到了泛型。使用方面泛型用的不多,但是相信如果能把泛型撸明白了,写一些应用功能就很简单了。
3. vite
vite这次给我印象最深的就是它的模块热更新(HMR) ,确实是很快,基本上改完文件一保存,就更新好了。
不过也碰到一些问题:就是提取新组件出来的时候,vite没有加载新的组件,导致页面上显示出来。重新启动一下服务就可以了。
4. vscode+volar
这次使用踩了一个坑,因为之前是用vetur,安装volar之后,没有卸载掉vetur插件,结果页面一致报如下的一些错误:
一开始没有在意,以为是volar的一些bug,毕竟新东西一开始估计都有些问题。
后来才注意到这个Vetur插件给的提示,果断卸载掉Vetur,然后就正常了。不过卸载Vetur导致在Vue模板中直接输出vue就不会自动补全代码了。
其他暂时没有什么坑,整体来看还是很爽的。截止到写作本文的时候,volar只有有19万+的下载量,看来使用的人还不多,毕竟vetur有900万+。
小总结
总来的看,不管是编辑器、还是Vue3框架、Typescript语言、vite工具,使用起来还是挺顺手的。
因为东西比较新,有时碰到一些坑,网上找文章不太容易找到。相关官网都快被我翻烂了,不过幸好的是都有解决办法。
这次就先分享到这里了,下次有进展再分享出来,谢谢观看。
参考文章
vue官网:v3.cn.vuejs.org/
typescript: docs.microsoft.com/zh-cn/learn…
vite官网:vitejs.cn/
vue-route:next.router.vuejs.org/zh/