从vue2迁移到vue3的编码实战思考
前言
习惯了
vue2全家桶
项目的开发,突然转向vue3
,如果单纯的使用选项式的模式来编写vue3的项目的话,与vue2
并没有太大的差别,无非是将data从原本的data(){}
函数中转移到了setup()
函数中而已,但在vue3
中提供了另外一种组合式编程的模式,让我们能够以函数调用的方式来编写对应的项目,下面将通过实际的项目编码方式上的对比,来进行整理两者之间的一个区别,加深对vue3
项目的理解!
项目实战
👇 基于 1⃣ 开源的项目进行学习与分析:
☝ 是对应的项目的源码目录,主要 🈶 api、assets、components、hooks、icons、locates、plugins、router、store、styles、utils、views,下面将一一分析每个文件夹中都代表着什么意义,以及以下都有哪些文件资源,都有各自对应的什么内容!
1、api
一般是前端项目中与业务相关的接口定义,可根据实际业务场景情况进行定义,一般是通过调用公共的
axios
工具类,来对外暴露业务本地化调用的接口,但是在以前我们所编写的方法中,我们一般是通过接收url+params
的方式,来发起的接口调用,而且在调用的过程中,根本不知道应该传递的什么参数,即将响应的响应体是怎样的,通过typescript
,可以在编写代码的时候,就晓得应该传递的什么参数,即将返回的结果又是怎样的?如下图所示:
🌠 这里我们通过typescript
所提供的函数参数类型定义,采用对象字面量的方式,来进行参数化提示的代码编写方式!
2、assets
资源目录文件夹,主要包括有
*.json
、相关的图片
等静态资源,用户本地代码直接访问用途;
3、components
项目中所使用到的组件,可根据实际情况将其拆分为
全局共享型
与业务共享型
,对于频繁使用的组件,虽然vue3
可以不用显示地在每个组件中去注册,但总需要import
进来使用,可使用全局注册组件的方式:app.component('组件名称', 导入的组件)
而且关于组件的定义,有 2⃣ 种方式来定义:
- SFC(Single File Component): 单文件组件(*.vue),一般是通过
template
+script
+style
来组成组件; - defineComponent: 调用一函数来注册一组件,通过传递的
options对象
来实现一函数的创建;
4、hooks
提供的公共的全局组合式函数,关于组合式函数的描述与使用场景,可见vue官网 具体的描述,通过利用这个组合式函数,将公共的逻辑部分进行一个抽离,并可以结合vue3所提供的
h
函数,来创建具有全局逻辑的响应式数据以及全局逻辑封装其中的组件,可作为替代vue2中的mixin
机制,同时也可作为函数式组件来直接使用:
5、icons
SVG图片来源定义目录,一般定义的一SVG图片组件
6、locates
多语言包的相关目录,借助于
vue-i18n
三方库的实现
👉 关于该三方库的描述,见 i18n官网 的描述
👽 关于这个vue-i18n
的简单使用如下:
1⃣ 首先创建一i18n
实例,并对外提供相关的API:
1 | // 可以将这个实例的创建,放到单独的ts文件中来进行统一维护 |
2⃣ 关于 ☝ 中使用的每个语言包的格式定义如下:
1 | export default{ |
3⃣ 在template模版中或者在js代码中使用:
1 | <template> |
😕 如果我们需要占位符的字符串展示的话,我们可以借助于在配置中定义占位符的方式来使用国际化的字符串:
1 | export default { |
这里有一个疑问 😖 ,就是如果展示的文案内容是来自于后台的响应的话,那么这里应当如何做到全局统一配置比较好呢? 👉 个人的猜想可以是将这个字符串key与后台协商好,返回的在语言包中定义的一关键词key(比如是:common.addMsg),然后在对应的语言包中预先声明好即可,也就是后台返回的预先定义在语言包中的相关key属性!!!
7、plugins
插件目录,一般用于对HTML进行额外的追加动作,一般是对html的原生层面的“加持”,比如是追加的样式,追加的meta等等,由于是动作,所以一般可定义为一函数,在
main.ts
应用程序入口来使用,在main.ts
中来直接调用!!!
8、router
与
vue2
中所使用的vue-router
无异,用于路由器的定义,只不过替换为一方法的调用来创建一路由器对象!!!
9、store
与
vue-vuex
使用类似,只不过升级为pina
,去除了mutations
,同样也是以state + getters + actions
来组成,无需显示地合并到统一的一store出口,可凭借最终的/store/index.ts
来对modules
中各个业务模块中的store进行统一的对外暴露!!
10、styles
项目所需的样式,一般包括全局样式+局部的样式+三方库的样式!!
11、typings
项目的编译器类型定义目录,主要讲当前项目/库中所涉及的对象类型进行一全局的定义,使得编译器以及ide能够识别并补货编写异常的代码,主要包括 🈶 👇 几种类型的声明:
- 业务方面的声明(*.d.ts);
- 环境变量的声明(env.d.ts);
- 全局变量的声明(global.d.ts):可通过
interface window{}
来对window全局变量进行扩展1
2
3
4
5
6interface Window {
$loadingBar?: import('naive-ui').LoadingBarProviderInst;
$dialog?: import('naive-ui').DialogProviderInst;
$message?: import('naive-ui').MessageProviderInst;
$notification?: import('naive-ui').NotificationProviderInst;
}
12、utils
项目中所需的工具文件目录
13、views
实际的页面组件!
迁移后的思考
由于采用了组合式编程的方式来编写代码,这边简单整理了 👇 几个编写要点,以便于后续更好的来编写vue3
的相关代码:
- 项目中可以说是没有了
this
关键词的使用,并且采用的commonjs
来对外暴露的api,尽量采用局部暴露的方式来暴露,👉 可以在使用的时候按需使用,而且无需整个js文件直接导入来使用; - 使用
use*
开头的组合式函数,替代了mixin
以及函数式组件,封装的逻辑更加简洁以及组件更加干练; - 组合式函数,个人角度认为就是使用
vue3
所提供的api,来产出“响应式的数据”或者“函数式组件”的目的; - 尽量使用
async
+await
,保持代码的简洁性; vue2
中用得比较爽的一个场景,就是通过this.$XXX()
方法,可直接通过实例的$XXX()方法,来调用我们的某个组件,而免去导入组件,注册组件,并通过标识来控制组件的显隐,到了vue3
,已经没有了this
关键词的使用,也就没有了实例的直接调用,但我们可以通过一个间接的方式:🌠 这里通过1
2
3
4
5
6
7
8
9
10
11
12
13
14
15function registerNaiveTools() {
window.$loadingBar = useLoadingBar()
window.$dialog = useDialog()
window.$message = useMessage()
window.$notification = useNotification()
}
const NaiveProviderContent = defineComponent({
name: 'NaiveProviderContent',
setup() {
registerNaiveTools()
},
render() {
return h('div')
},
})defineComponent()
API来创建一临时组件,并在该组件中的setup()
方法中注册相关的全局API到window对象中, 😕 这样子之后,就可以通过window.$dialog()
的方式,在任何一处代码位置来发起全局调用的动作!!!