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} 是只读属性不能修改`)
         },
    })
}
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