組件注冊
定義好的組件需要注冊才能被使用。 注冊方式有兩種
-
全局注冊
-
局部注冊
全局注冊
.component() 方法,讓組件在當(dāng)前 Vue 應(yīng)用中全局可用。 在 main.ts 中
import?'./assets/main.css'
import?{?createApp?}?from?'vue'
import?{?createPinia?}?from?'pinia'
import?GlobalTitle?from?'@/components/GlobalTitle.vue'
import?App?from?'./App.vue'
import?router?from?'./router'
const?app?=?createApp(App)
app.component('GlobalTitle',?GlobalTitle)
app.use(createPinia())
app.use(router)
app.mount('#app')
在 vue 中直接使用無需導(dǎo)入
<script?lang="ts"?setup>
import?{?ref?}?from?'vue'
</script>
<template>
??<div?class="container">
????<GlobalTitle></GlobalTitle>
??</div>
</template>
<style?lang="scss"?scoped>
.container?{
}
</style>
效果:
全局注冊的組件可以在此應(yīng)用的任意組件的模板中使用,所有的子組件也可以使用全局注冊的組件。
全局組件缺點
-
全局注冊,但并沒有被使用的組件無法在生產(chǎn)打包時被自動移除 (也叫“tree-shaking”)。如果你全局注冊了一個組件,即使它并沒有被實際使用,它仍然會出現(xiàn)在打包后的 JS 文件中。
-
全局注冊在大型項目中使項目的依賴關(guān)系變得不那么明確。在父組件中使用子組件時,不太容易定位子組件的實現(xiàn)。和使用過多的全局變量一樣,這可能會影響應(yīng)用長期的可維護(hù)性。
局部注冊
局部注冊的組件需要在使用它的父組件中顯式導(dǎo)入,并且只能在該父組件中使用。
它的優(yōu)點是使組件之間的依賴關(guān)系更加明確,并且對 tree-shaking 更加友好。
定義組件
<script?lang="ts"?setup>
import?{?ref?}?from?'vue'
</script>
<template>
??<div?class="container">
????<h2>這是一個局部組件</h2>
??</div>
</template>
<style?lang="scss"?scoped>
.container?{
}
</style>
局部使用組件
<script?lang="ts"?setup>
import?{?ref?}?from?'vue'
import?PartTitle?from?'@/components/PartTitle.vue'
</script>
<template>
??<div?class="container">
????<PartTitle?/>
??</div>
</template>
<style?lang="scss"?scoped>
.container?{
}
</style>
組件名格式
推薦 PascalCase 作為組件名的注冊格式。
-
PascalCase 是合法的 JavaScript 標(biāo)識符。這使得在 JavaScript 中導(dǎo)入和注冊組件都很容易,同時 IDE 也能提供較好的自動補全。
-
<PascalCase /> 在模板中更明顯地表明了這是一個 Vue 組件,而不是原生 HTML 元素。同時也能夠?qū)?Vue 組件和自定義元素 (web components) 區(qū)分開來。
在單文件組件和內(nèi)聯(lián)字符串模板中,我們都推薦這樣做。
為了方便,Vue 支持將模板中使用 kebab-case 的標(biāo)簽解析為使用 PascalCase 注冊的組件。
這意味著一個以 MyComponent 為名注冊的組件,在模板中可以通過 <MyComponent> 或 <my-component> 引用。這讓我們能夠使用同樣的 JavaScript 組件注冊代碼來配合不同來源的模板。
props
Props 聲明
一個組件需要顯式聲明它所接受的 props,這樣 Vue 才能知道外部傳入的哪些是 props,哪些是透傳 attribute。
setup 寫法
組件定義
<script?lang="ts"?setup>
import?{?ref?}?from?'vue'
const?props?=?defineProps(['person'])
</script>
<template>
??<div?class="container">
????<h1>{{?props.person?}}</h1>
??</div>
</template>
<style?lang="scss"?scoped>
.container?{
}
</style>
組件使用
<script?lang="ts"?setup>
import?{?ref?}?from?'vue'
import?Com14?from?'@/components/Com14.vue'
</script>
<template>
??<div?class="container">
????<Com14?person="'王大可'"?/>
??</div>
</template>
<style?lang="scss"?scoped>
.container?{
}
</style>
聲明對象形式的屬性 setup JavaScript 形式
defineProps({
??title:?String,
??likes:?Number
})
setup TypeScript 形式
<script?setup?lang="ts">
defineProps<{
??title?:?string
??likes?:?number
}>()
</script>
對象形式的 props 聲明不僅可以一定程度上作為組件的文檔,而且如果其他開發(fā)者在使用你的組件時傳遞了錯誤的類型,也會在瀏覽器控制臺中拋出警告。
傳遞 prop 的細(xì)節(jié)
Prop 屬性命名
如果一個 prop 的名字很長,應(yīng)使用 camelCase 形式,因為它們是合法的 JavaScript 標(biāo)識符
defineProps({
??greetingMessage:?String
})
<span>{{?greetingMessage?}}</span>
//推薦寫法
<MyComponent?greeting-message="hello"?/>
//或者
<MyComponent?greetingMessage="hello"?/>
模版上使用屬性則通常會將其寫為 kebab-case 形式,這樣和 HTML attribute 寫法就一致了。
靜態(tài) vs. 動態(tài) Prop
簡單講 就是傳入數(shù)值是字符串還是變量
//這是靜態(tài)
<Com14?person="王大可"?/>
//這是動態(tài)
<Com14?:person="personName"?/>
使用一個對象綁定多個 prop
v-bind 直接綁定對象,即只使用 v-bind 而非某一個屬性
const?post?=?{
id:?1,
title:?'My?Journey?with?Vue'
}
<BlogPost?v-bind="post"?/>
//?實際等價于
<BlogPost?:id="post.id"?:title="post.title"?/>
單向數(shù)據(jù)流
-
所有的 props 都遵循著單向綁定原則,props 因父組件的更新而變化,自然地將新的狀態(tài)向下流往子組件,而不會逆向傳遞。
-
這避免了子組件意外修改父組件的狀態(tài)的情況,不然應(yīng)用的數(shù)據(jù)流將很容易變得混亂而難以理解。
-
每次父組件更新后,所有的子組件中的 props 都會被更新到最新值,這意味著你不應(yīng)該在子組件中去更改一個 prop。若你這么做了,Vue 會在控制臺上向你拋出警告:
const?props?=?defineProps(['foo'])
//???警告!prop?是只讀的!
props.foo?=?'bar'
「更改 props 的場景:」
prop 被用于傳入初始值;而子組件想在之后將其作為一個局部數(shù)據(jù)屬性。
在這種情況下,最好是新定義一個局部數(shù)據(jù)屬性,從 props 上獲取初始值即可
const?props?=?defineProps(['initialCounter'])
//?計數(shù)器只是將?props.initialCounter?作為初始值
//?像下面這樣做就使?prop?和后續(xù)更新無關(guān)了
const?counter?=?ref(props.initialCounter)
需要對傳入的 prop 值做進(jìn)一步的轉(zhuǎn)換。
在這種情況中,最好是基于該 prop 值定義一個計算屬性:
const?props?=?defineProps(['size'])
//?該?prop?變更時計算屬性也會自動更新
const?normalizedSize?=?computed(()?=>?props.size.trim().toLowerCase())
Prop 校驗
-
Vue 組件可以更細(xì)致地聲明對傳入的 props 的校驗要求。
-
比如我們上面已經(jīng)看到過的類型聲明,如果傳入的值不滿足類型要求,Vue 會在瀏覽器控制臺中拋出警告來提醒使用者。
defineProps({
??//?基礎(chǔ)類型檢查
??//?(給出?`null`?和?`undefined`?值則會跳過任何類型檢查)
??propA:?Number,
??//?多種可能的類型
??propB:?[String,?Number],
??//?必傳,且為?String?類型
??propC:?{
????type:?String,
????required:?true
??},
??//?Number?類型的默認(rèn)值
??propD:?{
????type:?Number,
????default:?100
??},
??//?對象類型的默認(rèn)值
??propE:?{
????type:?Object,
????//?對象或數(shù)組的默認(rèn)值
????//?必須從一個工廠函數(shù)返回。
????//?該函數(shù)接收組件所接收到的原始?prop?作為參數(shù)。
????default(rawProps)?{
??????return?{?message:?'hello'?}
????}
??},
??//?自定義類型校驗函數(shù)
??//?在?3.4+?中完整的?props?作為第二個參數(shù)傳入
??propF:?{
????validator(value,?props)?{
??????//?The?value?must?match?one?of?these?strings
??????return?['success',?'warning',?'danger'].includes(value)
????}
??},
??//?函數(shù)類型的默認(rèn)值
??propG:?{
????type:?Function,
????//?不像對象或數(shù)組的默認(rèn),這不是一個
????//?工廠函數(shù)。這會是一個用來作為默認(rèn)值的函數(shù)
????default()?{
??????return?'Default?function'
????}
??}
})
defineProps() 宏中的參數(shù)不可以訪問 <script setup> 中定義的其他變量,因為在編譯時整個表達(dá)式都會被移到外部的函數(shù)中。
額外說明:
-
所有 prop 默認(rèn)都是可選的,除非聲明了 required: true
-
除 Boolean 外的未傳遞的可選 prop 將會有一個默認(rèn)值 undefined。
-
Boolean 類型的未傳遞 prop 將被轉(zhuǎn)換為 false。這可以通過為它設(shè)置 default 來更改——例如:設(shè)置為 default: undefined 將與非布爾類型的 prop 的行為保持一致。
-
如果聲明了 default 值,那么在 prop 的值被解析為 undefined 時,無論 prop 是未被傳遞還是顯式指明的 undefined,都會改為 default 值。
當(dāng) prop 的校驗失敗后,Vue 會拋出一個控制臺警告 (在開發(fā)模式下)。
運行時類型檢查
校驗選項中的 type 可以是下列這些原生構(gòu)造函數(shù):
-
String
-
Number
-
Boolean
-
Array
-
Object
-
Date
-
Function
-
Symbol
type 也可以是自定義的類或構(gòu)造函數(shù),Vue 將會通過 instanceof 來檢查類型是否匹配。
class?Person?{
??constructor(firstName,?lastName)?{
????this.firstName?=?firstName
????this.lastName?=?lastName
??}
}
defineProps({
??author:?Person
})
Vue 會通過 instanceof Person 來校驗 author prop 的值是否是 Person 類的一個實例。
Boolean 類型轉(zhuǎn)換
-
組件屬性使用 Boolean 類型
defineProps({
??disabled:?Boolean
})
<!--?等同于傳入?:disabled="true"?-->
<MyComponent?disabled?/>
<!--?等同于傳入?:disabled="false"?-->
<MyComponent?/>
-
prop 被聲明為允許多種類型時文章來源:http://www.zghlxwxcb.cn/news/detail-824529.html
只有當(dāng) Boolean 出現(xiàn)在 String 之前時,Boolean 轉(zhuǎn)換規(guī)則才適用文章來源地址http://www.zghlxwxcb.cn/news/detail-824529.html
//?disabled?將被轉(zhuǎn)換為?true
defineProps({
??disabled:?[Boolean,?Number]
})
//?disabled?將被轉(zhuǎn)換為?true
defineProps({
??disabled:?[Boolean,?String]
})
//?disabled?將被轉(zhuǎn)換為?true
defineProps({
??disabled:?[Number,?Boolean]
})
//?disabled?將被解析為空字符串?(disabled="")
defineProps({
??disabled:?[String,?Boolean]
})
到了這里,關(guān)于vue3-深入組件-組件注冊和props更多細(xì)節(jié)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!