Vue3——Hook函數(shù) & 生命周期 & toRef和toRefs & 其他的組合式API

一、Hook函數(shù)

Vue3 的hook函數(shù)相當(dāng)于 vue2 的 mixin,不同點(diǎn)在于hooks是函數(shù)。Vue3的hook函數(shù)可以幫助我們提高代碼的復(fù)用性,能在不同的組件中都使用hook函數(shù)。

在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

// 導(dǎo)入ref,computed
import { ref, computed } from "vue";
export default function () {
  // 飛機(jī)名稱
  let planeName = ref("波音747");
  // 飛機(jī)價格
  let planePrice = ref(20000);
  // 修改飛機(jī)名稱的方法
  let updatePlaneName = (name) => {
    planeName.value = name;
  };
  // 修改飛機(jī)價格的方法
  let updatePlanePrice = (price) => {
    planePrice.value = price;
  };
  // 飛機(jī)在美國的價格
  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轟炸機(jī)')">修改飛機(jī)名稱</button></p>
        <p>汽車價格:{{'¥'+planePrice}}<button @click="updatePlanePrice(50000)">修改飛機(jī)價格</button></p>
        <p>美國價格:{{usaPlanePrice}}</p>
    </div>
</div>
import {computed, ref} from 'vue'
// 導(dǎo)入hook函數(shù)useCar
import useCar from '../hooks/useCar'
// 導(dǎo)入hook函數(shù)usePlane
import usePlane from '../hooks/usePlane'
export default {
  name: "Child",
  setup() {
      return {
          ...useCar(),
          ...usePlane()
      }
  }
};

二、生命周期

Vue3 中,可以在 setup() 函數(shù)中使用生命周期,定義組合式API生命周期函數(shù)。組合式API生命周期函數(shù),會先與傳統(tǒng)的生命周期函數(shù)執(zhí)行。
與vue2相比,在vue3中對beforeDestroy和destroyed這兩個生命周期函數(shù),進(jìn)行了重命名,beforeUnmount 替換了 beforeDestroy;unmounted 替換了 destroyed。
setup()函數(shù),可以替代beforeCreate 和 created 這兩個生命周期函數(shù),因為vue2中的beforeCreate和created生命周期的執(zhí)行幾乎與VUE3中的setup在同一時間執(zhí)行。

<div class="child3">
  {{ count }}
  <button @click="updateCount">count++</button>
</div>
// 導(dǎo)入生命周期組合式api,除了beforeCreate和created這兩個生命周期函數(shù)沒有組合式api
// 其他的生命周期函數(shù),都有對應(yīng)的組合式api,命名方式只是在原有方法名的前面加上on
// setup()函數(shù)在這里充當(dāng)了beforeCreate和created這兩個生命周期函數(shù)的功能。
import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount,onUnmounted } from "vue";
export default {
  name: "Child3",
  data() {
    return {
      show:true
    }
  },
  setup() {
    //注意:setup是在beforeCreate和created之前運(yùn)行的。
    //所以,在setup里面,無法調(diào)用data和methods里面的數(shù)據(jù)
    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++;
    },
  }, */
  // 數(shù)據(jù)初始化前
  /*beforeCreate() {
    console.log("--beforeCreate--");
  },
  // 數(shù)據(jù)初始化完成
  created() {
    console.log("--created--");
  },
  // 頁面掛載前
  beforeMount() {
    console.log("--beforeMount--");
  },
  // 頁面掛載完成
  mounted() {
    console.log("--mounted--");
  },
  // 數(shù)據(jù)修改后,頁面重新掛載前
  beforeUpdate() {
    console.log(this.count);
    console.log("--beforeUpdate--");
  },
  // 數(shù)據(jù)修改后,頁面重新掛載完成
  updated() {
    console.log(this.count);
    console.log("--updated--");
  },
  // 卸載組件之前前
  beforeUnmount() {
    console.log("--beforeUnmount--");
  },
  // 卸載組件完成
  unmounted() {
    console.log("--unmounted--");
  }, */
};

三、toRef和toRefs

toRef()函數(shù):可以用來為一個 reactive 對象里面的指定屬性創(chuàng)建一個 ref,這個 ref 可以被傳遞并且能夠保持響應(yīng)性。這樣做的好處是簡化了模板中的表達(dá)式。toRef()函數(shù),需要傳兩個參數(shù):reactive 對象、具體的屬性名。
toRefs()函數(shù):把一個響應(yīng)式對象轉(zhuǎn)換成普通對象,該普通對象的每個屬性都是一個 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">修改學(xué)生信息</button></li>
  </ul>
