「寫在前面」
本文為尚硅谷禹神 Vue3 教程的學(xué)習(xí)筆記。本著自己學(xué)習(xí)、分享他人的態(tài)度,分享學(xué)習(xí)筆記,希望能對大家有所幫助。推薦先按順序閱讀往期內(nèi)容:
1. Vue3 學(xué)習(xí)筆記(Day1)
目錄
-
3 Vue3 核心語法 -
3.1 選項式API 與 組合式API -
3.2 setup -
3.3 ref 和 reactive -
3.4 computed -
3.5 watch -
3.6 標簽的 ref 屬性 -
3.7 props -
3.8 生命周期 -
3.9 hook
-
3 Vue3 核心語法
3.1 選項式API 與 組合式API
P6:https://www.bilibili.com/video/BV1Za4y1r7KE?p=6
-
Vue2
的API
設(shè)計是Options
(選項式)風(fēng)格的。 -
Vue3
的API
設(shè)計是Composition
(組合式)風(fēng)格的。
Options API 的弊端:
Options
類型的 API
,數(shù)據(jù)、方法、計算屬性等,是分散在:data
、methods
、computed
中的,若想新增或者修改一個需求,就需要分別修改:data
、methods
、computed
,不便于維護和復(fù)用。


Composition API 的優(yōu)勢:
可以用函數(shù)的方式,更加優(yōu)雅的組織代碼,讓相關(guān)功能的代碼更加有序的組織在一起。


