百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

字节二面:说一下Vue3中你知道的Composition API

ztj100 2024-11-26 11:15 15 浏览 0 评论

大家都知道,现在Vue3的各个版本已经陆续发布了,并且有很多的团队已经着手各个库的开发与Vue2向Vue3的升级,我们当然也不能落后,所以赶紧将跟着本文一起学习新的API吧

一、setup

setup的理解:

Vue3.0的一个配置项,值为一个函数,setup是所有Composition API(组合API)的入口“表演舞台”,组件中所用到的:数据、方法等等,均要配置在setup中。

setup函数有两种返回值:

若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用

若返回一个渲染函数:则可以自定义渲染内容。

setup使用注意点:

尽量不要与Vue2.x配置混用

setup不能是一个async函数,因为返回值不再是return的对象, 而是promise, 模板看不到return对象中的属性。(后期也可以返回一个Promise实例,但需要Suspense和异步组件的配合)

vue2可以获取vue3中的属性和方法,vue3无法获取vue2中的属性和方法。

setup函数的使用:

setup 函数是在 created 时候(实例被初始化前)执行的。里边返回数据或者方法,插值函数可以检测到。

因为是实例初始化前执行,因此 setup 里不能使用 this 访问到实例。

<template>

<div>

<h3>姓名:{{ name }}</h3>

<h3>年龄:{{ age }}</h3>

<h3>技能:{{ skill }}</h3>

</div>

</template>

<script>

export default {

setup() {

let name = "张三";

let age = 18;

let skill = "犯罪";

return {

name,

age,

skill,

};

},

};

</script>

<style scoped></style>

setup 函数里有两个参数,第一个是 props,指组件从父组件那儿接收到的参数,第二个是 context,暴露了 attrs、slot、emit 等实用方法。

二、ref和reactive

上面看着很合理,但是 name 和 age 都是非响应式的,即数据改变并不会触发渲染。

如何解决问题呢?现在需要响应式的引用:通过 proxy 对数据进行封装。当数据变化时,触发模板等内容的更新。

后面的例子都是通过一秒后修改 name 的值来查看是否有响应式。如果页面数据没有改变,说明没有响应式。

ref:响应式封装基本类型数据

使用ref函数,如ref(‘张三’),对基本类型的数据进行封装,变成proxy({value:‘张三’})这样一个响应式的数据。

<template>

<div>

<h3>姓名:{{ name }}</h3>

<h3>年龄:{{ age }}</h3>

<h3>技能:{{ skill }}</h3>

</div>

</template>

<script>

import { ref } from "vue";

export default {

setup() {

let name = ref("张三");

let age = ref(18);

let skill = ref("犯罪");

setTimeout(() => {

name.value = "李四",

age.value = 19,

skill.value = "飞刀"

}, 1000);

return {

name,

age,

skill,

};

},

};

</script>

<style scoped>

</style>

改成响应式引用后数据变化,页面也会发生变化

备注:

接收的数据可以是:基本类型、也可以是对象类型

  • 基本类型:响应式依然是靠Object.defineProperty()的get与set完成的
  • 对象类型:内部借用了Vue3.0中的一个新函数-reactive函数

(ref处理基本类型用的是get与set处理对象数据用的是es6中的Proxy)

reactive:响应式封装非基本类型数据

使用reactive函数,将非基本数据类型转为响应式,一般是对象或者数组。

原理:reactive({name:‘张三’})转为proxy({name:‘张三’})

<template>

<div>

<h3>姓名:{{ obj.name }}</h3>

<h3>年龄:{{ obj.age }}</h3>

<h3>技能:{{ obj.skill }}</h3>

</div>

</template>

<script>

import { reactive } from "vue";

export default {

setup() {

let obj = reactive({

name: '张三',

age: 18,

skill: '犯罪'

})

setTimeout(() => {

obj.name = '李四',

obj.age = 19,

obj.skill = '飞刀'

})

return {

obj

};

},

};

