Vue3——Hook函数 & 生命周期 & toRef和toRefs & 其他的组合式API

一、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,
  };
}

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

汽车名称:{{carName}}

汽车价格:{{'¥'+carPrice}}

美国价格:{{usaCarPrice}}


汽车名称:{{planeName}}

汽车价格:{{'¥'+planePrice}}

美国价格:{{usaPlanePrice}}

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()
      }
  }
};

二、生命周期

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


image.png
{{ count }}
// 导入生命周期组合式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

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

  • 姓名:{{ name }}
  • 年龄:{{ age }}
  • 性别:{{ sex }}
  • 地址:{{ address }}
  • 汽车名称:{{ car.name }}
  • 汽车价格:{{ car.price }}
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,返回一个原始对象的只读代理。一个只读的代理是“深层的”,对象内部任何嵌套的属性也都是只读的。
注意:该方法,不能将一个普通值类型数据转为只读数据

{{ student }}
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对象(普通对象),不再具备任何响应式了。

汽车信息:{{ car3 }}
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和toRefs & 其他的组合式API)