3.2 setup
setup 概述
P7:https://www.bilibili.com/video/BV1Za4y1r7KE?p=7
setup
是Vue3
中一個新的配置項,值是一個函數(shù),它是 Composition API
“表演的舞臺”,組件中所用到的:數(shù)據(jù)、方法、計算屬性、監(jiān)視......等等,均配置在setup
中。
特點如下:
-
setup
函數(shù)返回的對象中的內(nèi)容,可直接在模板中使用。 -
setup
中訪問this
是undefined
。 -
setup
函數(shù)會在beforeCreate
之前調(diào)用,它是“領(lǐng)先”所有鉤子執(zhí)行的。
<template>
<div class="person">
<h2>姓名:{{name}}</h2>
<h2>年齡:{{age}}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">年齡+1</button>
<button @click="showTel">點我查看聯(lián)系方式</button>
</div>
</template>
<script lang="ts">
export default {
name:'Person',
setup(){
// 數(shù)據(jù),原來寫在data中(注意:此時的name、age、tel數(shù)據(jù)都不是響應(yīng)式數(shù)據(jù))
let name = '張三'
let age = 18
let tel = '13888888888'
// 方法,原來寫在methods中
function changeName(){
name = 'zhang-san' //注意:此時這么修改name頁面是不變化的
console.log(name)
}
function changeAge(){
age += 1 //注意:此時這么修改age頁面是不變化的
console.log(age)
}
function showTel(){
alert(tel)
}
// 返回一個對象,對象中的內(nèi)容,模板中可以直接使用
return {name,age,tel,changeName,changeAge,showTel}
}
}
</script>
setup 的返回值
P8:https://www.bilibili.com/video/BV1Za4y1r7KE?p=8
-
若返回一個 對象:則對象中的:屬性、方法等,在模板中均可以直接使用 (重點關(guān)注)。 -
若返回一個 函數(shù):則可以自定義渲染內(nèi)容,代碼如下:
setup(){
return ()=> '你好??!'
}
setup 與 Options API 的關(guān)系
P9:https://www.bilibili.com/video/BV1Za4y1r7KE?p=9
-
Vue2
的配置(data
、methos
......)中 可以訪問到setup
中的屬性、方法。 -
但在 setup
中 不能訪問到Vue2
的配置(data
、methos
......)。 -
如果與 Vue2
沖突,則setup
優(yōu)先。
setup 語法糖
P10:https://www.bilibili.com/video/BV1Za4y1r7KE?p=10
setup
函數(shù)有一個語法糖,這個語法糖,可以讓我們把setup
獨立出去,代碼如下:
<template>
<div class="person">
<h2>姓名:{{name}}</h2>
<h2>年齡:{{age}}</h2>
<button @click="changName">修改名字</button>
<button @click="changAge">年齡+1</button>
<button @click="showTel">點我查看聯(lián)系方式</button>
</div>
</template>
<script lang="ts">
export default {
name:'Person234', // 定義組件名
}
</script>
<!-- 下面的寫法是setup語法糖 -->
<script setup lang="ts">
console.log(this) //undefined
// 數(shù)據(jù)(注意:此時的name、age、tel都不是響應(yīng)式數(shù)據(jù))
let name = '張三'
let age = 18
let tel = '13888888888'
// 方法
function changName(){
name = '李四'//注意:此時這么修改name頁面是不變化的
}
function changAge(){
console.log(age)
age += 1 //注意:此時這么修改age頁面是不變化的
}
function showTel(){
alert(tel)
}
</script>
擴展:上述代碼,還需要編寫一個不寫setup
的script
標簽,去指定組件名字,比較麻煩,我們可以借助vite
中的插件簡化
-
第一步: npm i vite-plugin-vue-setup-extend -D
-
第二步:在 vite.config.ts
文件中添加以下內(nèi)容
import { defineConfig } from 'vite'
import VueSetupExtend from 'vite-plugin-vue-setup-extend'
export default defineConfig({
plugins: [ VueSetupExtend() ]
})
-
第三步: <script setup lang="ts" name="Person234">
3.3 ref 和 reactive
ref 創(chuàng)建:基本類型的響應(yīng)式數(shù)據(jù)
P11:https://www.bilibili.com/video/BV1Za4y1r7KE?p=11
-
作用:定義響應(yīng)式變量。 -
語法: let xxx = ref(初始值)
。 -
返回值:一個 RefImpl
的實例對象,簡稱ref對象
或ref
,ref
對象的value
屬性是響應(yīng)式的。 -
注意點: -
JS
中操作數(shù)據(jù)需要:xxx.value
,但模板中不需要.value
,直接使用即可。 -
對于 let name = ref('張三')
來說,name
不是響應(yīng)式的,name.value
是響應(yīng)式的。
-
<template>
<div class="person">
<h2>姓名:{{name}}</h2>
<h2>年齡:{{age}}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">年齡+1</button>
<button @click="showTel">點我查看聯(lián)系方式</button>
</div>
</template>
<script setup lang="ts" name="Person">
import {ref} from 'vue'
// name和age是一個RefImpl的實例對象,簡稱ref對象,它們的value屬性是響應(yīng)式的。
let name = ref('張三')
let age = ref(18)
// tel就是一個普通的字符串,不是響應(yīng)式的
let tel = '13888888888'
function changeName(){
// JS中操作ref對象時候需要.value
name.value = '李四'
console.log(name.value)
// 注意:name不是響應(yīng)式的,name.value是響應(yīng)式的,所以如下代碼并不會引起頁面的更新。
// name = ref('zhang-san')
}
function changeAge(){
// JS中操作ref對象時候需要.value
age.value += 1
console.log(age.value)
}
function showTel(){
alert(tel)
}
</script>
reactive 創(chuàng)建:對象類型的響應(yīng)式數(shù)據(jù)
P12:https://www.bilibili.com/video/BV1Za4y1r7KE?p=12
-
作用:定義一個 響應(yīng)式對象(基本類型不要用它,要用 ref
,否則報錯) -
語法: let 響應(yīng)式對象= reactive(源對象)
。 -
返回值:一個 Proxy
的實例對象,簡稱:響應(yīng)式對象。 -
注意點: reactive
定義的響應(yīng)式數(shù)據(jù)是“深層次”的。
<template>
<div class="person">
<h2>汽車信息:一臺{{ car.brand }}汽車,價值{{ car.price }}萬</h2>
<h2>游戲列表:</h2>
<ul>
<li v-for="g in games" :key="g.id">{{ g.name }}</li>
</ul>
<h2>測試:{{obj.a.b.c.d}}</h2>
<button @click="changeCarPrice">修改汽車價格</button>
<button @click="changeFirstGame">修改第一游戲</button>
<button @click="test">測試</button>
</div>
</template>
<script lang="ts" setup name="Person">
import { reactive } from 'vue'
// 數(shù)據(jù)
let car = reactive({ brand: '奔馳', price: 100 })
let games = reactive([
{ id: 'ahsgdyfa01', name: '英雄聯(lián)盟' },
{ id: 'ahsgdyfa02', name: '王者榮耀' },
{ id: 'ahsgdyfa03', name: '原神' }
])
let obj = reactive({
a:{
b:{
c:{
d:666
}
}
}
})
function changeCarPrice() {
car.price += 10
}
function changeFirstGame() {
games[0].name = '流星蝴蝶劍'
}
function test(){
obj.a.b.c.d = 999
}
</script>
ref 創(chuàng)建:對象類型的響應(yīng)式數(shù)據(jù)
P13:https://www.bilibili.com/video/BV1Za4y1r7KE?p=13
-
其實 ref
接收的數(shù)據(jù)可以是: 基本類型、 對象類型。 -
若 ref
接收的是對象類型,內(nèi)部其實也是調(diào)用了reactive
函數(shù)。
<template>
<div class="person">
<h2>汽車信息:一臺{{ car.brand }}汽車,價值{{ car.price }}萬</h2>
<h2>游戲列表:</h2>
<ul>
<li v-for="g in games" :key="g.id">{{ g.name }}</li>
</ul>
<h2>測試:{{obj.a.b.c.d}}</h2>
<button @click="changeCarPrice">修改汽車價格</button>
<button @click="changeFirstGame">修改第一游戲</button>
<button @click="test">測試</button>
</div>
</template>
<script lang="ts" setup name="Person">
import { ref } from 'vue'
// 數(shù)據(jù)
let car = ref({ brand: '奔馳', price: 100 })
let games = ref([
{ id: 'ahsgdyfa01', name: '英雄聯(lián)盟' },
{ id: 'ahsgdyfa02', name: '王者榮耀' },
{ id: 'ahsgdyfa03', name: '原神' }
])
let obj = ref({
a:{
b:{
c:{
d:666
}
}
}
})
console.log(car)
function changeCarPrice() {
car.value.price += 10
}
function changeFirstGame() {
games.value[0].name = '流星蝴蝶劍'
}
function test(){
obj.value.a.b.c.d = 999
}
</script>
ref 對比 reactive
P14:https://www.bilibili.com/video/BV1Za4y1r7KE?p=14
宏觀角度看:
-
ref
用來定義: 基本類型數(shù)據(jù)、 對象類型數(shù)據(jù); -
reactive
用來定義: 對象類型數(shù)據(jù)。
區(qū)別:
-
ref
創(chuàng)建的變量必須使用.value
(可以使用volar
插件自動添加.value
)。 -
reactive
重新分配一個新對象,會 失去響應(yīng)式(可以使用Object.assign
去整體替換)。
使用原則:
-
若需要一個基本類型的響應(yīng)式數(shù)據(jù),必須使用 ref
。 -
若需要一個響應(yīng)式對象,層級不深, ref
、reactive
都可以。 -
若需要一個響應(yīng)式對象,且層級較深,推薦使用 reactive
。
toRefs 與 toRef
P15:https://www.bilibili.com/video/BV1Za4y1r7KE?p=15
-
作用:將一個響應(yīng)式對象中的每一個屬性,轉(zhuǎn)換為 ref
對象。 -
備注: toRefs
與toRef
功能一致,但toRefs
可以批量轉(zhuǎn)換。 -
語法如下:
<template>
<div class="person">
<h2>姓名:{{person.name}}</h2>
<h2>年齡:{{person.age}}</h2>
<h2>性別:{{person.gender}}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年齡</button>
<button @click="changeGender">修改性別</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {ref,reactive,toRefs,toRef} from 'vue'
// 數(shù)據(jù)
let person = reactive({name:'張三', age:18, gender:'男'})
// 通過toRefs將person對象中的n個屬性批量取出,且依然保持響應(yīng)式的能力
let {name,gender} = toRefs(person)
// 通過toRef將person對象中的gender屬性取出,且依然保持響應(yīng)式的能力
let age = toRef(person,'age')
// 方法
function changeName(){
name.value += '~'
}
function changeAge(){
age.value += 1
}
function changeGender(){
gender.value = '女'
}
</script>
3.4 computed
P16:https://www.bilibili.com/video/BV1Za4y1r7KE?p=16
作用:根據(jù)已有數(shù)據(jù)計算出新數(shù)據(jù)(和Vue2
中的computed
作用一致)。