</script>

<style scoped>

</style>

toRefs

使用过对象解构的同学会觉得插值函数里的写法好麻烦啊,所以会用对象解构。但是这里需要注意的一点,如果直接使用结构后的值,这些值不是响应式的。

解构会将对象或数组解构成普通的数据,丢失了响应。因此解构之前需要用 toRefs 包裹一下,使解构后所有值变成响应式的。

原理:toRefs({ name: "张三", age: 18,skill:"犯罪" }) 转化成 { name: proxy({ value: "张三" }), age: proxy({ value: 18 }),skill:proxy({value:"犯罪"}) },将内部的所有数据变成响应式的。现在使用解构后就不会丢失响应式了。

<template>

<div>

<h3>姓名:{{ name }}</h3>

<h3>年龄:{{ age }}</h3>

<h3>技能:{{ skill }}</h3>

</div>

</template>

<script>

import { reactive, toRefs } from "vue";

export default {

setup() {

let obj = reactive({

name: "张三",

age: 18,

skill: "犯罪",

});

setTimeout(() => {

obj.name = "李四",

obj.age = 19,

obj.skill = "飞刀";

});

let { name, age, skill } = toRefs(obj);

return {

name,

age,

skill,

};

},

};

</script>

<style scoped>

</style>

reactive对比ref

从定义数据角度对比:

ref用来定义:基本类型数据。

reactive用来定义:对象(或数组)类型数据。

备注:ref也可以用来定义对象(或数组)类型数据,它内部会自动通过reactive转为代理对象。

从原理角度对比:

ref定义一个基本数据类型是通过Object.defineProperty()的get()与set()来实现响应式(数据劫持)。

ref如果定义的是一个引用数据类型,其底层本质还是reactive,会将我们传入的值自动转变为:ref(1) ==> reactive({value:1})

reactive通过使用Proxy来实现响应式(数据劫持),并通过Reflect操作源对象内部的数据。

从使用角度对比:

ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value。

reactive定义的数据:操作数与读取数据:均不需要.value。

三、computed和watch

computed函数

与Vue2.X的computed的配置功能一致

写法:

<template>

<h1>一个人的信息</h1>

姓:<input type="text" v-model="person.firstName">

<br>

名:<input type="text" v-model="person.lastName">

<!-- 只读 -->

<br>

<!-- <span>全名:{{person.fullName}}</span> -->

全名:<input type="text" v-model="person.fullName">

</template>

<script>

import { reactive, computed } from 'vue'

export default {

name: 'Demo',

setup() {

//数据

let person = reactive({

firstName: '李',

lastName: '四'

})

//计算属性---简写(不考虑计算属性被修改的情况)

// person.fullName = computed(()=>{

// return person.firstName + '-' +person.lastName

// })

//计算属性---完整版(考虑读和写)

person.fullName = computed({

get() {

return person.firstName + '-' + person.lastName

},

set(value) {

const nameArr = value.split('-')

person.firstName = nameArr[0]

person.lastName = nameArr[1]

}

})

//返回一个对象

return {

person,

}

}

}

</script>

可以看到,在 Composition API 中,需要先引入 computed 函数,然后正常使用即可。

watch函数

与Vue2.X的配置功能一致

注意:

监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置失效)

监视reactive定义的响应式数据中的某个属性(属性为对象时)时:deep配置有效

<template>

<h2>当前求和为:{{ sum }}</h2>

<button @click="sum++">点我+1</button>

<hr>

<h2>信息为:{{ msg }}</h2>

<button @click="msg += '!'">修改信息</button>

<hr>

<h2>一个人的信息:</h2>

<h2>姓名:{{ person.name }}</h2>

<h2>年龄:{{ person.age }}</h2>

<h3>工资:{{ person.job.j1.salary }}</h3>

<button @click="person.name += '~'">修改姓名</button>

<button @click="person.age++">修改年龄</button>

