vue 3.0

// 安装
npm install -g @vue/cli
$ vue -V
@vue/cli 4.3.1
// 创建项目
vue create vue-next-test
// 下载插件
vue add vue-next
// 运行
npm run serve

| 亮点

  • Performance:性能更比Vue 2.0强(编译模板的优化/重写了虚拟Dom的实现/更高效的组件初始化/update性能提高1.3~2倍/SSR速度提高了2~3倍)
  • Tree shaking support:可以将无用模块“剪辑”,仅打包需要的。「按需引入」
  • Composition API:组合API
  • Fragment, Teleport, Suspense:“碎片”,Teleport即Protal传送门,“悬念”
  • Better TypeScript support:更优秀的Ts支持
  • Custom Renderer API:暴露了自定义渲染API

编译模板的优化

模板渲染生成 PatchFlag(>0的number) 标记,仅带有 PatchFlag 标记的节点会被真正追踪,且无论层级嵌套多深,它的动态节点都直接与 Block 根节点绑定,无需再去遍历静态节点。模板编译网站

// PatchFlag 枚举定义,源码:`packages/shared/src/patchFlags.ts`
export const PatchFlagNames = {
  [PatchFlags.TEXT]: `TEXT`,
  [PatchFlags.CLASS]: `CLASS`,
  [PatchFlags.STYLE]: `STYLE`,
  [PatchFlags.PROPS]: `PROPS`,
  [PatchFlags.FULL_PROPS]: `FULL_PROPS`,
  [PatchFlags.HYDRATE_EVENTS]: `HYDRATE_EVENTS`,
  [PatchFlags.STABLE_FRAGMENT]: `STABLE_FRAGMENT`,
  [PatchFlags.KEYED_FRAGMENT]: `KEYED_FRAGMENT`,
  [PatchFlags.UNKEYED_FRAGMENT]: `UNKEYED_FRAGMENT`,
  [PatchFlags.DYNAMIC_SLOTS]: `DYNAMIC_SLOTS`,
  [PatchFlags.NEED_PATCH]: `NEED_PATCH`,
  [PatchFlags.HOISTED]: `HOISTED`,
  [PatchFlags.BAIL]: `BAIL`
}

| Composition API

混入(mixin) 将不再作为推荐使用, Composition API可以实现更灵活且无副作用的复用代码。文档参考

Composition API 包含了六个主要API

<template>
    <div class='Test'>
        <h1>test count: 8</h1>
        <div>count * 2 = </div>
        <div>state from vuex </div>
        <button @click="add">add</button>
        <button @click="update">update a</button>
        <HelloWorld msg="Hello word"></HelloWorld>
    </div>
</template>

<script>
    import { ref, toRefs, computed, watch, getCurrentInstance, reactive, watchEffect, watch } from 'vue'
    export default {
        name: 'Test',
        props: {
            msg: String
        },
        /**
         * 1.调用时间:在 props 初始化后,beforeCreate 执行之前
         * 2.ref 接受一个参数值并返回一个响应式且可改变的 ref 对象。ref 对象拥有一个指向内部值的单一属性 .value。在 setup 中使用时需要`.value`,在模板中使用不需要`.value`,例如:count
         * 3.setup 可以返回一个对象,也可以返回一个 render function
         * 4.setup 中 this 不能获取 vue 实例
         * 5.computed:传入一个 getter 函数,返回一个默认不可手动修改的 ref 对象
         */
        setup(props, context) {

            /**
            * 1. 函数中接收 props 作为第一个参数,使用 watchEffect or watch 可以监听 props 的改变,注意:若参数使用解构赋值形式(setup({msg}){})则监* 听不到数据改变
            * 2. 接收对象 context 作为第二个参数,可使用解构赋值形式(setup(props,{attrs,slots,emit}){})
            */
            watchEffect(() => { console.log(`name is: ` + props.msg)}) // 响应,msg 改变即执行
            watch(() => { console.log(`name2 is: ` + props.msg)}) // 响应,msg 改变即执行
            console.log(`name3 is: ` + props.msg) // 非响应,只执行一次

            /** 状态: */
            const count = ref(0)

            /** 事件绑定 */
            const add = () => { count.value++ }

            /** 计算属性 */
            const doubleCount = computed(() => count.value * 2)
            console.log("setup -> doubleCount", doubleCount)


            /** 获取当前组件的实例 ctx */
            const { ctx } = getCurrentInstance()
            console.log("组件实例 -> ", ctx)

            /** 获取路由 */
            console.log("路由 -> ", ctx.$router.currentRoute.value)

            /** 通过计算属性来引用 Vuex 中的状态 */
            const a = computed(() => { return ctx.$store.state.test.a })

            /** 更新 Vuex 状态 */
            const update = () => {  ctx.$store.commit('setTestA', count)  }

             /** reactive 设置对象可响应 */
            const object = reactive({ foo: 'bar' }) // 数据发生改变触发相应更新
            // const object = { foo: 'bar' }  // 数据发生改变,视图不会相应更新
            const updateobject = () => { object.foo = "ss" }

            /** ref */
            const state = reactive({ count })
            console.log("setup -> state", state)
            const arr = reactive([ref(0)])
            // need .value here
            console.log("setup -> arr", arr[0].value)
            const map = reactive(new Map([ ['foo', ref(0)] ]))
            // need .value here
            console.log("setup -> map", map.get('foo').value)

            /** computed 计算属性 */
            // const plusOne = computed(() => count.value + 1)
            // plusOne.value++ // error
            /** with get and set functions to create a writable ref object */
            const plusOne = computed({
                get: () => count.value + 1,
                set: val => {  count.value = val - 1 }
            })
            plusOne.value = 5
            console.log("setup -> plusOne", plusOne.value)

            /** readonly 只读 */
            const original = reactive({ count: 0 })
            const copy = readonly(original)
            watchEffect(() => { console.log("setup -> copy.count", copy.count) })
            original.count++ // mutating original will trigger watchers relying on the copy
            copy.count++ // mutating the copy will fail and result in a warning

            /**
             * watchEffect
             * 1. 组件卸载自动停止
             * 2. 调用返回值 stop,停止监听
             */
            const stop = watchEffect(() => console.log("watchEffect ->", count.value))
            stop()

            /** 异步请求数据 */
            // const data = ref(null)
            // watchEffect(async () => { data.value = await fetchData(props.id) })

            /**
             * watch
             * 1参-监听的值
             * 2参-触发监听,执行的回调函数
             */
            watch(() => count.value, val => { console.log(`count is ${val}`) })
            const state = reactive({ count: 0 })
            watch( () => state.count, (count, prevCount) => { })  // watching a getter
            watch(count, (count, prevCount) => { })  // directly watching a ref
            watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => { })  // Watching Multiple Sources

            /** 返回对象 */
            return { count, doubleCount,  add, a,  update }

            /** 返回 render 函数 */
            // return () => h('div', [count.value, object.foo])
        },
    }
</script>

| Lifecycle Hooks

Mapping between 2.x Lifecycle Options and Composition API:

  • beforeCreate -> use setup()
  • created -> use setup()
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeDestroy -> onBeforeUnmount
  • destroyed -> onUnmounted
  • errorCaptured -> onErrorCaptured

New hooks(debug hooks):

  • onRenderTracked
  • onRenderTriggered

参考链接