Vue3.0学习笔记

目录

         一、组合API

二、reactive函数

三、ref函数

四、ref和reactive的区别: 

五、 递归监听和非递归监听

递归监听

非递归监听

应用场景

六、toRaw 

七、markRaw 

八、ref、toRef、toRefs


一、组合API

setup函数是组合API的入口函数。

setup函数执行时机是在beforeCreate之前。

在setup函数中,不能使用data和methods,为了避免出现错误,setup中的this为undefined。

setup函数是同步的。

注意点:
1.在组合API中定义的变量/方法,要想在外界使用的话,必须通过 return {xxx,xxx} 暴露出来。
2.在组合API中,定义的方法不用定义到methods中,直接定义即可。

二、reactive函数

1.什么是reactive?

reactive是vue3中提供的实现响应式数据的方法。在vue2中的响应式数据使用defineProperty来实现的。在vue3中实现响应式数据使用ES6中的proxy方法来实现。

注意点:

  1.    reactive的参数必须是对象的形式(json/arr)。
  2. 如果给reactive传递了其他对象,默认情况下修改对象,界面不会更新,若想更新,则通过赋值的方式 。       
<template>
  <div>
    <p>{{ user }}</p>
    <button @click="increase">click me! one year later</button>
  </div>
</template>
 
<script>
import { reactive } from "vue";
export default {
  name: "reactive",
//创建一个响应式数据
//本质:就是将传入的数据包装成proxy对象
  setup() {
    const user = reactive({ name: "Alice", age: 12 });
    function increase() {
      ++user.age
    }
    return { user, increase };
  },
};
</script>

 三、ref函数

1.什么是ref函数?

ref和reactive一样,也是用来实现响应式数据的方法。由于reactive函数你需传递一个对象,所以导致在企业开发中,只是实现单个对象的时候会非常的麻烦。所以vue3提供了一个ref方法,实现对简单值的监听。

2.ref的本质

ref底层的本质其实还是reactive,系统会根据我们传入的ref的值将它转化为reactive

ref(xxx)------->> reactive({ value:xxx })

3.ref的注意点:

在vue中使用的ref的值不用通过value来获取。 

在js中ref的值必须要通过value来获取。 

四、ref和reactive的区别: 

如果在template中,使用的是ref类型是数据,那么vue会自动帮我们添加.value

如果在template中,使用的是reactive类型是数据,那么vue不会自动帮我们添加.value

vue如何决定是否需要自动添加ref类型的?

vue在解析数据之前,会自动判断ref类型,如果是就添加.value,反之则否。

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

通过当前数据的_ _v_ref来判断的,如果有这个私有的属性,并且取值为true,那么代表是一个ref类型的数据。

我们也可以通过isRef和isReactive的值的true和false来判断当前的数据的类型。

五、 递归监听和非递归监听

递归监听

默认情况下,无论是ref还是reactive都是递归监听,即可以实时监听到数据的变化。

注意点:递归监听存在很大的问题,如果数据量比较大的话,非常消耗性能。

在reactive中:

<template>
<div>
  <p>msg.a.b.c = {{msg.a.b.c}}</p>
  <p>msg.e.f = {{msg.e.f}}</p>
  <p>msg.g = {{msg.g}}</p>
  <button @click="c">button</button>
</div>
</template>

<script>
import { reactive } from 'vue'
export default {
  name: 'App',
  setup() {
    let msg = reactive({
      a: {
        b: {
          c: 'c'
        }
      },
      e: {
        f: 'f'
      },
      g: 'g'
    });
    function c() {
      console.log(msg);
      msg.a.b.c = 'C';
      msg.e.f = 'F';
      msg.g = 'G';
    };
    return {
      msg,
      c
    };
  }
}
</script>

在ref中:

<template>
<div>
  <p>msg.a.b.c = {{msg.a.b.c}}</p>
  <p>msg.e.f = {{msg.e.f}}</p>
  <p>msg.g = {{msg.g}}</p>
  <button @click="c">button</button>
</div>
</template>

<script>
import { reactive } from 'vue'
export default {
  name: 'App',
  setup() {
    let msg = ref({
      a: {
        b: {
          c: 'c'
        }
      },
      e: {
        f: 'f'
      },
      g: 'g'
    });
    function c() {
      console.log(msg);
      msg.value.a.b.c = 'C';
      msg.value.e.f = 'F';
      msg.value.g = 'G';
    };
    return {
      msg,
      c
    };
  }
}
</script>

