• vue3带来的新特性及亮点


    1. 压缩包体积更小

    当前最小化并被压缩的 Vue 运行时大小约为 20kB(2.6.10 版为 22.8kB)。Vue 3.0捆绑包的大小大约会减少一半,即只有10kB!

    2. Object.defineProperty -> Proxy

    • Object.defineProperty是一个相对比较昂贵的操作,因为它直接操作对象的属性,颗粒度比较小。将它替换为es6的Proxy,在目标对象之上架了一层拦截,代理的是对象而不是对象的属性。这样可以将原本对对象属性的操作变为对整个对象的操作,颗粒度变大。
    • javascript引擎在解析的时候希望对象的结构越稳定越好,如果对象一直在变,可优化性降低,proxy不需要对原始对象做太多操作。

    3. Virtual DOM 重构

    vdom的本质是一个抽象层,用javascript描述界面渲染成什么样子。react用jsx,没办法检测出可以优化的动态代码,所以做时间分片,vue中足够快的话可以不用时间分片

    • 传统vdom的性能瓶颈:

      • 虽然 Vue 能够保证触发更新的组件最小化,但在单个组件内部依然需要遍历该组件的整个 vdom 树。
      • 传统 vdom 的性能跟模版大小正相关,跟动态节点的数量无关。在一些组件整个模版内只有少量动态节点的情况下,这些遍历都是性能的浪费。
      • JSX 和手写的 render function 是完全动态的,过度的灵活性导致运行时可以用于优化的信息不足
    • 那为什么不直接抛弃vdom呢?

      • 高级场景下手写 render function 获得更强的表达力
      • 生成的代码更简洁
      • 兼容2.x

    vue的特点是底层为Virtual DOM,上层包含有大量静态信息的模版。为了兼容手写 render function,最大化利用模版静态信息,vue3.0采用了动静结合的解决方案,将vdom的操作颗粒度变小,每次触发更新不再以组件为单位进行遍历,主要更改如下

    • 将模版基于动态节点指令切割为嵌套的区块
    • 每个区块内部的节点结构是固定的
    • 每个区块只需要以一个 Array 追踪自身包含的动态节点

    vue3.0将 vdom 更新性能由与模版整体大小相关提升为与动态内容的数量相关

    Vue 3.0 动静结合的 Dom diff

    • Vue3.0 提出动静结合的 DOM diff 思想,动静结合的 DOM diff其实是在预编译阶段进行了优化。之所以能够做到预编译优化,是因为 Vue core 可以静态分析 template,在解析模版时,整个 parse 的过程是利用正则表达式顺序解析模板,当解析到开始标签、闭合标签和文本的时候都会分别执行对应的回调函数,来达到构造 AST 树的目的。
    • 借助预编译过程,Vue 可以做到的预编译优化就很强大了。比如在预编译时标记出模版中可能变化的组件节点,再次进行渲染前 diff 时就可以跳过“永远不会变化的节点”,而只需要对比“可能会变化的动态节点”。这也就是动静结合的 DOM diff 将 diff 成本与模版大小正相关优化到与动态节点正相关的理论依据。

    4. Performance

    vue3在性能方面比vue2快了2倍。

    • 重写了虚拟DOM的实现
    • 运行时编译
    • update性能提高
    • SSR速度提高

    5. Tree-shaking support

    vue3中的核心api都支持了tree-shaking,这些api都是通过包引入的方式而不是直接在实例化时就注入,只会对使用到的功能或特性进行打包(按需打包),这意味着更多的功能和更小的体积。

    6. Composition API

    vue2中,我们一般会采用mixin来复用逻辑代码,用倒是挺好用的,不过也存在一些问题:例如代码来源不清晰、方法属性等冲突。基于此在vue3中引入了Composition API(组合API),使用纯函数分隔复用代码。和React中的hooks的概念很相似

    • 更好的逻辑复用和代码组织
    • 更好的类型推导
    <template>
        <div>X: {{ x }}div>
        <div>Y: {{ y }}div>
    template>
    
    <script>
    import { defineComponent, onMounted, onUnmounted, ref } from "vue";
    
    const useMouseMove = () => {
        const x = ref(0);
        const y = ref(0);
    
        function move(e) {
            x.value = e.clientX;
            y.value = e.clientY;
        }
    
        onMounted(() => {
            window.addEventListener("mousemove", move);
        });
    
        onUnmounted(() => {
            window.removeEventListener("mousemove", move);
        });
    
        return { x, y };
    };
    
    export default defineComponent({
        setup() {
            const { x, y } = useMouseMove();
    
            return { x, y };
        }
    });
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    7. 新增的三个组件Fragment、Teleport、Suspense

    Fragment

    在书写vue2时,由于组件必须只有一个根节点,很多时候会添加一些没有意义的节点用于包裹。Fragment组件就是用于解决这个问题的(这和React中的Fragment组件是一样的)。

    这意味着现在可以这样写组件了。

    /* App.vue */
    <template>
      <header>...</header>
      <main v-bind="$attrs">...</main>
      <footer>...</footer>
    </template>
    
    <script>
    export default {};
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    或者这样

    // app.js
    import { defineComponent, h, Fragment } from 'vue';
    
    export default defineComponent({
        render() {
            return h(Fragment, {}, [
                h('header', {}, ['...']),
                h('main', {}, ['...']),
                h('footer', {}, ['...']),
            ]);
        }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    Teleport

    Teleport其实就是React中的Portal。Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。

    一个 portal 的典型用例是当父组件有 overflow: hidden 或 z-index 样式时,但你需要子组件能够在视觉上“跳出”其容器。例如,对话框、悬浮卡以及提示框。

    /* App.vue */
    <template>
        <div>123</div>
        <Teleport to="#container">
            Teleport
        </Teleport>
    </template>
    
    <script>
    import { defineComponent } from "vue";
    
    export default defineComponent({
        setup() {}
    });
    </script>
    
    /* index.html */
    <div id="app"></div>
    <div id="container"></div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    Suspense

    同样的,这和React中的Supense是一样的。

    Suspense 让你的组件在渲染之前进行“等待”,并在等待时显示 fallback 的内容

    // App.vue
    <template>
        <Suspense>
            <template #default>
                <AsyncComponent />
            </template>
            <template #fallback>
                Loading...
            </template>
        </Suspense>
    </template>
    
    <script lang="ts">
    import { defineComponent } from "vue";
    import AsyncComponent from './AsyncComponent.vue';
    
    export default defineComponent({
        name: "App",
        
        components: {
            AsyncComponent
        }
    });
    </script>
    
    // AsyncComponent.vue
    <template>
        <div>Async Component</div>
    </template>
    
    <script lang="ts">
    import { defineComponent } from "vue";
    
    const sleep = () => {
        return new Promise(resolve => setTimeout(resolve, 1000));
    };
    
    export default defineComponent({
        async setup() {
            await sleep();
        }
    });
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    8. Better TypeScript support

    在vue2中使用过TypesScript的童鞋应该有过体会,写起来实在是有点难受。vue3则是使用ts进行了重写,开发者使用vue3时拥有更好的类型支持和更好的编写体验。

  • 相关阅读:
    Python+Selenium:Google patent数据爬取
    浅谈 Spring AOP
    数据挖掘学习——聚类分析(k-均值聚类、DBSCAN、AGNES)、python代码
    python之PyQt按钮右键菜单功能的实现代码
    python3 学习记录 字符串处理
    K8S--常用的命令
    将 CSS 过滤器与 SVG 一起使用的完整指南
    国内手机安装 Google Play 服务 (GMS/Google Mobile Services)
    C Primer Plus(6) 中文版 第1章 初识C语言 1.6 语言标准
    easylogging++ 使用笔记(ubuntu 20.04)
  • 原文地址:https://blog.csdn.net/php_martin/article/details/125872728