(VUE3) 三磷账、Vue3高階(Hook函數(shù) & 生命周期 & toRef和toRefs & 其他的組合式API)

1.Hook函數(shù)

hooks是一種開發(fā)思想悠咱,我們可以利用hooks把相關(guān)代碼剝離出去蒸辆。hook有個(gè)編碼習(xí)慣是用use開頭征炼。

在src下新建hooks文件夾,下新建useCar.js躬贡。useCar.js里是個(gè)函數(shù)谆奥,且直接export default給它導(dǎo)出去,且直接return返回定義的這些東東西西拂玻。
// 導(dǎo)入ref,computed
import {ref,computed} from 'vue'

let carName = ref("奔馳");
    let carPrice = ref(5000);
    // 修改汽車名稱的方法
    let updateCarName = (name) => {
      carName.value = name;
    };
    // 修改汽車價(jià)格的方法
    let updateCarPrice = (price) => {
      carPrice.value = price;
    };
    // 汽車的美國(guó)價(jià)格
    let usaCarPrice = computed(() => {
      return '$'+(carPrice.value / (Math.random() + 6)).toFixed(2);
    });

    return {
      carName,
      carPrice,
      updateCarName,
      updateCarPrice,
      usaCarPrice
    }

同理酸些,再搞一份飛機(jī)的hook函數(shù),hooks文件下usePlane.js

// 導(dǎo)入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;
    };
    // 飛機(jī)的美國(guó)價(jià)格
    let usaPlanePrice = computed(() => {
      return  '$'+ (planePrice.value / (Math.random() + 6)).toFixed(2);
    });
    return {
        planeName,
        planePrice,
        updatePlaneName,
        updatePlanePrice,
        usaPlanePrice
    }
}

components下Child.vue組件:
在組件里導(dǎo)入所需的hook函數(shù)useCar檐蚜,
import useCar from'../hooks/useCar'魄懂,然后在setup(){ } 里 return{ } 里 ...useCar()(三個(gè)點(diǎn)是展開運(yùn)算符)

  <div class="child">
    <div class="car">
      <p>汽車名稱:{{ carName }}<button @click="updateCarName('寶馬')">修改汽車名稱</button></p>
      <p>汽車價(jià)格:{{ '¥'+carPrice }}<button @click="updateCarPrice(10000)">修改汽車價(jià)格</button></p>
      <p>美國(guó)價(jià)格:{{usaCarPrice}}</p>
    </div>
    <hr>
    <div class="plane">
      <p>汽車名稱:{{ planeName }}<button @click="updatePlaneName('B2轟炸機(jī)')">修改飛機(jī)名稱</button></p>
      <p>汽車價(jià)格:{{ '¥'+planePrice }}<button @click="updatePlanePrice(50000)">修改飛機(jī)價(jià)格</button></p>
      <p>美國(guó)價(jià)格:{{usaPlanePrice}}</p>
    </div>
  </div>
<script>
import { computed, ref } from "vue";

// 導(dǎo)入hook函數(shù)useCar
import useCar from'../hooks/useCar'
// 導(dǎo)入hook函數(shù)userPlane
import usePlane from'../hooks/usePlane'

export default {
  name: "Child",
  setup() {
    return {
      ...useCar(),
      ...usePlane()
    };
  },
};
</script>

頁面效果:

hooks下每個(gè)xx.js文件就是一個(gè)業(yè)務(wù),這里面的業(yè)務(wù)可以在多個(gè)xx.vue組件中使用闯第。分別在組件中導(dǎo)入所需的hook函數(shù)useCar市栗,然后在setup(){ } 里 return{ } 里 ...useCar(),就可以惹咳短。


2.生命周期


vue3是上來就掛載填帽。vue2是先走一半再掛載。

App.vue組件:

<template>
  <div class="app">
    <div>
      {{count}}
      <button @click="updateCount">count++</button>
    </div>
    <Child></Child>
    <Child2></Child2>
  </div>
