目录
前言
vue3已经出了好长一段时间了,最近闲来无事简单学习了一下,新增的东西还是挺多的,写一篇文章来记录一下。
概述
Vue3组合式api VS Vue2选项式api
谈到 vue3,首先想到的就是组合式api,很大程度的解决了vue2选项式api的缺点,那有啥缺点?当文件中的业务代码非常多的时候,阅读修改代码的时候是非常痛苦的,data,method,watch还有计算属性之间来回跳转, 我已经准备拔刀了。
下面这些图被疯转,很形象的展现了vue2和vue3的区别,可以看到组合式api就是将单个功能的状态,方法,计算属性等等需要用到的东西都组合在一起抽离成一个hook,也就是对应图4的function,最终再统一引入组合到一起。这样做的好处就是单个功能的代码都在一起,方便调式修改。
基础部分
setup
setup是vue3的一个新的配置项,只在初始化的时候执行一次,所有的组合式函数都在此使用。setup可以在选项式api的风格中使用也可以通过组合式api的风格 。通过代码简单对比一下。vue3推荐使用组合式。
选项式api的风格
<script>
import { ref } from 'vue'
export default {
setup() {
const sum = ref(1)
return {
sum,
}
},
}
</script>
<template>
<div>
<h1>v3</h1>
<h3>{
{ sum }}</h3>
<button @click="sum++">+1</button>
</div>
</template>
<style scoped></style>
组合式api的风格
<script setup>
import { ref } from 'vue'
const sum = ref(1)
</script>
<template>
<div>
<h1>v3</h1>
<h3>{
{ sum }}</h3>
<button @click="sum++">+1</button>
</div>
</template>
<style scoped></style>
区别
<script setup>
中的导入和顶层变量/函数都能够在模板中直接使用, 选项式则需要导出<script setup>打包出来的体积更小
<script setup>对ts更友好
官网介绍的比较详细,感兴趣可以查看
组合式 API 常见问答 | Vue.js
响应式数据
vue2中 data 函数返回的对象就是响应式的数据,但是在增加删除对象属性时不是响应式的,当然vue2中也有对应的解决方法,this.$set(), this.$delete(), 其实这也能够理解,毕竟vue2的响应式式基于 Object.defineProperty 实现的,这个函数只提供了 get 和 set 以及一些描述符 descriptor,并没有提供 add 和 delete 方法。
vue3中的响应式包含了两种形态, ref(底层还是Object.defineProperty进行数据劫持, 处理简单数据类型),reactive(使用es6的Proxy进行数据劫持,处理复杂数据类型),完全修复了vue2响应式的痛点,vue3的响应式更加的友好。
ref
ref 接受一个值,返回一个响应式对象,一般用来处理简单数据类型的响应式,但如果传入的值是对象 ref 会求助 reactive,返回RefImpl的实例简称ref对象。 此时可能会有疑惑,既然ref是一个响应式的对象,为什么模板中能正常解析。这是因为在解析templete时遇到ref对象会自动取其value属性,但是如果要在方法中修改ref创建的响应式数据,你的写法应该是这样的 state.value = xxx
<script setup>
import { ref } from 'vue'
const sum = ref(1)
function add() {
sum.value++
}
</script>
<template>
<div>
<h1>v3</h1>
<h3>{
{ sum }}</h3>
<button @click="add">+1</button>
</div>
</template>
<style scoped></style>
reactive
为对象做深层!!!!响应式代理, 也就是如果对象有多层依旧是响应式的,返回一个Proxy实例, 如果传入一个字符串或者数字,它将不是响应式的。Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)Proxy - JavaScript | MDN。Vue使用 Proxy 进行数据劫持, Reflect 进行反射修改 Reflect - JavaScript | MDN
<script setup>
import { reactive } from 'vue'
const person = reactive({
name: '张三',
age: 12,
job: {
j1: {
jname: '前端开发',
},
},
})
function add() {
person.hobby = ['唱', '跳', 'rap']
}
function deleteHB() {
delete person.hobby
}
</script>
<template>
<div>
<h1>v3</h1>
<h1>{
{ sum }}</h1>
<h3>姓名:{
{ person.name }}</h3>
<h3>年龄:{
{ person.age }}</h3>
<h3>工作:{
{ person.job.j1.jname }}</h3>
<h3 v-if="person.hobby">爱好: {
{ person.hobby }}</h3>
<button @click="person.name += '-'">修改姓名</button>
<button @click="person.age++">修改年龄</button>
<button @click="person.job.j1.jname += '!'">修改工作</button>
<button @click="add">增加爱好</button>
<button @click="deleteHB">删除爱好</button>
</div>
</template>
<style scoped></style>
shallowReactive 与 shallowRef
shallowRef 直译过来意思是浅层的 ref,shallowRef 传入对象不会求助 reactive,仅仅对ref对象的 value 属性具有响应式。
shallowReactive 只处理对象第一层的响应式, 如果修改了深层的数据页面是不会响应的,但是会在下次页面更新中渲染出来。
<script setup>
import { shallowReactive, shallowRef, ref, reactive } from 'vue'
const shallowRef_jack = shallowRef({ name: 'jack', sex: '女' })
const shallowReactive_ben = shallowReactive({
name: 'ben',
sex: '女',
child: {
son: {
name: '张三',
},
},
})
const ref_jack = ref({ name: 'jack', sex: '女' })
const reactive_ben = reactive({
name: 'ben',
sex: '女',
child: {
son: {
name: '张三',
},
},
})
</script>
<template>
<div>
<h1>v3</h1>
<h3>
shallowRef_jack: {
{ shallowRef_jack }}
<button @click="shallowRef_jack = {}">修改整个对象</button>
<button @click="shallowRef_jack.name += '!'