vue3基礎(chǔ)語(yǔ)法學(xué)習(xí)

前言:vue2中復(fù)雜組件的代碼變得越來越難以維護(hù),缺少一種在多個(gè)組件之間提取和復(fù)用邏輯的機(jī)制,現(xiàn)在的重用機(jī)制又存在一些弊端,所以vue3中隆重推出了Composition API。
關(guān)于Composition API:
一、ref和reactive
1.ref:
作用:用于定義基本類型數(shù)據(jù),例如:String,Number,Boolean等,將其轉(zhuǎn)換為一個(gè)帶有響應(yīng)式特性的數(shù)據(jù)類型
語(yǔ)法:const x = ref(100)
訪問:在setup中使用.value訪問,在模板中讀取時(shí),不需要使用.value

<script lang="ts" setup>
import { ref} from 'vue'
const count = ref(9)
const increase = () => {
  count.value++
}
const decrease = () => {
  count.value--
}
</script>
<template>
  <div>
    <h1> count is a number {{ count }}</h1>
    <div>
      <button @click="increase">count +1</button>
      <button @click="decrease">count -1</button>
    </div>
  </div>
</template>

2.reactive
作用:用于定義引用數(shù)據(jù)類型,例如:數(shù)組,對(duì)象等,將其轉(zhuǎn)換為一個(gè)帶有響應(yīng)式特性的數(shù)據(jù)類型
語(yǔ)法:const info = reactive( { count: 0 } )
注意:響應(yīng)式轉(zhuǎn)換是深層的,它會(huì)影響所有嵌套的屬性;若要避免深層響應(yīng)式的轉(zhuǎn)換,只想保留對(duì)這個(gè)對(duì)象頂層次訪問的響應(yīng)性,請(qǐng)使用ShallowReactive()

<script lang="ts" setup>
import { reactive} from 'vue'
const data = reactive({
  count: 5
})
const increase = () => {
  data.count++
}
const decrease = () => {
  data.count--
}
</script>
<template>
  <div class="about">
    <h1> count is a number {{ data.count }}</h1>
    <div>
      <button @click="increase">count +1</button>
      <button @click="decrease">count -1</button>
    </div>
  </div>
</template>

上述示例中,如果將reactive對(duì)象中的屬性解構(gòu)后單獨(dú)拿出來使用,則會(huì)失去響應(yīng)性,比如:
const {count} = data
官方推薦我們使用toRefs()來解構(gòu)reactive對(duì)象,使其展開的每個(gè)屬性都是響應(yīng)式的;
const {count} = toRefs(data)
二、computed和watch
1.computed
作用:描述依賴響應(yīng)式狀態(tài)的復(fù)雜邏輯;會(huì)自動(dòng)追蹤響應(yīng)式依賴。
用法:computed()方法接收一個(gè)getter函數(shù)作為參數(shù),返回值為一個(gè)計(jì)算屬性ref,即可以通過.value訪問計(jì)算結(jié)果,在模板表達(dá)式中無(wú)需添加.value

<script lang="ts" setup>
import { reactive, computed, toRefs } from 'vue'
const data = reactive({
  count: 5
})
const { count } = toRefs(data)
const doubleCount = computed(() => {
  return count.value * 2
})
 
const increase = () => {
  count.value++
  console.log(doubleCount.value)
}
const decrease = () => {
  count.value--
  console.log(doubleCount.value)
}
</script>
<template>
  <div class="about">
    <h1>count is a number {{ count }}</h1>
    <div>
      <button @click="increase">count +1</button>
      <button @click="decrease">count -1</button>
    </div>
    <h1>this is doubleCount{{ doubleCount }}</h1>
  </div>
</template>

計(jì)算屬性vs方法:
不同點(diǎn):
計(jì)算屬性值會(huì)基于其響應(yīng)式依賴被緩存,即一個(gè)計(jì)算屬性僅會(huì)在其響應(yīng)式依賴更新時(shí)才重新計(jì)算;而方法調(diào)用總是會(huì)在重新渲染發(fā)生時(shí)再次執(zhí)行函數(shù)。
2.watch
作用:用于監(jiān)聽響應(yīng)式變量的變化
語(yǔ)法:watch(x,(new, old) => {})
watch的第一個(gè)參數(shù)可以是:一個(gè)ref(包括計(jì)算屬性)、一個(gè)響應(yīng)式對(duì)象、一個(gè)getter函數(shù)、或多個(gè)數(shù)據(jù)源組成的數(shù)組

const { count } = ref(3)
const doubleCount = computed(() => {
  return count.value * 2
})
 
watch(doubleCount, (newValue, oldValue) => {
  console.log('new', newValue)
  console.log('old', oldValue)
})

注意:不能直接偵聽響應(yīng)式對(duì)象的屬性值!!
而是 需要返回該屬性的getter函數(shù):

const data = reactive({
  count: 5
})
// 提供一個(gè)getter函數(shù)
watch(
  () => data.count,
  (count) => {
    console.log('count is', count)
  }
)

三、新的生命周期函數(shù)
1.選項(xiàng)式的beforeCreatecreated,被setup替代了,setup表示組件被創(chuàng)建之前,props被解析之后執(zhí)行,它是組合式API的入口
2.選項(xiàng)式的beforeDestroydestroyed被更名為beforeUnmountunmounted