</template>

<script>
import Child from './components/Child.vue'
import Child2 from './components/Child2.vue'
export default {
  name: 'App',
  components:{
    Child,
    Child2

  },
  data() {
    return {
      count:1
    }
  },
  methods: {
    updateCount(){
      this.count++
    }
  },
  beforeCreate() {
    // console.log(this.count);
    console.log('--beforeCreate--');
  },
  created() {
    // console.log(this.count);
    console.log('--created--');
  },
  beforeMount() {
    console.log('--beforeMount--');
  },
  mounted() {
    console.log('--mounted--');
  },
  beforeUpdate() {
    console.log(this.count);
    // debugger;
    console.log('--beforeUpdate--');
  },
  updated() {
    console.log(this.count);
    // debugger
    console.log('--updated--');
  },
}
</script>

<style>
*{
  margin: 0;
  padding: 0;
  list-style: none;
}
.app{
  border: 1px solid #ccc;
  margin: 10px;
  padding: 10px;
}
</style>

后臺(tái)打印效果:

點(diǎn)擊count++之前:

點(diǎn)擊count++之后:

beforeUpdate和updated會(huì)在什么場(chǎng)景下使用咙好?
顧sensei答盲赊,這會(huì)是一個(gè)補(bǔ)救措施,或是修改后的跟蹤措施敷扫;或有點(diǎn)像監(jiān)視器哀蘑,能夠監(jiān)測(cè)到頁面是否在更新,watch是針對(duì)某一個(gè)變量去監(jiān)視葵第,但它是監(jiān)測(cè)到整個(gè)頁面绘迁。

在vue3中,beforeDestroy和destroyed這兩個(gè)生命周期函數(shù)卒密,進(jìn)行了重命名缀台,替換成了 beforeUnmount 和 unmounted 。
在vue3中哮奇,除了beforeCreate和created這兩個(gè)生命周期函數(shù)沒有組合式api膛腐,其他的生命周期函數(shù)都有對(duì)應(yīng)的組合式api,命名方式只是在原有方法名的前面加上on鼎俘。
setup()函數(shù)在這里充當(dāng)了beforeCreate和created這兩個(gè)生命周期函數(shù)的功能哲身。

注意:setup是在beforeCreate和created之前運(yùn)行的。所以贸伐,在setup里面勘天,無法調(diào)用data和methods里面的數(shù)據(jù)。

Child3.vue組件:

<template>
  <div class="child3">
    {{ count }}
    <button @click="updateCount">count++</button>
  </div>
</template>
<script>
// 導(dǎo)入生命周期組合式api,除了beforeCreate和created這兩個(gè)生命周期函數(shù)沒有組合式api脯丝,
// 其他的生命周期函數(shù)都有對(duì)應(yīng)的組合式api商膊,命名方式只是在原有方法名的前面加上on。
// setup()函數(shù)在這里充當(dāng)了beforeCreate和created這兩個(gè)生命周期函數(shù)的功能宠进。
import { ref, onBeforeMount, onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted } from "vue";
export default {
  name: "Child3",
  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,
    };
  }
};
</script>
<style scoped>
.child3 {
  border: 1px solid #ccc;
  padding: 10px;
  margin-top: 10px;
}
</style>

App.vue組件:

<template>
  <div class="app">
    <button @click="unMount">卸載Child3組件</button>
    <Child3 v-if="isShow"></Child3>
  </div>
</template>

<script>
import Child3 from './components/Child3.vue'
export default {
  name: 'App',
  components:{
    Child3
  },
  data() {
    return {
      isShow:true
    }
  },
  methods: {
    unMount(){
      this.isShow=false
    }
  },
}
</script>

<style>
*{
  margin: 0;
  padding: 0;
  list-style: none;
}
.app{
  border: 1px solid #ccc;
  margin: 10px;
  padding: 10px;
}
</style>

3.toRef 和 toRefs

