vue3学习 4.toRaw
1.toRaw 获取原始数据不是引用关系 而是全等关系1.toRaw从Reactive或Ref中得到原始数据2.toRaw作用做一些不想被监听的事情(提升性能)let obj ={name:'zs',age:19}/*ref/reactive数据类型的特点:每次修改都会被追踪,都会更新UI界面,但是这样其实是非常消耗性能的所以如果我们有一些操作不需要追踪,不需要更新UI界面,那么这个时候,
·
1.toRaw 获取原始数据不是引用关系 而是全等关系
1.toRaw
从Reactive或Ref中得到原始数据
2.toRaw作用
做一些不想被监听的事情(提升性能)
let obj ={name:'zs',age:19}
/*
ref/reactive数据类型的特点:
每次修改都会被追踪,都会更新UI界面,但是这样其实是非常消耗性能的
所以如果我们有一些操作不需要追踪,不需要更新UI界面,那么这个时候,
我们就可以通过toRaw方法拿到它的原始数据,对原始数据进行修改
这样就不会被追踪,这样就不会更新UI界面,这样性能就有提高了
*/
let state =reactive(obj)
let obj2 =toRaw(state) //toRaw作用是获取原始数据
//这里 如果获取的是ref的类型的值 则toRaw则要加上.value 才能获取到正确的值 如
let a = {name:'aa',age:19}
let b = ref(a)
let c = toRaw(b.value) //这样才可以获取到正确的值 c 才===与 a
console.log(obj === obj2) //true
console.log(obj === state) //false
// state和obj的关系:
// 引用关系, state的本质是一个Proxy对象,在这个Proxy对象中引用了obj 所以 如果修改了obj的name的值 state里面的值也改变了
//在组合API中 如果想定义方法不用定义到methods里直接定义就能用(但是要暴露出去)
function myFn(){
//如果直接修改obj那么是无法触发界面更新的
//只有通过包装之后的对象来修改,才会出发界面的更新 也就是只有修改state页面才会更新渲染
obj.name='ls'; //页面不会更新 虽然数据变化了
console.log(obj) // {name:'ls'}
console.log(state) // {name:'ls'}
}
//注意点:
//组合API中定义的变量/方法,要想在外面使用 必须通过return {xxx,xxx}暴露出去
return{count,state,myFn}
markRaw 让数据不会被追踪(即使数据改变了 页面也不会渲染)
让数据不会被追踪 页面不会渲染
setup(){
let obj ={name:'zs',age:19}
obj = markRaw(obj) //markRaw 让这个数据永远不会被追踪 这样的话
//就算方法里面已经更改了name的值变成ls 但是不会被追踪所以页面也就不会被渲染
let state =reactive(obj)
function myFn(){
state.name='ls'; //页面不会更新 虽然数据变化了
console.log(state.name)
}
//注意点:
//组合API中定义的变量/方法,要想在外面使用 必须通过return {xxx,xxx}暴露出去
return{state,myFn}
},
toRef 让把原始数据和现在关联起来 这样修改数据 原始数据也会变化(但是UI层面不会变 不会渲染)
setup(){
let obj ={name:{name1:'asd'},age:19}
// ref(obj.name) -> ref('zs') -> reactive({name:'zs'})
//ref -> 复制 只是把值拿出来了 所以ref的时候修改后的数据影响不到原来的数据 初始化的数据还是原来的
// let state =ref(obj.name)
let state =ref(obj.name)
//toRef的本质是一个引用内存地址 所以修改了现在的数据会影响到以前的数据
// let state =toRef(obj,'name')
/**
* ref和toRef的区别:
* ref是复制 修改响应式数据不会影响以前的数据
* toRef是一个引用 修改响应式数据会影响以前的数据
* ref->数据会发生改变界面会自动更新
* toRef->数据发生改变页面不会自动更新
*
* toRef应用场景:
* 如果想让响应式数据和以前的数据关联连起来,并且更新响应式数据之后还不想更新UI,那么就可以使用toRef
*/
console.log(state)
function myFn(){
state.value='ls';
/**
* 结论:如果利用ref将某一个对象中的属性变成响应式的数据
* 我们修改响应式的数据是不会影响到原始数据的 原来的数据不会变(obj里面的数据值不变)
*/
/**
* 结论:如果利用toRef将某一个对象中的属性变成响应式的数据
* 我们修改响应式的数据是会影响到原始数据的
* 但是如果响应式的数据是通过toRef创建的,那么修改了数据并不会触发UI界面的更新
*/
console.log(obj)
console.log(state)
}
//注意点:
//组合API中定义的变量/方法,要想在外面使用 必须通过return {xxx,xxx}暴露出去
return{state,myFn}
},
toRefs 作用和toRef一样 只不过可以传递多个参数
setup(){
let obj ={name:'zs',age:19}
let state =toRefs(obj,'name','age')
function myFn(){
state.name.value='ls';
state.age.value=20;
console.log(obj)
console.log(state)
}
//注意点:
//组合API中定义的变量/方法,要想在外面使用 必须通过return {xxx,xxx}暴露出去
return{state,myFn}
},
customRef 返回一个ref对象,可以显式的控制依赖追踪和触发响应
dd
<template>
<div>
<p>{{age}}</p>
<button @click="myFn">按钮</button>
</div>
</template>
<script>
import {ref,reactive,toRaw,markRaw,toRef,toRefs, customRef,} from 'vue'
//ref需要注意: ref只能监听简单类型的变化,不能监听复杂类型的变化(对象 数组).
//如果要监听复杂类型的变化 要用reactive
function myRef(value) {
//自定义一个customRef方法 相当于自定义了一个ref方法
//里面的track是追踪的意思 放在get里 就是告诉这个方法 这个值需要追踪
//trigger 意思是触发 高速vue 这个值需要触发 才能更新页面渲染 不然页面不会盖面
return customRef((track,trigger)=>{
return {
get(){
track()//告诉vue,这个数据是需要追踪变化的
console.log('get',value)
return value
},
set(newvalue){
console.log('set',newvalue)
value = newvalue
trigger(); // 高速vue 触发界面更新
}
}
})
}
export default {
name: 'App',
components: {
},
setup(){
//customRef
//返回一个ref对象,可以显示的控制依赖追踪和触发响应
// let age = ref(18) // reactive({value:18})
let age = myRef(18)
function myFn(){
age.value+=1;
}
//注意点:
//组合API中定义的变量/方法,要想在外面使用 必须通过return {xxx,xxx}暴露出去
return{age,myFn}
},
}
es6 获取本地文件数据的方法
自定义customRef里面调使用异步请求方法调用接口
ref 获取元素的理解 setup里面执行别的生命周期注意时机
在vue2中我们可以通过给元素添加ref="aa" 然后在代码中通过refs.aa获取到元素
在vue3中 我们也可以通过ref来获取元素
/**
* setup在beforeCreate之前执行
*/
setup(){
let box = ref(null) //自动转化reactive({value:'zs'})
//onMounted 执行时机 在setup方法里面 但是生命周期在beforeCreate 之前 更在mounted之前 所以先打印下面的 在打印 onMounted这个
onMounted(()=>{
console.log('onMounted',box.value)
})
console.log(box.value)//null
return{box}
},
readonly :只读 让属性的值不能被修改
readonly 是深拷贝 所有数据的值都不能修改 shallowReadonly是浅拷贝 只有最顶层不能修改 深层的可以修改属性的值
const的区别下面写了
setup(){
//const 赋值保护,不能重新赋值 (不能修改基本类型或者复杂类型里面的属性的值!)
//readonly 属性保护,不能重新复制 (不管是基础类型还是复杂类型 不能修改const xxx 的这个xxx不能被修改)
//readonly 用于创建一个只读的数据, 并且是递归只读 下面的方法调用后 里面数据都不会发生变化
// let state = readonly({
// name:'zs',
// attr:{
// age:18,
// height:180,
// },
// })
//shallowReadonly 创建的数据只有表层是只读 不递归只影响首层 触发方法后下面的数据会发生变化 shallow== 浅的意思
let state = shallowReadonly({
name:'zs',
attr:{
age:18,
height:180,
},
})
const value = 123;//这里用const创建的数据也是只读 但是只能是简单类型
const obj = {name:'zd',age:19} //这里就算用const 创建的数据 虽然不能修改obj 但是能修改obj.name 或者obj.age 因为这里
function myFn() {
// state.name = 'zhibo'
// state.attr.age = 20
// state.attr.height = 2000
// value = 456 //会报错
// console.log(value) //报错 所以不执行
obj.name = 'ls' //这里是可以修改成功的
console.log(obj) //这里打印出{name: "ls", age: 19}
}
return{state,myFn}
},
响应式数据的本质 把对象包装成Proxy 变成响应式数据 手写一些方法
1,vue3响应式数据的本质
-在vue2中是通过defindProperty来实现响应式数据的
详见:手写vue全家桶视频
-在vue3中是通过Proxy来实现响应式数据的
// let obj = { name: 'zs', age: 18 }
let arr = [1,3,5]
let state = new Proxy(obj,{
get(obj, key) {//获取值
console.log(obj,key) //{name:'zs',age:18} //[1,3,5] 1
return obj[key]
},
set(obj,key,value) {//修改值
console.log(obj)// [1,3,5,7]
console.log('更新了数据并且更新UI界面')
obj[key] = value
return true //这里加上return true 是为了高速回调函数 赋值完成了 不然外面不知道是否完成
//就不会继续执行其他方法(如果是数组的push方法 不仅要修改数据还要修改length的值 所以会进来两次)
}
})
state.push(7)
// console.log(state.name)
function shallowRef(val) {
//只能监听到最外层value 的值 如果传递来是个对象 是不会监听到
return shallowReactive({value:val})
}
function shallowReactive(obj) {
//可以监听到数据内部的改变 使obj变成动态数据
return new Proxy(obj, {
get(obj,key) {
return obj[key]
},
set(obj,key,value) {
obj[key] = value
return true
},
})
}
function ref(val) {
//只能监听到最外层value 的值 如果传递来是个对象 是不会监听到
return reactive({value:val})
}
function reactive(obj) {
//可以监听到数据内部的改变 使obj变成动态数据
if (typeof obj === 'object') {
if (obj instanceof Array) {
//如果是一个数组,那么驱逐数组中的每一个元素,
//判断每一个元素是否又是一个对象,如果又是一个对象 那么也要包装成Proxy
obj.forEach((item, index) => {
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) {
return obj[key]
},
set(obj,key,value) {
obj[key] = value
return true
},
})
} else {
console.log(`${obj}不是一个对象`)
}
}
function shallowReadonly(obj) {
return new Proxy(obj, {
get(obj, key) {
return obj[key]
},
set(obj, key, value) {
// obj[key] = value
// return true
console.warn(`${key} 是只读属性不能修改`)
},
})
}
更多推荐
已为社区贡献1条内容
所有评论(0)