非递归监听

shallowRef / shallowReactive

如果通过shallowRef创建数据,监听的是.value的变化,而不是第一层的变化 。

如何触发非递归监听来更新页面?

如果是shallowRef类型数据,则通过triggerRef来触发。

在 shallowReactive 中,并没有提供 trigger 方案来主动唤醒监测变化。

(1)shallowRef的本质:通过shallowRef创建的数据,监听的是.value的变化,因为底层本质上value才是第一层。

<template>
    <div></div>
</template>
<script setup>
    import { reactive } from 'vue'
    import { shallowReactive } from 'vue'
    import { shallowRef } from 'vue'
    export default {
        setup() {
            //  ref  ->  reactive
            // ref(10) -> reactive({value:10})
            // shallowRef -> shallowReactive
            // shallowRef(10) ->  shallowReactive({value:10}) 
          let state1 = shallowRef({
                a: 'a',
                gf: {
                    b: 'b',
                    f: {
                        c: 'c',
                        s: {
                            d: 'd'
                        }
                    }
                }
            })

            let state2 = shallowReactive({
                value: {
                    a: 'a',
                    gf: {
                        b: 'b',
                        f: {
                            c: 'c',
                            s: {
                                d: 'd'
                            }
                        }
                    }
                }
            })

        }
    }
</script>

应用场景

一般情况下,我们监听数据变化使用ref和reactive即可

如果数据量比较大的情况下,我们才使用shallowReactive和shallowRef来监听数据变化。

六、toRaw 

ref/reactive数据类型的特点:每次修改都会被追踪,更新ui界面,非常消耗性能

如果不需要更新ui界面,不会被追踪数据,可以使用toRaw拿到原始数据,对原始数据进行修改。这样可以提高性能。

注意:当toRaw方法接收的参数是ref对象时,需要加上.value才能获取到原始数据对象。

reactive中的toRaw

<template>
  <div>
      <p>{{state}}</p>
    <button @click="myFn">按钮</button>
  </div>
</template>

<script>
  /*
  1.toRaw
  从Reactive 或 Ref中得到原始数据

  2.toRaw作用
  做一些不想被监听的事情(提升性能)
  * */
  import {reactive, toRaw} from 'vue';
export default {
  name: 'App',
  setup() {
    
      /*
      ref/reactive数据类型的特点:
      每次修改都会被追踪, 都会更新UI界面, 但是这样其实是非常消耗性能的
      所以如果我们有一些操作不需要追踪, 不需要更新UI界面, 那么这个时候,
      我们就可以通过toRaw方法拿到它的原始数据, 对原始数据进行修改
      这样就不会被追踪, 这样就不会更新UI界面, 这样性能就好了
      * */
      let state = reactive(
        {name:'lnj', age:18}
      );
      // 获取state的源数据
      let obj2 = toRaw(state);
      // console.log({name:'lnj', age:18} === obj2); // true

      // console.log({name:'lnj', age:18} === state); // false

      function myFn() {
        // 获取的源数据更改,不会触发页面更新
          obj2.name = 'zs';
          console.log(obj2); // {name: "zs", age: 18}
          // state.name = 'zs';
          // console.log(state);// {name: "zs", age: 18}
      }
    return {state, myFn}
  }
}
</script>

<style>

</style>

ref中的toRaw

<template>
  <div>
      <p>{{state}}</p>
    <button @click="myFn">按钮</button>
  </div>
</template>

<script>
  import { toRaw, ref} from 'vue';
export default {
  name: 'App',
  setup() {
      /*
      1.ref本质: reactive
      ref(obj) -> reactive({value: obj})
      * */
      let state = ref({name:'lnj', age:18});
      // 注意点: 如果想通过toRaw拿到ref类型的原始数据(创建时传入的那个数据)
      //        那么就必须明确的告诉toRaw方法, 要获取的是.value的值
      //        因为经过Vue处理之后, .value中保存的才是当初创建时传入的那个原始数据
      // let obj2 = toRaw(state);
      let obj2 = toRaw(state.value);
      console.log(state);
      console.log(obj2);

      function myFn() {
        // 获取的源数据更改,不会触发页面更新
          obj2.name = 'zs';
          console.log(obj2); // {name: "zs", age: 18}
          // state.name = 'zs';
          // console.log(state);// {name: "zs", age: 18}
      }
    return {state, myFn}
  }
}
</script>

