# Vue2 vs Vue3

# Vue3优点

# diff算法优化

vue2是对所有虚拟dom的全量对比,vue3新增了静态标记(patch tag),在每次对比时,忽略静态dom,只对比动态dom

例如:下面的模板包含一个div,div内包含三个段落,其中前两个段落是静态固定不变的,而第三个段落的内容绑定的msg属性,当msg改变的时候,Vue会生成新的虚拟DOM然后和旧的进行对比。

<div>
 <p>云驻共创</p>
 <p>如何评价 vue3</p>
 <p>{{msg}}</p>
</div>

当视图更新时,只对动态节点部分进行diff运算,减少了资源的损耗。Patchflag是个枚举,取值为1代表这个元素的文本是动态绑定的,取值为2代表元素的class是动态绑定的。

# 静态提升

在vue2中,元素是否参与更新,每次都会被重新创建渲染

在vue3中,对静态元素进行了提升,每次不会进行重新渲染,大大的减少了浏览器渲染负担。

提升前

export function render(...) {
    return (
        _openBlock(),
        _createBlock('div', null, [
            _createVNode('div', null, '共创1'),
            _createVNode('div', null, '共创2'),
            _createVNode(
                'div',
                null,
                _toDisplayString(_ctx.name),
                1 /* TEXT */
            ),
        ])
    )
}

提升后

const _hoisted_1 = /*#__PURE__*/ _createVNode(
    'div',
    null,
    '共创1',
    -1 /* HOISTED */
)
const _hoisted_2 = /*#__PURE__*/ _createVNode(
    'div',
    null,
    '共创2',
    -1 /* HOISTED */
)

export function render(...) {
    return (
        _openBlock(),
        _createBlock('div', null, [
            _hoisted_1,
            _hoisted_2,
            _createVNode(
                'div',
                null, 
                _toDisplayString(_ctx.name),
                1 /* TEXT */
            ),
        ])
    )
}

# 双向数据绑定优化

在vue2中,数据的绑定是通过object.defineProperty()的getter,setter来实现的,但该中方式无法处理数组的改变。

在vue3中,改用es6 proxy来进行实现,较之前相比,proxy提供了更丰富的方法 ,除get,set外,还有has,isOwnProperty等供我们使用,再也不需要使用$set来处理数据的更新。

# Compostion Api

较vue2,template,script,style来说,它的出现是将js逻辑部分集中起来,更好的维护封装组件。 增加了可读性逻辑性

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>hello vue3</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@3.0.0-beta.14/dist/vue.global.js"></script>
    <!-- <script src="../dist/vue.global.js"></script> -->
</head>

<body>
    hello vue3
    <div id='app'>
        <h2>{{state.count}}--{{count2}}---{{state.doubleCount}}</h2>
        <div @click="add">count: {{ state.count }}</div>
        <div @click="add2">count: {{ count2 }}</div>
    </div>
    <script>
        const { createApp, reactive, ref, computed, watch } = Vue
        // reactive: 接收一个普通对象然后返回该普通对象的响应式代理。等同于 2.x 的 Vue.observable()
        // ref: 接受一个参数值并返回一个响应式且可改变的 ref 对象。ref 对象拥有一个指向内部值的单一属性 .value。
        // computed: 传入一个 getter 函数,返回一个默认不可手动修改的 ref 对象。
        // watch API 完全等效于 2.x this.$watch (以及 watch 中相应的选项)。watch 需要侦听特定的数据源,并在回调函数中执行副作用。默认情况是懒执行的,也就是说仅在侦听的源变更时才执行回调。
        const App = {
            // setup 函数是一个新的组件选项。作为在组件内使用 Composition API 的入口点。
            // 调用时刻是初始化属性props确定后,beforeCreate之前
            setup() {
                const count2 = ref(1)
                // 响应化:接收一个对象,返回一个响应式的代理对象
                const state = reactive({
                    count: 1,
                    // computed()返回一个不可变的响应式引用对象 
                    // 它封装了getter的返回值 
                    doubleCount: computed(() => state.count * 2)
                })
                watch(
                    () => state.count,
                    (count, prevCount) => {
                        /* ... */
                        console.log('state.count', count, prevCount);

                    }
                )
                watch(count2, (count, prevCount) => {
                    /* ... */
                    console.log('count2', count, prevCount);
                })
                function add() {
                    state.count++
                }
                function add2() {
                    count2.value++
                }
                // 返回对象将和渲染函数上下文合并
                return { count2, state, add, add2 }
            }
        }
        createApp(App).mount('#app')
    </script>
</body>

</html>