<button @click="person.job.j1.salary++">涨薪</button>

</template>

<script>

import { ref, reactive, watch } from 'vue'

export default {

name: 'Demo',

setup() {

//数据

let sum = ref(0)

let msg = ref("nihao")

let person = reactive({

name: '李四',

age: 39,

job: {

j1: {

salary: 20

}

}

})

//情况一:监视ref所定义的一个响应式数据

// watch(sum,(newValue,oldValue)=>{

// console.log('sum变了',newValue,oldValue)

// },{immediate:true})

//情况二:监视ref所定义的多个响应式数据

// watch([sum,msg],(newValue,oldValue)=>{

// console.log('sum或msg变了',newValue,oldValue)

// },{immediate:true})

//情况三:监视reactive所定义的一个响应式数据的全部属性

//1.此处无法正确的获取oldValue

//2.强制开启了深度监视,且无法关闭(deep配置无效)

// watch(person,(newValue,oldValue)=>{

// console.log('person变了',newValue,oldValue)

// },{immediate:true,deep:false})

//情况四:监视reactive所定义的一个响应式数据的某个属性

// watch(()=>person.age,(newValue,oldValue)=>{

// console.log('年龄变了',newValue,oldValue)

// },{immediate:true})

//情况四:监视reactive所定义的一个响应式数据的某些属性

// watch([()=>person.age,()=>person.name],(newValue,oldValue)=>{

// console.log('年龄或姓名变了',newValue,oldValue)

// })

//特殊情况

//此处由于监视的是reactive定义的对象中的某个属性,所以deep有效

watch(() => person.age, (newValue, oldValue) => {

console.log('年龄变了', newValue, oldValue)

}, { deep: true })

//返回一个对象

return {

sum,

msg,

person

}

}

}

</script>

<style>

</style>

watchEffect

watchEffect 和 watch 的区别:

只要写了 watchEffect,回调就立即执行,没有惰性

watchEffect 会自己感知内部的代码数据是否因为相关依赖发生了改变,如果发生了改变就会执行,因此不需要传递很多参数。watch 需要通过参数指定监听哪个数据。

watchEffect 无法获取之前的数据和当前的数据。watch 可以获取之前和当前的数据

watchEffect有点像computed:

但computed注重的是计算出来的值(回调函数的返回值),所以必须要写返回值。

而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值。

watchEffect(() => {

// 当 nameObj.name 发生改变,会触发 watchEffect 的回调函数

console.log(nameObj.name)

})

暂停watchEffect

例如:5S后结束监听

const stop = watchEffect(() => {

console.log(nameObj.name)

setTimeout(() => {

stop()

}, 5000)

})

四、生命周期函数

现在用 Composition API 来写生命周期钩子和Vue2的生命周期钩子的对比:

选项式API

组合式API

beforeCreate

setup

created

setup

beforeMount

onBeforeMount

mounted

onMounted

beforeUpdate

onBeforeUpdate

updated

onUpdated

beforeUnmount

onBeforeUnmount

unmounted

onUnmounted

errorCaptured

onErrorCaptured

activated

onActivated

deactivated

onDeactivated

选项式 API 就是 vue2 的那种 API,因为 vue 组件是通过对象内的配置新建出来的。

因为 setup 函数执行的时间就在 beforeCreate 和 created 之间,因此 Composition API 没有提供对应的钩子。

export default {

setup() {

// mounted

onMounted(() => {

console.log('Component is mounted!')

})

}

}

总结

Vue3.X与Vue2.X的区别

1.重构响应式系统,使用Proxy替换Object.defineProperty。

2.使用Proxy优势:可直接监听数组类型的数据变化,监听的目标为对象本身,不需要像Object.defineProperty一样遍历每个属性,有一定的性能提升,可拦截apply、ownKeys、has等13种方法,而Object.defineProperty不行,直接实现对象属性的新增/删除。

3.新增Composition API,更好的逻辑复用和代码组织。

