Vue3知识点总结
vue2与vue3 渲染性能区别:diff 优化:https://vue-next-template-explorer.netlify.appvue2对虚拟DOM 是进行一个全局对比vue3新增了静态标记(PatchFlag)生成DOM树时,只会对动态渲染的DOM数据添加标识,下次数据变化的时候只需要对有标记的DOM进行比对,并且可以同归flag的信息得知当前节点要对比的内容hoistStatic
vue2 与 vue3 渲染性能区别:
diff 优化: https://vue-next-template-explorer.netlify.app
vue2 对虚拟DOM 是进行一个全局对比
vue3 新增了静态标记(PatchFlag)
生成DOM树时,只会对动态渲染的DOM数据添加标识,下次数据变化的时候只需要对有标记的DOM进行比对,
并且可以同归flag的信息得知当前节点要对比的内容
hoistStatic 静态提升:
vue2 无论DOM元素是否参与更新,都会重新创建,进行渲染
vue3 对不参与更新的DOM元素,会提出静态提升,只会创建一次,渲染时进行复用
cacheHandlers 事件侦听器缓存:
默认情况下onClick被视为动态监听,每次都会追踪变化,但是因为是同一个函数,不需要追踪变化,所以缓存起来使用即可。
vue 点击事件中加括号与不加括号的区别:
- 不加括号默认第一参数为event
- 加括号需要手动传入$event才能获得事件对象
vue Composition API 与 Option API
- Option API:vue2 的data定义数据方式以及methods 声明方法;
- Composition API的 在setup中定义数据暴露注入data中、定义方法暴露注入methods中,以供使用.
vue3 setup
1:执行顺序 生命周期
- setup
- beforeCreate 表示组件刚刚创建,data和methods还没有初始化
- created 表示组件刚刚创建,data和methods已经初始化
- beforeMount 修改数据触发
- renderTracked 跟踪虚拟 DOM 重新渲染时调用
- unmounted 第一次进入页面不会触发,修改数据触发
- mounted 修改dom节点触发
- beforeUpdate 第一次进入页面不会触发,修改dom节点触发
- updated 第一次进入页面不会触发,修改dom节点触发
2: setup注意点 - 由于执行setup函数时,还没有执行created,所以在setup函数中,是无法使用data中的数据以及methods中的方法
- 由于不能再setup函数中使用data和methods,vue为避免错误使用,会直接将setup函数中的this定义为undefined
- setup函数只能是同步不能是异步,无法使用async awit。
vue3 reactive | ref
- ref、reactive是vue3实现响应式数据的方法
- vue2中响应式是通过defineProperty()来实现的
- vue3中响应式是通过es6中的Proxy()来实现的
- ref底层的本质还是 reactive,系统会自动根据给ref传入的值将其转换成ref(x) -> reactive({value:x})
- ref在vue中使用不需添加.value,在js/ts 中使用需要使用.value
注意点: ~ reactive参数必须是对象(json/arr)
~ 如果传递的是其他对象
修改对象,界面不会自动更新
如果要更新,必须重新赋值
~ 使用reactive类型的数据需要添加.value
reactive | ref 区别
- 在template中使用 ref 类型数据,vue会自动添加.value
- 在template中使用 reactive 类型数据,vue不会自动添加.value
vue如何判断是否添加.value
- vue在解析数据前,会自动判断当前数据是否为ref类型
- 如果是就添加,不是就不添加
vue如何判断当前数据是否为ref类型
通过当前数据的__v_ref来判断,如果有这个私有属性,并且取值为true,那么就代表是一个ref类型数据
默认情况下,reactive ref 都是递归监听;当数据量大时,十分消耗性能
shallowReactive,shallowRef,triggerRef
- shallowReactive 只监听跟踪对应的自身属性的反应式,不执行嵌套对象的深度反应式转换
- shallowRef 跟踪监听自身的.value突变,不会使其值具有反应性
- triggerRef 可以跟踪监听与shallowRef手动相关的任何变化
- 无triggerreactive API
在使用中 reactive | ref 类型的数据每次修改都会去跟踪并更新UI界面,但是这样其实很消耗性能的;
如果有些操作无需跟踪并且也不需要更新UI界面,那么就可以通过 toRaw() API获取元素数据,对原始数据进行修改,
这样就不会进行跟踪并且不会更新UI界面,对性能上就有所提升。
let obj = { name: 'lnj', age: 18 }
let state = reactive(obj)
let obj2 = toRaw(state)
obj 与 state 的关系: 引用关系,state 的本质是一个Proxy对象,在这个Proxy对象中引用了obj
obj.name = 'zs'
如果直接修改原始数据是不会更新UI界面,必须修改、使用包装后的数据才能更新UI界面。
let state1 = ref(obj)
let obj3 = toRaw(state1.value)
注意点: 如果需要通过 toRaw()获取 ref 类型的数据时,就必须要明确告诉 toRaw方法,所要获取的是.value 的值,
因为经过vue3 的处理,.value才是创建传入的元素数据
let obj3 = toRaw(state1.value) => let obj3 = toRaw(state1.value => obj)
ref toRef toRefs customRef
let obj = {name: 'lili'}
ref -> 复制 let state = ref(obj.name)
toRef -> 单个引用 let age = toRef(obj,'name')
toRefs -> 对象引用 let state = toRefs(obj)
customRef -> 创建自定义ref 返回一个ref对象,可以显式地控制依赖追踪和触发响应
function myRef(value){
return customRef((track,trigger)=>{
// 调用网络请求
return{
get(){
track(); // 告诉vue这个数据是需要追踪变化的
console.log('get',value);
return value;
// 注意点:
// 不能再get方法中发送网络请求
// 渲染界面 -> 调用get -> 发送网络请求
// 保存数据 -> 更新界面 -> 调用get
},
set(newValue){
console.log('set',newValue);
value = newValue;
trigger(); // 告诉vue 触发界面更新
}
}
})
}
区别:
ref -> 修改响应式数据,UI界面自动更新,但不会影响原始数据
toRef -> 修改响应式数据,UI界面不会更新,但会影响原始数据
使用: 如果需要响应式数据和原始数据关联,并且更新响应式数据后不更新UI,就可以使用 toRef
toRefs -> 在 toRef 的基础上,能够直接引入对象
使用: 与 toRef 等同
vue3 获取元素
eg: <div ref="box">我是123</div>
setup(){
let box = ref(null);
console.log(box.value) //null 无法获取
// 生命周期
onMounted(() => {
console.log('onMounted',box.value)
})
return{ box }
}
vue3 readonly 用于创建一个只读的数据,并且是递归只读
shallowReadonly 用于创建一个只读的数据,但不是递归只读
const: 赋值保护,不能给变量重新赋值
readonly: 属性保护,不能给属性重新赋值
vue3 响应式原理 Proxy
let state = new Proxy(obj,{
get(obj,key){
return obj[key];
},
set(obj,key,value){
// 需要return 一个返回值 告诉Proxy当前操作是否成功
return true;
}
})
// API 封装
function shallowReactive(obj){
return new Proxy(obj,{
get(obj,key){
return obj[key];
},
set(obj,key,val){
obj[key] = val
// 需要return 一个返回值 告诉Proxy当前操作是否成功
return true;
}
})
}
function shallowRef(val){
return shallowReactive({value:val})
}
function reactive(obj){
if(typeof obj === 'object'){
if(obj instanceof Array){
obj.forEach((item,, index) =>{
// 如果是数组,则取出数组中的,每一个元素,
// 判断每个元素是否是一个对象,如果是,那么需要包装成 Proxy
if(typeof item === 'object'){
obj[index] = reactive(item)
}
})
} else{
// 如果是一个对象,则取出对象属性的值,
// 判断对象属性的取值是否是一个对象,如果是,那么需要包装成 Proxy
for(let key in obj){
let item = obj[key];
if(typeof item === 'object'){
obj[key] = reactive(item)
}
}
}
return new Proxy(obj,{
get(obj,key){
if(key === '_is_reactive') return true
return obj[key];
},
set(obj,key,val){
obj[key] = val
// 需要return 一个返回值 告诉Proxy当前操作是否成功
return true;
}
})
} else {
console.warn(`${obj} is not object`);
}
}
function ref(val){
_is_ref = true;
target = reactive({value:val})
}
function shallowReadonly(obj){
return new Proxy(obj,{
get(obj,key){
return obj[key];
},
set(obj,key,val){
// obj[key] = val
// 需要return 一个返回值 告诉Proxy当前操作是否成功
// return true;
console.warn(`${key}是只读的,不能赋值`)
}
})
}
function readonly(obj){
if(typeof obj === 'object'){
if(obj instanceof Array){
obj.forEach((item,, index) =>{
// 如果是数组,则取出数组中的,每一个元素,
// 判断每个元素是否是一个对象,如果是,那么需要包装成 Proxy
if(typeof item === 'object'){
obj[index] = reactive(item)
}
})
} else{
// 如果是一个对象,则取出对象属性的值,
// 判断对象属性的取值是否是一个对象,如果是,那么需要包装成 Proxy
for(let key in obj){
let item = obj[key];
if(typeof item === 'object'){
obj[key] = reactive(item)
}
}
}
return new Proxy(obj,{
get(obj,key){
if(key === '_is_reactive') return true
return obj[key];
},
set(obj,key,val){
// obj[key] = val
// 需要return 一个返回值 告诉Proxy当前操作是否成功
// return true;
console.warn(`${key}是只读的,不能赋值`)
}
})
} else {
console.warn(`${obj} is not object`);
}
}
function isReactive(obj){
return obj && obj._is_reactive;
}
function isRef(obj){
return obj && obj._is_ref;
}
function isReadonly(obj){
return obj && obj._is_readonly;
}
function isProxy(obj){
return isReactive(obj) || isReadonly(obj)
}
更多推荐
所有评论(0)