1 setup函数
- 组件中所有的数据、方法均写在setup函数中
- 数据和方法直接定义在setup中,不在需要data,methods
- setup返回值如果是一个对象,可以在模版中直接使用,还可以返回一个渲染函数
- 尽量不要跟vue2混用,vue2可以访问vue3setup中的配置,vue3不能访问vue2的配置,如果冲突以vue3为主
- setup不能是async函数 ex:(下面写法会失去响应式)
setup(){
let a = 111
let b = 222
function sayHello(){
console.log(111)
}
return {
a,
b,
sayHello
}
}
注意点:
- setup执行时机比beforeCreate快,this是undefined
- setup接受2个参数(props,context)
- 1 props:值为对象,包含:组件外部传递过来且组件内部声明接收了的属性
- 2 context:上下文对象
2 ref函数
ref函数是帮助数据响应式,拿到的是一个ref引用对象,注意这种写法需要属性.value获取值,模版中直接用不需要.value,对象形式:obj.value.属性名获取值。ref对于基本类型通过Object.defineProperty(),get,set实现响应式,对于引用类型通过proxy处理。
setup(){
let a = ref(111)
let b = ref(222)
let c = ref({
name:'张三',
age:18
})
function sayHello(){
a.value = 456
c.value.name='李四'
}
return {
a,
b,
sayHello
}
}
3 reactive函数
reactive只对引用类型有效,不能处理基本类型,返回一个代理对象(proxy对象),直接可以通过obj.属性名拿到值。
4 回顾vue2响应式原理
- 对象
- 通过Object.defineProperty()对属性读取修改进行拦截(数据劫持)
- 数组
- 通过重写更新数组的一系列方法进行拦截(包裹数组更新方法)
存在问题
- 新增属性,删除属性界面不会更新
- 直接通过下标修改数组界面不会更新
Object.defineProperty(data,index,{
get(){},
set(){}
})
5 vue3响应式原理
- 通过proxy(代理):拦截对象中任意属性变化,包括属性读写,添加,删除等。
- 通过Reflect(反射):对代理对象属性进行操作。
let person = {
name:'章三',
age:18
}
const p = new Proxy(person,{
//读取属性时调用
get(target,propName){
// target=>person对象 propName=>属性名
return Reflect.get(target,propName)
},
//修改/追加 某个属性时调用
set(target,propName,value){
// value=>修改后的值
Reflect.set(target,propName,value)
}
//删除某个属性时调用
deleteProperty(target,propName){
return Reflect.deleteProperty(target,propName)
}
})
6 reactive与ref对比
- 定义数据角度
- ref用来定义基本数据类型,reactive用来定义对象(数组)类型数据。ref也可以用来定义对象(数组)类型数据,内部会通过reactive转为代理对象 2 原理角度
- ref通过Object.defineProperty()get,set实现响应(数据劫持)
- reactive通过Proxy(数据劫持),并通过Reflect来操作原对象内部的数据 3 使用角度
- ref定义数据,操作需要.value,在模版中直接使用
-
- reactive操作与读取均不需要.value
7 computed函数 && watch函数
computed:
setup(){
const person = {
firstName:'张',
lastName:'三'
}
person.fullName = conputed(() => `${firstName}${lastName}` )
return {
person,
}
}
watch:
setup(){
const person = {
name:'张',
age:18
}
const str = ref('hello')
const num = ref(0)
//监听一个值
wtach(num,(newVal,oldVal) => {
console.log(newVal)
})
//监听多个值
wtach([num,str],(newVal,oldVal) => {
console.log(oldVal) // [0,'hello']
})
//第三个参数 配置项
wtach([num,str],(newVal,oldVal) => {
console.log(oldVal) // [0,'hello']
},{immediate:true})
return {
num,
str,
person
}
}
注意:
- 1 watch监听一个reactive定义的对象类型,目前没办法拿到正确的oldvalue。
- 2 强制开启深度监听(deep属性无效,reactive监听一个对象的情况)( 如果监听的是一个对象中的某个属性,deep生效)
- 3 如果想监听对象中的某个属性,第一个参数写成函数并把这个属性作为返回值返回即可
wtach(()=>person.age,(newVal,oldVal) => {
//此写法监听age属性并且oldvalue不受影响
})
- 4 监听对象中的多个属性,第一个参数的回调返回值写在数组里
- 5 watch在监听基本类型数据时,不需要.value。在监听用ref监听的对象时,需要.value.属性名(这时监听的不再是ref定义的数据,而是ref求助reactive所定义的数据)或直接监听obj.value或这开启deep:true。
watchEffect函数
- watchEffect不用指明监听哪个属性,只要在回调函数中用到的属性都会监听。类似于computed,但computed更注重计算出的值,watchEffect更注重逻辑。
vue3生命周期
vue3可以继续使用vue2的生命周期钩子,但是有两个改名了
- beforeDestory => beforeUnmount
- destoryed => unmounted vue3也提供了组合式api形式的生命周期钩子
- beforeCreate => setup()
- created => setup()
- beforeMount => onBeforeMount
- mounted => onMounted
- beforeUpdate => onBeforeUpdate
- updated => onUpdated
- beforeDestroy => onBeforeUnmount
- destroyed => onUnmounted
- activated => onActivated
- deactivated => onDeactivated
toRef和toRefs
toRef与toRefs把数据变为响应式数据
setup() {
// toRefs
// const money = ref(100)
// const car = reactive({
// brand: '宝马',
// price: 1000000
// })
// const name = ref('zs')
const state = reactive({
money: 100,
car: {
brand: '宝马',
price: 1000000
},
name: 'zs'
})
return {
// money,
// car,
// name
...toRefs(state) //ES6扩展运算符,会取消双向数据绑定的特性,使用toRefs(),转为响应式数据
}
}
toRaw和markRaw
- 我们更新数据不需要改变界面,就可以用toRaw和markRaw
- toRaw将一个reactive生成的响应式对象转为普通对象(不支持)
- markRaw会将一个对象永远变成不是响应式的对象 customRef用来自定义一个响应式数据