安裝router自動生成與設置

Vite 安裝router自動生成與設置

Vite版本必須小於Vite6,

1
npm create vite@5

安裝router自動生成

1
npm install -D vue-router vite-plugin-pages vite-plugin-vue-layouts

router.ts

在src新增router資料夾,新增router.ts

1
2
3
4
5
6
7
8
9
import { Router,createRouter, createWebHistory } from 'vue-router'
import { setupLayouts } from 'virtual:generated-layouts'
import generatedRoutes from 'virtual:generated-pages'
const options= {
history: createWebHistory(),
routes: setupLayouts(generatedRoutes)
}
const router: Router = createRouter(options);
export default router

Ssr 專案 router.ts

改為 createMemoryHistory
history: createMemoryHistory(),

1
2
3
4
5
6
7
8
9
import { Router,createRouter, createMemoryHistory } from 'vue-router'
import { setupLayouts } from 'virtual:generated-layouts'
import generatedRoutes from 'virtual:generated-pages'
const options= {
history: createMemoryHistory(),
routes: setupLayouts(generatedRoutes)
}
const router: Router = createRouter(options);
export default router
錯誤訊息:找不到模組 'virtual:generated-layouts' 或其對應的型別宣告。ts(2307)

處理方式:tsconfig.json檔案內compilerOptions加入以下
1
2
3
4
"types": [
"vite-plugin-pages/client",
"vite-plugin-vue-layouts/client"
]

tsconfig.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ESNext", "DOM"],
"skipLibCheck": true,

/* Bundler mode */
"moduleResolution": "node",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",

/* Linting */
"strict": true,
"noUnusedLocals": false,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"types": [
"vite-plugin-pages/client",
"vite-plugin-vue-layouts/client"
]
},
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}

全局設置於main.ts

1
2
3
4
5
6
7
8
9
import { createApp } from 'vue'

import App from './App.vue'
+ import router from "./router/router"


+ const app = createApp(App);
+ app.use(router);
+ app.mount("#app");

全局設置於main.ts

Ssr 專案 全局設置於main.t

1
2
3
4
5
6
7
8
9
10
11
12
13
import { createSSRApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const pinia = createPinia()
+ import router from "./router/router.ts"

export function createApp() {
const app = createSSRApp(App);
app.use(pinia)
+ app.use(router);
return { app }
}

vite.config.ts 設置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
+ import Pages from 'vite-plugin-pages'
+ import Layouts from 'vite-plugin-vue-layouts'
export default defineConfig({
plugins: [
vue(),
+ Pages({
+ dirs: [
+ { dir: 'src/views/frontdesk/', baseRoute: '/' },//前台
+ // { dir: 'src/views/admin/', baseRoute: 'admin' },
+ ]
+ }),
+ Layouts(),
]
})

vite.config.ts 設置

App.vue 新增router-view

1
2
3
4
5
<template>
<main class="main">
<router-view></router-view>
</main>
</template>

設置layouts
新增layouts資料夾內新增
frontLayout.vue,
LayoutBack.vue,
Layout404.vue
layouts資料夾內容

按前後台設置layout:
views/index.vue 內容
前台必須重新導向到/frontdesk/index;

1
2
3
4
5
6
7
<route lang="yaml">
path: "/",
redirect: "/frontdesk/index",
meta:
layout: frontLayout
</route>

新增frontdesk資料夾(這是前台的內頁檔案),
新增index.vue,
aboutme.vue;

1
2
3
4
<route lang="yaml">
meta:
layout: frontLayout
</route>

佈局頁面的製作

src/layouts/內有兩個frontLayout.vue,Layout404.vue
frontLayout.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//frontLayout.vue
<template>
<Nav :navLists="navLists" ></Nav>
<router-view />
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import Nav from '../components/Nav.vue'
interface navListType {
id?: number,
name?: string,
href?: string,
}
const navLists = ref<navListType[]>([
{ id: 0, name: '首頁', href: '/' },
{ id: 2, name: '關於', href: '/about' },
])
</script>

Layout404.vue

1
2
3
4
5
6
<template>
<router-view></router-view>
</template>

<script setup lang="ts">
</script>

404頁面
新增[…all].vue
route lang=”yaml” =>meta:layout: Layout404

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//這個檔案要注意別命名錯誤[...all].vue
<template>
<main class="flex flex-col items-center space-y-3">
<span class="text-2xl">
404
</span>
<router-link class="text-xl border p-1" to="/">回首頁</router-link>
</main>
</template>

<route lang="yaml">
meta:
layout: Layout404
</route>

動態router

新增user資料夾與資料夾內新增[id].vue
例如:edit[id].vue,
獲取動態id => route.params.id

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<template>
<div>
{{title}}
</div>
</template>

<route>
{
path: '/user/:id',
name: 'User',
meta: {
layout: 'frontLayout',
}
}
</route>

<script setup lang="ts">
import {ref,onMounted} from 'vue'
import { useRoute, useRouter } from 'vue-router';
const route = useRoute();
const router = useRouter()
const title =ref<string>('ID');
onMounted(() => {
const id = route.params.id;
console.log('讀取動態參數id',id)
})
</script>
router params
1
2
3
4
5
6
7
8
9
<route>
{
path: '/user/:userId',
name: 'User',
meta: {
layout: 'frontLayout',
}
}
</route>

要連結到一個命名的路由,可以傳遞一個物件到 router-link 元件的 to 屬性:

1
2
3
<router-link :to="{ name: 'User', params: { userId: 'erina' }}">
User
</router-link>

這跟程式碼呼叫 router.push() 是一樣:

1
router.push({ name: 'user', params: { userId: 'erina' } })
router 重定向
1
2
3
4
5
6
7
8
9
10
11
<route>
{
path: '/user/:userId',
name: 'User',
redirect: '/'
//redirect: { name: 'homepage' }
meta: {
layout: 'frontLayout',
}
}
</route>

Vercel 404錯誤

Vercel 平台出現404頁面無法導到正確位置
新增vercel.json在根目錄 加入以下代碼

1
2
3
4
5
6
vercel.json
{
"rewrites": [
{"source": "/(.*)", "destination": "/"}
]
}

參考資料:
Vite Vecel 404

github