美文网首页
Vue3——Hook函数 & 生命周期 & toRef和toRe

Vue3——Hook函数 & 生命周期 & toRef和toRe

作者: 叽里咕呱 | 来源:发表于2022-01-03 16:28 被阅读0次

    一、Hook函数

    Vue3 的hook函数相当于 vue2 的 mixin,不同点在于hooks是函数。Vue3的hook函数可以帮助我们提高代码的复用性,能在不同的组件中都使用hook函数。

    在src目录下建立一个 hooks 文件夹,文件夹中新建一个我们要用的方法的名字.js文件(一般情况下use开头)。
    useCar.js

    import { ref, computed } from 'vue'
    export default function () {
        let carName = ref("奔驰")
        let carPrice = ref(50000)
        // 修改汽车名称
        let updateCarName = (name) => {
            carName.value = name
        }
        // 修改汽车价格
        let updateCarPrice = (price) => {
            carPrice.value = price
        }
        let usaCarPrice = computed(() => {
            return '$' + (carPrice.value / (Math.random() + 6)).toFixed(2)
        })
        return {
            carName,
            carPrice,
            updateCarName,
            updateCarPrice,
            usaCarPrice
        }
    }
    

    usePlane.js

    // 导入ref,computed
    import { ref, computed } from "vue";
    export default function () {
      // 飞机名称
      let planeName = ref("波音747");
      // 飞机价格
      let planePrice = ref(20000);
      // 修改飞机名称的方法
      let updatePlaneName = (name) => {
        planeName.value = name;
      };
      // 修改飞机价格的方法
      let updatePlanePrice = (price) => {
        planePrice.value = price;
      };
      // 飞机在美国的价格
      let usaPlanePrice = computed(() => {
        return "$" + (planePrice.value / (Math.random() + 6)).toFixed(2);
      });
      return {
        planeName,
        planePrice,
        updatePlaneName,
        updatePlanePrice,
        usaPlanePrice,
      };
    }
    
    

    组件
    将文件引入到要使用的组件中。

    <div class="child">
        <div class="car">
            <p>汽车名称:{{carName}}<button @click="updateCarName('宝马')">修改汽车名称</button></p>
            <p>汽车价格:{{'¥'+carPrice}}<button @click="updateCarPrice(10000)">修改汽车价格</button></p>
            <p>美国价格:{{usaCarPrice}}</p>
        </div>
        <hr>
        <div class="plane">
            <p>汽车名称:{{planeName}}<button @click="updatePlaneName('B2轰炸机')">修改飞机名称</button></p>
            <p>汽车价格:{{'¥'+planePrice}}<button @click="updatePlanePrice(50000)">修改飞机价格</button></p>
            <p>美国价格:{{usaPlanePrice}}</p>
        </div>
    </div>
    
    import {computed, ref} from 'vue'
    // 导入hook函数useCar
    import useCar from '../hooks/useCar'
    // 导入hook函数usePlane
    import usePlane from '../hooks/usePlane'
    export default {
      name: "Child",
      setup() {
          return {
              ...useCar(),
              ...usePlane()
          }
      }
    };
    

    二、生命周期

    Vue3 中,可以在 setup() 函数中使用生命周期,定义组合式API生命周期函数。组合式API生命周期函数,会先与传统的生命周期函数执行。
    与vue2相比,在vue3中对beforeDestroy和destroyed这两个生命周期函数,进行了重命名,beforeUnmount 替换了 beforeDestroy;unmounted 替换了 destroyed。
    setup()函数,可以替代beforeCreate 和 created 这两个生命周期函数,因为vue2中的beforeCreate和created生命周期的执行几乎与VUE3中的setup在同一时间执行。

    <div class="child3">
      {{ count }}
      <button @click="updateCount">count++</button>
    </div>
    
    // 导入生命周期组合式api,除了beforeCreate和created这两个生命周期函数没有组合式api
    // 其他的生命周期函数,都有对应的组合式api,命名方式只是在原有方法名的前面加上on
    // setup()函数在这里充当了beforeCreate和created这两个生命周期函数的功能。
    import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount,onUnmounted } from "vue";
    export default {
      name: "Child3",
      data() {
        return {
          show:true
        }
      },
      setup() {
        //注意:setup是在beforeCreate和created之前运行的。
        //所以,在setup里面,无法调用data和methods里面的数据
        console.log('setup');
        let count = ref(1);
        let updateCount = () => {
          count.value++;
        };
        //挂载前
        onBeforeMount(() => {
            console.log('onBeforeMount');
        }),
        //挂载完成
        onMounted(()=>{
            console.log('onMounted');
        })
        //修改后,页面重新挂载前
        onBeforeUpdate(()=>{
            console.log('onBeforeUpdate');
        })
        //修改后,页面重新挂载完成
        onUpdated(()=>{
            console.log('onUpdated');
        })
        //卸载前
        onBeforeUnmount(()=>{
            console.log('onBeforeUnmount');
        })
        //卸载完成
        onUnmounted(() => {
            console.log('onUnmounted');
        })
    
        return {
          count,
          updateCount,
        };
      },
      /* data() {
        return {
          count: 1,
        };
      },
      methods: {
        updateCount() {
          this.count++;
        },
      }, */
      // 数据初始化前
      /*beforeCreate() {
        console.log("--beforeCreate--");
      },
      // 数据初始化完成
      created() {
        console.log("--created--");
      },
      // 页面挂载前
      beforeMount() {
        console.log("--beforeMount--");
      },
      // 页面挂载完成
      mounted() {
        console.log("--mounted--");
      },
      // 数据修改后,页面重新挂载前
      beforeUpdate() {
        console.log(this.count);
        console.log("--beforeUpdate--");
      },
      // 数据修改后,页面重新挂载完成
      updated() {
        console.log(this.count);
        console.log("--updated--");
      },
      // 卸载组件之前前
      beforeUnmount() {
        console.log("--beforeUnmount--");
      },
      // 卸载组件完成
      unmounted() {
        console.log("--unmounted--");
      }, */
    };
    

    三、toRef和toRefs

    toRef()函数:可以用来为一个 reactive 对象里面的指定属性创建一个 ref,这个 ref 可以被传递并且能够保持响应性。这样做的好处是简化了模板中的表达式。toRef()函数,需要传两个参数:reactive 对象、具体的属性名。
    toRefs()函数:把一个响应式对象转换成普通对象,该普通对象的每个属性都是一个 ref。

    <div class="child1">
      <ul>
        <li>姓名:{{ name }}</li>
        <li>年龄:{{ age }}</li>
        <li>性别:{{ sex }}</li>
        <li>地址:{{ address }}</li>
        <li>汽车名称:{{ car.name }}</li>
        <li>汽车价格:{{ car.price }}</li>
        <li><button @click="updateStudent">修改学生信息</button></li>
      </ul>
    </div>
    
    import { reactive, toRefs } from "vue";
    export default {
      name: "Child1",
      setup() {
        // 学生对象
        let student = reactive({
          name: "张三",
          age: 20,
          sex: "男",
          address: "南京",
          car: {
            name: "宝马",
            price: 1000,
          },
        });
        // 修改学生的方法
        let updateStudent = () => {
          student.name = "李四";
          student.age = 22;
          student.sex = "女";
          student.address = "成都";
          student.car.name = "奔驰";
          student.car.price = 2000;
        };
        return {
          // toRef()方法,用于将一个reactive对象里面的指定属性以ref形式的对象返回
          // name:toRef(student,'name'),
          // age:toRef(student,'age'),
          // sex:toRef(student,'sex'),
          // address:toRef(student,'address'),
    
          // 假如 reactive 对象中,有100个属性,上面的操作要写100次,所以,一般都直接用toRefs函数
          // 注意:如果student里面的属性是一个对象,这个属性对象里面的内容是不能直接转为ref的
          // toRefs只能保证一级属性
          ...toRefs(student),
          updateStudent,
        };
      },
    };
    

    四、其他的组合式API

    1、readonly

    readonly()方法:用于返回一份只读数据。传入一个对象(响应式或普通)或 ref,返回一个原始对象的只读代理。一个只读的代理是“深层的”,对象内部任何嵌套的属性也都是只读的。
    注意:该方法,不能将一个普通值类型数据转为只读数据。

    <div>{{ student }} <button @click="updateStudent">修改学生信息</button></div>
    
    import { reactive, readonly } from "vue";
    export default {
      name: "Child2",
      setup() {
        let data = reactive({
          name: "张三",
          age: 20,
        });
        let student = readonly(data);
        // student是一个只读对象,无法修改数据
        let updateStudent = () => {
          student.name = "李四";
          student.age = 22;
        };
        return {
          student,
          updateStudent,
        };
      },
    };
    

    2、isReadonly

    检查一个对象是否是由 readonly 创建的只读代理。

    import { reactive, readonly, isReadonly } from "vue";
    
    let data = reactive({
      name: "张三",
      age: 20,
    });
    let student = readonly(data);
    console.log('student is readonly',isReadonly(student));   //true
    

    3、isRef

    isRef():检查一个值是否为一个 ref 对象。

    import { ref, isRef } from "vue";
    
    let name = ref('你好')
    console.log('name is ref',isRef(name));   //true
    

    4、isProxy

    isProxy():检查一个对象是否是由 reactive 或者 readonly 方法创建的代理。

    import { reactive, readonly, isProxy } from "vue";
    
    setup() {
    let data = reactive({
      name: "张三",
      age: 20,
    });
    let student = readonly(data);
    console.log('data is proxy',isProxy(data));   //true
    console.log('student is proxy',isProxy(student));   //true
    

    5、isReactive

    isReactive():检查一个对象是否是由 reactive 创建的响应式代理。如果这个代理是由 readonly 创建的,但是又被 reactive 创建的另一个代理包裹了一层,那么同样也会返回 true。

    import { reactive, isReactive } from "vue";
    
    setup() {
      let data = reactive({
        name: "张三",
        age: 20,
      });
      console.log('data is reactive',isReactive(data));   //true
    }
    

    6、unref

    unref()函数:如果参数是一个 ref 则返回它的 value,否则返回参数本身。等同于 val = isRef(val) ? val.value : val 。

    import { ref, unref } from "vue";
    
    setup() {
      let name = ref('你好')
      let age = 20
      console.log(unref(name));   // '你好'
      console.log(unref(age));   // 20
    }
    

    7、markRaw

    markRaw():使用markRaw()方法返回出来的对象,再也不能成为响应式对象,函数返回这个对象本身。如果被 markRaw 标记了,即使在响应式对象中作属性,也依然不是响应式的。

    import { reactive, markRaw } from "vue";
    
    setup() {
      // 使用markRaw()方法,返回出来的对象,再也不能成为响应式对象。
      let car = markRaw({
          name:'奔驰',
          price:20
      })
      let car2 = reactive(car)
      // car2只是一个普通对象,不是响应式对象
      console.log(car2);
    }
    

    8、shallowRef

    shallowRef():返回的对象 value 属性值是 object对象(普通对象),不再具备任何响应式了。

    <div>
      汽车信息:{{ car3 }}
      <button @click="updateCar">修改汽车</button>
    </div>
    
    import { shallowRef } from "vue";
    
    setup() {
      let car3 = shallowRef({
        name: "大众",
        type: {
          typeName: "SUV",
        },
      });
      let updateCar = () => {
        // 由于value返回的是object对象,所以,这里不再具有响应式
        car3.value.name = "奔驰";
        car3.value.type.typeName = "跑车";
      };
      return {
        car3,
        updateCar
      };
    }
    

    9、shallowReactive

    shallowReactive():用于定义浅响应式对象,只对第一层属性设置响应式。

    import { shallowReactive,isReactive } from "vue";
    
    setup() {
      let luhan = shallowReactive({
          name:'鹿晗',
          age:30,
          friend:{
              name:'关晓彤',
              age:20,
          }
      })
      let updateLuhan = ()=>{
          // luhan.name = '张艺兴',
          // luhan.age = 25
    
          // 如果只是修改对象的深层属性,不会触发页面更新
          luhan.friend.name = '小美'
          luhan.friend.age = 22
      }
    }
    

    10、shallowReadonly

    shallowReadonly:浅只读,只有第一层属性是只读的。

    import { shallowReadonly } from "vue";
    
    setup() {
      let luhan = shallowReactive({
          name:'鹿晗',
          age:30,
          friend:{
              name:'关晓彤',
              age:20,
          }
      })
      let luhan3 = shallowReadonly(luhan);
      // luhan3.name = '小明'      // 属性只读
      luhan3.friend.name = "小美";      // 属性可修改
    }
    

    11、toRaw

    toRaw()方法:用于将一个响应式对象转为普通对象。

    import { toRaw } from "vue";
    
    setup() {
      let luhan = shallowReactive({
          name:'鹿晗',
          age:30,
          friend:{
              name:'关晓彤',
              age:20,
          }
      })
      let luhan2 = toRaw(luhan);
      console.log("luhan2", luhan2);   // 普通对象
    }
    

    相关文章

      网友评论

          本文标题:Vue3——Hook函数 & 生命周期 & toRef和toRe

          本文链接:https://www.haomeiwen.com/subject/gozoqrtx.html