toRef() 方法茬缩,用于將一個(gè)響應(yīng)式對(duì)象里面的指定屬性以ref形式的對(duì)象返回,這樣寫的好處是吼旧,可以簡(jiǎn)化模板里面的語法凰锡。

toRefs() 方法,用于將一個(gè)reactive對(duì)象返回一個(gè)新對(duì)象圈暗,該對(duì)象里面的所有屬性都是一個(gè)ref對(duì)象掂为。

<template>
  <div class="child1">
      <ul>
          <li>姓名:{{name}}</li>
          <li>年齡:{{age}}</li>
          <li>性別:{{sex}}</li>
          <li>地址:{{address}}</li>
          <li>汽車名稱:{{car.name}}</li>
          <li>汽車價(jià)格:{{car.price}}</li>
          <li><button @click="updateStudent">修改學(xué)生信息</button></li>
      </ul>
  </div>
</template>
<script>
import {ref,reactive, toRef,toRefs} from 'vue'
export default {
  name: "Child1",
  setup() {
      let student = reactive({
          name:'張三',
          age:20,
          sex:'男',
          address:'南京',
          car:{
              name:'邁巴赫',
              price:200
          }
      })
      // 修改學(xué)生的方法
      let updateStudent =()=>{
          student.name = '李四'
          student.age = 22
          student.sex = '女'
          student.address = '杭州',
          student.car.name = '布加迪威龍',
          student.car.price = 100
      }
      return{
        // toRef()方法,用于將一個(gè)響應(yīng)式對(duì)象里面的指定屬性以ref形式的對(duì)象返回员串,
        // 這樣寫的好處是勇哗,可以簡(jiǎn)化模板里面的語法。
        //   name:toRef(student,'name'),
        //   age:toRef(student,'age'),
        //   sex:toRef(student,'sex'),
        //   address:toRef(student,'address'),

        // toRefs()方法寸齐,用于將一個(gè)reactive對(duì)象返回一個(gè)新對(duì)象欲诺,
        // 該對(duì)象里面的所有屬性都是一個(gè)ref對(duì)象。
        ...toRefs(student),
          updateStudent
      }
  }
};
</script>

4.其他的組合式API

readonly() 方法渺鹦,用于返回一份只讀數(shù)據(jù)扰法。注意:該方法,不能將一個(gè)普通值類型數(shù)據(jù)轉(zhuǎn)為只讀數(shù)據(jù)毅厚。
markRaw() 方法塞颁,返回出來的對(duì)象,再也不能成為響應(yīng)式對(duì)象吸耿。應(yīng)該用的也不多奧祠锣。
unref() 方法,用于判斷對(duì)象如果是ref咽安,就返回ref的value值伴网;如果不是ref,直接返回值板乙。
shallowReactive() / shallowRef() 方法是偷,用于定義淺響應(yīng)式對(duì)象拳氢。只對(duì)第一層屬性設(shè)置響應(yīng)式募逞。
shallowReadonly() 是淺只讀蛋铆,只有第一層屬性是只讀的。
toRaw() 方法放接,用于將一個(gè)響應(yīng)式對(duì)象轉(zhuǎn)為普通對(duì)象刺啦。

<template>
  <div class="child2">
    <div>{{ student }}</div>
    <button @click="updateStudent">修改學(xué)生</button>
    <hr>
    <div>{{luhan}}</div>
    <button @click="updateLuhan">修改鹿晗</button>
  </div>