</div>
import { reactive, toRefs } from "vue";
export default {
  name: "Child1",
  setup() {
    // 學(xué)生對象
    let student = reactive({
      name: "張三",
      age: 20,
      sex: "男",
      address: "南京",
      car: {
        name: "寶馬",
        price: 1000,
      },
    });
    // 修改學(xué)生的方法
    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函數(shù)
      // 注意:如果student里面的屬性是一個對象,這個屬性對象里面的內(nèi)容是不能直接轉(zhuǎn)為ref的
      // toRefs只能保證一級屬性
      ...toRefs(student),
      updateStudent,
    };
  },
};

四、其他的組合式API

1、readonly

readonly()方法:用于返回一份只讀數(shù)據(jù)。傳入一個對象(響應(yīng)式或普通)或 ref,返回一個原始對象的只讀代理。一個只讀的代理是“深層的”,對象內(nèi)部任何嵌套的屬性也都是只讀的。
注意:該方法,不能將一個普通值類型數(shù)據(jù)轉(zhuǎn)為只讀數(shù)據(jù)。

<div>{{ student }} <button @click="updateStudent">修改學(xué)生信息</button></div>
import { reactive, readonly } from "vue";
export default {
  name: "Child2",
  setup() {
    let data = reactive({
      name: "張三",
      age: 20,
    });
    let student = readonly(data);
    // student是一個只讀對象,無法修改數(shù)據(jù)
    let updateStudent = () => {
      student.name = "李四";
      student.age = 22;
    };
    return {
      student,
      updateStudent,
    };
  },
};

2、isReadonly

檢查一個對象是否是由 readonly 創(chuàng)建的只讀代理。

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 方法創(chuàng)建的代理。

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 創(chuàng)建的響應(yīng)式代理。如果這個代理是由 readonly 創(chuàng)建的,但是又被 reactive 創(chuàng)建的另一個代理包裹了一層,那么同樣也會返回 true。

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

6、unref

unref()函數(shù):如果參數(shù)是一個 ref 則返回它的 value,否則返回參數(shù)本身。等同于 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()方法返回出來的對象,再也不能成為響應(yīng)式對象,函數(shù)返回這個對象本身。如果被 markRaw 標(biāo)記了,即使在響應(yīng)式對象中作屬性,也依然不是響應(yīng)式的。

import { reactive, markRaw } from "vue";
setup() {
  // 使用markRaw()方法,返回出來的對象,再也不能成為響應(yīng)式對象。
  let car = markRaw({
      name:'奔馳',
      price:20
  })
  let car2 = reactive(car)
  // car2只是一個普通對象,不是響應(yīng)式對象
  console.log(car2);
}

8、shallowRef

shallowRef():返回的對象 value 屬性值是 object對象(普通對象),不再具備任何響應(yīng)式了。

<div>
  汽車信息:{{ car3 }}
  <button @click="updateCar">修改汽車</button>
</div>
import { shallowRef } from "vue";
setup() {
  let car3 = shallowRef({
    name: "大眾",
    type: {
      typeName: "SUV",
    },
  });
  let updateCar = () => {
    // 由于value返回的是object對象,所以,這里不再具有響應(yīng)式
    car3.value.name = "奔馳";
    car3.value.type.typeName = "跑車";
  };
  return {
    car3,
    updateCar
  };
}

9、shallowReactive

shallowReactive():用于定義淺響應(yīng)式對象,只對第一層屬性設(shè)置響應(yīng)式。

import { shallowReactive,isReactive } from "vue";
setup() {
  let luhan = shallowReactive({
      name:'鹿晗',
      age:30,
      friend:{
          name:'關(guān)曉彤',
          age:20,
      }
  })
  let updateLuhan = ()=>{
      // luhan.name = '張藝興',
      // luhan.age = 25

      // 如果只是修改對象的深層屬性,不會觸發(fā)頁面更新
      luhan.friend.name = '小美'
      luhan.friend.age = 22
  }
}

10、shallowReadonly

shallowReadonly:淺只讀,只有第一層屬性是只讀的。

import { shallowReadonly } from "vue";
setup() {
  let luhan = shallowReactive({
      name:'鹿晗',
      age:30,
      friend:{
          name:'關(guān)曉彤',
          age:20,
      }
  })
  let luhan3 = shallowReadonly(luhan);
  // luhan3.name = '小明'      // 屬性只讀
  luhan3.friend.name = "小美";      // 屬性可修改
}

11、toRaw

toRaw()方法:用于將一個響應(yīng)式對象轉(zhuǎn)為普通對象。

import { toRaw } from "vue";
setup() {
  let luhan = shallowReactive({
      name:'鹿晗',
      age:30,
      friend:{
          name:'關(guān)曉彤',
          age:20,
      }
  })
  let luhan2 = toRaw(luhan);
  console.log("luhan2", luhan2);   // 普通對象
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容