Vue3.0系列(Composition API:组合API)
1.Vue3.0六大亮点
- Performance:性能比Vue 2.x快1.2~2倍
- Tree shaking support:按需编译,体积比Vue2.x更小
Composition API: 组合API(类似React Hooks)
- Better TypeScript support:更好的 Ts 支持
- Custom Renderer API:暴露了自定义渲染API
- Fragment, Teleport(Protal), Suspense:更先进的组件
2.项目快速搭建
2.1 Vue3.0-快速上手
创建Vue3的3种方式
- Vue-CLI
npm install -g @vue/cli
vue create projectName
cd projectName
vue add vue-next
npm run serve
- Webpack
git clone https://github.com/vuejs/vue-next-webpack-preview.git projectName
cd projectName
npm install
npm run dev
- Vite
2.2 什么是Vite?
Vite是Vue作者开发的一款意图取代webpack的工具, 其实现原理是利用ES6的import会发送请求去加载文件的特性,
拦截这些请求, 做一些预编译, 省去webpack冗长的打包时间
-
安装Vite
npm install -g create-vite-app
-
利用Vite创建Vue3项目
create-vite-app projectName
-
安装依赖运行项目
cd projectName
npm install
npm run dev
3.Composition API:组合API
为什么要有组合API(又叫注入API)呢?
3.1 vue 2.x存在的问题
因为数据和逻辑是很分散的,当我们的项目非常大时,维护起来是比较麻烦的,需要我们的鼠标不停的滑上滑下,
export default {
name: 'App',
data() {
return{
// 新增功能1的数据
// 新增功能2的数据
}
},
methods:{
// 新增功能1的业务逻辑
// 新增功能2的业务逻辑
},
computed:{
// 新增功能1的业务逻辑
// 新增功能2的业务逻辑
},
watch:{
// 新增功能1的业务逻辑
// 新增功能2的业务逻辑
}
}
所以才有了compositionAPI,它是如何把数据和逻辑聚合在一起的呢?
3.2 Composition API
3.2.1 组合API入口函数 setup
注意:
- vue3.0兼容vue2.x的Options API!
- 且 setup的执行时机是在
beforecreate之前
完成的,因此是无法使用data
和methods
的 - 所以Vue为了避免我们错误的使用, 它直接将setup函数中的
this
修改成了undefined
- setup
只能是同步
的,不能是异步的
export default {
name: 'App',
// setup函数是组合API的入口函数
setup(){
//1.数据管理。 通过 ref 或 reactive管理
//2.方法。在组合API中,如果想定义方法,不用定义到methods中,直接在 setup函数中定义即可。
//3. 在组合API中定义的变量/方法,要想在外界使用,必须return出去。
},
data(){
},
methods:{
}
}
3.2.2 reactive
作用:是vue3中提供实现响应复杂数据
的方法;
原理:在vue2中 响应数据是通过 defineProperty 来实现的,vue3是通过而是ES6中的 Proxy 来实现的;
注意点:
-
reactive 的参数传递
必须是一个对象(json / array)
否则无法实现响应式
import {reactive} from 'vue';
export default {
name: 'App',
setup() {
//数据
let state = reactive({
stus:[
{id:1, name:'zs', age:10},
{id:2, name:'ls', age:20},
{id:3, name:'ww', age:30},
]
});
//逻辑
function remStu(index) {
state.stus = state.stus.filter((stu, idx) => idx !== index);
}
let {state, remStu} = useRemoveStudent();
//导出
return {state, remStu}
//我们可以发现数据和逻辑是在一起的,变得模块化了
//如果想要setup看起来更简洁,可以把一个功能直接抽成模块导出,在setup导入
- 如果给 reactive 传递了其他对象(指: 非 json 和 array 对象),此时,
修改对象则不更新
,需要通过重新赋值的方式。
3.2.3 ref
ref是vue3用于响应简单数据的方法:
特点: 是对原始数据进行赋值 ,修改时并不修改原始数据
import {ref} from "vue"
export default {
name: 'App',
// setup函数是组合API的入口函数
setup(){
// 1. 定义了一个名称叫做count变量, 这个变量的初始值是0
// 这个变量发生改变之后, Vue会自动更新UI
let count = ref(0);
// 2.在组合API中, 如果想定义方法, 不用定义到methods中, 直接定义即可
function myFn() {
//你知道这里为什么要通过.value来访问count吗?往下看就知道了
count.value += 1;
}
// 注意点:
// 3. 在组合API中定义的变量/方法, 要想在外界使用, 必须通过return {xxx, xxx}暴露出去
return{count, myFn}
}
}
为什么ref创建的数据要通过.value来访问count呢?
ref的本质
它的本质还是reactive,当我们给ref函数传递一个值时,ref函数会自动将ref转换成reactive
ref(0) --> reactive({
value:0
})
- 所以我们在
script
中修改ref创建的数据时,必须通过.value
来获取 - 需要注意的是,如果是通过ref创建出来的数据,
在template
中使用的时候不用通过.value来获取
。因为Vue会自动
给我们添加.value 。
vue是如何判断当前的数据是否是ref类型的?
通过当前数据的__v_ref来判断的,如果有这个私有的属性,并且取值为true,那么就代表是一个ref类型的数据。
开发者自己判断。isRef(数据),返回true或者是false。
import {isRef} from 'vue'
3.2.4 ref和reactive区别:
如果在template里使用的是ref类型的数据, 那么Vue会自动帮我们添加.value
如果在template里使用的是reactive类型的数据, 那么Vue不会自动帮我们添加.valueVue是如何决定是否需要自动添加.value的
Vue在解析数据之前, 会自动判断这个数据是否是ref类型的,
如果是就自动添加.value, 如果不是就不自动添加.valueVue是如何判断当前的数据是否是ref类型的
通过当前数据的__v_ref来判断的
如果有这个私有的属性, 并且取值为true, 那么就代表是一个ref类型的数据
import {isRef, isReactive} from 'vue'
...
setup() {
let age = ref(18);
let name = reactive({value: 'zs'});
function myFn() {
console.log(isRef(age));
console.log(isReactive(name));
}
return {age, name, myFn}
}
4.递归监听和非递归监听
4.1 递归监听
1. 默认情况下, 无论是通过ref还是reactive都是递归监听
每一层都监听
<template>
<div>
<p>{{state.a}}</p>
<p>{{state.gf.b}}</p>
<p>{{state.gf.f.c}}</p>
<p>{{state.gf.f.s.d}}</p>
<button @click="myFn">按钮</button>
</div>
</template>
<script>
import {reactive} from 'vue';
// import {ref} from 'vue';
export default {
name: 'App',
setup() {
let state = reactive({
a:'a',
gf:{
b:'b',
f:{
c:'c',
s:{
d:'d'
}
}
}
});
function myFn() {
state.a = '1';
state.gf.b = '2';
state.gf.f.c = '3';
state.gf.f.s.d = '4';
console.log(state);
console.log(state.gf);
console.log(state.gf.f);
console.log(state.gf.f.s);
}
return {state, myFn}
}
}
</script>
2.递归监听存在的问题
如果数据量比较大, 非常消耗性能
打印后,发现每一层对象都被包装为了Proxy对象,
如果数据量比较大, 非常消耗性能
4.2 非递归监听
使用shallowReactive
和shallowRef
shallowReactive:
<script>
// 3.非递归监听
import {shallowReactive} from 'vue';
export default {
name: 'App',
setup() {
let state = shallowReactive({
// let state = ref({
a:'a',
gf:{
b:'b',
f:{
c:'c',
s:{
d:'d'
}
}
}
});
function myFn() {
state.a = '1';
state.gf.b = '2';
state.gf.f.c = '3';
state.gf.f.s.d = '4';
console.log(state);
console.log(state.gf);
console.log(state.gf.f);
console.log(state.gf.f.s);
}
return {state, myFn}
}
}
</script>
再次打印输出结果,发现只有第一层被封装为了Proxy对象
,
但是第2, 3,4层数据为什么也发生了变化呢?
因为修改了第一层,它就去修改UI了
shallowRef:
注意点:
- 如果是通过shallowRef创建数据,
那么Vue监听的是.value的变化, 并不是第一层的变化 - Vue3只提供了triggerRef方法, 没有提供triggerReactive方法
- 所以如果是reactive类型的数据, 是无法主动触发界面更新的
triggerRef(state);
参考:B站李南江老师
上一篇: 警惕!孕妇经常熬夜的三大坏处
下一篇: 女性养生护发四大饮食技巧 拥有亮丽秀发
推荐阅读
-
[系列] go-gin-api 路由中间件 - 日志记录(三)
-
ElasticSearch实战系列三: ElasticSearch的JAVA API使用教程
-
循序渐进学.Net Core Web Api开发系列【4】:前端访问WebApi
-
循序渐进学.Net Core Web Api开发系列【5】:文件上传
-
Word/Excel文档操作API哪家强?一张表带你了解Aspose和Spire系列全功能对比
-
HBase 系列(六)——HBase Java API 的基本使用
-
Java日期时间API系列5-----Jdk7及以前的日期时间类TimeUnit在并发编程中的应用
-
Java日期时间API系列12-----Jdk8中java.time包中的新的日期时间API类,日期格式化,常用日期格式大全
-
Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析
-
Java日期时间API系列11-----Jdk8中java.time包中的新的日期时间API类,使用java8日期时间API重写农历LunarDate