Vue3知识点

简介

  • 2020年9月18日发布Vue3正式版本V3.0.0,命名为One Piece。
  • Vue 的组件可以按两种不同的风格书写:选项式 API 和组合式 API。

该选哪一个?

  • 两种 API 风格都能够覆盖大部分的应用场景。它们只是同一个底层系统所提供的两套不同的接口。实际上,选项式 API 是在组合式 API 的基础上实现的!关于 Vue 的基础概念和知识在它们之间都是通用的。

  • 选项式 API 以“组件实例”的概念为中心 (即上述例子中的 this),对于有面向对象语言背景的用户来说,这通常与基于类的心智模型更为一致。同时,它将响应性相关的细节抽象出来,并强制按照选项来组织代码,从而对初学者而言更为友好。

  • 组合式 API 的核心思想是直接在函数作用域内定义响应式状态变量,并将从多个函数中得到的状态组合起来处理复杂问题。这种形式更加自由,也需要你对 Vue 的响应式系统有更深的理解才能高效使用。相应的,它的灵活性也使得组织和重用逻辑的模式变得更加强大。

[图片上传失败...(image-a9c136-1660454836197)]

Vue3带来的变化

1. 性能提升1.3~2.x

  • 核心代码 + Composition API :13.5kb,最小可以到11.75kb
  • 所有的Runtime:22.5kb(Vue2是32kb)
    为什么会有这么大的性能提升呢? 这里就要说到 Compiler 的原理:
  • 静态Node不再做更新处理
  • 静态绑定的class和id不再做更新处理
  • vue在mount的过程中会编译成ast语法树, 会给动态的内容打上一个标记PatchFlag,进行更新分析(动态绑定),会区分哪些是静态内容哪些是动态内容,然后对动态内容去做更新处理
  • 事件监听器Cache缓存处理(cacheHandlers),组件创建的过程中不会去重复的多次实例化,对内存的优化是非常好的,减少创建对象的数量,从而减少内存占用提高性能
  • hoistStatich自动针对多静态节点进行优化,输出字符串
    测试地址:https://vue-next-template-explorer.netlify.app

2. Ts支持,新增:Fragment、Teleport、Suspense

  • Fragment不受根节点限制,渲染函数可接收Array。意思就是我们在temeplate中不再受根节点限制,可以任意的插入多个文本,字符串或者图片
  • Teleport--类似Portal,随用随取比如:弹窗、Actions,比如我们有可能需要在app节点之外比如body中控制一个弹窗的显示或者隐藏,可以用到它
  • Suspense 从框架层面的一个异步组件,可以支持嵌套加载的一个场景,比如树形组件我们要加载多层加的组织架构,我们希望把下面所有的组织架构都加载完成以后再显示整个组件,这个时候就需要用到它。例如:async setup()

3. 按需加载(配合vite)& 组合Api

  • 官方文:https://v3.cn.vuejs.org
  • 组合式Api: https://composition-api.vuejs.org/api.html

Vue2和Vue3的比较

1. 为什么要用 Composition API?

(1) Vue2对于复杂逻辑的组件,后期变得无法维护
下面是vue2实现加减的代码:



上面代码只是实现了对 count 的加减以及显示倍数, 就需要分别在data、methods、computed中进行操作,当我们增加一个需求,就会出现下图的情况:

[图片上传失败...(image-7fc1e4-1660454836197)]
当我们业务复杂了就会大量出现上面的情况, 随着复杂度上升,就会出现这样一张图:

[图片上传失败...(image-43cb6f-1660454836197)]
当这个组件的代码超过几百行时,这时增加或者修改某个需求, 就要在data、methods、computed以及mounted中反复的跳转
如果可以按照逻辑进行分割,将上面这张图变成下边这张图,是不是就清晰很多了呢, 这样的代码可读性和可维护性都更高:

[图片上传失败...(image-6d6040-1660454836197)]

那么vue2.x版本给出的解决方案就是Mixin, 但是使用Mixin会有缺陷:

  • 命名空间冲突
  • 不清楚暴露出来的变量的作用
  • 逻辑重用到其他 component 经常遇到问题(不易复用)
    Vue3.x就推出了 Composition API 主要就是为了解决上面的问题,将零散分布的逻辑组合在一起来维护,并且还可以将单独的功能逻辑拆分成单独的文件。

(2)scoped slot作用域插槽(配置项多、代码分裂、性能差)
(3) Vue2对Ts支持不充分
(4)Vue3使复杂组件逻辑进行分离,组件间的逻辑共享
(5)Vue3组合式API + 函数式编程

