Vue3?單文件中不同的組件
在 Vue 3 的單文件組件(.vue 文件)中,組件可以從多個(gè)層面來理解。下面我將詳細(xì)說明哪些部分算是組件,以及如何識(shí)別它們。
?? 組件定義的多個(gè)層次
1.文件本身就是一個(gè)組件
這是最直觀的理解:每個(gè) .vue 文件本身就是一個(gè) Vue 組件。
<!-- UserCard.vue - 這個(gè)文件本身就是一個(gè)組件 -->
<template>
<div class="user-card">
<h3>{{ user.name }}</h3>
<p>{{ user.email }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const user = ref({
name: '張三',
email: 'zhangsan@example.com'
})
</script>識(shí)別要點(diǎn):
- 文件擴(kuò)展名是
.vue - 包含標(biāo)準(zhǔn)的 Vue 組件結(jié)構(gòu)(template/script/style)
- 可以被其他組件導(dǎo)入和使用
2.組件中的子組件
在單個(gè) .vue 文件中,可以在 <template> 中使用的自定義標(biāo)簽都是組件。
示例1:使用全局注冊(cè)的組件
<!-- ParentComponent.vue -->
<template>
<div>
<!-- 這些都是組件 -->
<el-button>按鈕組件</el-button> <!-- Element Plus 組件 -->
<el-input placeholder="輸入框組件" /> <!-- Element Plus 組件 -->
<router-view /> <!-- Vue Router 組件 -->
</div>
</template>示例2:使用局部注冊(cè)的組件
<!-- ParentComponent.vue -->
<template>
<div>
<!-- 這些都是子組件 -->
<ChildComponentA />
<ChildComponentB />
<UserAvatar :user="currentUser" />
</div>
</template>
<script setup>
// 導(dǎo)入的組件
import ChildComponentA from './ChildComponentA.vue'
import ChildComponentB from './ChildComponentB.vue'
import UserAvatar from './UserAvatar.vue'
// 在 <script setup> 中,導(dǎo)入的組件會(huì)自動(dòng)在模板中可用
</script>3.動(dòng)態(tài)組件
使用 Vue 的 <component> 標(biāo)簽配合 :is 屬性也是組件。
<template>
<div>
<!-- 動(dòng)態(tài)組件 -->
<component :is="currentComponent" />
<!-- 也可以是異步組件 -->
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<LoadingSpinner />
</template>
</Suspense>
</div>
</template>
<script setup>
import { shallowRef, defineAsyncComponent } from 'vue'
import HomePage from './HomePage.vue'
import AboutPage from './AboutPage.vue'
// 動(dòng)態(tài)組件
const currentComponent = shallowRef(HomePage)
// 異步組件
const AsyncComponent = defineAsyncComponent(() =>
import('./AsyncComponent.vue')
)
</script>4.內(nèi)置組件
Vue 3 提供的內(nèi)置組件,雖然不寫在文件中,但使用它們也算作組件。
<template>
<!-- 內(nèi)置組件 -->
<Teleport to="body">
<Modal />
</Teleport>
<KeepAlive>
<component :is="currentComponent" />
</KeepAlive>
<Transition name="fade">
<div v-if="show">過渡內(nèi)容</div>
</Transition>
</template>5.函數(shù)式組件
在同一個(gè)文件中定義的函數(shù)式組件。
<!-- FunctionalComponentExample.vue -->
<template>
<div>
<!-- 使用函數(shù)式組件 -->
<DynamicHeading :level="1">標(biāo)題1</DynamicHeading>
<DynamicHeading :level="2">標(biāo)題2</DynamicHeading>
</div>
</template>
<script setup>
import { h } from 'vue'
// 函數(shù)式組件 - 這也是一個(gè)組件
const DynamicHeading = (props, { slots }) => {
return h(`h${props.level}`, {}, slots.default())
}
// 定義 props
DynamicHeading.props = ['level']
</script>6.渲染函數(shù)組件
在 <script> 中使用渲染函數(shù)定義的組件。
<!-- RenderFunctionExample.vue -->
<script>
import { h, defineComponent } from 'vue'
// 渲染函數(shù)組件
const CustomButton = defineComponent({
props: {
type: {
type: String,
default: 'button'
}
},
setup(props, { slots }) {
return () => h(
'button',
{
class: 'custom-button',
type: props.type
},
slots.default()
)
}
})
export default defineComponent({
components: {
CustomButton
}
})
</script>
<template>
<CustomButton>點(diǎn)擊我</CustomButton>
</template>7.JSX 組件
如果在 Vue 3 中使用 JSX,那么在同一個(gè)文件中定義的 JSX 函數(shù)也是組件。
<!-- JsxComponentExample.vue -->
<script>
import { defineComponent } from 'vue'
// JSX 組件
const JsxButton = defineComponent({
props: ['onClick'],
setup(props, { slots }) {
return () => (
<button onClick={props.onClick} class="jsx-button">
{slots.default()}
</button>
)
}
})
export default defineComponent({
components: {
JsxButton
}
})
</script>?? 實(shí)際項(xiàng)目示例分析
讓我們通過一個(gè)完整的示例來識(shí)別其中所有的組件:
<!-- App.vue -->
<template>
<div id="app">
<!-- 1. 路由組件(動(dòng)態(tài)組件) -->
<router-view />
<!-- 2. UI 框架組件 -->
<el-button @click="showModal = true">打開彈窗</el-button>
<el-dialog v-model="showModal" title="提示">
<span>這是一個(gè)彈窗</span>
</el-dialog>
<!-- 3. 內(nèi)置組件 -->
<Teleport to="body">
<!-- 4. 全局注冊(cè)的組件 -->
<GlobalNotification />
</Teleport>
<!-- 5. 局部注冊(cè)的組件 -->
<Header :title="appTitle" />
<Sidebar :menus="menuItems" />
<MainContent>
<!-- 6. 插槽中的組件 -->
<UserList :users="users" />
</MainContent>
<Footer />
<!-- 7. 條件渲染的組件 -->
<template v-if="user.isAdmin">
<AdminPanel />
</template>
<!-- 8. 循環(huán)渲染的組件 -->
<template v-for="item in featuredItems" :key="item.id">
<FeaturedCard :item="item" />
</template>
<!-- 9. 動(dòng)態(tài)組件 -->
<component :is="currentTabComponent" />
</div>
</template>
<script setup>
import { ref, shallowRef, computed, defineAsyncComponent } from 'vue'
import { useRouter } from 'vue-router'
import { ElButton, ElDialog } from 'element-plus'
// 10. 導(dǎo)入的組件
import Header from './components/Header.vue'
import Sidebar from './components/Sidebar.vue'
import MainContent from './components/MainContent.vue'
import Footer from './components/Footer.vue'
import UserList from './components/UserList.vue'
// 11. 異步組件
const AdminPanel = defineAsyncComponent(() =>
import('./components/AdminPanel.vue')
)
// 12. 全局組件(已經(jīng)在 main.js 中注冊(cè))
// GlobalNotification 已在全局注冊(cè)
// 13. 函數(shù)式組件
const StatusBadge = (props, context) => {
// 渲染函數(shù)返回虛擬節(jié)點(diǎn)
return h('span', {
class: `badge badge-${props.type}`,
style: { backgroundColor: props.color }
}, context.slots.default())
}
StatusBadge.props = ['type', 'color']
// 14. 動(dòng)態(tài)組件定義
const tabs = {
home: defineAsyncComponent(() => import('./views/Home.vue')),
about: defineAsyncComponent(() => import('./views/About.vue')),
contact: shallowRef({
template: '<div>聯(lián)系我們</div>'
})
}
const currentTab = ref('home')
const currentTabComponent = computed(() => tabs[currentTab.value])
// 響應(yīng)式數(shù)據(jù)
const showModal = ref(false)
const appTitle = ref('我的應(yīng)用')
const menuItems = ref([/* ... */])
const users = ref([/* ... */])
const user = ref({ isAdmin: true })
const featuredItems = ref([/* ... */])
</script>
<style scoped>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
}
</style>?? 組件分類總結(jié)
| 序號(hào) | 組件類型 | 示例 | 定義位置 | 使用方式 |
|---|---|---|---|---|
| 1 | 文件組件 | App.vue 本身 | 獨(dú)立的 .vue 文件 | 被其他文件導(dǎo)入 |
| 2 | 子組件 | Header, Sidebar | 其他 .vue 文件 | 在模板中作為標(biāo)簽使用 |
| 3 | UI 框架組件 | el-button, el-dialog | Element Plus 庫 | 在模板中作為標(biāo)簽使用 |
| 4 | 內(nèi)置組件 | router-view, Teleport | Vue 3 核心 | 在模板中作為標(biāo)簽使用 |
| 5 | 動(dòng)態(tài)組件 | <component :is="..."> | 當(dāng)前文件或?qū)?/td> | 通過 :is 動(dòng)態(tài)切換 |
| 6 | 異步組件 | defineAsyncComponent() | 通過函數(shù)定義 | 延遲加載 |
| 7 | 函數(shù)式組件 | StatusBadge 函數(shù) | 在當(dāng)前文件定義 | 通過函數(shù)調(diào)用或標(biāo)簽 |
| 8 | 渲染函數(shù)組件 | 使用 h() 函數(shù) | 在 <script> 中 | 通過渲染函數(shù) |
| 9 | 全局組件 | GlobalNotification | 在 main.js 注冊(cè) | 在任何地方使用 |
| 10 | 插槽組件 | <UserList> 在插槽內(nèi) | 子組件 | 通過插槽傳遞 |
?? 如何識(shí)別組件
1.在模板中識(shí)別
<template> <!-- 這些都是組件 --> <ComponentName /> <!-- 自定義組件 --> <el-button /> <!-- UI 框架組件 --> <router-view /> <!-- 內(nèi)置組件 --> <component :is="comp" /> <!-- 動(dòng)態(tài)組件 --> </template>
識(shí)別規(guī)則:
- 以大寫字母開頭的標(biāo)簽(PascalCase)通常是組件
- 以短橫線連接的標(biāo)簽(kebab-case)也可能是組件
- 使用自閉合標(biāo)簽
<ComponentName />通常是組件 - 使用非 HTML 標(biāo)準(zhǔn)標(biāo)簽的都是組件
2.在 script 中識(shí)別
// 這些都是組件的定義或?qū)?
import UserCard from './UserCard.vue' // 導(dǎo)入組件
const AsyncComp = defineAsyncComponent(...) // 定義異步組件
const FunctionalComp = () => h('div', ...) // 定義函數(shù)式組件
export default { components: { ... } } // 注冊(cè)組件
3.在實(shí)際代碼中識(shí)別
<template>
<!-- 組件示例 -->
<div>
<!-- 1. 原生 HTML 元素 -->
<div>這是 HTML 元素</div>
<button>這是 HTML 按鈕</button>
<!-- 2. Vue 組件 -->
<MyComponent /> <!-- 自定義組件 -->
<el-button>按鈕</el-button> <!-- UI 庫組件 -->
<router-link to="/">首頁</router-link> <!-- 路由組件 -->
<!-- 3. 內(nèi)置組件 -->
<Transition>
<div v-if="show">內(nèi)容</div>
</Transition>
<!-- 4. 動(dòng)態(tài)組件 -->
<component :is="currentView" />
</div>
</template>?? 快速識(shí)別技巧
技巧1:查看導(dǎo)入語句
// 這些導(dǎo)入的都是組件
import Button from './Button.vue' // 文件組件
import { ElButton } from 'element-plus' // UI 庫組件
import { RouterView } from 'vue-router' // 內(nèi)置組件
技巧2:查看組件注冊(cè)
// Options API
export default {
components: {
Button, // 局部注冊(cè)的組件
ElButton, // UI 組件
RouterView // 內(nèi)置組件
}
}
// Composition API (<script setup>)
// 導(dǎo)入的組件自動(dòng)注冊(cè)技巧3:查看模板使用
<template>
<!-- 組件特征 -->
<!-- 1. 屬性綁定 -->
<Component :prop="value" @event="handler" />
<!-- 2. 插槽使用 -->
<Component>
<template #header>標(biāo)題</template>
內(nèi)容
</Component>
<!-- 3. 作用域插槽 -->
<Component v-slot="{ item }">
{{ item.name }}
</Component>
</template>?? 實(shí)際項(xiàng)目中的應(yīng)用
項(xiàng)目結(jié)構(gòu)示例
src/ ├── components/ # 可復(fù)用組件 │ ├── common/ # 通用組件 │ │ ├── Button.vue │ │ ├── Input.vue │ │ └── Modal.vue │ └── layout/ # 布局組件 │ ├── Header.vue │ ├── Sidebar.vue │ └── Footer.vue ├── views/ # 頁面組件 │ ├── Home.vue │ ├── About.vue │ └── User/ │ ├── List.vue │ └── Detail.vue └── App.vue # 根組件
組件使用示例
<!-- Home.vue -->
<template>
<div class="home">
<!-- 布局組件 -->
<AppHeader />
<AppSidebar />
<!-- 頁面內(nèi)容 -->
<main class="content">
<!-- 功能組件 -->
<SearchBar v-model="searchText" />
<UserList :users="filteredUsers" />
<!-- UI 組件 -->
<el-pagination
:current-page="currentPage"
:total="total"
@current-change="handlePageChange"
/>
<!-- 內(nèi)置組件 -->
<router-link to="/about">關(guān)于我們</router-link>
<!-- 動(dòng)態(tài)組件 -->
<component :is="getComponentByType(user.type)" />
</main>
<!-- 布局組件 -->
<AppFooter />
</div>
</template>?? 總結(jié)
在 Vue 3 的單文件組件中,以下這些都算是組件:
- 文件本身:每個(gè)
.vue文件就是一個(gè)組件 - 導(dǎo)入的子組件:從其他文件導(dǎo)入的 Vue 組件
- UI 框架組件:如 Element Plus、Ant Design Vue 等
- 內(nèi)置組件:Vue 3 提供的
<component>、<Transition>等 - 路由組件:Vue Router 提供的
<router-view>、<router-link> - 動(dòng)態(tài)組件:通過
<component :is="...">動(dòng)態(tài)渲染的組件 - 異步組件:通過
defineAsyncComponent()定義的組件 - 函數(shù)式組件:通過函數(shù)定義的渲染函數(shù)組件
- 全局組件:在應(yīng)用級(jí)別注冊(cè)的組件
- 渲染函數(shù)組件:在
<script>中使用h()函數(shù)定義的組件
核心要點(diǎn):
- 組件是 Vue 應(yīng)用的基本構(gòu)建塊
- 組件可以被復(fù)用、組合和嵌套
- 組件化是 Vue 的核心思想
- 理解組件的各種形式有助于更好地組織代碼
簡(jiǎn)單的識(shí)別方法:
在 Vue 模板中,不是標(biāo)準(zhǔn) HTML 標(biāo)簽的元素,基本上都是組件。標(biāo)準(zhǔn) HTML 標(biāo)簽包括:
div、span、p、a、button、input等約 100 個(gè)元素。其他自定義標(biāo)簽都是組件。
通過理解這些概念,您就能準(zhǔn)確地識(shí)別 Vue 3 單文件中的各種組件,并正確地使用它們來構(gòu)建應(yīng)用。
到此這篇關(guān)于Vue3 單文件中不同的組件的文章就介紹到這了,更多相關(guān)Vue3 單文件組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue源碼解析之?dāng)?shù)組變異的實(shí)現(xiàn)
這篇文章主要介紹了Vue源碼解析之?dāng)?shù)組變異的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-12-12
Vue如何實(shí)現(xiàn)分批加載數(shù)據(jù)
這篇文章主要介紹了Vue如何實(shí)現(xiàn)分批加載數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
vue scroller返回頁面記住滾動(dòng)位置的實(shí)例代碼
這篇文章主要介紹了vue scroller返回頁面記住滾動(dòng)位置的實(shí)例代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-01-01
Vue 解決父組件跳轉(zhuǎn)子路由后當(dāng)前導(dǎo)航active樣式消失問題
這篇文章主要介紹了Vue 解決父組件跳轉(zhuǎn)子路由后當(dāng)前導(dǎo)航active樣式消失問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-07-07
axios向后臺(tái)傳遞數(shù)組作為參數(shù)的方法
今天小編就為大家分享一篇axios向后臺(tái)傳遞數(shù)組作為參數(shù)的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-08-08
Vue+WebSocket頁面實(shí)時(shí)刷新長(zhǎng)連接的實(shí)現(xiàn)
最近vue項(xiàng)目要做數(shù)據(jù)實(shí)時(shí)刷新,數(shù)據(jù)較大,會(huì)出現(xiàn)卡死情況,所以本文主要介紹了頁面實(shí)時(shí)刷新長(zhǎng)連接,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06
vue項(xiàng)目使用CDN引入的配置與易出錯(cuò)點(diǎn)
在日常開發(fā)過程中,為了減少最后打包出來的體積,我們會(huì)用到cdn引入一些比較大的庫來解決,下面這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目使用CDN引入的配置與易出錯(cuò)點(diǎn)的相關(guān)資料,需要的朋友可以參考下2022-05-05
基于VUE實(shí)現(xiàn)判斷設(shè)備是PC還是移動(dòng)端
這篇文章主要介紹了基于VUE實(shí)現(xiàn)判斷設(shè)備是PC還是移動(dòng)端,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07