vue 2.x vue 3.x
beforeCreate setup
created setup
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeDestroy onBeforeUnmount
destroyed onUnmounted

四、自定義函數(shù)-Hooks函數(shù)
新建hooks/useXXX.ts文件,將邏輯代碼都放在函數(shù)里:

hooks/useMousePosition.ts
import {ref,onMounted,onUnmounted} from 'vue'
function useMousePosition () {
    const x = ref(0)
    const y = ref(0)
    const updateMouse = (event:MouseEvent) => {
        x.value = event.pageX
        y.value = event.pageY
    }
    onMounted(() => {
        document.addEventListener('click', updateMouse)
    })
    onUnmounted(() => {
        document.removeEventListener('click', updateMouse)
    })
    return {
        x,
        y
    }
}
export default useMousePosition
xxx.vue
<script setup lang="ts">
    import useMousePosition from './hooks/useMousePosition'
    const { x, y } = useMousePosition()
</script>

優(yōu)點(diǎn):

  1. 清楚x,y變量來源
  2. 可以給x,y設(shè)置別名,這樣的話可以避免命名沖突的風(fēng)險(xiǎn)
  3. 邏輯可以脫離組件存在,和組件本身的實(shí)現(xiàn)沒有任何關(guān)系,不需要添加任何組件實(shí)現(xiàn)的功能,完美實(shí)現(xiàn)了邏輯重用
    五、其他新增特性:
    ? Teleport-瞬移組件的位置,"傳送"
    作用:把指定的元素或組件渲染到任意父級(jí)作用域的其它DOM節(jié)點(diǎn)上
    應(yīng)用場(chǎng)景:常用于封裝Modal彈框組件
    語(yǔ)法:<Teleport> 接收一個(gè) to prop 來制定傳送的目標(biāo)。to 的值可以是一個(gè) CSS 選擇器(如:to=".box"、to="#box"),也可以是一個(gè) DOM 元素對(duì)象(如:to="body"
Modal.vue
<script lang="ts" setup>
import { defineProps, defineEmits } from 'vue'
const props = defineProps({
  visible: {
    type: Boolean,
    default: false
  }
})
const emit = defineEmits(['cancel'])
const closeModal = () => {
  emit('cancel')
}
</script>

 
<template>
  <!-- 當(dāng)Modal彈窗顯示時(shí),將其插入到<body>標(biāo)簽中去 -->
  <teleport to="body">
    <div class="modal-layer" v-if="visible">
      <div class="modal">
        <header @click="closeModal" class="close">X</header>
        <main>
          <slot></slot>
        </main>
        <footer></footer>
      </div>
    </div>
  </teleport>
</template>

defineProps 用于接收父組件傳遞過來的自定義屬性
defineEmits 用于聲明父組件傳遞過來的自定義事件;子組件通過 defineEmits 獲取 emit 對(duì)象(因?yàn)闆]有 this)

Page.vue
<script lang="ts" setup>
import { ref } from 'vue'
import Modal from '../components/Modal.vue'
const isShow = ref(false)
const openModal = () => {
  isShow.value = true
}
const closeModal = () => {
  isShow.value = false
}
</script>
 
 
<template>
  <div class="page">
    <Modal :visible="isShow" @cancel="closeModal">
      <div>彈框主體內(nèi)容</div>
    </Modal>
    <button @click="openModal" class="btn">打開彈窗</button>
  </div>
</template>

? Suspense-異步加載組件
作用:常用于給異步組件加載時(shí),顯示loading

xxx.vue
<script lang="ts" setup>
// import AsyncCom from '../components/AsyncCom.vue'
import { defineAsyncComponent } from 'vue'
const AsyncCom = defineAsyncComponent(() => import('../components/AsyncCom.vue'))
</script>
 
 
<template>
  <div class="my">
    <Suspense>
      <!-- 具有深層異步依賴的組件 -->
      <AsyncCom></AsyncCom>
 
      <!-- 在fallback插槽中顯示'正在加載中' -->
      <template #fallback> Loading... </template>
    </Suspense>
  </div>
</template>
AsyncCom.vue
<script lang="ts" setup>
import { ref } from 'vue'
const data = ref(null)
function delay(ms, value) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(value)
    }, ms)
  })
}
data.value = await delay(1000, 3)
</script>
 
 
<template>
  <div class="child">
    <h1>child page{{ data }}</h1>
  </div>
</template>

監(jiān)控Suspense出現(xiàn)的錯(cuò)誤:使用onErrorCaptured() 生命周期鉤子函數(shù),返回一個(gè)boolean

const error = ref(null)
onErrorCaptured((e) => {
    error.value = e
    // return true 表示錯(cuò)誤是否向上傳遞
    return true
)

? 全局API的修改和優(yōu)化
全局配置Vue.configapp.config
全局注冊(cè)類API:Vue.componentapp.component
全局指令:Vue.directiveapp.directive
行為擴(kuò)展類API:Vue.mixinapp.mixin
安裝全局插件 Vue.useapp.use
nextTick()observable() ...
? 直接使用script添加一個(gè)setup屬性就可以直接使用Composition API

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,797評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,179評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,628評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,642評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,444評(píng)論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,948評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,040評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,185評(píng)論 0 287
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,717評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,602評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,794評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,045評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,418評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評(píng)論 1 281
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,414評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,750評(píng)論 2 370

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