一、vite初始化项目
# 创建vite项目,选择vue -> 选择vue-ts
npm init @vitejs/app myProject
# 进入项目
cd myProject
# 安装依赖
npm install
# 启动项目
npm run dev
二、Composition API(常用部分)
2.1setup和ref
- setup是组合api中第一个要使用的函数
- setup是组合api的入口函数
- ref对象是一个函数,作用是定义一个响应式数据,返回一个ref对象,对象中有一个value属性,如果需要对修改,可以修改value
- ref可以获取页面中的元素const inputRef = ref<HTMLElement | null>(null)
- html是不需要用count.value取数据的,直接count就可以
setup(){
//变量
//const number = 10 // 此时还不是相应数据
const count = ref(0) // ref对象是一个函数,作用是定义一个响应式数据,返回一个ref对象,对象中有一个value属性,如果需要对修改,可以修改value
//方法
function updateCount(){
count.value ++
}
//返回一个对象
//把变量和方法都暴露出去
return {
count,
updateCount
}
}
setup执行的时机
- setup是beforeCreate声明周期回调之前就执行了,而且执行一次
- 由此可以推断出,在setup执行的时候,当前的组件还没有创建,也就意味着:组件实例对象this根本就不能使用
- this是undefined,说明,就不能通过this再去调用data/computed/methods/props中的相关内容了
- 其实所有的composition API相关回调函数中也都不可以
setup返回值 - setup中的返回值是一个对象,内部的属性和方法是给html模板使用
- setup中的对象内部的属性和data函数中的return对象的属性都可以在html模板中使用
- setup中的对象中的属性和data函数中的对象中的属性会合并为组件对象的属性
- setup中的对象中的方法和methods对象中的方法会合并为组件的方法
- 在vue3中尽量不要混合使用data\setup\method\setup
- setup不能是一个async函数:因为返回值不再是return的对象,而是promise,模板看不到return对象中的属性数据
setup中的参数
setup(props,context){
// props参数,是一个对象,里面有父级组件向子集组件传递的数据,并且在子集组件中使用prop接收到的所有的属性
// 包含props配置声明且传入了的所有属性的对象
// context参数,是一个对象,里面有attar对象(获取当前组件标签上的所有的属性的对象,但是该属性是在props中没有声明接收的所有的需要的对象),emit方法(分发事件),slots对象(插槽)
// 包含没有在props配置中声明的属性的对象,相当于this.$attrs
}
2.2reactive的使用
- 作用:定义一个响应式复杂数据
- 使用proxy实现,通过代理对象操作源对象内部数据都是响应式的
- const proxy = reactive(obj): 接口一个普通对象然后返回该普通对象的响应式代理器对象。
- 响应式转换是‘深层的’:会影响对象内部所有嵌套的属性
setup(){
// 把复杂数据变成响应式数据
// 返回的是一个Proxy的代理对象,被代理者的对象就是obj对象
// user现在式代理对象,obj式目标对象
const obj = {
name:'小明',
age:20,
wife:{
name: '小红',
age: 18
}
}
const user = reactive(obj)
// 方法
const updateUser = () =>{
// 直接使用目标对象的方式来更新目标对象中的成员值,式不可能的,只能使用代理对象更新目标对象
user.name = '小小'
obj.gender = '男' //界面不会更新
}
return {
user,
updateUser
}
}
// user对象或者obj对象添加一个新的属性,删除一个新的属性
// === 添加
// 对obj操作界面没有变化,对user操作界面会变化,obj确实变化啦
// 对user操作,obj也会会更新值,界面变化
细节:
2.3vue2和vue3的响应式
vue2的响应式
核心:
- 对象:通过defineProperty对对象的已有的读取和修改进行拦截(监听和拦截)
- 数据:通过重写数组更新数组一些列更新元素的方式来实现元素修改的劫持
Object.defineProperty(data,'count',{
get(){},
set(){}
})
问题:
- 对象直接新添加的属性或者删除已有属性,界面不会自动更新
- 直接通过下标替换元素或者更新length,界面不会自动更新arr[1] = {}
- 所有有了后来的$set()方法实现响应式
vue3的响应式
核心:
- 通过Proxy(代理):拦截对data任意属性的操作,包括属性值的读写,属性的添加、属性的删除等
- 通过Reflect(反射):动态对被代理对象的相应属性进行特定的操作
new Proxy(data,{
//拦截获取属性值
get(target,prop){
return Reflect.get(target,prop)
},
//拦截设置属性值
set(target,prop,value){
return Reflect.set(target,prop,value)
}
})
2.4ref和reactive
- 重要的响应式API(ref和reactive)
- ref用来处理基本类型数据,react用来处理对象(递归深度响应式)
- 如果ref对象/数组,内部会自动将对象/数组转换为reactive的代理对象
- ref内部:通过给value属性添加getter/setter来实现对数据的劫持
- reactive内部:通过proxy来实现对对象内部所有数据的劫持,并通过Reflect来更新源目标对象
- ref的数据操作,在js中要.value,在模板中不需要(内部自动解析)
2.5计算属性和监视
setup(){
firstName:'东方',
lastName:'不败'
const fullName = computed(() => {
return user.firstName + '_' + user.lastName
})
const fulName3 = ref('')
//监视指定数据
watch(user,(firstName,lastName)=>{
fullName3.value = firstName + '_' + lastName
},{immediate:true,deep:true})
// immediate默认执行一次,deep深度监视
//监视,不需要配置immediate,本身默认就会进行监视,默认执行一次
watchEffect(() => {
fullName3.value = user.firstName + '_' + user.lastName
})
// watch可以监视多个数据,如果不是响应式数据需要回调的方式
watch([()=>firstName,()=>lastName,()=>fullName3],()=>{
})
return {
user,
fullName,
fullName3
}
}
2.6声明周期对比
2.6.1与2.0的声明周期对应的组合API
- beforeCreate -> setup()
- created -> setup()
- beforeMount -> onBeforeMount
- mounted -> onMounted
- beforeUpdate -> onBeforeUpdate
- updated -> onupdated
- beforeDestroy改名啦 -> onBeforeUnmount
- destroyed改名啦 -> onUnmounted
- errCaptured -> one rrorCaptured
2.6.2 新增钩子函数
- onRenderTracked
- onRenderTriggred
- 两个钩子函数都接收一个DebuggerEvent,与watchEffect参数选项中的onTrack和onTrigger类似
onMounted(()=>{
console.log()
})
2.7hook函数自定义
- 类似于axios封装
2.8toRefs
- 把一个响应式对象转换成普通对象,该普通对象的每个property都有一个ref
- 应用: 当从合成函数返回响应式对象时,toRefs非常有用,这样消费组件就可以在不丢失响应式的情况下,返回对象进行分解使用
setup(){
const state = reactive({
name: '自来也',
age: 47
})
const {name,age} = toRefs(state)
setInterval(()=>{
name.name += '=='
},2000)
return {
...state, // 不是响应式的数据
name,
age
}
}
三、Composition API(其他部分)
3.1 shallowReactive 与 shallowRef
- shallowReactive 浅劫持:只处理了对象内最外层属性的响应式
- shallowRef 浅劫持: 只处理了value的响应式,不进行对象的reactive处理
- 如果一个对象数据,结构比较深,但变化时只是外层属性变化 shallowReactive
- 如果一个对象数据,后面会产生新的对象来替换 shallowRef
3.1 readonly和shallowReadonly
- readonly 深度只读
- shallowReadonly 浅只读的
3.2 toRaw和markRaw
- toRaw 把代理对象变成普通对象,数据变化,界面不变化
- markRaw 标记的对象数据,从此以后再也不能成为代理对象啦
3.3 toRef和ref
- ref---->复制,修改响应式数据不会影响原始数据
- toref---->引用,修改响应式数据,会影响原始数据
- ref------>数据发生改变,界面就会自动更新
- toref-----> 数据发生改变,界面也不会更新
- torefs是影响多个参数
3.4 customRef
(1) customRef 用于自定义返回一个ref对象,可以显式地控制依赖追踪和触发响应,接受工厂函数
(2) 两个参数分别是用于追踪的 track 与用于触发响应的 trigger,并返回一个一个带有 get 和 set 属性的对象
function useDebouncedRef(value) {
return customRef((track, trigger) => {
return {
get() {
track() 追踪当前数据
return value
},
set(newValue) {
value=newValue
trigger() 触发响应,即更新界面
},
}
})
}
通过customRef返回的ref对象,和正常ref对象一样,通过x.value修改或读取值
3.5 provide和inject
- 作用:用于父组件向子孙组件传递数据
- 使用方法:provide在父组件中返回要传给下级的数据,inject在需要使用这个数据的子辈组件或者孙辈等下级组件中注入数据。
- 使用场景:由于vue有$parent属性可以让子组件访问父组件。但孙组件想要访问祖先组件就比较困难。通过provide/inject可以轻松实现跨级访问父组件的数据
3.6 响应式判断
- isRef:检查一个值是否为一个ref对象
- isReactive:检查一个值是否为一个reactive创建的响应式对象
- isReadonly:检查一个值是否为一个readonly创建的只读代理
- isProxy:检查一个值是否为一个reactive或者readonly方法创建的代理
四、Composition API(新)
4.1 Fragment
- vue2中必须有一个根组件,vue3不需要
4.2 Teleport瞬移
- 提供一种干净的方法,让组件的html在父组件界面外的特定标签
<Teleport to="body">
</Teleport>
4.3 Supense不确定
- 他们允许我们的应用程序在等待异步组件时渲染一些后备内容,可以让我们创建一个平滑的用户体验
- 骨架屏