总结下vue3相对vue2升级的点

前言

vue3相对vue2是一个大的版本升级,数据劫持的apiObject.defineProperty变成Proxy,对数组 的监听和对象的动态添加属性的响应式更加友好了。

然后vue3也推出了新的逻辑和语法,比如组合式api,reactive,ref,setup钩子等,今天总结下vue3相对vue2升级的点。

正文

组合式api

之前vue2是使用选项式api,需要定义data,methods,watch,computed, 一部分逻辑有可能在methods,一部分逻辑在watch等等。

而vue3的组合式api,可以把关联的逻辑写在一起,这样如果需要复用的时候,可以单独拎出来复用。

组合式api:

js 复制代码
import { reactive, watch } from 'vue'
export default {
  name: 'HomeView',
  setup () {
    // 以下是关联的逻辑
    const info = reactive({ name: '答案cp3' })
    watch(() => info.name, () => {
      console.log('名字改变了')
    })
    const changeNameFn = () => {
      info.name = 'cp3'
    }
    // 其它逻辑
    return {
      info,
      changeNameFn
    }
  }
}

选项式api:

js 复制代码
export default {
  name: 'HomeView',
  data () {
    return {
      info: { name: '答案cp3' }
    }
  },
  watch: {
    // ...可能有其它逻辑
    'info.name' () {
      console.log('名字改变了')
    }
  },
  methods: {
    // ...可能有其它逻辑
    changeNameFn () {
      this.info.name = 'cp3'
    }
  }
}

上面这个是简单的例子,如果我们组件的逻辑变得更复杂,选项式api的逻辑就会变得更分散,而组合式api的逻辑还是很直观的,因为它是一块一块的。

生命周期钩子

vue3推出了setup钩子,它是组合式api的入口,其它的生命周期钩子一般得在它内部执行。

vue3对比vue2,钩子函数都重命名了,请看表格:

vue3组合式api vue2选项式api
- beforeCreate
- created
onBeforeMount beforeMount
onMounted mounted
onBeforeUpdate beforeUpdate
onUpdated updated
onActivated activated
onDeactivated deactivated
onBeforeMount beforeDestroy
onUnmounted destroyed
onErrorCaptured errorCaptured

它有2个参数props,context

js 复制代码
 setup (props, context) {
     // props: 父组件传的props
     // context: 值有attrs,slots,emit, expose。
 }

attrs等同于vue2的attrs, slots相当于vue2的slots,emit相当于vue2的emit

dispose是新增的,可以选择返回暴露哪些公共属性,当父组件访问时,只能访问这些属性。

js 复制代码
 setup (props, { expose }) {
     expose({
       // 属性
     })
 }

注意:attrs和slots是非响应式的

reactive/ref

vue3的setup钩子执行在beforeCreate之前,没有this,所以无法访问data的变量,同时vue3也不建议把变量定义在data中。

vue3重新定义了变量的语法,比较常见是reactiveref

reactive

reactive一般用来监听对象类型,如果不是对象类型,会报错

js 复制代码
import { reactive } from 'vue'
const info = reactive({name:'答案cp3'}) // 正确
const name = reactive('答案cp3') // 错误❌

info.name = 'cp3' // 修改属性触发响应更新
info.age = 18 // 新增属性也能响应更新

定义后对对象的属性赋值修改会触发响应更新,如果对整个对象赋值,会让对象丢失响应式

js 复制代码
import { reactive } from 'vue'
let info = reactive({name:'答案cp3'}) 

// 这个赋值会让info丢失响应式
info =  {name: 'cp3'} 

info.name = '答案' // 没有响应式了

如果需要整体赋值,应该再嵌套一层对象,让info成为嵌套对象的一个属性,或者使用下面说的ref

ref

大家一般会在基本数据类型使用ref,但是其实它也支持引用类型,比如对象。

然后使用的时候需要加上.value(模板上的语法不需要)。

js 复制代码
<div @click="changeNameFn">{{ name }}</div>

import { ref } from 'vue'
const name = ref('答案cp3')
const changeNameFn = () => {
   name.value = 'cp3'
}
return  {
  name,
  changeNameFn
}

ref监听对象也是可以

js 复制代码
<div @click="changeInfoFn">{{ info.name }}</div>

import { ref } from 'vue'
const info = ref({name: '答案cp3'})
const changeInfoFn = () => {
  info.value = {name: 'cp3'} // 或者info.value.name = 'cp3' 都可以
}
return  {
  info,
  changeInfoFn
}

reactive和ref的异同

reactive返回的是proxy对象,ref返回的是RefImpl对象。

packages/reactivity/src/reactive.ts

js 复制代码
export function reactive(target: object) {
  // ...省略
  return createReactiveObject(
    target,
    false,
    mutableHandlers,
    mutableCollectionHandlers,
    reactiveMap
  )
}
function createReactiveObject() {
  if (!isObject(target)) {
    if (__DEV__) {
      console.warn(`value cannot be made reactive: ${String(target)}`)
    }
    return target
  }
  // ...省略
  const proxy = new Proxy(
    target,
    targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
  )
  proxyMap.set(target, proxy)
  return proxy // 返回proxy对象
}

packages/reactivity/src/ref.ts

js 复制代码
export function ref(value?: unknown) {
  return createRef(value, false)
}

function createRef(rawValue: unknown, shallow: boolean) {
  if (isRef(rawValue)) {
    return rawValue
  }
  return new RefImpl(rawValue, shallow) // 返回RefImpl对象
}

虽然二者对象不一样,但是也有相通点,如果你是使用ref监听对象类型 ,内部也是调用的reactive

js 复制代码
// ref.ts
class RefImpl<T> {
  // ...省略
  constructor(
    value: T,
    public readonly __v_isShallow: boolean
  ) {
    this._value = __v_isShallow ? value : toReactive(value)
  }
 // reactive.ts 
export const toReactive = <T extends unknown>(value: T): T =>
  isObject(value) ? reactive(value) : value

可以看到,会在RefImpl实例化的时候调用toReactive函数,在toReactive函数中判断是否为对象,如果是就调用reactive函数。

一般我们会在引用类型使用reactive,基本数据类型使用ref(但是它也支持引用类型)

总结

以上就是vue3相对vue2升级的点,包括组合式apisetup钩子函数 ,以及reactive和ref语法,vue3还有其它升级的点,欢迎大家去探索发现。

感谢大家的阅读。

相关推荐
工业互联网专业7 分钟前
毕业设计选题:基于springboot+vue+uniapp的驾校报名小程序
vue.js·spring boot·小程序·uni-app·毕业设计·源码·课程设计
J不A秃V头A36 分钟前
Vue3:编写一个插件(进阶)
前端·vue.js
司篂篂1 小时前
axios二次封装
前端·javascript·vue.js
姚*鸿的博客1 小时前
pinia在vue3中的使用
前端·javascript·vue.js
宇文仲竹2 小时前
edge 插件 iframe 读取
前端·edge
Kika写代码2 小时前
【基于轻量型架构的WEB开发】【章节作业】
前端·oracle·架构
天下无贼!3 小时前
2024年最新版Vue3学习笔记
前端·vue.js·笔记·学习·vue
Jiaberrr3 小时前
JS实现树形结构数据中特定节点及其子节点显示属性设置的技巧(可用于树形节点过滤筛选)
前端·javascript·tree·树形·过滤筛选
赵啸林3 小时前
npm发布插件超级简单版
前端·npm·node.js
我码玄黄4 小时前
THREE.js:网页上的3D世界构建者
开发语言·javascript·3d