<style>

</style>

七、markRaw 

将数据标记为永远不能追踪的数据

<template>
  <div>
      <p>{{state}}</p>
    <button @click="myFn">按钮</button>
  </div>
</template>

<script>
  /*
  1.markRaw
  将数据标记为永远不能追踪的数据
  一般在编写自己的第三方库时使用
  * */
  import {reactive, markRaw} from 'vue';
export default {
  name: 'App',
  setup() {
      let obj = {name: 'lnj', age: 18};
      // 不能追踪,监听,作为响应式的数据
      obj = markRaw(obj);
      let state = reactive(obj);
      function myFn() {
        // 数据更改了,但是页面ui还是没有发生改变
          state.name = 'zs';
      }
    return {state, myFn}
  }
}
</script>

<style>

</style>

八、ref、toRef、toRefs

1、ref和toRef的区别
(1). ref本质是拷贝,修改响应式数据不会影响原始数据;toRef的本质是引用关系,修改响应式数据会影响原始数据
(2). ref数据发生改变,界面会自动更新;toRef当数据发生改变是,界面不会自动更新
(3). toRef传参与ref不同;toRef接收两个参数,第一个参数是哪个对象,第二个参数是对象的哪个属性
 

2、toRef和toRefs区别:

(1)toRef是创建一个ref数据,和原始数据相关联 

(2)toRefs是批量创建ref数据,和原始数据相关联

ref代码:

<template>
  <div>
      <p>{{state}}</p>
    <button @click="myFn">按钮</button>
  </div>
</template>

<script>

  import {ref} from 'vue';
export default {
  name: 'App',
  setup() {
      let obj = {name:'lnj'};
 
      let state = ref(obj.name);
 

      function myFn() {
          state.value = 'zs';
          console.log(obj); //{name:'lnj'}
          console.log(state); // {name:'zs'}
      }
    return {state, myFn}
  }
}
</script>

<style>

</style>

toRef代码:

<template>
  <div>
      <p>{{state}}</p>
    <button @click="myFn">按钮</button>
  </div>
</template>

<script>
  /*
  1.toRef
  创建一个ref类型数据, 并和以前的数据关联
  2.toRefs
  批量创建ref类型数据, 并和以前数据关联
  3.toRef和ref区别
  ref-创建出来的数据和以前无关(复制)
  toRef-创建出来的数据和以前的有关(引用)
  ref-数据变化会自动更新界面
  toRef-数据变化不会自动更新界面
  * */
  import {ref, toRef} from 'vue';
export default {
  name: 'App',
  setup() {
      let obj = {name:'lnj'};
      /*
      ref(obj.name) -> ref(lnj)
      -> reactive({value:lnj})
      * */
      // ref->复制
      // let state = ref(obj.name);
      // toRef->引用
      /*
      ref和toRef区别:
      ref->复制, 修改响应式数据不会影响以前的数据
      toRef->引用, 修改响应式数据会影响以前的数据
      ref->数据发生改变, 界面就会自动更新
      toRef->数据发生改变, 界面也不会自动更新

      toRef应用场景:
      如果想让响应式数据和以前的数据关联起来, 并且更新响应式数据之后还不想更新UI, 那么就可以使用toRef
      * */
      let state = toRef(obj, 'name'); 

      function myFn() {
          state.value = 'zs';
          /*
          结论: 如果利用ref将某一个对象中的属性变成响应式的数据
               我们修改响应式的数据是不会影响到原始数据的obj !== state
          * */
          /*
          结论: 如果利用toRef将某一个对象中的属性变成响应式的数据
               我们修改响应式的数据是会影响到原始数据的
               但是如果响应式的数据是通过toRef创建的, 那么修改了数据并不会触发UI界面的更新
          * */
          console.log(obj);  //{name:'zs'}
          console.log(state);  //{name:'zs'}
      }
    return {state, myFn}
  }
}
</script>

<style>

</style>

toRefs代码:

<template>
  <div>
      <p>{{state}}</p>
    <button @click="myFn">按钮</button>
  </div>
</template>

