最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 初探Vue3.0--响应式api理解~

    正文概述 掘金(MFYNGUFD)   2021-02-24   567

    掘金的第一篇文章献给vue3.0,

    组合api(Composition API)

    最大的感受,组合api是将具有独立功能的函数封装组合在一起,提高复用性; 后来实际封装了相关功能,变量较多的情况下,设计高内聚的功能是非常必要的

    demo 学生和教师显示

    分别用vue2.x以及vue3.x进行了学生列表和老师列表的展示,其代码功能分部图如下图所示

    vue2.x 学生和老师展示代码功能图 初探Vue3.0--响应式api理解~

    vue 3.x! 学生和老师展示代码功能图 初探Vue3.0--响应式api理解~ 其中不同颜色表示页面中两个功能的代码分布;

    • 对于vue2.x而言,主要分为三个部分
      • data中的数据定义
      • methods中的方法定义
      • 视图使用
    • 对于Vue3.x而言
      • 学生、老师中的变量和功能定义
      • setup中引用功能
      • 视图使用

    根据颜色而言,其实vue2.x的功能相对而言是比较分散的,而vue3.0中的功能和数据定义可以定义在一个函数中,功能比较集中;因此在进行组合性api的是时候是需要思考如何设计是比较合理的;vue3.x在功能上能够实现高度的一个复用,想到vue.mixin的方法,实现代码的复用;

    响应式数据定义

    响应式数据是实现mvvm非常重要的一个部分,在vue3.x中,在支持data方式定义响应式的数据外,还提供很多可自定义的api;

    在响应式的数据中值得注意的部分 深层次响应还是浅层次响应;

    reactive

    • vue3中提供实现响应式数据的方法
    • vue2中响应式数据是通过Objec.defineProperty\color{red}{Objec.defineProperty}Objec.defineProperty 来实现的,而在vue3中数据通过es6的Proxy\color{red}{Proxy}Proxy来实现的,

    reactive使用

      setup(props) {
         let state =reactive({
            msg:{
              name:'mafe',
              age:24, 
            },
            time: new Date(), //只能进行 赋值更新
            list:[
              {name:'mfy'},
              {name:'mfy1'},
              {name:'mfy2'},
            ]
         })
         function changeName(){
           //定义的是对象能够直接修改赋值
           state.msg.name = '333'
            //无法更改state中time的赋值对象 
           // state.time.setDate(state.time.getDate()+1)
           let newDate =new Date(state.time.getTime())
           newDate.setDate(state.time.getDate()+1) 
           state.time = newDate ;//不是对象类型 只能修改数据内容
         }
         return  {
           state,
           changeName
         }
      }
    
    

    初探Vue3.0--响应式api理解~

    reactive 使用注意事项

    • reactive定义的基础类型数据
      • 使用只能通过state.time = XXX 赋值的方式进行更改;
      • 获得到的只能是当前的值,比如time初始使用new Date() 进行赋值,得到的time的原型并非是Date的,再次修改time的值的时候不能通过setDate赋值;
    • reactive定义复杂数据类型
      • 对象的每一层都会被包装成一个Proxy的代理,用于页面的响应式数据构建;
      • 更改对象中的某一个属性的值都会因此视图的响应;

    ref

    ref使用

    ref的本质还是reactive,系统会自动根据我们传入的值转换成ref(xxx)->reactive({value:xx})

      setup(props) {
        // 传递一个值 
         let age = ref(33);
         function changeAge(){ 
           age.value +=1;
         }
         return{
           age,
           changeAge
         }
      }
    

    ref 定义的内容: 初探Vue3.0--响应式api理解~

    ref的注意点

    • 在Vue中使用ref的值不用通过value获取;
    • 在js中使用ref的值必须要用value获取;
    • 在setup 中定义的变量是无法在method中获取的;

    triggerRef 更新变量

    ref定义对象类型时候更新问题 ref定义的对象类型,如果是只想更改某一层的变化 需要调用triggerRef进行触发更新

      // 只想更改ref中某一层的变化
      msg.value.a = 'myy'
      //增加triggerRef 引起视图的更新 
      // Vue3 只提供了triggerRef 没有提供reactRef相关的
      triggerRef(msg)
    

    unRef返回其原始值

    如果参数为 ref,则返回内部值,否则返回参数本身。这是 val = isRef(val) ? val.value : val

    let age = ref(33);
    console.log(age)
    console.log(unref(age))
    

    初探Vue3.0--响应式api理解~

    ref 和reactive的扩展讲解

    ref 和reactive的区别

    • 在template中使用ref类型的数据,vue会自动帮我们计算.value
    • 在template中使用reactive类型的数据,vue不会自动帮我们计算.value

    vue 是如何决定是否自动添加.value

    Vue在解析数据之前,会自动判断这个数据是否是ref类型的,如果是,则自动添加上.value,如果不是,则不会自动添加

    vue 是如何判断当前数据是否是ref类型的

    • 通过当前按数据的__v_isRef来进行判断的,
    • 如果有私有的属性,并且取值为true,那么就代表是一个ref类型的数据
     console.log("判断是否是ref类型数据",isRef(age))
     console.log("判断是否是isReactive类型数据",isReactive(age))
    

    监听层级问题

    无论是ref还是reactive的都是递归监听的过程,也就是无论我们嵌套了多少层级,其每一层的每个数据都会发生监听;

    递归监听

    reactive

    let state= reactive({
          a:'2',
          gf:{
            b:'b',
            f:'c',
            c:{
              a:3
            }
          }
        })
      // 多个层级 每个层级内容改变的时候,都会改变;
        function changeValue(){
          console.log(state)
          console.log(state.gf)
        }
    

    打印后可以发现在reactive中定义的对象,发现对象中的每一层对象都是通过Proxy进行代理 初探Vue3.0--响应式api理解~

    ref

    let msg = ref({
           a:'2',
            gf:{
              b:'b',
              f:'c',
                c:{
                a:3
              }
            }
        }) 
     function changeRef(){
        //直接更改ref 
        console.log(msg.value)
        console.log(msg.value.gf) 
     }
    

    初探Vue3.0--响应式api理解~

    非递归监听

    只监听对象的第一层,

    • 只有第一层被包装,第二层未被包装;
    • 第一层的数据发生改变,第一层的ui也会变化
    • 第二层的数据修改,但是不会更新ui
    • shallowRef Vue监听的是.value的变化,并不是第一层的变化

    利用shallowRef 和shallowReactive能够改变当前对象的监听层级

    shallowReactive

    let state = shallowReactive({
          a:'2',
          gf:{
            b:'b',
            f:'c',
            c:{
              a:3
            }
          }
        })
      function changeValue(){
          console.log(state)
          console.log(state.gf)
        }
    

    初探Vue3.0--响应式api理解~ 第二层的对象不会包装成响应式内容

    shallowRef

     let msg = shallowRef({
           a:'2',
            gf:{
              b:'b',
              f:'c',
                c:{
                a:3
              }
            }
        })
    function changeRef(){ 
          console.log(msg)
          console.log(msg.value)
          console.log(msg.value.gf) 
        }
    

    初探Vue3.0--响应式api理解~

    注意内容:

    • 通过ref定义的内容会被reactive包装成一个.value的对象,因此这个对象的第一层的就是value
    • 当访问msg.value的时候,其实已经访问它的值了,自然是没有内容的;

    readonly

    存在一组对象,我们只能读取,但是不能更改,因此可以使用readonly进行包裹;

    • 对于对象深度包裹,递归到最底层的变量
    let state = readonly({name:'mfy',age:34,attr:{weight:45,height:1.88}})
      function changeReadonly(){
          state.age = 2; //修改第一层 
          state.attr.weight = 2; //修改深层
          console.log(state)
          console.log(isReadonly(state)) 
        }
    

    点击进行修改时候 初探Vue3.0--响应式api理解~

    readonly定义的对象和reactive数据结构的区别

      const obj = reactive({name:'33'})
      console.log(obj)
      let state = readonly({name:'mfy',age:34,attr:{weight:45,height:1.88}})
      console.log(state)
    

    初探Vue3.0--响应式api理解~

    • reactive定义的参数在Proxy函数的set支持传入四个参数
    • readonly只能收到两个参数,在set中直接进行警告提示

    shallowReadonly

    shallowRef以及shallowReactive的性质一样,只能控制第一层的数据是不可修改的;

    let state = shallowReadonly({name:'mfy',age:34,attr:{weight:45,height:1.88}})
    console.log(state)
     function changeReadonly(){
       state.age = 2; //修改第一层
       state.attr.weight = 2; //修改第二层
       console.log(state) 
       console.log(state.attr)
    }
    

    初探Vue3.0--响应式api理解~

    • 第二层数据的对象发生变化
    • 视图无法进行更新,因为第二层的数据不是响应式的
    • shllowReadonly 非递归包装,只包装第一层数据,第二层将不会进行包装

    不得不比较const

    • const 和 readonly的区别
    • const 赋值保护 不能给变量重新赋值
    • readonly 属性保护,不能给属性重新赋值

    toRef

    let obj1 = {age:34,name:'mfy'} 
      let state2 = toRef(obj1,'name')
     
      function changeRef(){
         state2.value = 333
         console.log('obj1',obj1)
         console.log('state2',state2) 
       }
    

    初探Vue3.0--响应式api理解~

    toRef修改的值不仅仅使定义的值发生了改变,其原始值也发生了改变;

    • 利用toRef将某一个对象的属性变成响应式的,此时修改是会影响到原始值
    • 如果响应数据是通过toRef变化的,是不会触发页面更新的

    ref和toRef

    • ref
      • 复制,修改响应式数据不会影响到以前的数据
      • 数据发生改变,ui会自动更新
    • toRef
      • 引用 修改响应式数据会影响到以前怼数据
      • 数据发生改变,ui不会自动更新

    toRefs

    定义多个属性的响应式

    let state3 = toRefs(obj1,'name','age')   
    

    转化reactive定义的响应式

    let obj = {age:34,name:'mfy'} 
     let state =reactive(obj);
     console.log(state) 
     let state2 = toRefs(state)
     console.log(state2) 
    

    打印出来statestate2 初探Vue3.0--响应式api理解~

    state2中的引用和原始数据类型以及通过reactive定义的类型都是属于同一引用关系;即修改objstatestate2中的任何一个元素属性值,都会发生改变;

      let obj = {age:34,name:'mfy'} 
       let state =reactive(obj);
       console.log(state) 
       let state2 = toRefs(state)
       console.log(state2) 
      
       function changeRef(){  
         //修改值 
         obj.age = 232323;
         console.log('state2',state2)
         console.log('state',state)
         console.log('obj',obj)
    
       }
    

    初探Vue3.0--响应式api理解~

    使用场景

    使用reactive定义的对象是不具有响应式的,因此在使用的时候无法进行结构出来使用,而toRefs可以定义每个属性都是响应式的,

    function useFeatureX() {
      const state = reactive({
        foo: 1,
        bar: 2
      }) 
      // 返回时转换为ref
      return toRefs(state)
    }
    export default {
      setup() {
        // 可以在不失去响应性的情况下破坏结构
        const { foo, bar } = useFeatureX() 
        return {
          foo,
          bar
        }
      }
    }
    

    总结内容

    初探Vue3.0--响应式api理解~

    找到原始数据

    toRaw

    追踪reactive的特性进行定义响应式

        //默认情况下不是一个响应式数据
       let obj = {age:34,name:'mfy'}
       let state  =reactive(obj); 
       //把创建时候的参数分解出来
       let obj2 = toRaw (state); // 和obj是一个样子
       function changeRef(){ 
         //引用修改的内容,页面不会自动更新 只有通过修改包装的方法才能更新  
          obj2.name = 'myy'  
          //state和obj是引用关系,其中的一个值更改时候,另外一个值也会更改
          console.log(state)
          console.log(obj) 
          console.log(obj2) 
       }
    

    初探Vue3.0--响应式api理解~

    • toRaw获取到的变量,是一个引用的关系
    • 修改每一个值的是时候,都会影响到所依赖的值

    追踪ref定义的数据

    对于ref定义的值,必须要准确的告诉toRaw.value 如果通过toRaw 获取ref的数据,必须明确告诉ref.value的值 经过Vue处理之后,.value中保存的是当初创建时传入的那个原始数据;

      let obj = {age:34,name:'mfy'} 
       let state  =ref(obj); 
       //把创建时候的参数分解出来
       let obj2 = toRaw(state.value); // 必须指定定义的ref内部变量的value
       function changeRef(){ 
          obj2.name = 'myy'   
          console.log('state',state)
          console.log('obj',obj) 
          console.log('obj2',obj2) 
       }
    

    初探Vue3.0--响应式api理解~

    markRaw

      let obj = {age:34,name:'mfy'}
       //告诉这个对象 永远不能被监听
       obj = markRaw(obj) 
       let state =reactive(obj);  
       function changeRef(){
         state.name ='mfy';//监听到这个的变化
         console.log(state)
       }
    

    初探Vue3.0--响应式api理解~

    通过markRaw定义的属性再次被定义成响应式的时候,无论怎样对state进行赋值,是无法更改其内容的;

    Composition API 的入口 (setup)

    setupvue3.x中加入的一个新的生命周期,也是组合api的入口,由于在执行 setup 时尚未创建组件实例,因此在 setup 选项中没有this。这意味着,除了props 之外,你将无法访问组件中声明的任何属性——本地状态、计算属性或方法。

    执行时间

    setup ->beforeCreate -> created

    • 由于setup在执行的时候是在beforeCreate之前,因此是无法进行获取到this
    • setup中只能执行同步的,不能是异步的
     setup(props) { 
        //定义数据
        let age = ref(33) 
        
         //定义函数
        function changeAge(){
          age.value = 333
        }
        // 必须将变量暴露出去才能进行使用
        return{
          age,
          changeAge
        } 
      }
    

    setup中生命周期

    在setup的函数中,其内部提供了很多的可进行兼容的方法 初探Vue3.0--响应式api理解~

    setup响应式数据监控方法

    computed

    let firstName = ref("马");
    let lastName = ref("fyy") 
    let fullName = computed(()=> firstName.value + lastName.value)
    console.log(fullName)  
    

    初探Vue3.0--响应式api理解~

    若想要直接修改computed的变量,可以使用set的方法,将依赖的属性的值进行修改;

     let age = ref(12)
     let ageCom = computed({
          get: () => age.value + 1,
          set: val => {
            age.value = val - 1
          }
     })
    

    watchEffect

    let firstName = ref("马");
    let lastName = ref("fyy") 
    let fullName = computed(()=> firstName.value + lastName.value) 
    watchEffect(() => { 
      console.log('%c 内容发生改变了','color:yellow',fullName.value)
    })
    function changeName(){
      firstName.value = 'Ming'+Math.random()   
    }
    

    初探Vue3.0--响应式api理解~
    每次watchEffect里面的内容发生改变的时候都会触发;

    watch

    watch API 与选项式 API this.$watch (以及相应的 watch 选项) 完全等效。watch 需要侦听特定的 data 源,并在单独的回调函数中副作用。默认情况下,它也是惰性的——即,回调是仅在侦听源发生更改时调用。 与 watchEffect 比较,watch 允许我们:

    • 惰性地执行副作用;
    • 更具体地说明应触发侦听器重新运行的状态;
    • 访问侦听状态的先前值和当前值。

    侦听一个数据源

    const state = reactive({ count: 0 }) 
     watch(
       ()=>state.count,
       (count,preCount)=>{
         console.log('%c count的值发生修改了','color:yellow','count='+count,' preCount='+preCount)
       }
     ) 
    function changeCount(){
      state.count +=1  
    }
    
    

    初探Vue3.0--响应式api理解~

    侦听多个数据源

     let name = ref('myy')
         let age = ref(22)
         watch([name,age],([name,age],[prevName,prevAge])=>{
           console.log("%c --姓名和年龄更改--",'color:yellow')
           console.log("%c 姓名更改",'color:green','prevName='+prevName,' name='+name )
           console.log("%c 年龄更改",'color:green','prevAge='+prevAge,' age='+age )
         })
         function changeCount(){
           name.value = 'myyyyy'
           age.value +=1  
         }
    

    初探Vue3.0--响应式api理解~

    setup 中定义的参数

    基础类型 (最准确的来说 是使用ref定义的基础类型)

    • setup中定义的参数,只能在setup的作用域下进行修改
    • 在外部的method中进行修改,则会报错
    • 在setup暴露出去后,其暴露的就是当前变量的值;
    changeValue(){ 
          console.log(this.isShowAddModal) //false
          this.isShowAddModal.value =3
        }
    

    复杂数据类型(使用reactive)

    在外部的method中进行修改数据 能够修改成功

     changeValue(){ 
        console.log(this.heorData)
        this.heorData.list=[] 
      }
    //setup内部的监听函数是否会触发
      watch(heorData,()=>{
        console.log("watch:: heroData--数据修改了",heorData)
      }) 
    

    调用setup内部暴露的函数,在setup内部是可以被检测到的 初探Vue3.0--响应式api理解~

    • ref定义的参数,无法在setup外部进行参数的修改
    • reactive定义的参数能够进行修改,并且能够被watch监听到

    总结

    自己通过文档+视频+实际操作对Vue3.x有了一点点了解,有些内容其实不是不够深入的,比较好奇的点会通过自己想要了解的内容去实际操作一波;

    • Composition API 的使用
    • 响应式数据的定义
      • 引用类型、基础类型定义
      • 递归响应和非递归响应数据的定义
      • 只读响应数据
    • setup函数的使用

    参考文档

    官方文档api b站vue3.0入门讲解视频


    起源地下载网 » 初探Vue3.0--响应式api理解~

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元