<template>
<div class="person">
姓:<input type="text" v-model="firstName"> <br>
名:<input type="text" v-model="lastName"> <br>
全名:<span>{{fullName}}</span> <br>
<button @click="changeFullName">全名改為:li-si</button>
</div>
</template>
<script setup lang="ts" name="App">
import {ref,computed} from 'vue'
let firstName = ref('zhang')
let lastName = ref('san')
// 計算屬性——只讀取,不修改
/* let fullName = computed(()=>{
return firstName.value + '-' + lastName.value
}) */
// 計算屬性——既讀取又修改
let fullName = computed({
// 讀取
get(){
return firstName.value + '-' + lastName.value
},
// 修改
set(val){
console.log('有人修改了fullName',val)
firstName.value = val.split('-')[0]
lastName.value = val.split('-')[1]
}
})
function changeFullName(){
fullName.value = 'li-si'
}
</script>
3.5 watch
P17:https://www.bilibili.com/video/BV1Za4y1r7KE?p=17
-
作用:監(jiān)視數(shù)據(jù)的變化(和 Vue2
中的watch
作用一致) -
特點: Vue3
中的watch
只能監(jiān)視以下 四種數(shù)據(jù):
-
ref
定義的數(shù)據(jù)。 -
reactive
定義的數(shù)據(jù)。 -
函數(shù)返回一個值( getter
函數(shù))。 -
一個包含上述內(nèi)容的數(shù)組。
我們在Vue3
中使用watch
的時候,通常會遇到以下幾種情況:
情況一
監(jiān)視ref
定義的【基本類型】數(shù)據(jù):直接寫數(shù)據(jù)名即可,監(jiān)視的是其value
值的改變。
<template>
<div class="person">
<h1>情況一:監(jiān)視【ref】定義的【基本類型】數(shù)據(jù)</h1>
<h2>當前求和為:{{sum}}</h2>
<button @click="changeSum">點我sum+1</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {ref,watch} from 'vue'
// 數(shù)據(jù)
let sum = ref(0)
// 方法
function changeSum(){
sum.value += 1
}
// 監(jiān)視,情況一:監(jiān)視【ref】定義的【基本類型】數(shù)據(jù)
const stopWatch = watch(sum,(newValue,oldValue)=>{
console.log('sum變化了',newValue,oldValue)
if(newValue >= 10){
stopWatch()
}
})
</script>
情況二
P18:https://www.bilibili.com/video/BV1Za4y1r7KE?p=18
監(jiān)視ref
定義的【對象類型】數(shù)據(jù):直接寫數(shù)據(jù)名,監(jiān)視的是對象的【地址值】,若想監(jiān)視對象內(nèi)部的數(shù)據(jù),要手動開啟深度監(jiān)視。
注意:
-
若修改的是 ref
定義的對象中的屬性,newValue
和oldValue
都是新值,因為它們是同一個對象。 -
若修改整個 ref
定義的對象,newValue
是新值,oldValue
是舊值,因為不是同一個對象了。
<template>
<div class="person">
<h1>情況二:監(jiān)視【ref】定義的【對象類型】數(shù)據(jù)</h1>
<h2>姓名:{{ person.name }}</h2>
<h2>年齡:{{ person.age }}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年齡</button>
<button @click="changePerson">修改整個人</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {ref,watch} from 'vue'
// 數(shù)據(jù)
let person = ref({
name:'張三',
age:18
})
// 方法
function changeName(){
person.value.name += '~'
}
function changeAge(){
person.value.age += 1
}
function changePerson(){
person.value = {name:'李四',age:90}
}
/*
監(jiān)視,情況一:監(jiān)視【ref】定義的【對象類型】數(shù)據(jù),監(jiān)視的是對象的地址值,若想監(jiān)視對象內(nèi)部屬性的變化,需要手動開啟深度監(jiān)視
watch的第一個參數(shù)是:被監(jiān)視的數(shù)據(jù)
watch的第二個參數(shù)是:監(jiān)視的回調(diào)
watch的第三個參數(shù)是:配置對象(deep、immediate等等.....)
*/
watch(person,(newValue,oldValue)=>{
console.log('person變化了',newValue,oldValue)
},{deep:true})
</script>
情況三
P19:https://www.bilibili.com/video/BV1Za4y1r7KE?p=19
監(jiān)視reactive
定義的【對象類型】數(shù)據(jù),且默認開啟了深度監(jiān)視。
<template>
<div class="person">
<h1>情況三:監(jiān)視【reactive】定義的【對象類型】數(shù)據(jù)</h1>
<h2>姓名:{{ person.name }}</h2>
<h2>年齡:{{ person.age }}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年齡</button>
<button @click="changePerson">修改整個人</button>
<hr>
<h2>測試:{{obj.a.b.c}}</h2>
<button @click="test">修改obj.a.b.c</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {reactive,watch} from 'vue'
// 數(shù)據(jù)
let person = reactive({
name:'張三',
age:18
})
let obj = reactive({
a:{
b:{
c:666
}
}
})
// 方法
function changeName(){
person.name += '~'
}
function changeAge(){
person.age += 1
}
function changePerson(){
Object.assign(person,{name:'李四',age:80})
}
function test(){
obj.a.b.c = 888
}
// 監(jiān)視,情況三:監(jiān)視【reactive】定義的【對象類型】數(shù)據(jù),且默認是開啟深度監(jiān)視的
watch(person,(newValue,oldValue)=>{
console.log('person變化了',newValue,oldValue)
})
watch(obj,(newValue,oldValue)=>{
console.log('Obj變化了',newValue,oldValue)
})
</script>
情況四
P20:https://www.bilibili.com/video/BV1Za4y1r7KE?p=20
監(jiān)視ref
或reactive
定義的【對象類型】數(shù)據(jù)中的某個屬性,注意點如下:
-
若該屬性值 不是【對象類型】,需要寫成函數(shù)形式。 -
若該屬性值 依然是【對象類型】,可直接編,也可寫成函數(shù),建議寫成函數(shù)。
結(jié)論:監(jiān)視的要是對象里的屬性,那么最好寫函數(shù)式,注意點:若是對象監(jiān)視的是地址值,需要關(guān)注對象內(nèi)部,需要手動開啟深度監(jiān)視。
<template>
<div class="person">
<h1>情況四:監(jiān)視【ref】或【reactive】定義的【對象類型】數(shù)據(jù)中的某個屬性</h1>
<h2>姓名:{{ person.name }}</h2>
<h2>年齡:{{ person.age }}</h2>
<h2>汽車:{{ person.car.c1 }}、{{ person.car.c2 }}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年齡</button>
<button @click="changeC1">修改第一臺車</button>
<button @click="changeC2">修改第二臺車</button>
<button @click="changeCar">修改整個車</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {reactive,watch} from 'vue'
// 數(shù)據(jù)
let person = reactive({
name:'張三',
age:18,
car:{
c1:'奔馳',
c2:'寶馬'
}
})
// 方法
function changeName(){
person.name += '~'
}
function changeAge(){
person.age += 1
}
function changeC1(){
person.car.c1 = '奧迪'
}
function changeC2(){
person.car.c2 = '大眾'
}
function changeCar(){
person.car = {c1:'雅迪',c2:'愛瑪'}
}
// 監(jiān)視,情況四:監(jiān)視響應(yīng)式對象中的某個屬性,且該屬性是基本類型的,要寫成函數(shù)式
/* watch(()=> person.name,(newValue,oldValue)=>{
console.log('person.name變化了',newValue,oldValue)
}) */
// 監(jiān)視,情況四:監(jiān)視響應(yīng)式對象中的某個屬性,且該屬性是對象類型的,可以直接寫,也能寫函數(shù),更推薦寫函數(shù)
watch(()=>person.car,(newValue,oldValue)=>{
console.log('person.car變化了',newValue,oldValue)
},{deep:true})
</script>
情況五
P21:https://www.bilibili.com/video/BV1Za4y1r7KE?p=21
監(jiān)視上述的多個數(shù)據(jù)
<template>
<div class="person">
<h1>情況五:監(jiān)視上述的多個數(shù)據(jù)</h1>
<h2>姓名:{{ person.name }}</h2>
<h2>年齡:{{ person.age }}</h2>
<h2>汽車:{{ person.car.c1 }}、{{ person.car.c2 }}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年齡</button>
<button @click="changeC1">修改第一臺車</button>
<button @click="changeC2">修改第二臺車</button>
<button @click="changeCar">修改整個車</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {reactive,watch} from 'vue'
// 數(shù)據(jù)
let person = reactive({
name:'張三',
age:18,
car:{
c1:'奔馳',
c2:'寶馬'
}
})
// 方法
function changeName(){
person.name += '~'
}
function changeAge(){
person.age += 1
}
function changeC1(){
person.car.c1 = '奧迪'
}
function changeC2(){
person.car.c2 = '大眾'
}
function changeCar(){
person.car = {c1:'雅迪',c2:'愛瑪'}
}
// 監(jiān)視,情況五:監(jiān)視上述的多個數(shù)據(jù)
watch([()=>person.name,person.car],(newValue,oldValue)=>{
console.log('person.car變化了',newValue,oldValue)
},{deep:true})
</script>
watchEffect
P22:https://www.bilibili.com/video/BV1Za4y1r7KE?p=22
官網(wǎng):立即運行一個函數(shù),同時響應(yīng)式地追蹤其依賴,并在依賴更改時重新執(zhí)行該函數(shù)。
watch
對比watchEffect
-
都能監(jiān)聽響應(yīng)式數(shù)據(jù)的變化,不同的是監(jiān)聽數(shù)據(jù)變化的方式不同 -
watch
:要明確指出監(jiān)視的數(shù)據(jù) -
watchEffect
:不用明確指出監(jiān)視的數(shù)據(jù)(函數(shù)中用到哪些屬性,那就監(jiān)視哪些屬性)。
示例代碼:文章來源:http://www.zghlxwxcb.cn/news/detail-834734.html
<template>
<div class="person">
<h1>需求:水溫達到50℃,或水位達到20cm,則聯(lián)系服務(wù)器</h1>
<h2 id="demo">水溫:{{temp}}</h2>
<h2>水位:{{height}}</h2>
<button @click="changePrice">水溫+1</button>
<button @click="changeSum">水位+10</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {ref,watch,watchEffect} from 'vue'
// 數(shù)據(jù)
let temp = ref(0)
let height = ref(0)
// 方法
function changePrice(){
temp.value += 10
}
function changeSum(){
height.value += 1
}
// 用watch實現(xiàn),需要明確的指出要監(jiān)視:temp、height
watch([temp,height],(value)=>{
// 從value中獲取最新的temp值、height值
const [newTemp,newHeight] = value
// 室溫達到50℃,或水位達到20cm,立刻聯(lián)系服務(wù)器
if(newTemp >= 50 || newHeight >= 20){
console.log('聯(lián)系服務(wù)器')
}
})
// 用watchEffect實現(xiàn),不用
const stopWtach = watchEffect(()=>{
// 室溫達到50℃,或水位達到20cm,立刻聯(lián)系服務(wù)器
if(temp.value >= 50 || height.value >= 20){
console.log(document.getElementById('demo')?.innerText)
console.log('聯(lián)系服務(wù)器')
}
// 水溫達到100,或水位達到50,取消監(jiān)視
if(temp.value === 100 || height.value === 50){
console.log('清理了')
stopWtach()
}
})
</script>
3.6 標簽的 ref 屬性
P23:https://www.bilibili.com/video/BV1Za4y1r7KE?p=23
作用:用于注冊模板引用。
-
用在普通 DOM
標簽上,獲取的是DOM
節(jié)點。 -
用在組件標簽上,獲取的是組件實例對象。
用在普通DOM
標簽上:
<template>
<div class="person">
<h1 ref="title1">尚硅谷</h1>
<h2 ref="title2">前端</h2>
<h3 ref="title3">Vue</h3>
<input type="text" ref="inpt"> <br><br>
<button @click="showLog">點我打印內(nèi)容</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {ref} from 'vue'
let title1 = ref()
let title2 = ref()
let title3 = ref()
function showLog(){
// 通過id獲取元素
const t1 = document.getElementById('title1')
// 打印內(nèi)容
console.log((t1 as HTMLElement).innerText)
console.log((<HTMLElement>t1).innerText)
console.log(t1?.innerText)
/************************************/
// 通過ref獲取元素
console.log(title1.value)
console.log(title2.value)
console.log(title3.value)
}
</script>
用在組件標簽上:
<!-- 父組件App.vue -->
<template>
<Person ref="ren"/>
<button @click="test">測試</button>
</template>
<script lang="ts" setup name="App">
import Person from './components/Person.vue'
import {ref} from 'vue'
let ren = ref()
function test(){
console.log(ren.value.name)
console.log(ren.value.age)
}
</script>
<!-- 子組件Person.vue中要使用defineExpose暴露內(nèi)容 -->
<script lang="ts" setup name="Person">
import {ref,defineExpose} from 'vue'
// 數(shù)據(jù)
let name = ref('張三')
let age = ref(18)
/****************************/
/****************************/
// 使用defineExpose將組件中的數(shù)據(jù)交給外部
defineExpose({name,age})
</script>
3.7 props
回顧 TS 中的接口
P24:https://www.bilibili.com/video/BV1Za4y1r7KE?p=24
props 的使用
P25:https://www.bilibili.com/video/BV1Za4y1r7KE?p=25
type/index.ts
中代碼:
// 定義一個接口,限制每個Person對象的格式
export interface PersonInter {
id:string,
name:string,
age:number
}
// 定義一個自定義類型Persons
export type Persons = Array<PersonInter>
App.vue
中代碼:
<template>
<Person :list="persons"/>
</template>
<script lang="ts" setup name="App">
import Person from './components/Person.vue'
import {reactive} from 'vue'
import {type Persons} from './types'
let persons = reactive<Persons>([
{id:'e98219e12',name:'張三',age:18},
{id:'e98219e13',name:'李四',age:19},
{id:'e98219e14',name:'王五',age:20}
])
</script>
Person.vue
中代碼:
<template>
<div class="person">
<ul>
<li v-for="item in list" :key="item.id">
{{item.name}}--{{item.age}}
</li>
</ul>
</div>
</template>
<script lang="ts" setup name="Person">
import {defineProps} from 'vue'
import {type PersonInter} from '@/types'
// 第一種寫法:僅接收
// const props = defineProps(['list'])
// 第二種寫法:接收+限制類型
// defineProps<{list:Persons}>()
// 第三種寫法:接收+限制類型+指定默認值+限制必要性
let props = withDefaults(defineProps<{list?:Persons}>(),{
list:()=>[{id:'asdasg01',name:'小豬佩奇',age:18}]
})
console.log(props)
</script>
3.8 生命周期
P26:https://www.bilibili.com/video/BV1Za4y1r7KE?p=26
概念:Vue
組件實例在創(chuàng)建時要經(jīng)歷一系列的初始化步驟,在此過程中Vue
會在合適的時機,調(diào)用特定的函數(shù),從而讓開發(fā)者有機會在特定階段運行自己的代碼,這些特定的函數(shù)統(tǒng)稱為:生命周期鉤子
規(guī)律:生命周期整體分為四個階段,分別是:創(chuàng)建、掛載、更新、銷毀,每個階段都有兩個鉤子,一前一后。
P27:https://www.bilibili.com/video/BV1Za4y1r7KE?p=27
Vue2
的生命周期
-
創(chuàng)建階段: beforeCreate
、created
-
掛載階段: beforeMount
、mounted
-
更新階段: beforeUpdate
、updated
-
銷毀階段: beforeDestroy
、destroyed
P28:https://www.bilibili.com/video/BV1Za4y1r7KE?p=28
Vue3
的生命周期
-
創(chuàng)建階段: setup
-
掛載階段: onBeforeMount
、onMounted
-
更新階段: onBeforeUpdate
、onUpdated
-
卸載階段: onBeforeUnmount
、onUnmounted
常用的鉤子:onMounted
(掛載完畢)、onUpdated
(更新完畢)、onBeforeUnmount
(卸載之前)
示例代碼:
<template>
<div class="person">
<h2>當前求和為:{{ sum }}</h2>
<button @click="changeSum">點我sum+1</button>
</div>
</template>
<!-- vue3寫法 -->
<script lang="ts" setup name="Person">
import {
ref,
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted
} from 'vue'
// 數(shù)據(jù)
let sum = ref(0)
// 方法
function changeSum() {
sum.value += 1
}
console.log('setup')
// 生命周期鉤子
onBeforeMount(()=>{
console.log('掛載之前')
})
onMounted(()=>{
console.log('掛載完畢')
})
onBeforeUpdate(()=>{
console.log('更新之前')
})
onUpdated(()=>{
console.log('更新完畢')
})
onBeforeUnmount(()=>{
console.log('卸載之前')
})
onUnmounted(()=>{
console.log('卸載完畢')
})
</script>
3.9 hook
P29:https://www.bilibili.com/video/BV1Za4y1r7KE?p=29
什么是hook
?—— 本質(zhì)是一個函數(shù),把setup
函數(shù)中使用的Composition API
進行了封裝,類似于vue2.x
中的mixin
。
自定義hook
的優(yōu)勢:復(fù)用代碼, 讓setup
中的邏輯更清楚易懂。
示例代碼:
-
useSum.ts
中內(nèi)容如下:
import {ref,onMounted} from 'vue'
export default function(){
let sum = ref(0)
const increment = ()=>{
sum.value += 1
}
const decrement = ()=>{
sum.value -= 1
}
onMounted(()=>{
increment()
})
//向外部暴露數(shù)據(jù)
return {sum,increment,decrement}
}
-
useDog.ts
中內(nèi)容如下:
import {reactive,onMounted} from 'vue'
import axios,{AxiosError} from 'axios'
export default function(){
let dogList = reactive<string[]>([])
// 方法
async function getDog(){
try {
// 發(fā)請求
let {data} = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
// 維護數(shù)據(jù)
dogList.push(data.message)
} catch (error) {
// 處理錯誤
const err = <AxiosError>error
console.log(err.message)
}
}
// 掛載鉤子
onMounted(()=>{
getDog()
})
//向外部暴露數(shù)據(jù)
return {dogList,getDog}
}
-
組件中具體使用:
<template>
<h2>當前求和為:{{sum}}</h2>
<button @click="increment">點我+1</button>
<button @click="decrement">點我-1</button>
<hr>
<img v-for="(u,index) in dogList.urlList" :key="index" :src="(u as string)">
<span v-show="dogList.isLoading">加載中......</span><br>
<button @click="getDog">再來一只狗</button>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
export default defineComponent({
name:'App',
})
</script>
<script setup lang="ts">
import useSum from './hooks/useSum'
import useDog from './hooks/useDog'
let {sum,increment,decrement} = useSum()
let {dogList,getDog} = useDog()
</script>

本文由 mdnice 多平臺發(fā)布文章來源地址http://www.zghlxwxcb.cn/news/detail-834734.html
到了這里,關(guān)于Vue3 學(xué)習(xí)筆記(Day2)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!