保姆級Vue3+Vite專案實戰多佈局(上)
寫在前面
本文為 Vue3+Vite
專案實戰系列教程文章第二篇,系列文章建議從頭觀看效果更佳,大家可關注 Vue3 實戰系列 防走失!點個贊再看有助於全文完整閱讀!
此係列文章主要使用到的主要技術站棧為 Vue3+Vite
,那既然是 Vue3
,狀態庫我們使用的是 Pinia
而不是 Vuex
,在寫法上也肯定是以 CompositionAPI
為主而不是 OptionsAPI
,元件庫方面我們使用的是 ArcoDesign
(趕緊丟掉 ElementUI
吧!)。
上文 這是一份保姆級Vue3+Vite實戰教程 中我們主要介紹了 Vue3+Vite
專案的搭建以及專案上的一些配置,當然後續在開發過程中如果有需要也會陸陸續續的補充一些配置。
本文我們終於要開始寫程式碼了,但其實依舊還是在為專案做準備,因為此文的核心是專案的多佈局實戰,先把頁面佈局搭建好,隨後再開始寫專案,這也是專案開發中必不可少的一環,當然重要的還是寫程式碼過程中的細節以及小技巧,新同學可以跟著碼一遍,老同學可以快速閱讀一遍看有沒有什麼用得上的實戰小技巧。
👉🏻 專案 GitHub 地址
如果大家不想從頭來過可以直接下載截止到上文內容的程式碼,👉🏻 toolsdog tag v0.0.1-dev !
程式碼拉下來之後,npm install || pnpm install
下載依賴,然後 npm run serve || pnpm serve
啟動,如果一切沒問題的話,當前專案執行起來是這樣的:
PS: 在開始寫程式碼之前,你需要簡單看下 Vue3
官方文件,去了解一下基礎 API
,這很重要!!!
OK,接下來開始本文內容!
專案多佈局思路
你想要的多佈局是哪種?
我們平常所說的多佈局比較籠統,仔細分來其實有兩種需要多佈局的場景,大家可以自行匹配一下:
- 專案有很多頁面,有些頁面是一樣的佈局,但還有些頁面是另外一種佈局,所以我們需要多種佈局提供給不同的頁面。
- 專案有很多頁面,頁面都是統一的佈局,但是我們需要提供多種可以自由切換的佈局,讓使用者在生產環境自己去選擇。
多頁面不同佈局
如果你只是需要在不同的頁面使用不同的佈局,那麼很簡單。
因為你只需要寫多個不同的佈局元件,然後使用二級路由通過指定父級路由的 component
就可以決定採用哪個佈局,如下:
假如我們有 2 個佈局:
```js // layout 1 Layout1.vue
// layout 2 Layout2.vue ```
頁面 page_a
想要使用 Layout1
佈局,頁面 page_b
想要使用 Layout2
佈局,那麼只需在配置路由時如下:
```js { routes: [ { path: '/layout1', name: 'Layout1', component: () => import('/Layout1.vue'), redirect: '/layout1/page_a', children: [ { path: 'page_a', name: 'PageA', component: () => import('/PageA.vue') },
// ...
]
},
{
path: '/layout2',
name: 'Layout2',
component: () => import('***/Layout2.vue'),
redirect: '/layout2/page_b',
children: [
{
path: 'page_b',
name: 'PageB',
component: () => import('***/PageB.vue')
},
// ...
]
}
] } ```
如上所示,我們只需要在根元件和佈局元件中寫上 <router-view />
就 OK 了!
可動態切換的佈局
再來看可以動態切換的佈局,其實也很簡單,一般來說,我們使用 Vue
的 component
元件,通過 is
屬性去動態的渲染布局元件就可以了,如下:
```html
```
然後,我們直接在父路由中引入此頁面,就可以通過改變狀態來動態切換所有的子路由佈局了,如下:
```js { routes: [ { path: '/', component: () => import('/SwitchLayout.vue'), redirect: '/page_a', children: [ { path: 'page_a', name: 'PageA', component: () => import('/PageA.vue') },
// ...
]
},
} ```
PS: Vue
內建的component
元件在 Vue2
中 is
也可以通過元件名稱切換, Vue3
中只能通過元件例項切換!
OK,到此本文就結束了,謝謝大家觀看!!!🤨
準備工作
結束是不可能結束的,多佈局本身其實很簡單,更重要的其實還是我們寫的過程中遇到的一些技術點和細節,那接下來我們開始安排!!!
咱們先寫一個可以動態切換的佈局,首先,在專案 src
目錄下建立一個佈局資料夾 layout
。
接下來我們在 src/layout
檔案下建立一個可切換佈局的入口元件 SwitchIndex.vue
,內容和上面所寫的差不多,如下:
```html
```
component
元件我們暫且註釋,因為目前還沒有佈局元件。
接下來我們建立兩個佈局元件,由於我們要把這兩種佈局的選擇權交給使用者,所以我們在 layout
資料夾下新建一個 switch
資料夾,把可以切換的這兩個佈局元件放到裡面統一管理下。
建立可切換的預設佈局檔案:layout/switch/DefaultLayout.vue
```html
```
建立可切換的邊欄佈局檔案:layout/switch/SidebarLayout.vue
```html
```
這兩個佈局的預期如下:
其實就是兩種很普通很常見的佈局,一種是有側邊欄的 SidebarLayout
( 下文叫它邊欄佈局)、一種無側邊欄的 DefaultLayout
(下文叫它預設佈局),大家先了解下要寫的樣子即可。
OK,接下來我們先完善兩種佈局然後再寫動態切換。
預設佈局元件 DefaultLayout
上面我們已經建立好了 DefaultLayout
元件,那先來把它用上。
修改一下 DefaultLayout
元件,如下:
```html
```
然後直接在 SwitchIndex
元件引入使用這個佈局,上文中我們雖然配置了元件自動引入,但是並沒有配置 layout
目錄,所以 layout
資料夾下的元件是不會被自動引入的,那我們還需要現在 vite.config.js
配置檔案中把 layout
目錄加上,如下:
```js export default defineConfig(({ mode }) => { return { // ...
plugins: [
// ...
Components({
// 新增 'src/layout' 目錄配置
dirs: ['src/components/', 'src/view/', 'src/layout'],
include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
resolvers: [
ArcoResolver({
sideEffect: true
}),
VueUseComponentsResolver(),
VueUseDirectiveResolver(),
IconsResolver({
prefix: 'icon',
customCollections: ['user', 'home']
})
]
}),
]
} }) ```
OK,然後我們就可以直接在 SwitchIndex
元件中使用 DefaultLayout
佈局元件了,我們寫的元件是匿名元件,預設元件名即檔名,如下:
```html
```
然後,我們需要修改下路由檔案 router/index.js
,把 SwitchIndex
元件作為一級路由元件,那此路由下的所有子路由就都可以使用我們的佈局了:
js
routes: [
{
path: '/',
name: 'Layout',
component: () => import('@/layout/SwitchIndex.vue'),
redirect: '/',
children: [
{
path: '/',
name: 'HomePage',
meta: {
title: 'TOOLSDOG'
},
component: () => import('@/views/HomePage.vue')
}
]
}
]
儲存看頁面:
如果你的執行效果也同上,那就已經用上了佈局元件,到此都是 OK 的,接下來就可以調整佈局 UI
樣式了!
碼一下頁面佈局
上面也說了,我們的預設佈局其實很簡單,就是很普通的上中下三分佈局。
上文我們已經裝好了 ArcoDesign
,同樣也配置了其元件自動引入,這裡我們直接使用 ArcoDesign
的 layout
佈局元件做一個常規的上中下三分佈局即可,需要注意的是,我們給 Navbar
導航部分加了一個固釘元件 a-affix
,用於固定在頁面頂部。
PS: ArcoDesign
元件均以子母 a
開頭。
修改 DefaultLayout
元件,如下:
```html
```
接著我們簡單調整一下樣式。
注意,CSS
這裡我們接上文的配置,使用的是原子化 CSS
引擎(叫框架也行哈) UnoCSS ,不太瞭解的可以看下文件教程,如果你也跟著上文配置了它並下載了 UnoCSS for VSCode
外掛,那就跟著我寫,配合外掛提供懸浮提示原生樣式,跟著我這邊寫一寫其實就會了,很簡單,畢竟常用的 CSS
樣式也就那些,語法記住就 OK 了,當然,你如果不習慣或者沒有配置此項,也無所謂,因為都是些基礎 CSS
樣式,直接用 CSS
寫一下也可以,咱就是圖個省事兒 ~
還有一點,由於我們想保證風格統一,還有就是後面想搞一下黑白模式切換,對於一些顏色、字型、尺寸方面,我這邊直接全使用了 ArcoDesign
丟擲的 CSS
變數,沒有自己去自定義一套基礎變數,沒錯,同樣也是圖省事兒 ~
其實目前正經的 UI
庫都會丟擲其統一設計的顏色變數(您要是說 ElementUI
,OK,當我沒說),那對於我們這個專案來說,ArcoDesign
自身的這些變數已經夠了,如果你是真的寫正式專案,建議遵循自家 UI
的設計風格,搞一套自己的基礎 CSS
變數來用(對一些有主題、顏色切換需求的同學來說,沒有此需求寫死顏色即可),同時如果專案中使用了開源 UI
庫,你還需要定製一下 UI
庫樣式以匹配自家 UI
設計風格,目前正經的開源 UI
庫對定製主題這塊那都沒得說,清晰明瞭且 Easy (您要是還提 ElementUI
,再次當我沒說,苦 ElementUI
良久 😄)
那說了這麼多,我們先來看下 ArcoDesign
的顏色變數吧!👉🏻 ArcoDesign CSS變數傳送們
如上,我們直接使用對應的 CSS
變數即可,這樣後期我們處理黑白模式時,直接可以用 UI 庫自帶的黑暗模式。
OK,我們簡單的寫下佈局樣式
```html
```
如上,我們給 Navbar
一個下邊框以及 58px
高度,給 Footer
一個上邊框,同時,我們給 Navbar、Content、Footer
加了不同級別的背景顏色(AcroDesign
背景色 CSS
變數),最後我們為了讓 Footer
首頁不顯示出來,給 a-layout-content
元件加了一個最小高度,使用視口高度 100vh
減去 Navbar
的高度就是該元件的最小高度了!
再說一次:相信大家無論用沒用過 UnoCSS
都可以看懂寫的樣式是啥意思,@apply
是 UnoCSS
在 style
標籤中的寫法,那在 HTML
標籤中 class
屬性中可以直接去寫 UnoCSS
樣式,如上面我們在 a-layout-content
標籤中寫的那樣,如果裝了外掛,懸浮上去會有原生樣式的提示,如下:
一切都沒問題的話,我們的專案儲存執行就如下所示了(Footer
需要滾動檢視)
導航元件 Navbar
簡單的佈局元件做好了,接下來我們慢慢填充佈局內容,先來做 Navbar
元件。
上文我們已經看了我畫的草圖,好吧,再看一遍
我們想要實現的兩種佈局都有導航欄,唯一的區別就是選單的位置,所以我們這裡把導航欄中的各個元素單獨拆分作為獨立的元件,使用插槽的方式在 Navbar
元件去使用,Navbar
元件相當於導航欄的一個佈局元件。這樣導航欄元件在哪種佈局中都是可用的,避免重複程式碼。
好,開始做了,在 src/layout
資料夾下新建 components
資料夾存放佈局相關的公共元件。
在 src/layout/components
資料夾下建立 Navbar.vue
檔案,內容如下:
```html ```
如上,我們給 Navbar
元件做了三個具名插槽,採用左中右這種結構並使用 flex
佈局將中間的插槽撐滿,同時我們也將預設插槽放在了中間的插槽位置,這樣預設會往佈局中間填充內容。
注意,導航區域的高度在佈局元件中已經固定寫死 58px
了,導航元件這裡我沒有設定高度,讓它自己撐滿就行了。因為在任何佈局下,導航欄高度是相同的。
我們在 DefaultLayout
佈局元件中的 a-layout-header
標籤中使用一下導航條元件,同樣無需引入直接使用,如下:
```html
<!-- 預設插槽和center插槽,預設插槽可不加template直接寫內容,作用同center插槽 -->
<template #center></template>
<!-- right插槽 -->
<template #right></template>
```
由於插槽中沒有寫內容,所以頁面上沒有東西,導航條殼子搞好了,接下來我們開始填充內容。
左側插槽我們寫一個 Logo
元件,中間插槽就是導航選單 Menu
元件了,右側插槽則是一些頁面小功能元件,暫定為 Github
元件(用來跳轉 Github
的)、做佈局切換的 SwitchLayout
元件、切換模式的 SwitchMode
元件,暫時就這些。
OK,接下來我們依次寫一下這些元件。
Logo 元件
在 src/layout/components
資料夾下新建 Logo.vue
檔案,寫入如下內容:
```html
```
然後把 Logo
元件填充到我們 DefaultLayout
元件下 Navbar
元件的 左側插槽中即可:
html
<Navbar>
<template #left>
<Logo />
</template>
</Navbar>
執行如下:
OK,解釋下 Logo
元件,其實就是一個圖示加上一個路由標題。
樣式我就不解釋了,跟著一塊寫的同學有什麼不知道的樣式就用編譯器滑鼠懸浮看一下原生 CSS
是什麼即可,老同學應該都能大致看懂啥樣式。
那關於 logo
我們直接在 iconify 圖示庫中找了一個圖示用,我們這裡用的是 ri:hammer-fill
圖示,關於 icon
的配置以及使用這塊上文已經說過了,不瞭解的請看上文,下文中再使用該庫圖示我就直接寫個圖示名不再解釋了哈。另外,點選 logo
會跳轉首頁。
標題呢,我們直接用 Vue
的 watchEffect
方法監聽了當前路由 meta
物件中的 title
屬性並賦值給響應式變數 title
,這樣後面我們每次跳轉到某個功能頁面時, Logo
旁邊的文字資訊以及瀏覽器 Tab
頁籤都會變成該頁面路由中配置的 title
資訊。
useRoute
方法是 Vue3
組合式 API
,它返回一個當前頁面路由的響應式物件,同樣 Vue
的核心 API
我們都做了自動引入,所以這裡沒有引入。
watchEffect
也是 Vue3
的 API
,該方法會立即執行一個函式,同時響應式地追蹤其依賴,並在依賴更改時重新執行。簡單來說就是隻要該回調中有響應式資料,這些響應式資料的依賴發生改變時就會重新執行此回撥,預設會立即執行一次。那在這個場景下就比 watch
好用多了。
那響應式變數 title
是怎麼來的呢?程式碼中我們使用了 useTitle
方法,同樣沒有引入,它不是 Vue
的 API
,其實,它是 VueUse
庫中的一個方法,VueUse useTitle 傳送門,在上文我們已經給 VueUse
這個庫的方法做了自動引入,所以可以直接用,該方法會返回一個響應式變數,這個響應式變數在改變時會自動改變我們的網頁標題,注意這裡的標題指的是瀏覽器 Tab
標籤中的標題,如下:
如上圖,既然已經拿圖示當了 logo
,那一不做二不休,把 Tab
籤中的 ico
圖示也換了吧,就是上圖中預設的 Vue
圖示,再次去 iconify
圖示庫線上網站中找到我們使用的 logo
圖示,下載個 png
下來,然後找個免費線上的圖片 png
轉 ico
格式網站轉一下格式(百度、谷歌找),把轉換後的檔名改成 favicon.ico
,替換掉專案根目錄下的 public/favicon.ico
檔案即可,然後我們瀏覽器中的 Tab ico
圖片就換好了,如下:
OK,到此 Logo
元件就搞好了。
Github 跳轉小元件
寫 Github
跳轉元件之前我們需要在 config/index.js
檔案中配置一下 GitHub Url
地址,方便日後我們在專案中使用或統一修改,Config
配置檔案具體內容看文章開頭的程式碼或者看上文配置講解。
在 config/index.js
檔案的 configSource
物件中新增一個 github
屬性,屬性值寫上我們的專案地址,如下:
```js const configSource = { // ...
github: 'http://github.com/isboyjc/toolsdog' } ```
Github
跳轉元件很簡單,就是字面意思,我們搞一個圖示放上去,然後能夠點選開啟一個新標籤跳轉到專案的 GitHub
地址就行了。在 src/layout/components
資料夾下新建 Github.vue
檔案,寫入如下內容:
```html
```
GitHub
的圖示我們用的 iconify
圖示庫中 mdi:github
圖示,這個就沒啥需要說的了,什麼?你問我為啥不直接用 a
標籤或者 UI
庫的 Link
元件?答案是這個元件庫按鈕懸浮的互動很好看~
接著我們去使用一下,把 Github
元件填充到預設佈局 DefaultLayout
元件下 Navbar
元件的右側插槽中即可:
html
<Navbar>
<template #right>
<Github />
</template>
</Navbar>
執行如下:
SwitchLayout
元件、SwitchMode
元件我們得放到後面再說,接下來我們來寫導航選單元件。
選單元件 Menu
由於我們目前只有一個路由,就是首頁,還沒有其他正八經兒的功能頁面,所以,這裡我們要先寫一個路由頁面。
那佈局寫完之後我們第一個功能應該是要寫正則視覺化校驗功能,這裡我們就提前給它把路由以及頁面定義好吧!
首先,在 src/views
資料夾下新建 RegularPage.vue
檔案作為正則校驗頁面元件:
```html
```
接著我們要配置一下路由,注意,由於現在寫的頁面路由它同時還是個選單,所以我們把這些可以作為選單的路由單獨寫一個路由檔案,這樣我們後期可以直接可以匯出當作選單項配置用。
在 src/router
資料夾下新建 menuRouter.js
檔案,匯出一個選單路由陣列,如下:
js
export const menuRouter = []
在 src/router/index.js
中使用一下:
```js import { createRouter, createWebHistory } from 'vue-router' // 匯入選單路由 import { menuRouter } from './menuRouter'
const router = createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes: [ { path: '/', name: 'Layout', component: () => import('@/layout/index.vue'), redirect: '/', children: [ { path: '/', name: 'HomePage', meta: { title: 'TOOLSDOG' }, component: () => import('@/views/HomePage.vue') }, // 使用選單路由 ...menuRouter ] } ] })
export default router ```
OK,接下來我們配置選單路由陣列,由於我們將來可能會寫到很多不同種類的功能,所以我們使用多級路由的方式給這些頁面做個分類,正則視覺化校驗屬於開發工具類,所以我們給它一個 devtools
的父級路由,另外,在選單路由中,每個父級選單我們給他在 meta
物件中新增一個 icon
屬性,然後匯入一個圖片元件作為對應 icon
的值,這樣做的目的是將來要在導航選單中給每個分類的選單都加個圖示。
OK,修改 menuRouter.js
檔案如下:
```js import IconMaterialSymbolsCodeBlocksOutline from '~icons/material-symbols/code-blocks-outline'
export const menuRouter = [ { path: 'devtools', name: 'DevTools', meta: { title: '開發工具', icon: markRaw(IconMaterialSymbolsCodeBlocksOutline) }, redirect: { name: 'RegularPage' }, children: [ { path: 'regular', name: 'RegularPage', meta: { title: '正則線上校驗' }, component: () => import('@/views/RegularPage.vue') } ] } ] ```
如上,我們如果想要訪問此頁面,只需要訪問 /devtools/regular
路由即可,那可能有些人注意到該配置中的父級路由的重定向中我們使用的是 name
來做的重定向,這裡不用 path
是為了更安全,這個安全指的是由於我們單獨抽離出了這個選單路由模組,雖然目前是在把它引入並寫在了 /
路由下,但是將來萬一改變了一級路由,那整體的 path
都會改變,而使用 name
欄位重定向就不存在這個問題,我們只需要注意下各個路由的 name
欄位配置不重複即可。
注意,我們上面手動引入了 iconify
圖示庫中的圖示,可能有人會問不是做了 iconify
的自動引入嗎?為什麼還要手動去引入?其實,元件的自動引入是靠解析識別元件模板中引入的元件再做的匹配,而這裡我們沒有在元件模板中使用,而是在 JS
中直接使用的,包括我們做專案經常會做的選單配置,都是隻存一個圖示名,它是靠我們在執行時通過圖示名去匹配元件,這是一個執行時動態的過程,開發時是做不了自動引入的,這類情況我們需要手動引入一下。
還有一個大家可能發現了,在寫入圖示元件時,我們使用了 Vue3
的 markRaw
方法,markRaw
方法會標記一個物件,使其不能成為一個響應式物件,因為後面我們會將整個選單路由資料作為一個響應式物件傳入選單元件渲染,那如果我們在這個資料中存在 Vue
元件,將會造成一些不必要的效能開銷,所以這裡我們直接使用 markRaw
物件給它標記下,使該物件不會被遞迴解析成響應式物件即可。
接下來在瀏覽器訪問下 /devtools/regular
路由,看看效果,同下即沒問題:
已經有選單了資料了,我們去寫選單 Menu
元件。先理一下思路,通常元件庫中會有 Menu
元件,當然 ArcoDesign
也不例外,我們可以直接拿過來封裝一層去使用。封裝什麼呢?雖然我們目前只有一個路由,但是我們在應該要考慮到多級的情況,那其實解決辦法就是做一個可以無限遞迴的選單元件。
OK,在寫選單元件之前,路由選單資料還需要處理下,我們寫個遞迴方法拼接一下每個選單的完整路由,並把每個路由選單中的 meta
物件壓平到選單裡,方便我們後面使用,還是在 src/router
資料夾下的 menuRouter.js
檔案,新增一個 menuRouterFormat
方法處理選單資料並將處理後的資料匯出,如下:
```js export const menuRouter = [ // ... ]
/*
* @description 選單路由陣列 format
* @param { Array } router 路由陣列
* @param { String } parentPath 父級路由 path
* @return { Array }
/
export const menuRouterFormat = (router, parentPath) => {
return router.map(item => {
// 拼接路由,例:'devtools' -> '/devtools' 'regular' -> '/devtools/regular'
item.path = parentPath ? ${parentPath}/${item.path}
: /${item.path}
// 存在 children 屬性,且 children 陣列長度大於 0,開始遞迴
if (item.children && item.children.length > 0) {
item.children = menuRouterFormat(item.children, item.path)
}
return Object.assign({}, item, item.meta || {})
}) }
// 解析後 路由選單列表 export const menuRouterFormatList = menuRouterFormat([...menuRouter]) ```
在 src/layout/components
資料夾下新建 Menu/index.vue
檔案:
```html
```
簡單說一下上面程式碼,我們先匯入了之前 menuRouter.js
中的選單解析後的資料 menuRouterFormatList
對選單資料進行了一個初始化。
再來看模板,我們用到了 arcoDesign
元件庫的 a-menu
元件。
accordion
開啟手風琴效果。mode
屬性是設定選單模式(水平或垂直),我們給它設定成水平即horizontal
。menuItemClick
子選單點選時觸發,該回調引數為key
。selected-keys
選中的選單項key
陣列。auto-open-selected
預設展開選中的選單。
這塊還是建議看下元件庫文件哈。
子選單點選方法中我們直接使用 router.push
傳入 key
跳轉路由即可。那對於 selectedKeys
,我們直接用計算屬性 computed
返回了當前路由物件 route
中 path
屬性值組成的陣列,這樣每次路由改變該方法就會被觸發,selectedKeys
陣列值就會響應式的改變。key
值即子選單的唯一標識,下面我們寫子選單元件時會將每個子選單的 key
設定為選單對應的路由 path
。
上面我們用到了一個還沒有建立的 MenuItem
元件,它其實就是我們的子選單元件,接下來我們還是在 src/layout/components/Menu
資料夾下新建 MenuItem.vue
檔案,內容如下:
```html
```
子選單元件 MenuItem
如上,首先,它是一個完全受控元件,就是字面意思,這個元件完全依靠父元件傳入的資料,它只做渲染使用,所以叫完全受控元件。
我們在 Menu
元件中遍歷了選單資料,並給每個子選單元件傳入了一個 menu
屬性即對應的選單資訊物件。
在子選單中,我們使用 defineProps
定義了一個 menu
屬性,Vue3
有個 toRefs
方法可以將響應式物件轉換成普通物件,但是這個普通物件中的屬性會變成一個個響應式屬性。正常情況下我們需要使用 props.menu
才能呼叫父元件傳入的屬性並且該屬性是單向傳遞,也就是我們不能在子元件中修改它,但是我們可以使用 Vue3
的 toRefs
方法將整個 props
物件解構,解構出的每個屬性值都是響應式的物件,並且在子元件中直接修改該值可以同步父元件。我們這裡使用 toRefs
只是為了方便,並沒有在子元件去修改父元件傳入的值,這裡簡單提一下可以這樣做,算是一個小技巧吧,不然我們想要在子元件修改父元件傳入的值,只能先定義一個響應式資料接收傳入的值,再在該響應值改變時,emit
出去一個事件,那在 Vue3
中使用 emit
還需要使用 defineEmits
去定義一下事件名,還是比較麻煩的,不理解沒關係,後面有案例會用到這種方法,到時候還會說!!!
OK,接著說,我們拿到了父元件中傳入的 menu
物件,接下來看元件模板,首先我們在模板中校驗了一下傳入的 menu
物件中是否存在 children
屬性。
如果不存在 children
屬性,那它就是一個選單,我們直接使用 a-menu-item
元件寫入子選單並把唯一標識 key
設定為 menu
物件的 path
屬性即可(選單路由),該元件有兩個插槽,預設插槽我們寫入選單標題 menu.title
,接著校驗了一下傳入的 menu
物件中有沒有 icon
屬性,有的話就在 icon
插槽中使用 component
直接渲染 icon
元件(這裡傳入的 icon
屬性值必須為元件物件,其實目前我們只是在帶有子級的選單傳入了 icon
元件)。
如果存在 children
屬性,那它就是一個帶子級的選單項,我們使用 a-sub-menu
元件去渲染它,和之前不一樣的是,帶子級的選單元件 a-sub-menu
我們直接把選單標題傳入該元件的 title
屬性就可以了,icon
還是一樣的操作,劃重點,那既然是帶子級的選單,我們還需要把它的子級再渲染出來,那它的子級可能還有子級(無限套娃),這裡我們只需要遞迴的呼叫一下元件自身就可以無限的渲染直到沒有子級資料。那 Vue3
的遞迴元件(元件自身呼叫自身),寫法和 Vue2
其實也沒太大差別,我們這裡由於配置了自動引入,所以都不需要引入,直接像在外部呼叫該元件一樣,直接呼叫自己就行,這裡其實涉及到匿名元件和具名元件的問題,我們這個元件是個匿名元件,但是在匿名狀態下,我們可以直接將該元件檔名作為元件名呼叫即可,那如果元件檔名是 index.vue
,Vue
會自動將上層的資料夾名作為元件名呼叫,注意,僅僅是呼叫而已,其他的都操作不了,想要通過元件名操作一個元件,還是得具名,Vue3
組合式 API
元件的具名方法下文有案例會提到,這裡不多說。如上程式碼,還是像父元件 Menu
中呼叫 MenuItem
元件一樣呼叫自己調自己就行了,到此我們的選單元件就寫好了。
在 Menu
元件中還寫了一些樣式,其實就是簡單調整一下元件庫中選單元件的樣式,具體樣式這裡就不多說了,因為會的能看懂,不會的自己跟著實踐一下就懂了(太佔篇幅)。
OK,寫完了使用一下看看效果,把 Menu
元件填充到預設佈局 DefaultLayout
元件下 Navbar
元件的中間插槽或者預設插槽中即可:
```html
<!-- 預設插槽和center插槽,預設插槽可不加template直接寫內容,作用同center插槽 -->
<template #center>
<Menu />
</template>
<!-- ... -->
```
看下頁面效果:
到此預設佈局的導航元件就寫的差不多了,下面來寫下頁尾元件!
頁尾元件 Footer
頁尾區域我們在佈局元件中沒有設定高度,因為頁尾的高度不固定,可能隨時會在頁尾加個內容啥的,所以就讓它隨元件內容高度自由撐開吧。。
由於頁尾需要展示一些個人資訊,所以我們統一把這些資料都放在 config/index.js
中的基礎配置物件裡,Config
檔案內容配置以及使用上文已經說過了,不再描述,這裡的資料沒什麼重要的,不需要脫敏,如需脫敏,可以配合 env.local
環境變數配置檔案去做,env.local
環境變數配置檔案預設會被 git
忽略,寫入該環境變數檔案,並在 config
檔案中引入環境變數即可,關於環境變數的配置也請看上文或者直接看文件 👉🏻 Vite 中 env 配置文件
```js // ...
const configSource = { // ...
// 個人配置 me: { name: 'isboyjc', // 公眾號 gzhName: '不正經的前端', gzhUrl: 'http://qiniuimages.isboyjc.com/picgo/202210030159449.jpeg', // github github: 'http://github.com/isboyjc' } } ```
我們在 src/components
資料夾下新建 Footer.vue
檔案,Footer
元件比較簡單,暫時也沒寫太多內容,這裡我就不會多描述了,直接看程式碼吧。
```html
```
在佈局檔案中使用一下:
在 DefaultLayout
預設佈局元件中的 a-layout-footer
元件標籤中使用一下 Footer 元件,同樣無需引入直接使用,如下:
```html