</template>
<script>
import { unref,isProxy,isRef,isReactive, isReadonly, markRaw, 
onMounted,ref,reactive, readonly, shallowReactive, toRaw } from "vue";
export default {
  name: "Child2",
  setup() {
    let name =ref('你好')
    let age=20
    let data = reactive({
      name: "張三",
      age: 20,
    });
    // readonly()方法,用于返回一份只讀數(shù)據(jù)
    // 注意:該方法纠脾,不能將一個(gè)普通值類型數(shù)據(jù)轉(zhuǎn)為只讀數(shù)據(jù)
    let student = readonly(data);
    let updateStudent = () => {
      // student.name += "!";
      data.name +="!"
      // 此處玛瘸,student是返回出去的數(shù)據(jù),改不了苟蹈,data是原數(shù)據(jù)所以改得了糊渊。
      // student本質(zhì)上是個(gè)代理對(duì)象proxy,但不能改奧慧脱,一改就報(bào)錯(cuò)渺绒,使用場(chǎng)景并不多。
    };

    // 使用markRaw()方法菱鸥,返回出來的對(duì)象宗兼,再也不能成為響應(yīng)式對(duì)象。應(yīng)該用的也不多奧氮采。
    let car = markRaw({
      name: "奔馳",
      price: 20,
    });
    // console.log(car);
    let car2 = reactive(car);
    console.log(car2);

    // shallowReactive() shallowRef() 用于定義淺響應(yīng)式對(duì)象殷绍。
    // 只對(duì)第一層屬性設(shè)置響應(yīng)式。
    // shallowReadonly()是淺只讀鹊漠,只有第一層屬性是只讀的主到。
    let luhan = shallowReactive({
      name: "鹿晗",
      age: 30,
      friend: {
        name: '關(guān)曉彤',
        age: 20
      },
    });
    console.log('luhan',luhan);   //luhan是個(gè)響應(yīng)式對(duì)象Proxy

    // toRaw()方法,用于將一個(gè)響應(yīng)式對(duì)象轉(zhuǎn)為普通對(duì)象躯概。
    let luhan2 = toRaw(luhan)
    console.log('luhan2',luhan2);

    let updateLuhan = () => {
      // luhan.name = "張藝興",
      // luhan.age = 25
      // 如果只是修改對(duì)象的深層屬性登钥,不會(huì)觸發(fā)頁面更新。
      luhan.friend.name='小美'
      luhan.friend.age=22
    };

    onMounted(() => {
        console.log('name is ref',isRef(name));
        console.log('data is reactive',isReactive(data));
        console.log('data is proxy',isProxy(data));
        console.log('student is readonly',isReadonly(student));
        console.log('student is proxy',isProxy(student));

        // unref()方法楞陷,用于判斷對(duì)象如果是ref怔鳖,就返回ref的value值;如果不是ref固蛾,直接返回值结执。
        // 等同于:  val = isRef(val) ? val.value : val
        console.log(unref(name));
        console.log(unref(age));
    })

    return {
      student,
      updateStudent,
      luhan,
      updateLuhan
    };
  },
};
</script>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市艾凯,隨后出現(xiàn)的幾起案子献幔,更是在濱河造成了極大的恐慌,老刑警劉巖趾诗,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜡感,死亡現(xiàn)場(chǎng)離奇詭異蹬蚁,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)郑兴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門犀斋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人情连,你說我怎么就攤上這事叽粹。” “怎么了却舀?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵虫几,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我挽拔,道長(zhǎng)辆脸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任螃诅,我火速辦了婚禮啡氢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘州刽。我一直安慰自己空执,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布穗椅。 她就那樣靜靜地躺著辨绊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪匹表。 梳的紋絲不亂的頭發(fā)上门坷,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音袍镀,去河邊找鬼默蚌。 笑死,一個(gè)胖子當(dāng)著我的面吹牛苇羡,可吹牛的內(nèi)容都是我干的绸吸。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼设江,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼锦茁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起叉存,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤码俩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后歼捏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體稿存,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡笨篷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瓣履。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片率翅。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖拂苹,靈堂內(nèi)的尸體忽然破棺而出安聘,到底是詐尸還是另有隱情痰洒,我是刑警寧澤瓢棒,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站丘喻,受9級(jí)特大地震影響脯宿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜泉粉,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一连霉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧嗡靡,春花似錦跺撼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至哈误,卻和暖如春哩至,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蜜自。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工菩貌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人重荠。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓箭阶,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親戈鲁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子仇参,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容