<script>
  /*
  1.toRef
  创建一个ref类型数据, 并和以前的数据关联
  2.toRefs
  批量创建ref类型数据, 并和以前数据关联
  3.toRef和ref区别
  ref-创建出来的数据和以前无关(复制)
  toRef-创建出来的数据和以前的有关(引用)
  ref-数据变化会自动更新界面
  toRef-数据变化不会自动更新界面
  * */
  import {ref, toRef, toRefs} from 'vue';
export default {
  name: 'App',
  setup() {
      let obj = {name:'lnj', age:18};
      // let name = toRef(obj, 'name');
      // let age = toRef(obj, 'age');
      let state = toRefs(obj);

      function myFn() {
          // name.value = 'zs';
          // age.value = 666;
          state.name.value = 'zs';
          state.age.value = 666;
          console.log(obj); //{name:'zs', age:666}
          console.log(state);  //{name:'zs', age:666}
          // console.log(name); 
          // console.log(age);
      }
    return {state, myFn}
  }
}
</script>

<style>

</style>

九、customRef

customRef:返回一个对象,可以显式地控制依赖追踪和响应触发

<template>
<div>
  <p>{{obj}}</p>
  <button @click="lnc">button</button>
</div>
</template>

<script>
import { customRef,ref } from 'vue';

// customRef用于 自定义ref
// 自定义 ref 需要提供参数传值
function myRef(value) {
    // 自定义 ref 需要提供 customerRef 返回值
    // customer 需要提供一个函数作为参数
    // 该函数默认带参数 track 和 trigger ,都是方法。
    return customRef((track, trigger) => {
      return {
        // customer 需要提供一个对象 作为返回值
        // 该对象需要包含 get 和 set 方法。
        get() {
          // track 方法放在 get 中,用于提示这个数据是需要追踪变化的
          track();
          console.log('get', value);
        
          return value;
        },
        // set 传入一个值作为新值,通常用于取代 value
        set(newValue) {
          console.log('set', newValue);
          value = newValue;
          // 记得触发事件 trigger,告诉vue触发页面更新
          trigger();
        }
      }
    })
}

export default {
  name: 'App',
  setup() {
    // let obj = ref(18); // reactive({value: 18})
// 应用上面的自定义 ref ,使用方案和之前的 ref 是类似的。
    const obj = myRef(123);
    function lnc() {
      obj.value += 1;
    }

    return {
      obj,
      lnc
    };
  }
}
</script>

十、readonly 、shallowReadonly、isReadonly

readonly 用于创建一个只读的数据,并且是递归只读。层级深的数据也是没有变化。而且页面并没有更新 。

shallowReadonly用于创建一个只读的数据,但是不是递归只读。

isReadonly用于判断是否是只读数据。

<template>
  <div>
    <p>{{state.name}}</p>
    <p>{{state.attr.age}}</p>
    <p>{{state.attr.height}}</p>
    <button @click="myFn">按钮</button>
  </div>
</template>

<script>

  /*
  1.readonly
  - 只读数据

  2.readonly和const
  - const    赋值保护
  - readonly 递归保护

  3.isReadonly
  - 判断是否是readonly

  4.shallowReadonly
  - 非递归保护
  * */
  import {readonly, isReadonly, shallowReadonly} from 'vue'
export default {
  name: 'App',
  setup() {
    // readonly:用于创建一个只读的数据, 并且是递归只读
    let state = readonly({name:'lnj', attr:{age:18, height: 1.88}});
    // shallowReadonly: 用于创建一个只读的数据, 但是不是递归只读的
    // let state = shallowReadonly({name:'lnj', attr:{age:18, height: 1.88}});
    // const和readonly区别:
    // const: 赋值保护, 不能给变量重新赋值,
    // readonly: 属性保护, 不能给属性重新赋值
    // const value = 123;
    const value = {name:'zs', age:123};
    function myFn() {
      state.name = '知播渔';
      state.attr.age = 666;
      state.attr.height = 1.66;
      console.log(state);
      console.log(isReadonly(state));  //true
      // value = 456;
      // console.log(value);
      value.name = 'ls';
      value.age = 456;
      console.log(value);
    }
    return {state, myFn};
  }
}
</script>

<style>

</style>

十一、vue3响应式数据的本质

  • 在Vue2.x中是通过defineProperty来实现响应式数据的
  • 在Vue3.x中是通过Proxy来实现响应式数据的,Proxy除了可以监听对象外还可以监听数组
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值