Vite Router安裝

一安裝vue-route

1
npm install --save vue-router@next

二配置路由

在src資料夾內創建router/router.ts
在src下創建 views/Home.vue 和 views/errorPage/404.vue

  • 引入{createRouter,createWebHashHistory,createWebHistory,RouterOptions, Router, RouteRecordRaw} from 'vue'
  • 路由表的設定區域,設定內容會有 path 、 name 、 component 三個部分:
    path 是設定路徑, name 是頁面名稱(方便動態載入), component 則是 import 頁面檔案的路徑
  • createWebHashHistory: 路由:創建WebHash歷史記錄
  • createWebHistory: 路由:創建Web歷史記錄 ,井字號會不顯示
  • 巢狀路由:巢狀路由就是在原本的路由表的頁面裡面再加入下一層的路由
    • 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
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      import { createRouter,createWebHistory } from 'vue-router'
      import type { RouteRecordRaw,RouterOptions,Router } from 'vue-router'

      //RouterRecordRaw路由組件對象
      import Layout from '../layout/Layout.vue';

      import { createRouter,createWebHistory } from 'vue-router'
      import type { RouteRecordRaw, RouterOptions, Router } from 'vue-router'
      import Layout from '../layout/Layout.vue';
      const routes: Array<RouteRecordRaw> = [
      {
      path: '/',
      name: 'Home',
      component: () => import('../views/Home.vue')
      },
      {
      path: '/about_us',
      name: 'About Us',
      component: () => import("../views/AboutUs.vue"),
      },
      {
      path: '/admin/',
      redirect: '/admin/index', //重新導向
      component: Layout,
      children: [
      {
      path: "index",
      component: () => import("../views/Dashboard/Admin.vue"),
      name: "Admin",
      meta: { title: "admin", requiresAuth: true },
      },
      ]
      },
      //**404頁面 =>當沒有這個頁面時就會導到此頁
      {
      path: '/:catchAll(.*)',
      name: '404',
      //views資料夾內必須要有errorPage/404.vue
      component: () => import('../views/errorPage/404.vue'),
      meta: {
      title: '404'
      },
      }
      ]



      // RouterOptions是路由選項類型
      const options: RouterOptions = {
      // history: createWebHashHistory(),
      history: createWebHistory(),//井字號會不顯示
      routes,
      }

      // Router是路由對象類型
      const router: Router = createRouter(options)

      //路由守衛
      router.beforeEach((to, from, next) => {
      const teacherId: any = localStorage.teacherId;
      const talkId: any = localStorage.talkId;
      const isLogin: Boolean =localStorage.token? true : false;
      if(to.path === "/admin" || to.path === "/login"|| to.path === "/index" || to.path==="/teachers" || to.path === "/user_login" || to.path === "/register" || to.path===`/teacher/${teacherId}` || to.path==='/onetoone' || to.path===`/talk/${talkId}`){
      next()
      } else {
      isLogin ? next() : next("/index") ;

      }
      })
      //輸出router
      export default router

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      另一種寫法
      import { createRouter, createWebHashHistory, RouterOptions, Router, RouteRecordRaw } from 'vue-router'

      // RouterOptions是路由選項類型
      const options: RouterOptions = {
      history: createWebHashHistory(),//井字號會不顯示
      routes,
      }

      // Router是路由對象類型
      const router: Router = createRouter(options)

      main.ts引入router

      1
      2
      3
      4
      5
      6
      7
      8
      import { createApp } from 'vue'
      import router from '../router' //引入router
      import App from './App.vue'

      createApp(App)
      .use(router) //使用router
      .mount('#app')

      router-view

      在App.vue
      加入

      1
      <router-view></router-view>
      插槽 傳遞任意參數:

      什麼情景要用 keep-alive ?

      keep-alive 的作用是緩存一個元件的資料狀態,即使它被切換掉,不再呈現在畫面上時,它的資料狀態依然會把存起來,並不會像一般元件那樣被銷毀。
      只會跑一次生命週期

      • 減少呼叫 API 的次數。例如該元件每次重新渲染時都要呼叫 API 取資料,除了加重後端負擔,也會因為等候時間而影響使用者體驗。
      • 多步式表單填寫。當使用者按下「上一步」按鈕時,需要呈現在前一個元件裏他所填寫的資料。
      • 官方例子提到的 Tab 標籤切換內容。當按下其中一個 tab,再按回上一個 tab,該元件的狀態應該要被保留,而不是被重新渲染。
      能接收 3 個 props

      is 屬性的作用是動態載入元件,實現切換元件的效果。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      //router-view 與 keep-alive
      //同樣地, router-view 也是一個元件,一樣可以被 keep-alive 包起來,把此 router-view 裏的所有元件都緩存起來:
      <router-view v-slot="{ Component }">
      <transition>
      <keep-alive>
      <component :is="Component" />
      </keep-alive>
      </transition>
      </router-view>

      參考資料

      404頁面

      加入按鈕 @click=”$router.push(‘/‘)”

      1
      2
      3
      4
      5
      6
      <template>
      <div>
      <h1>404</h1>
      <button @click="$router.push('/')">回首頁</button>
      </div>
      </template>

      github 說明

      router-link基本的用法:to="/about"
      1
      2
      3
      4
      5
      6
      7
      8
      //與 v-bind 綁定,省略 path
      <router-link :to="'/home'">Home</router-link>
      //指定 path,作用與前面一樣
      <router-link :to="{ path: '/home' }">Home</router-link>
      //搭配具名路由
      <router-link :to="{ name: 'user', params: { userId: '123' }}">User</router-link>
      // 搭配query參數,編譯後的結果會出現在 queryString: `/register?plan=private
      <router-link :to="{ path: '/register', query: { plan: 'private' }}">Register</router-link>

      replace 屬性

      不希望在瀏覽器留下紀錄,可以在 加上 replace 屬性

      1
      <router-link to="/abc" replace></router-link>

      透過 router.push() / router.replace() 操作路由

      1
      2
      3
      4
      5
      router.push('/users/eduardo')
      router.push({ path: '/users/eduardo' })
      router.push({ name: 'users',params: { userId: '123' } })
      router.push({ path: '/register', query: { plan: 'private' } })
      router.push({ path: '/about', hash:"#team" })

      Router 使用範例
      NavMenu

      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
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      <template>
      <ul class="navMenu">
      <li
      v-for="(item, index, id) in homeMenu"
      :key="id"
      :class="active == index ? 'isActive' : ''"
      @click="clickActive(index)"
      >
      <router-link
      :to="item.href"
      class="hvr-underline-from-center">
      {{ item.title }}
      </router-link>
      </li>
      </ul>
      </template>

      <script setup lang="ts">
      import { ref, onMounted } from 'vue';

      const active = ref<number>(0)
      const isActive = ref<boolean>(false)
      const clickActive = (index: number) => {
      active.value = index
      }
      //homeMenuType屬性
      interface homeMenuType{
      id?: string;
      title?: string;
      href?: string;
      }

      const homeMenu = ref<homeMenuType[]>([
      {id:'teleport', title: 'Teleport', href: '/teleport' },
      { id: 'table1', title: 'Table1', href: '/table1' },
      { id: 'table2', title: 'Table2', href: '/table2' },

      ])

      </script>


      <style lang="scss">
      .navMenu{
      list-style-type: none;
      display: flex;
      li{
      list-style-type: none;
      display: flex;
      margin: auto 10px;
      a{
      text-decoration:none;
      }
      }
      }
      </style>

      github範例

      動態Router

      • router 新增 router 新增頁面
        { path: '/products', component: () => import('../views/Products.vue') },
        { path: '/product/:id', component: () => import('../views/Product.vue') },
        views資料夾新增Products.vue,Product.vue
      • openItem(item.UID) 點擊獲取UID
      • 引入
        import { useRoute, useRouter } from 'vue-router';
        const route = useRoute();
        const router = useRouter()
      • 在openItem函式內將獲取得UID 塞入動態Router, router.push({path: `/product/${UID}`})router 新增頁面
      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
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      <template>
      <div class="products">
      <div class="item"
      v-for="(item,index, UID) in lists" :key="UID">
      <a @click="openItem(item.UID)"> <div class="card">
      <img :src="item.imageUrl">
      {{ item.title }}
      </div></a>
      </div>
      </div>
      </template>

      <script setup lang="ts">
      import axios from 'axios'
      import { ref, onMounted } from 'vue'
      import { useRoute, useRouter } from 'vue-router';
      const route = useRoute();
      const router = useRouter()
      interface listType {
      UID?: string;
      category?: string;
      comment?: string;
      descriptionFilterHtml?: string;
      discountInfo?: string | any;
      editModifyDate?: string;
      endDate?: string;
      hitRate?: number;
      imageUrl?: string;
      masterUnit?: object;
      otherUnit?: object;
      showInfo?: object;
      showUnit?: string;
      sourceWebName?: string | any;
      sourceWebPromote?: string;
      startDate?: string | any;
      subUnit?: object;
      supportUnit?: object;
      version?: string;
      title?: string | any;
      webSales?: string;
      }
      const openItem = (UID:any) => {
      console.log(UID)
      router.push({path: `/product/${UID}`})
      }
      const lists = ref<listType[]>([]);
      const getData = async () => {
      try {
      const api = 'https://cloud.culture.tw/frontsite/trans/SearchShowAction.do?method=doFindTypeJ&category=200';
      await axios.get(api)
      const res = await axios.get(api);
      if (res.status === 200) {
      lists.value = res.data;
      }

      } catch (error) {
      console.log(error)
      }

      }
      onMounted(() => {
      getData();
      const id = route.params.id;
      console.log('讀取動態參數id',id)
      })
      </script>

      導航守衛

      1
      2
      3
      4
      5
      6
      7
      const router = createRouter({ ... })

      router.beforeEach((to, from) => {
      // ...
      // 返回 false 以取消导航
      return false
      })
      • to: 即將要進入的目標
      • from: 目前導航正要離開的路線
      官網導航守衛
      可選的第三個參數 next
      1
      2
      3
      4
      5

      router.beforeEach((to, from, next) => {
      if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
      else next()
      })

      官網Vue Router 和 组合式 API
      RouterView 插槽
      KeepAlive & Transition
      Transition 的 API 在这里同样适用。
      單個路由的過度