4.重构 Virtual DOM:模板编译时的优化,将一些静态节点编译成常量,slot优化,将slot编译为lazy函数,将slot的渲染的决定权交给子组件,模板中内联事件的提取并重用(原本每次渲染都重新生成内联函数)。

5.代码结构调整,更便于Tree shaking,使得体积更小。

6.使用Typescript替换Flow。

7.当然vue3.0,完全兼容vue2.0,不喜欢新语法的伙伴可以保持使用2.0语法。

相关推荐

如何将数据仓库迁移到阿里云 AnalyticDB for PostgreSQL

阿里云AnalyticDBforPostgreSQL(以下简称ADBPG,即原HybridDBforPostgreSQL)为基于PostgreSQL内核的MPP架构的实时数据仓库服务,可以...

Python数据分析:探索性分析

写在前面如果你忘记了前面的文章,可以看看加深印象:Python数据处理...

CSP-J/S冲奖第21天:插入排序

...

C++基础语法梳理:算法丨十大排序算法(二)

本期是C++基础语法分享的第十六节,今天给大家来梳理一下十大排序算法后五个!归并排序...

C 语言的标准库有哪些

C语言的标准库并不是一个单一的实体,而是由一系列头文件(headerfiles)组成的集合。每个头文件声明了一组相关的函数、宏、类型和常量。程序员通过在代码中使用#include<...

[深度学习] ncnn安装和调用基础教程

1介绍ncnn是腾讯开发的一个为手机端极致优化的高性能神经网络前向计算框架,无第三方依赖,跨平台,但是通常都需要protobuf和opencv。ncnn目前已在腾讯多款应用中使用,如QQ,Qzon...

用rust实现经典的冒泡排序和快速排序

1.假设待排序数组如下letmutarr=[5,3,8,4,2,7,1];...

ncnn+PPYOLOv2首次结合!全网最详细代码解读来了

编辑:好困LRS【新智元导读】今天给大家安利一个宝藏仓库miemiedetection,该仓库集合了PPYOLO、PPYOLOv2、PPYOLOE三个算法pytorch实现三合一,其中的PPYOL...

C++特性使用建议

1.引用参数使用引用替代指针且所有不变的引用参数必须加上const。在C语言中,如果函数需要修改变量的值,参数必须为指针,如...

Qt4/5升级到Qt6吐血经验总结V202308

00:直观总结增加了很多轮子,同时原有模块拆分的也更细致,估计为了方便拓展个管理。把一些过度封装的东西移除了(比如同样的功能有多个函数),保证了只有一个函数执行该功能。把一些Qt5中兼容Qt4的方法废...

到底什么是C++11新特性,请看下文

C++11是一个比较大的更新,引入了很多新特性,以下是对这些特性的详细解释,帮助您快速理解C++11的内容1.自动类型推导(auto和decltype)...

掌握C++11这些特性,代码简洁性、安全性和性能轻松跃升!

C++11(又称C++0x)是C++编程语言的一次重大更新,引入了许多新特性,显著提升了代码简洁性、安全性和性能。以下是主要特性的分类介绍及示例:一、核心语言特性1.自动类型推导(auto)编译器自...

经典算法——凸包算法

凸包算法(ConvexHull)一、概念与问题描述凸包是指在平面上给定一组点,找到包含这些点的最小面积或最小周长的凸多边形。这个多边形没有任何内凹部分,即从一个多边形内的任意一点画一条线到多边形边界...

一起学习c++11——c++11中的新增的容器

c++11新增的容器1:array当时的初衷是希望提供一个在栈上分配的,定长数组,而且可以使用stl中的模板算法。array的用法如下:#include<string>#includ...

C++ 编程中的一些最佳实践

1.遵循代码简洁原则尽量避免冗余代码,通过模块化设计、清晰的命名和良好的结构,让代码更易于阅读和维护...

取消回复欢迎 发表评论: