关于vue.js:vue3带来的新特性亮点

5次阅读

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

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.js
import {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.js
import {defineComponent, h} from 'vue';

export default defineComponent({render() {
        return h('Article', {onClick() {console.log('点击文章');
            }
        }, [h('Title', { align: 'center'}, '这是文章题目')
        ]);
    }
});

// main.js
import {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'));
正文完
 0