组合式 API (Composition API)

  • 通过组合式 API,我们可以使用导入的 API 函数来描述组件逻辑。在单文件组件中,组合式 API 通常会与

    上面的代码中,我们绑定到页面是通过user.name, user.age;这样写感觉很繁琐,我们能不能直接将user中的属性解构出来使用呢? 答案是不能直接对user进行结构, 这样会消除它的响应式, 这里就和上面我们说props不能使用 ES6 直接解构就呼应上了。那我们就想使用解构后的数据怎么办,解决办法就是使用toRefs
    toRefs 用于将一个 reactive 对象转化为属性全部为 ref 对象的普通对象。具体使用方式如下:

    
    
    
    

    生命周期钩子

    [图片上传失败...(image-e57ed6-1660454836197)]

    从图中我们可以看到 Vue3.0 新增了setup,这个在前面我们也详细说了, 然后是将 Vue2.x 中的beforeDestroy名称变更成beforeUnmount; destroyed 表更为 unmounted,作者说这么变更纯粹是为了更加语义化,因为一个组件是一个mountunmount的过程。其他 Vue2 中的生命周期仍然保留。
    上边 生命周期图 中并没包含全部的生命周期钩子, 还有其他的几个, 全部生命周期钩子如图所示:
    [图片上传失败...(image-e1eadd-1660454836197)]

    我们可以看到 beforeCreatecreatedsetup 替换了(但是Vue3中你仍然可以使用, 因为Vue3是向下兼容的, 也就是你实际使用的是vue2的)。其次,钩子命名都增加了 on ; Vue3.x还新增用于调试的钩子函数 onRenderTriggeredonRenderTricked

    自定义 Hooks

    开篇的时候我们使用 Vue2.x 写了一个实现加减的例子, 这里可以将其封装成一个 hook, 我们约定这些「自定义 Hook」以 use 作为前缀,和普通的函数加以区分。 useCount.ts 实现:

    import { ref, Ref, computed } from "vue";
    
    type CountResultProps = {
      count: Ref;
      multiple: Ref;
      increase: (delta?: number) => void;
      decrease: (delta?: number) => void;
    };
    
    export default function useCount(initValue = 1): CountResultProps {
      const count = ref(initValue);
    
      const increase = (delta?: number): void => {
        if (typeof delta !== "undefined") {
          count.value += delta;
        } else {
          count.value += 1;
        }
      };
      const multiple = computed(() => count.value * 2);
    
      const decrease = (delta?: number): void => {
        if (typeof delta !== "undefined") {
          count.value -= delta;
        } else {
          count.value -= 1;
        }
      };
    
      return {
        count,
        multiple,
        increase,
        decrease,
      };
    }
    

    接下来看一下在组件中使用useCount这个 hook:

    
    
    
    

    简单对比 vue2.x 与 vue3.x 响应式

    Vue3.x 将使用 Proxy 取代 Vue2.x 版本的 Object.defineProperty
    这里就简单对比一下:

    • Object.defineProperty只能劫持对象的属性, 而 Proxy 是直接代理对象

    由于Object.defineProperty只能劫持对象属性,需要遍历对象的每一个属性,如果属性值也是对象,就需要递归进行深度遍历。但是 Proxy 直接代理对象, 不需要遍历操作

    • Object.defineProperty对新增属性需要手动进行Observe

    因为Object.defineProperty劫持的是对象的属性,所以新增属性时,需要重新遍历对象, 对其新增属性再次使用Object.defineProperty进行劫持。也就是 Vue2.x 中给数组和对象新增属性时,需要使用set内部也是通过调用Object.defineProperty去处理的

    Teleport

    Teleport 就像是哆啦 A 梦中的「任意门」,任意门的作用就是可以将人瞬间传送到另一个地方。有了这个认识,我们再来看一下为什么需要用到 Teleport 的特性呢,看一个小例子:

    • 在子组件Header中使用到Dialog组件,我们实际开发中经常会在类似的情形下使用到 Dialog ,此时Dialog就被渲染到一层层子组件内部,处理嵌套组件的定位、z-index和样式都变得困难。
    • Dialog从用户感知的层面,应该是一个独立的组件,从 dom 结构应该完全剥离 Vue 顶层组件挂载的 DOM;同时还可以使用到 Vue 组件内的状态(data或者props)的值。简单来说就是,即希望继续在组件内部使用Dialog, 又希望渲染的 DOM 结构不嵌套在组件的 DOM 中。
    • 此时就需要 Teleport 上场,我们可以用包裹Dialog, 此时就建立了一个传送门,可以将Dialog渲染的内容传送到任何指定的地方。
    • 接下来就举个小例子,看看 Teleport 的使用方式:

    我们希望 Dialog 渲染的 dom 和顶层组件是兄弟节点关系, 在index.html文件中定义一个供挂载的元素:

    
      

    定义一个Dialog组件Dialog.vue, 留意 to 属性, 与上面的id选择器一致:

    
    

    最后在一个子组件Header.vue中使用Dialog组件

    ...

    [图片上传失败...(image-8ff413-1660454836197)]

    可以看到,我们使用 teleport 组件,通过 to 属性,指定该组件渲染的位置与

    同级,也就是在 body 下,但是 Dialog 的状态 dialogVisible 又是完全由内部 Vue 组件控制.

    Suspense

    Suspense是 Vue3.x 中新增的特性, 那它有什么用呢?我们通过 Vue2.x 中的一些场景来认识它的作用。 Vue2.x 中应该经常遇到这样的场景:

    
    

    在前后端交互获取数据时, 是一个异步过程,一般我们都会提供一个加载中的动画,当数据返回时配合v-if来控制数据显示。
    如果你使用过vue-async-manager这个插件来完成上面的需求, 你对Suspense可能不会陌生,Vue3.x 感觉就是参考了vue-async-manager.
    Vue3.x 新出的内置组件Suspense, 它提供两个template slot, 刚开始会渲染一个 fallback 状态下的内容, 直到到达某个条件后才会渲染 default 状态的正式内容, 通过使用Suspense组件进行展示异步渲染就更加的简单。注意如果使用 Suspense, 要返回一个 promise
    使用:

     
            
            
      
    

    asyncComponent.vue:

    
    
    
    

    从上面代码来看,Suspense 只是一个带插槽的组件,只是它的插槽指定了defaultfallback 两种状态。

    片段(Fragment)

    在 Vue2.x 中, template中只允许有一个根节点:

    
    

    但是在 Vue3.x 中,你可以直接写多个根节点

    
    

你可能感兴趣的:(Vue3知识点)