浅谈VUE3和VUE2的区别

  1. 生命周期变化

    变化不大,只是名字大部分需要加on,功能上类似,使用上 Vue3 组合式 API 需要先引入,Vue2 选项 API 则可以直接调用,
// vue3
<script setup>     
import { onMounted } from 'vue'

onMounted(() => {
  ...
})
// 可将不同的逻辑拆开成多个onMounted,依然按顺序执行,不被覆盖
onMounted(() => {
  ...
})
</script>

// vue2
<script>     
   export default {         
      mounted() {             
        ...         
      },           
   }
</script> 
Vue2Vue3
beforeCreateNot needed*
createdNot needed*
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeDestroyonBeforeUnmount
destroyedonUnmounted
  1. 响应式原理

Vue2 响应式原理基础是Object.defineProperty;Vue3 响应式原理基础是Proxy
Object.defineProperty
基本用法:直接在一个对象上定义新的属性或修改现有的属性,并返回对象。
Tips: writable value getter setter 不共存。

let obj = {}
let name = 'TJ.'
Object.defineProperty(obj, 'name', {
  enumerable: true, // 可枚举(是否可通过for...in 或 Object.keys()进行访问)
  configurable: true, // 可配置(是否可使用delete删除,是否可再次设置属性)
  // value: '', // 任意类型的值,默认undefined
  // writable: true, // 可重写
  get: function() {
    return name
  },
  set: function(value) {
    name = value
  }
})

Vue3 为什么会使用 Proxy?
主要原因:无法监听对象或数组新增、删除的元素。
Vue2 方案:针对常用数组原型方法pushpopshiftunshiftsplicesortreverse进行了hack处理;提供Vue.set监听对象/数组新增属性。对象的新增/删除响应,还可以new个新对象,新增则合并新属性和旧对象;删除则将删除属性后的对象深拷贝给新对象。
Proxy
Proxy是ES6新特性,通过第2个参数handler拦截目标对象的行为。相较于Object.defineProperty提供语言全范围的响应能力,消除了局限性。但在兼容性上放弃了(IE11以下)

  1. 组合式 API

Vue2 是 选项式API(Option API),一个逻辑会散乱在文件不同位置(data、props、computed、watch、生命周期函数等),导致代码的可读性变差,需要上下来回跳转文件位置。Vue3 组合式API(Composition API)则很好地解决了这个问题,可将同一逻辑的内容写到一起。

除了增强了代码的可读性、内聚性,组合式API 还提供了较为完美的逻辑复用性方案,举个例子,如下所示公用鼠标坐标案例:

// main.vue
<template>
  <span>mouse position {{x}} {{y}}</span>
</template>

<script setup>
import { ref } from 'vue'
import useMousePosition from './useMousePosition'

const {x, y} = useMousePosition()

}
</script>
// useMousePosition.js
import { ref, onMounted, onUnmounted } from 'vue'

function useMousePosition() {
  let x = ref(0)
  let y = ref(0)
  
  function update(e) {
    x.value = e.pageX
    y.value = e.pageY
  }
  
  onMounted(() => {
    window.addEventListener('mousemove', update)
  })
  
  onUnmounted(() => {
    window.removeEventListener('mousemove', update)
  })
  
  return {
    x,
    y
  }
}
</script>
  1. 多跟节点

Vue3 支持了多根节点组件,也就是fragment

<template>
  <header>...</header>
  <main>...</main>
  <footer>...</footer>
</template>

Vue2 中编写页面的时候,我们需要去将组件包裹在<div>中,否则报错。

<template>
  <div>
    <header>...</header>
    <main>...</main>
    <footer>...</footer>
  </div>
</template>
  1. Teleport

Vue3 提供Teleport组件可将部分DOM移动到 Vue app 之外的位置。比如项目中常见的弹框组件。

<button @click="dialogVisible = true">点击</button>
<teleport to="body">
   <div class="dialog" v-if="dialogVisible">
   </div>
</teleport>
  1. 异步组件

