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

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

ztj100 2024-11-26 11:15 31 浏览 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语法。

相关推荐

Python 操作excel的坑__真实的行和列

大佬给的建议__如何快速处理excelopenpyxl库操作excel的时候,单个表的数据量大一些处理速度还能接受,如果涉及多个表甚至多个excel文件的时候速度会很慢,还是建议用pandas来处理,...

Python os.path模块使用指南:轻松处理文件路径

前言在Python编程中,文件和目录的操作是非常重要的一部分。为了方便用户进行文件和目录的操作,Python标准库提供了os模块。其中,os.path子模块提供了一些处理文件路径的函数和方法。本文主要...

Python常用内置模块介绍——文件与系统操作详解

Python提供了多个强大的内置模块用于文件和系统操作,下面我将详细介绍最常用的几个模块及其核心功能。1.os模块-操作系统交互...

Python Flask 建站框架实操教程(flask框架网页)

下面我将带您从零开始构建一个完整的Flask网站,包含用户认证、数据库操作和前端模板等核心功能。##第一部分:基础项目搭建###1.创建项目环境```bash...

为你的python程序上锁:软件序列号生成器

序列号很多同学可能开发了非常多的程序了,并且进行了...

PO设计模式全攻略,在 UI 自动化中的实践总结(以企业微信为例)

一、什么是PO设计模式?PO(PageObject)设计模式将某个页面的所有元素对象定位和对元素对象的操作封装成一个Page类,即一个py文件,并以页面为单位来写测试用例,实现页面对象和测试用例的...

这种小工具居然也能在某鱼卖钱?我用Python一天能写...

前两天在某鱼闲逛,本来想找个二手机械键盘,结果刷着刷着突然看到有人在卖——Word批量转PDF小工具...

python打包成exe,程序有图标,但是任务栏和窗口都没有显示图标

代码中指定图标信息#设置应用ID,确保任务栏图标正确显示ifsys.platform=="win32":importctypesapp_id=...

使用Python构建电影推荐系统(用python做推荐系统)

在日常数据挖掘工作中,除了会涉及到使用Python处理分类或预测任务,有时候还会涉及推荐系统相关任务。...

python爬取并分析淘宝商品信息(python爬取淘宝商品数据)

python爬取并分析淘宝商品信息背景介绍一、模拟登陆二、爬取商品信息1.定义相关参数2.分析并定义正则3.数据爬取三、简单数据分析1.导入库2.中文显示3.读取数据4.分析价格分布5.分析销售...

OpenCV入门学习基础教程(从小白变大神)

Opencv是用于快速处理图像处理、计算机视觉问题的工具,支持多种语言进行开发如c++、python、java等,下面这篇文章主要给大家介绍了关于openCV入门学习基础教程的相关资料,需要的朋友可以...

python图像处理-一行代码实现灰度图抠图

抠图是ps的最基本技能,利用python可以实现用一行代码实现灰度图抠图。基础算法是...

从头开始学python:如何用Matplotlib绘图表

Matplotlib是一个用于绘制图表的库。如果你有用过python处理数据,那Matplotlib可以更直观的帮你把数据展示出来。直接上代码看例子:importmatplotlib.pyplot...

Python爬取爱奇艺腾讯视频 250,000 条数据分析为什么李诞不值得了

在《Python爬取爱奇艺52432条数据分析谁才是《奇葩说》的焦点人物?》这篇文章中,我们从爱奇艺爬取了5万多条评论数据,并对一些关键数据进行了分析,由此总结出了一些明面上看不到的数据,并...

Python Matplotlib 库使用基本指南

简介Matplotlib是一个广泛使用的Python数据可视化库,它可以创建各种类型的图表、图形和可视化效果。无论是简单的折线图还是复杂的热力图,Matplotlib提供了丰富的功能来满足我们...

取消回复欢迎 发表评论: