关于vue.js:对于Vue3和Ts的心得和思考

8次阅读

共计 3691 个字符,预计需要花费 10 分钟才能阅读完成。

作者:京东物流 吴云阔

1 前言

Vue3 曾经正式公布了一段时间了,各种生态曾经成熟。最近应用 taro+vue3 重构冷链的小程序,通过了一段时间的开发和应用,有了一些本人的思考。

总的来说,Vue3 无论是在底层原理还是在理论开发过程中,都有了很大的提高。

从源码层面来说,应用 Proxy 代替 Object.defineProperty 的 API,一个是代理的对象,一个是递归监控的属性,从而在性能上有了很大的提高,并且,也解决了对象动静属性减少、数组扭转监听上的缺点;对 diff 算法进行优化,减少了动态标记,大大提高了 Vue 的执行效率;还有动态晋升、事件监听缓存等一系列晋升效率的伎俩。

从利用层面来说,次要的扭转是将 option API 改成了 composition API(组合式 API),在业务中摈弃 data、methods、生命周期函数隔离开的开发方式,使代码绝对于业务有更强的聚合性,在代码开发、代码浏览、代码保护方面对于开发者都是更加敌对。

对于 typescript 有了更好的反对,咱们晓得,对于大型的前端我的项目来说,应用 typescript 的类型校验,能使前端我的项目有更强的健壮性,这也使得 Vue3 对于大型项目的开发提供了更强的质量保证。

2 组合式 API

所谓的组合式 API,将 Vue2 中的 data、methods、生命周期、数据监听等 option,都封装成钩子函数,而后组合到 setup 函数中,其外围就在于 setup 函数。setup 函数存在的意义,就是为了应用这些新增的组合式 API,并且这些 API 只能在 setup 函数中应用。

setup 函数执行的机会是,props 初始化之后,beforeCreate 函数执行之前,所以在执行 setup 时,还没有初始化 Vue 实例,因而在 setup 中不能应用 this 对象。setup 函数的返回值会被注入到 Vue 实例中,供 Vue 组件应用,所以任何数据想在 Vue 组件的模板中应用,必须在 setup 函数中 return 进来。

组合式 API 的组合,体现在两个层面。第一层的意思是,将某一业务相干数据和解决逻辑放到一起,这是一种关注点的聚合,更不便咱们编写代码、解决业务逻辑,并且能更聚焦业务逻辑,更不便咱们看代码。第二层面的意思,当某个组件的业务逻辑足够简单,setup 中的代码足够大的状况下,咱们能够在 setup 外部,进一步提取相干的一块业务,使代码逻辑更加清晰,做到了进一步的聚合作用。

如上面代码所示,将业务代码块 A 抽出来,则代码块 A 中 return 进去的数据就能够在组件中应用:

  1. // 组件
  2. import functionA from 'A'
  3. export default defineComponent({
  4. name: 'componentName',
  5. setup() {
  6. ...functionA()
  7. }
  8. })
  9. // 代码块 A
  10. export default () => {
  11. return {
  12. a: 1
  13. }
  14. }

3 响应式 API

在 Vue3 中响应式 API,次要体现在 ref 和 reactive 两个函数。对于响应式 API,想说两个问题,第一个是为什么要减少响应式 API,第二个是响应式 API 函数 ref 和 reactive 的异同点。

3.1 为什么减少响应式 API

在 Vue2 中所有数据都写在 data 的 option 中,data 中的数据都是响应式的,这样产生的一个问题是,有些常量数据自身不须要监听,从而造成了资源的节约。所以在 Vue3 中减少了响应式 API,只须要对须要动静更新 dom 的数据进行响应式,不须要动静更新 dom 的数据不进行响应式解决,从很大水平上节俭了资源。这里我感觉须要留神的是,写代码的时候肯定要认真思考一下,哪些数据须要进行响应式绑定,哪些数据不须要进行响应式绑定,而不是一股脑的全给绑定上,这样即便代码逻辑不能很清晰易懂,并且也会影响执行效率(写惯了 Vue2 的同学须要留神)。

3.2 ref 和 reactive 的异同点

在理解了为什么要减少响应式 API 后,咱们发现 Vue3 提供了两个响应式 API 函数,ref 和 reactive。为什么会提供两个 API 呢?一个不就能够了吗?那么这两个 API 之间的区别是什么呢?