Vue3 提供Suspense组件,允许程序在等待异步组件时渲染兜底的内容,如loading ,使用户体验更平滑。使用它,需在模板中声明,并包括两个命名插槽:defaultfallbackSuspense确保加载完异步内容时显示默认插槽,并将fallback插槽用作加载状态。
项目中踩过坑,若想在setup中调用异步请求,需在setup 前加async关键字。这时,会受到警告async setup() is used without a suspense boundary
解决方案:在父页面调用当前组件外包裹一层Suspense组件。

  1. 虚拟 DOM

Vue3 相比于 Vue2 虚拟DOM 上增加patchFlag字段。我们借助Vue3 Template Explorer来看。

<div id="app">
  <h1>技术摸鱼</h1>
  <p>今天天气真不错</p>
  <div>{{name}}</div>
</div>
import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from "vue"

const _withScopeId = n => (_pushScopeId("scope-id"),n=n(),_popScopeId(),n)
const _hoisted_1 = { id: "app" }
const _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode("h1", null, "技术摸鱼", -1 /* HOISTED */))
const _hoisted_3 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode("p", null, "今天天气真不错", -1 /* HOISTED */))

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createElementBlock("div", _hoisted_1, [
    _hoisted_2,
    _hoisted_3,
    _createElementVNode("div", null, _toDisplayString(_ctx.name), 1 /* TEXT */)
  ]))
}

注意第 3 个_createElementVNode的第 4 个参数即patchFlag字段类型,字段类型情况如下所示。1 代表节点为动态文本节点,那在diff过程中,只需比对文本对容,无需关注class、style等。除此之外,发现所有的静态节点,都保存为一个变量进行静态提升,可在重新渲染时直接引用,无需重新创建。

export const enum PatchFlags { 
  TEXT = 1, // 动态文本内容
  CLASS = 1 << 1, // 动态类名
  STYLE = 1 << 2, // 动态样式
  PROPS = 1 << 3, // 动态属性,不包含类名和样式
  FULL_PROPS = 1 << 4, // 具有动态 key 属性,当 key 改变,需要进行完整的 diff 比较
  HYDRATE_EVENTS = 1 << 5, // 带有监听事件的节点
  STABLE_FRAGMENT = 1 << 6, // 不会改变子节点顺序的 fragment
  KEYED_FRAGMENT = 1 << 7, // 带有 key 属性的 fragment 或部分子节点
  UNKEYED_FRAGMENT = 1 << 8,  // 子节点没有 key 的fragment
  NEED_PATCH = 1 << 9, // 只会进行非 props 的比较
  DYNAMIC_SLOTS = 1 << 10, // 动态的插槽
  HOISTED = -1,  // 静态节点,diff阶段忽略其子节点
  BAIL = -2 // 代表 diff 应该结束
}
  1. 事件缓存

Vue3 的cacheHandler可在第一次渲染后缓存我们的事件。相比于 Vue2 无需每次渲染都传递一个新函数。加一个click事件。

<div id="app">
  <h1>小丽SPA</h1>
  <p>今天天气好晴朗</p>
  <div>{{name}}</div>
  <span onCLick="() => {}"><span>
</div>

渲染函数如下:

import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from "vue"

const _withScopeId = n => (_pushScopeId("scope-id"),n=n(),_popScopeId(),n)
const _hoisted_1 = { id: "app" }
const _hoisted_2 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode("h1", null, "小丽SPA", -1 /* HOISTED */))
const _hoisted_3 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode("p", null, "今天天气好晴朗", -1 /* HOISTED */))
const _hoisted_4 = /*#__PURE__*/ _withScopeId(() => /*#__PURE__*/_createElementVNode("span", { onCLick: "() => {}" }, [
  /*#__PURE__*/_createElementVNode("span")
], -1 /* HOISTED */))

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createElementBlock("div", _hoisted_1, [
    _hoisted_2,
    _hoisted_3,
    _createElementVNode("div", null, _toDisplayString(_ctx.name), 1 /* TEXT */),
    _hoisted_4
  ]))
}
  1. TypeScript 支持

Vue3 由TS重写,相对于 Vue2 有更好地 TypeScript 支持。

  • Vue2 Option APIoption 是个简单对象,而TS是一种类型系统,面向对象的语法,不是特别匹配。
  • Vue2 需要vue-class-component强化vue原生组件,也需要vue-property-decorator增加更多结合 Vue 特性的装饰器,写法比较繁琐。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值