---
theme: smartblue
---
## 创建vue3项目
1.首先node的版本在4.5以上<br/>
2.直接用vue-cli来创建vue3项目vue create project\_name
## 正式学习
### 一、常用Componention(组合式) Api
> setup
1. 组件中所用到的数据,方法,对象中的属性都写在setup中
2. setup中有两种返回值:对象和函数
3. **若返回一个对象,则对象中的属性、方法、在模板中均可以直接使用**
4. 若返回一个渲染函数:则可以自定义渲染内容。
//返回一个对象
return {
name,
age,
sayHello
}
// 返回一个函数
return ()=>{ // h是渲染哈描述,要是用的花,需要引入
return h('h1','张三')
} ```
5. setup不是async函数,因为返回值不再是return,而是promise.
6. setup的参数
* props:值为对象,包含组件外部传递过来,且组件内部声明接受了的属性
* context:上下文对象
* attrs:值为对象,包含:组件外部传递过来,但没有props配置中声明的属性
* slots:接受插槽内容,相当于this.\$slot.
* emit:分发自定义事件的函数,相当于this.\$emit
7. 注意点:
* 尽量不要和vue2混用
* vue2配置(data,methods,computed...)中可以访问到setup中的属性,反之不行
* 如果重名,setup优先级高
* setup比beforeCreate先执行,this是undefined.
> ref (实现vue3的响应式)
1. ref的返回体
![img_1.png](https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2287d4bf95054fa58b5899154e4c638b~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=1236&h=1009&s=116621&e=png&b=ffffff)
2. ref的代码使用
````angular2html
<template>
<div>
<h1>一个人的信息</h1>
<h2>名字:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<h2>工作:{{job.type}}</h2>
<h2>薪资:{{job.salary}}</h2>
<button @click="changeInfo">改变信息</button>
</div>
</template>
<script>
import {ref} from 'vue'
export default {
name: 'App',
props: {
},
setup(){
let name = ref('张三')
let age = ref(18)
let job = ref({
type :'前端开发',
salary:'30k'
})
// 返回一个对象
function changeInfo(){
// name.value = '李四'
// age.value = 38
console.log(job.value)
job.value.type = 'java开发'
job.value.salary = '40k'
}
return {
name,
age,
changeInfo,
job
}
}
}
</script>
```
3. ref 可以接受基本类型,对象类型
* 对基数据类型使用数据劫持(object.defineProperty()中的get set )来实现响应式;
* 对于对象类型的数据(复杂数据类型)使用了新的特性—— reactive函数。
4. reactive 函数
* 作用:定义一个**对象类型**的响应式数据(基本类型用ref)
* 代码使用
```vue
let job = reactive({
type :'前端开发',
salary:'30k'
})
console.log(job)
job.type = 'java开发'
job.salary = '40k'
````
![img_2.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e6e792702d6c4aebb3fb2df6d4ffbc9a~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=1239&h=534&s=55539&e=png&b=fefefe)
> Vue3.0中的响应式原理
1. vue2.0的响应式原理
* 实现原理
* 对象类型:通过object.defineProperty()对属性的读取、修改进行拦截(**数据劫持**)
* 数组类型:通过重写更新数组的一系列方法来实现拦截(对数组的变更进行了包裹)
<!---->
// 模拟数据
let person={
name:'张三',
age:10
}
//模拟vue2中实现响应式
let p = {}
Object.defineProperty(p,'name',{
get(){
return person.name
},
set(value){
console.log('有人修改了name属性,我去更新')
return person.name = value
}
})
Object.defineProperty(p,'age',{
get(){
return person.age
},
set(value){
console.log('有人修改了age属性,我去更新')
return person.age = value
}
})
![img_3.png](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2f26e4a10eac4261bdf7994c64bcd676~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=1204&h=797&s=55718&e=png&b=ffffff)
* 存在的问题:
* 新增属性、删除属性、界面不会更新(使用$set和$delete解决)
* 直接通过下标修改数组、界面不会自动更新(\$set,splice)
2. Vue3.0的响应式
* 实现原理:
* 通过**proxy(代理)**:拦截对象中任意属性的变化,包括:属性的读写、属性的添加、属性的删除等
* 通过**Reflect(反射)**: 对代理对象的属性进行操作
* **代码**:
```angular2html
//模拟vue3中实现响应式
//window.proxy
const p = new Proxy(person,{
get(target,propName){
console.log(`有人读取了p身上的${propName}属性`)
return Reflect.get(target,propName)
},
//修改和追加某个属性时会调用
set(target,propName,value){
console.log(`有人修改了p身上的${propName}属性,我要去更新页面`)
Reflect.set(target,propName,value)
},
deleteProperty(target, propName) {
console.log(`有人删除了p身上的${propName}属性,我要去更新页面`)
return Reflect.deleteProperty(target,propName)
}
})
```
> vue3.0计算属性与监视
1. 与vue2中computed配置功能一致
2. 代码
<!---->
setup(){
let person = reactive({
firstName : '张',
lastName :'三',
})
//计算属性-简写(没有考虑计算属性被修改的情况)
person.fullName = computed(()=>{
return person.firstName + '-' + person.lastName
})
//计算属性-完整写法
let fullName = computed({
get(){
return person.firstName + '-' + person.lastName
},
set(value){
const nameArr = value.split('-')
person.firstName = nameArr[0]
person.lastName = nameArr[1]
}
})
> watch函数
1. 与Vue2.x中watch配置功能一致
2. 代码
```vue
//情况一:监视ref所定义的一个响应式数据
/* watch(sum,(newValue,oldValue)=>{
/ console.log('sum或者msg变了',newValue,oldValue)
},{immediate:true,deep:true})*/
//情况二:监视ref所定义的多个响应式数据
/* watch([sum,msg],(newValue,oldValue)=>{
console.log('sum或者msg变了',newValue,oldValue)
},{immediate:true,deep:true})
*/
//情况三:监视reactive所定义的一个响应式数据,
// 注意:1.此处无法正确的获取oldValue 2.强制开启了深度监视,deep:false无效
// watch(person,(newValue,oldValue)=>{
// console.log('person变化了',newValue,oldValue)
// })
//情况四:监视reactive所定义的响应式数据中的某个属性
watch(()=>person.name,()=>person.age,(newValue,oldValue)=>{
console.log('person的name变化了',newValue,oldValue)
```
3.注意
* 监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置失败)
* 监视reactive定义的响应式数据中的某个属性时:deep配置有效
> watchEffect函数
1. watch:既要指明监视的属性,也要指明监视的回调
2. watchEffect:不用指明监视哪个属性,监视的回调用到哪个属性,那就监视哪个属性。
3. watchEffect有点像computed
4. 代码
```vue
watchEffect(()=>{
const x1 = sum.value
const x2 = person.job.j1.salary
console.log('watchEffect所指的回调函数执行了')
})
```
> 生命周期
1. **beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeUnmount、mounted**
2. 组合式api所对应的名称:**setup(),setup(),onBeforeMount,onMounted,onBeforeUpdate,onUpdate,onBeforeUnmount,onUmounted**
3. 组合式api的优先级更大一点。
> 自定义hook函数
1. hooks:本质上是一个函数,把setup函数中使用的Composition API进行了封装。
2. 类似于vue2中的mixin
3. hooks的优势:复用代码,让setup中的逻辑清晰易懂。
> toRef(把什么变成ref)
1. 作用:创建一个ref对象,其value指向另一个对象中的某个属性
2. 语法:const name = toRef(person,'name')
3. 应用将响应式对象中的某个属性单独提供给外部使用
4. toRefs与toRef功能一致,但可以创建多个ref对象,语法toRefs(person)
### 二、其它Componention(组合式) Api
> shallowReactive 和shallowRef
1.shallowReactive:只能处理对象最外层属性的响应式(浅响应式)
2.shallowRef:只能处理基本数据类型的响应式,不进行对象的响应式处理
3.when to use?
* 如果有一个对象数据,结构比较深,但是变化时只是外部属性变化===》shallowReactive
* 如果有一个对象数据,后续功能不会修改对象中的属性,而是生新的对象来替换===》shallowRef
> readonly 和 shallowReadonly
1.readonly:让一个响应式数据变为只读(深只读)
2.shallowReadonly:让一个响应式数据变为只读(浅只读)
> toRaw 与 markRow
1. toRaw:
* 作用:将一个由reactive生成的响应式对象转为普通对象
* 使用场景:用于读取响应式对象的普通对象,对这个普通对象的所有操作,不会引起页面更新
2. markRow:
* 标记一个对象,使其永远不会在成为响应式对象
* 应用场景:
1. 有些值不应设置为响应式的,例如复杂的第三方类库等
2. 当渲染具有不可变数据源的大列表时,跳过响应式转换可以调高性能
> customRef
1. 作用:创建一个自定义的ref,并对其依赖项跟踪和更新触发进行显示控制。
2. 实现防抖效果:
```vue
function myRef(value,delay){
let timer
// console.log('---myRef---',value)
return customRef((track,trigger)=>{
return{
get(){
console.log(`有人从myRef这个容器中读取数据了,我把${value}给他了`)
track()//通知vue追踪value的变化
return value
},
set(newValue){
console.log(`有人把myRef这个容器中数据改为了${newValue}`)
clearTimeout(timer)
setTimeout(()=>{
value = newValue
trigger()//通知vue重新解析模板
},delay)
}
}
})
}
let keyWord = myRef('hello',500)
return {
keyWord
}
```
> provide与inject
* 作用:实现祖孙组件之间的通信
* 代码
```vue
//父组件
setup(){
let car = reactive({
name:'奔驰',
price:'40w'
})
provide('car',car)//给自己的后代传入数据
return{
...toRefs(car)
}
}
//子组件
setup(){
let car = inject('car')
return {
car
}
}
}
```
### 三、Componention(组合式) Api 的优势
1. Option Api存在的问题:使用传统的配置式的api,新增或者修改一个需求,就需要分别在data,methods,computed里修改。
2. Composition API优势:更加优雅的组织代码,函数。让相关功能的代码更加有序的组织在一起。