在应用层面,ref 绑定的数据,须要应用 [data].value 进行数据更改。而 reactive 绑定的数据须要应用[data].[prpoerty] 的形式进行数据更改。在应用场景方面,个别的,单个的一般数据,咱们应用 ref 来定义响应式。而简单数据,如:表单数据对象、某一模块的一组数据等,应用 reactive 来定义响应式。

那么,对象是不是必须用 reactive 来定义呢?其实不是的,都能够。官网说法是:能够依据本身习惯应用不同的 API。其实,我感觉,他们是有各自的应用场景的,ref 更强调的是数据 Value 的扭转,reactive 更强调的是数据中某一属性的扭转。

4 treeShaking 思维

当 Javascript 我的项目达到肯定体积时,将代码分成模块会更易于治理。然而,当这样做时,咱们最终可能会导入实际上未应用的代码。Tree Shaking 是一种通过打消最终文件中未应用的代码来优化体积的办法。

Vue3 应用了 tree shaking 的办法,将组件以及其所有的生命周期函数等办法进行离开,如果在组件中应用的代码将不会呈现在最终的打包文件中,如此,会缩小大大 Vue3 我的项目的打包体积。由此造成的一个后果就是,应用办法的不同。

4.1 生命周期函数的应用办法

  1. import {defineComponent, ref, onMounted} from 'vue';
  2. export default defineComponent({
  3. name: 'Gift',
  4. setup() {
  5. const counter = ref(0);
  6. onMounted(() => {
  7. // 解决业务,个别进行数据申请
  8. })
  9. return {
  10. counter
  11. }
  12. }
  13. })

4.2 Vuex 的应用办法

  1. import {useStore} from "vuex";
  2. import {defineComponent, ref, computed} from 'vue';
  3. export default defineComponent({
  4. name: 'Gift',
  5. setup() {
  6. const counter = ref(0);
  7. const store = useStore();
  8. const storeData = computed(() => store); // 配合 computed,获取 store 的值。
  9. return {
  10. counter,
  11. storeData
  12. }
  13. }
  14. })

4.3 Router 的应用办法

  1. import {useStore} from "vuex";
  2. import {useRouter} from "vue-router";
  3. import {defineComponent, ref, computed} from 'vue';
  4. export default defineComponent({
  5. name: 'Gift',
  6. setup() {
  7. const counter = ref(0);
  8. const router = useRouter();
  9. const onClick = () => {
  10. router.push({name: "AddGift"});
  11. }
  12. return {
  13. counter,
  14. onClick
  15. }
  16. }
  17. })

5 对于 Typescript 的应用

这一部分是对于 Ts 的内容,不过它与 Vue3 的开发非亲非故。Vue3 整体是应用 Ts 写的,因而,开发 Vue3 的我的项目须要应用 Ts,所以,咱们还是要理解 TS 的。

对于 Ts 的应用这里就不在细说了,在这里想说的的是,在理论业务场景中是如何组织 Ts 代码的。通过对 TS 的大量应用,我的一个领会是:Ts 的外围思维是先关注数据结构,在依据数据结构进行页面开发。而以前的前端开发模式是,先写页面,而后再关注数据。

比如说,咱们要开发一个页面,咱们可能须要先定义一些 interface。开发页面的时候咱们要关注:页面数据的 interface、接口返回数据的类型、申请参数的类型等等。

上面是开发一个列表页面的例子:

  1. // 这是列表中每一项的数据类型
  2. interface IDataItem {
  3. id: string | number;
  4. name: string;
  5. desc: string;
  6. [key: string]: any;
  7. }
  8. // 接口返回值类型,一般来说,咱们不确定接口返回的数据的类型,因而应用泛型
  9. interface IRes<T> {
  10. code: number;
  11. msg: string;
  12. data: T
  13. }
  14. // 口返回数据类型定义
  15. interface IDataInfo {
  16. list: Array<IDataItem>;
  17. pageNum: number;
  18. pageSize: number;
  19. total: number;
  20. }
  21. // 申请
  22. export const getDatalist = (
  23. params: Record<string, any>
  24. ): Promise<IRes<IDataInfo>> => {
  25. return Http.get("/api/data/list", params);
  26. };

如下面代码,当咱们的 interface 定义实现后,咱们的页面数据根本都已分明,间接写页面就会清晰很多,且出错概率会大大降低。

正文完
 0