夏明

There is only one thing in the world worse than being talked about, and that is not being talked about.

vue3 新特性

2021-05-12


为什么要推出vue3

Vue.js 2.x 发展了很久,现在周边的生态设施都已经非常完善了,而且对于 Vue.js 用户而言,它几乎满足了我们日常开发的所有需求。你可能觉得 Vue.js 2.x 已经足够优秀,但是在 Vue.js 作者尤小右的眼中它还不够完美。

vue2.x还有哪些不足

vue3.0有哪些优化

源码优化

性能优化

composition API

setup

setup函数是Composition API逻辑组织的入口。

它是在props、data、computed、methods、生命周期函数之前运行的。返回一个对象,该对象上的属性将合并到组件模板的渲染上下文中,还可以返回一个render函数

<template>
  <div>
    <div>count的值为: {{ count }}</div>
    <div>double的值为: {{ double }}</div>
    <el-button type="primary" @click="increment">
      增加count值
    </el-button>
    <div>title的值为: {{ title }}</div>
    <el-button @click="decrement">
      修改title的值
    </el-button>
  </div>
</template>
<script lang="ts">
import {
  defineComponent,
  reactive,
  ref,
  toRefs,
  computed,
  onMounted
} from "vue";
export default defineComponent({
  setup() {
    const count = ref(0);
    const increment = () => {
      count.value++;
    };
    const state = reactive({
      title: "vue3.0",
      decrement: () => {
        state.title = "vue3.0 + typescript";
      }
    });
    const double = computed(() => count.value * 2);
    onMounted(() => {
      console.info("onMounted");
    });
    return {
      ...toRefs(state),
      count,
      increment,
      double
    };
  }
});
</script>

在setup函数内部,定义了一个响应式对象 state,它是通过 reactive API 创建的(还可以使用ref API创建)。

reactive

reactive是实现响应式的一种方法,它接收对象作为参数,返回的时候必须要使用toRefs包裹(toRefs函数是将reactive创建的响应式对象,转化成为普通的对象,并且这个对象上的每个节点,都是ref()类型的响应式数据)。

ref

ref 和 reactive 一样都是实现响应式数据的方法,它传入一个值作为参数,返回一个基于该值的响应式Ref对象。如上面的示例代码一样,通过修改count.value的值,从而触发模板的重新渲染。

computed

computed是一个函数,它接收一个回调函数作为参数,返回一个基于该值的响应式Ref对象。也可以接收一个对象形式(对象中只有set和get)作为参数。

<script lang="ts">
import { defineComponent, ref, computed } from "vue";
export default defineComponent({
  setup() {
    const count = ref(0);
    const increment = () => {
      count.value++;
    };
    const double = computed(() => count.value * 2);
    // const double = computed({
    //   get() {
    //     return count.value * 3;
    //   },
    //   set(val) {
    //     console.log(val);
    //     count.value = val - 1;
    //   }
    // });
    return {
      count,
      increment,
      double
    };
  }
});
</script>

watchEffect

watchEffect立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。它能够实现停止侦听,清除副作用、副作用刷新时机和侦听器调试行为。

<script lang="ts">
import { defineComponent, ref, watchEffect } from "vue";
export default defineComponent({
  setup() {
    const count = ref(0);
    watchEffect(() => console.info(count.value)); //0
    setTimeout(() => {
      count.value++; //1
    }, 100);
    return { count };
  }
});
</script>
const stop = watchEffect(() => {
  /* ... */
})

// later
stop()

侦听副作用传入的函数可以接收一个 onInvalidate 函数作入参,用来注册清理失效时的回调。当以下情况发生时,这个失效回调会被触发:副作用即将重新执行时或侦听器被停止。

watchEffect(onInvalidate => {
  const token = performAsyncOperation(id.value)
  onInvalidate(() => {
    // id has changed or watcher is stopped.
    // invalidate previously pending async operation
    token.cancel()
  })
})

watch

watch是一个函数,它不会立即执行,只有当监听源发生变化时才会执行。它可以监听多个数据,还有与watchEffect共享的行为(停止侦听,清除副作用、副作用刷新时机和侦听器调试行为。)。它接收两个参数。

<script lang="ts">
import { defineComponent, ref, watch } from "vue";
export default defineComponent({
  setup() {
    const count = ref(0);
    watch(count, () => console.info(count.value));
    return { count };
  }
});
</script>
<script lang="ts">
import { defineComponent, reactive, toRefs, watch } from "vue";
export default defineComponent({
  setup() {
  	const count = ref(0);
    const state = reactive({
      title: "",
      decrement: () => {
        state.title += "hi!";
      }
    });
    watch([count, () => state.title], () => {
      document.title = "updated " + state.title + count.value;
    });
    return { ...toRefs(state) };
  }
});
</script>
<script lang="ts">
import { defineComponent, reactive, toRefs, watch } from "vue";
export default defineComponent({
  setup() {
    const state = reactive({
      title: "",
      decrement: () => {
        state.title += "hi!";
      }
    });
    watch(
      () => state.title,
      () => {
        document.title = "updated " + state.title;
      }
    );
    return { ...toRefs(state) };
  }
});
</script>

生命周期

在vue3.0中,生命周期钩子函数做了全面替换,映射关系如下:

beforeCreate -> 使用 setup()
created -> 使用 use setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy-> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
deactivated -> onDeactivated
errorCaptured -> onErrorCaptured