Vue2/3特性复习

386 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情

她说,Vue2/3、React、NodeJs 都精通的男生真的很帅 于是我连夜把它们都过了一遍...

先举个计算器的小demo,对比一下组合式 API和选项式 API的写法差异

  • Vue2的 Options API
<script src="https://unpkg.com/vue@next"></script>
<div id="app">
    <div>{{count}} 的平方是: {{square}}</div>
    <button @click="add">+</button>
    <button @click="subtract">-</button>
</div>
<script>
    const App = {
        data() {
            return {
                count: 0
            }
        },
        methods: {
            add() {
                this.count++
            },
            subtract() {
                this.count--
            }
        },
        computed: {
            square() {
                return Math.pow(this.count, 2)
            }
        }
    }
    Vue.createApp(App).mount('#app') 
</script>
  • Vue3的Composition API
<script src="https://unpkg.com/vue@next"></script>
<div id="app">
    <div>{{state.count}} 的平方是: {{square}}</div>
    <button @click="add">+</button>
    <button @click="subtract">-</button>
</div>
<script>
    const { reactive, computed } = Vue
    const App = {
        setup() {
            const state = reactive({
                count: 1
            })
            const add = () => state.count++
            const subtract = () => state.count--
            const square = computed(() => Math.pow(state.count, 2))
            return { state, add, subtract, square }
        }
    }
    Vue.createApp(App).mount('#app')
</script>
  • 我们可以直观地看出,当业务逻辑不复杂时,选项式 API 数据和方法分离的特点,使得代码结构上比组合式 API更清晰,更好入手;但当组件变得庞大的时候,反而会使methods、data、computed的列表变得很长,比如代码超过了300行后,开发经常需要上下跳转,来搜集某个业务逻辑关心的数据以及方法

  • 我们可以得到一个结论,也就是Options API 把某个业务逻辑关心的数据以及方法分离开了,而Composition API 把同一个业务逻辑相关的代码封装进一个独立的函数,也就是说开发不再需要上下跳转,能更好维护我们的代码

  • Options API 的组件抽离通用逻辑只能用mixin,且存在命名冲突的困扰,而Composition API 通过独立函数进行封装,复用性更强

  • 我们可以任意拆分组件的功能(自定义Hooks),提高代码的可维护性

然后说下setup函数

  • setup 函数会在beforeCreate之前执行
  • 语法糖是<srcipt setup>
  • 接收props父组件传入的属性 和 context上下文对象
  • 自定义Hooks是把 setup组合函数之中的 ref、reactive、computed、watch、生命周期钩子等进行了封装抽离代码(公共代码,公共组件等),这样使得代码更加简洁。自定义Hooks相当于vue2中的mixin,我们约定这些自定义 Hooks 函数以 use 作为前缀,和普通的函数加以区分

接着是Vue的核心 -> 响应式方案

  • Vue2 的 defineProperty
const obj = {};
let current = 1,sum = 0;
const add = n => n += 1;
Object.defineProperty(obj, "current", {
  get() {
    return current;
  },
  set(val) {
    current = val;
    sum = add(val);
  },
});
console.log(sum); //0
obj.current = 2;
console.log(sum); //3
delete obj.current
console.log(sum);  //3 还是之前的值,这说明Vue2的defineProperty监听不到属性的删除,需要专门的$delete函数来清理数据
  • Proxy(用于Vue3 的 reactive )
const obj = {};
let current = 1,sum = 0;
const add = n => n += 1;
const proxy = new Proxy(obj, {
 get(target, prop) {
   return target[prop];
 },
 set(target, prop, value) {
   target[prop] = value;
   if (prop === "current") {
     sum = add(value);
   }
 },
 deleteProperty(target, prop) {
   delete target[prop];
   if (prop === "current") {
     sum = -1;
   }
 },
});
console.log(obj.current, sum); //undefined 0
proxy.current = 2;
console.log(obj.current, sum); // 2 3
delete proxy.current;
console.log(obj.current, sum);  //undefined -1 删除后值更新,说明Proxy可以监听到属性的删除
const obj = reactive({ count: 0 }) //深层的响应式对象,影响所有嵌套property

//类比一下react的usestate~
const [ state, setState ] = useState({ count: 0 }) 
  • value setter(用于Vue3 的 ref)
const add = n => n += 1;
let current = 1,sum = 0

const obj = {
  get value() {
    return current;
  },
  set value(val) {
    current = val;
    sum = add(current);
  },
};
console.log(obj.value, sum); //1 0
obj.value = 2;
console.log(obj.value, sum); //2 3
const count = ref(0) 
console.log(count.value) // 0 

//类比一下react的useRef~
const _count = useRef(0)
console.log(count.current) // 0 

新版生命周期

  • 可按需导入到组件中,且只能在 setup() 函数中使用
<script lang="ts">
import {
  defineComponent,
  onBeforeMount,
  onBeforeUnmount,
  onBeforeUpdate,
  onErrorCaptured,
  onMounted,
  onUnmounted,
  onUpdated,
} from "vue";
export default defineComponent({
  setup(props, context) {
    onBeforeMount(() => {
      console.log("beformounted----");
    });
    onMounted(() => {
      console.log("mounted----");
    });
    onBeforeUpdate(() => {
      console.log("beforupdated----");
    });
    onUpdated(() => {
      console.log("updated----");
    });
    onBeforeUnmount(() => {
      console.log("beforunmounted----");
    });
    onUnmounted(() => {
      console.log("unmounted----");
    });
    onErrorCaptured(() => {
      console.log("errorCaptured----");
    });
    return {};
  },
});
</script>

Vue3 所有模块使用 TypeScript 重构

  • TypeScript 类型系统带来了更方便的提示,并且让我们的代码能够更健壮,能够带来更好的可维护性
  • Vue 2 使用 Flow.js 来做类型校验。但现在 Flow.js 已经停止维护了

Vue3 新增了 Fragment、Teleport 和 Suspense 等组件

  • 本文不再介绍,可以自行了解