1. Performance

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

  • 重写了虚构DOM的实现
  • 运行时编译
  • update性能进步
  • SSR速度进步

2. Tree-shaking support

vue3中的外围api都反对了tree-shaking,这些api都是通过包引入的形式而不是间接在实例化时就注入,只会对应用到的性能或个性进行打包(按需打包),这意味着更多的性能和更小的体积。

3. Composition API

vue2中,咱们个别会采纳mixin来复用逻辑代码,用倒是挺好用的,不过也存在一些问题:例如代码起源不清晰、办法属性等抵触。基于此在vue3中引入了Composition API(组合API),应用纯函数分隔复用代码。和React中的hooks的概念很类似。

  1. 更好的逻辑复用和代码组织
  2. 更好的类型推导

一个简略的例子

<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>

4. 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>

或者这样

// app.jsimport { defineComponent, h, Fragment } from 'vue';export default defineComponent({    render() {        return h(Fragment, {}, [            h('header', {}, ['...']),            h('main', {}, ['...']),            h('footer', {}, ['...']),        ]);    }});

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>

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>

5. Better TypeScript support

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

6. Custom Renderer API

这个api定义了虚构DOM的渲染规定,这意味着应用自定义API能够达到跨平台的目标。上面是一个简略的例子。

// App.jsimport { defineComponent, h } from 'vue';export default defineComponent({    render() {        return h('Article', {            onClick() {                console.log('点击文章');            }        }, [            h('Title', { align: 'center' }, '这是文章题目')        ]);    }});// main.jsimport { createRenderer } from 'vue';import App from './App.js';import './assets/index.css';const { createApp } = createRenderer({    createElement(type) {        let nodeType = 'div';        switch(type) {            case 'Article': nodeType = 'article'; break;            case 'Title': nodeType = 'h1'; break;            case 'Content': nodeType = 'p'; break;        }        return document.createElement(nodeType);    },    insert(child, parent, anchor) {        parent.insertBefore(child, anchor || null);    },    setElementText(node, text) {        node.textContent = text;    },    patchProp(el, key, prevValue, nextValue) {        console.log(el, key, prevValue, nextValue);        switch(key) {            case 'onClick':                el.addEventListener('click', nextValue);                break;            default:                el.setAttribute(key, nextValue);        }    }});createApp(App).mount(document.querySelector('#app'));