Vue Router 4.x

思維導(dǎo)圖

簡介

Vue RouterVue 官方指定路由魂那,其賦能 Vue 實(shí)現(xiàn) 單頁應(yīng)用(SPA俯抖,Single Page Application) 前端路由功能。

本文主要介紹下 Vue Router 4.x 的相關(guān)使用方法缸兔。

基本使用

下面通過一個(gè)小例子驅(qū)動(dòng)闡述如何在 Vue3 下使用 Vue Router 4.x。

例子:假設(shè)當(dāng)前頁面有兩個(gè)標(biāo)簽:/home/me学辱,要求點(diǎn)擊不同的標(biāo)簽分別顯示不同的組件頁面缎除。

思路:使用 Vue Router 配置相關(guān)路由,點(diǎn)擊標(biāo)簽時(shí)荒辕,跳轉(zhuǎn)到對(duì)應(yīng)路由視圖汗销。具體操作步驟如下:

  1. 創(chuàng)建項(xiàng)目:首先創(chuàng)建一個(gè)示例項(xiàng)目:

    # 此處使用 vite 進(jìn)行構(gòu)建
    $ npm init vite@latest vue3_demos --template vue
    
    $ cd vue3_demos
    
    # 安裝相關(guān)依賴
    $ npm install
    
    # 啟動(dòng)應(yīng)用
    $ npm run dev
    

    :Vue3 安裝更多方法,可參考:Vue3 安裝

  2. 依賴引入:導(dǎo)入 Vue Router 依賴庫:

    $ npm install vue-router@4
    
  3. 創(chuàng)建組件:分別創(chuàng)鍵Home.vueMe.vue兩個(gè)組件:

    <!-- file: components/Home.vue -->
    <template>
      <h1>Home Component</h1>
    </template>
    
    <style scoped>
    h1 {
      background-color: green;
    }
    </style>
    
    <!-- file: components/Me.vue -->
    <template>
      <h1>Me Component</h1>
    </template>
    
    <style scoped>
    h1 {
      background-color: yellow;
    }
    </style>
    
  4. 創(chuàng)建并配置路由對(duì)象:新建router/index.js抵窒,在此創(chuàng)建并配置路由對(duì)象:

    // file: router/index.js
    // 導(dǎo)入相關(guān)路由組件對(duì)象
    import Home from '../components/Home.vue';
    import Me from '../components/Me.vue';
    
    // 定義路由映射:路由映射到具體組件
    const routes = [
      // 根路徑 / 重定向到 /home
      {
        path: '/',
        redirect: '/home',
      },
      // 前端路由 /home 對(duì)應(yīng)組件 Home
      {
        path: '/home',
        component: Home,
      },
      // 前端路由 /me 對(duì)應(yīng)組件 Me
      {
        path: '/me',
        component: Me,
      },
    ];
    
    // 導(dǎo)入相關(guān)函數(shù)
    import { createRouter, createWebHashHistory } from 'vue-router';
    
    // 創(chuàng)建路由實(shí)例(`router`)并傳遞路由映射配置(`route`)
    const router = createRouter({
      // 配置導(dǎo)航模式弛针,此處采用 hash 模式
      history: createWebHashHistory(),
      routes,
    });
    
    // 導(dǎo)出 router 實(shí)例
    export default router;
    
  5. 裝載 Router 實(shí)例:創(chuàng)建全局Vue實(shí)例,并裝載已配置的 Vue Router 實(shí)例:

    // file: main.js
    
    import { createApp } from 'vue';
    import App from './App.vue';
    
    import router from './router/index.js';
    
    const app = createApp(App);
    // 裝載 Vue Router 實(shí)例李皇,確保整個(gè) Vue 應(yīng)用全局支持路由
    app.use(router);
    app.mount('#app');
    
  6. 主頁面配置路由導(dǎo)航:主頁面通過<router-link>可配置路由導(dǎo)航削茁,匹配的組件會(huì)最終被渲染到<router-view>中:

    <!-- file: App.vue -->
    <template>
      <h1>Main Page</h1>
      <div class="nav">
        <!-- router-link 最終會(huì)被渲染為一個(gè) a 標(biāo)簽 -->
        <router-link to="/home">Home</router-link>
        <router-link to="/me">Me</router-link>
      </div>
      <!-- 路由出口:匹配組件最終被渲染位置 -->
      <router-view />
    </template>
    
    <style scoped>
    .nav {
      width: 100px;
      display: flex;
      justify-content: space-around;
    }
    </style>
    

以上,就是一個(gè)簡單的路由導(dǎo)航示例掉房,其效果如下所示:


簡單路由示例

功能介紹

下面會(huì)對(duì) Vue Router 4.x 提供的一些常見功能進(jìn)行簡介茧跋。

路由對(duì)象

Vue Router 中存在兩個(gè)最主要的路由對(duì)象為:

  1. Router:表示 Vue Router 實(shí)例對(duì)象。

    在 Vue Router 4.x 中卓囚,使用的是createRouter()函數(shù)創(chuàng)建Router實(shí)例:

    import { createRouter, createWebHashHistory } from 'vue-router';
    const routes = [...];
    
    // 創(chuàng)建路由實(shí)例(`router`)并傳遞路由映射配置(`route`)
    const router = createRouter({
      history: createWebHashHistory(),
      routes,
    });
    
    export default router;
    

    Router主要是提供了對(duì)歷史記錄棧的操作功能瘾杭,比如Router#push方法可以往歷史堆棧中推入一個(gè)新的 URL,Router#replace方法可用于替換當(dāng)前的 URL哪亿,還有Router#forward粥烁、Router#backRouter#go...

    :當(dāng)代碼中調(diào)用createApp().use(Router)時(shí)蝇棉,其實(shí)就向 Vue 實(shí)例全局中注入了一個(gè)Router實(shí)例讨阻,代碼中獲取該Router實(shí)例的方法有如下幾種:

    1. Options API:選項(xiàng)式 API 可通過this.$routers獲取全局路由實(shí)例
    2. Composition API:組合式 API 可通過函數(shù)useRouter()獲取全局路由實(shí)例
    3. template:模板中可通過$router獲取全局路由實(shí)例

    :創(chuàng)建Router時(shí),可設(shè)置一個(gè)激活樣式linkActiveClass篡殷,這樣在主頁選中<router-link>時(shí)钝吮,對(duì)應(yīng)標(biāo)簽就會(huì)被添加上自定義激活樣式:

    // file: router/index.js
    const router = createRouter({
      history: createWebHashHistory(),
      routes,
      // 設(shè)置標(biāo)簽激活時(shí),添加樣式類為 activeLink
      linkActiveClass: 'activeLink',
    });
    
    <!-- file: App.vue -->
    <template>
      <h1>Main Page</h1>
    
      <!-- 點(diǎn)擊選中標(biāo)簽時(shí)板辽,自動(dòng)添加 activeLink 類名 -->
      <router-link to="/home">Home</router-link>
      <router-link to="/me">Me</router-link>
    
      <router-view />
    </template>
    <style scoped>
    /* 設(shè)置選中樣式 */
    .activeLink {
      background-color: red;
    }
    </style>
    
  2. RouteLocationNormalized:表示當(dāng)前路由記錄實(shí)例奇瘦。

    routes中配置的每條路由映射,我們稱之為「路由記錄」戳气,其類型就是RouteLocationNormalized

    const routes = [
      { path: '/home', component: () => import('@/components/Home.vue'), },
      { path: '/me', component: Me, },
      { path: '/user/:id*', component: () => import('@/components/User.vue'), },
    ];
    

    當(dāng)在主頁上點(diǎn)擊選中相應(yīng)路由標(biāo)簽時(shí)链患,就會(huì)跳轉(zhuǎn)到相應(yīng)路由映射組件,此時(shí)可以通過Router#currentRoute得到當(dāng)前路由記錄瓶您。比如麻捻,點(diǎn)擊跳轉(zhuǎn)到/user時(shí)纲仍,Router#currentRoute就可以獲取/user路由相關(guān)配置信息。

    其實(shí)還有其他更方便的方法獲取到當(dāng)前路由地址實(shí)例贸毕,主要包含如下:

    1. Options API:對(duì)于選項(xiàng)式 API郑叠,可通過this.$route獲取當(dāng)前路由地址實(shí)例
    2. Composition API:對(duì)于組合式 API,可通過useRoute()函數(shù)獲取當(dāng)前路由地址實(shí)例
    3. template:模板中可通過$route獲取當(dāng)前路由地址實(shí)例

    RouteLocationNormalized提供了豐富的路由配置選項(xiàng)明棍,這里列舉一些比較常用的:

    • hashstring類型乡革,表示當(dāng)前路由hash部分√福總是以#開頭沸版,如果 URL 中沒有hash,則為空字符串兴蒸。

    • pathstring類型视粮,表示當(dāng)前路由路徑,形如/user/1

    • fullpathstring類型橙凳,表示當(dāng)前路由完整路徑蕾殴,包含pathqueryhash部分岛啸,

    • name:類型為RouteRecordName | null | undefined钓觉,表示當(dāng)前路由名稱。

      :建議為每個(gè)路由對(duì)象命名坚踩,方便后續(xù)編程導(dǎo)航荡灾。名稱命名需唯一。

      const routes = [
        {
          name: 'user', // 路由命名
          path: '/user/:id',
          component: () => import('@/components/User.vue'),
        },
      ];
      
    • redirectedFrom:類型為RouteLocation | undefined堕虹,表示觸發(fā)重定向的路由地址卧晓。

    • params:類型為RouteParams,用于獲取路徑參數(shù)赴捞。比如對(duì)于/user/:id$route.params獲取到的就是id對(duì)應(yīng)的信息郁稍。

    • query:類型為LocationQuery赦政,表示 URL 查詢參數(shù)。形如/user?id=1耀怜,則query對(duì)應(yīng)的就是{id: 1}

    • meta:類型為RouteMeta恢着,表示對(duì)當(dāng)前路由的元數(shù)據(jù),即額外信息描述财破。

      const routes = [
        {
          meta: { name: 'Whyn' },  // 路由元數(shù)據(jù)
          path: '/user/:id',
          component: () => import('@/components/User.vue'),
        },
      ];
      

歷史記錄模式

前端路由的改變掰派,其核心是不會(huì)向服務(wù)器發(fā)出請(qǐng)求,Vue Router 提供了兩種模式支持該功能:

  • Hash 模式:Hash 模式 URL 構(gòu)成中帶有一個(gè)哈希字符#左痢,更改#字符后面的路徑不會(huì)發(fā)送請(qǐng)求給服務(wù)器靡羡,其底層是基于瀏覽器的windows.onhashchange事件系洛。

    Hash 模式的優(yōu)點(diǎn)是編程簡單,缺點(diǎn)是路徑不夠簡潔(多了額外字符#)略步,且對(duì) SEO 不夠友好描扯。

    Vue Router 中通過createWebHashHistory()函數(shù)配置 Hash 模式:

    import { createRouter, createWebHashHistory } from 'vue-router'
    
    const router = createRouter({
      history: createWebHashHistory(),
      routes: [
        //...
      ],
    })
    
  • History 模式:History 模式利用了 HTML5 History Interface 中新增的pushState()replaceState()等方法,實(shí)現(xiàn)了瀏覽器的歷史記錄棧趟薄。調(diào)用這些方法修改 URL 歷史記錄時(shí)绽诚,不會(huì)觸發(fā)瀏覽器向后端發(fā)送請(qǐng)求。

    History 模式的優(yōu)點(diǎn)是路徑簡潔且控制更靈活杭煎,缺點(diǎn)是 History 模式下恩够,用戶在瀏覽器中直接訪問或手動(dòng)刷新時(shí),會(huì)觸發(fā)真正的請(qǐng)求羡铲,服務(wù)器沒有當(dāng)前請(qǐng)求資源時(shí)玫鸟,會(huì)返回一個(gè)404錯(cuò)誤。解決的方法也很簡單犀勒,就是后端添加一個(gè)回退路由屎飘,在 URL 匹配不到任何靜態(tài)資源時(shí),默認(rèn)返回前端頁面的index.html贾费。比如钦购,Nginx 中可以配置如下:

    location / {
      try_files $uri $uri/ /index.html;
    }
    

    Vue Router 中通過createWebHistory()函數(shù)配置啟動(dòng) History 模式:

    import { createRouter, createWebHistory } from 'vue-router'
    
    const router = createRouter({
      history: createWebHistory(),
      routes: [
        //...
      ],
    })
    

最后,Vue Router 更推薦使用 History 模式褂萧。

路由懶加載

前端每個(gè)路由都會(huì)對(duì)應(yīng)一個(gè)組件押桃,前面我們使用的方式都是導(dǎo)入相應(yīng)組件,然后配置映射到對(duì)應(yīng)路由中:

const Home = { template: '<div>Home</div>' }
const routes = [
  { path: '/', component: Home },
]

當(dāng)路由比較多時(shí)导犹,會(huì)導(dǎo)致加載的組件也變多唱凯,這樣在應(yīng)用打包后,生成的 JavaScript 包會(huì)臃腫變大谎痢,影響頁面加載效率磕昼。

因此,Vue Router 提供了 路由懶加載 功能节猿,其將不同路由對(duì)應(yīng)的組件分割成不同的代碼塊票从,然后當(dāng)路由被訪問時(shí),才動(dòng)態(tài)加載對(duì)應(yīng)組件滨嘱,這樣效率就會(huì)更高峰鄙。

Vue Router 支持開箱即用的動(dòng)態(tài)導(dǎo)入,如下所示:

// 直接加載
import Home from '@/components/Home.vue';
// 懶加載
const Me = () => import('@/components/Me.vue')

const routes = [
  { path: '/home', component: Home, }, // 直接加載
  { path: '/me', component: Me },      // 懶加載
];

:上述代碼使用@代表src目錄太雨,使能需要進(jìn)行如下配置:

// file: vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

const path = require('path');
export default defineConfig({
  plugins: [vue()],
  resolve: {
    // 別名配置
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
});

此時(shí)如果執(zhí)行構(gòu)建:

$ npm run build
dist/index.html                  0.48 KiB
dist/assets/index.4ada91f0.js    2.13 KiB / gzip: 1.13 KiB
dist/assets/Me.a2557100.js       0.23 KiB / gzip: 0.20 KiB # Me.vue
dist/assets/index.d8be49df.css   0.12 KiB / gzip: 0.12 KiB
dist/assets/Me.0aae35d5.css      0.04 KiB / gzip: 0.06 KiB # Me.vue
dist/assets/vendor.fd7d0278.js   71.78 KiB / gzip: 28.44 KiB

可以看到吟榴,配置懶加載組件Me.vue會(huì)被單獨(dú)打包到一個(gè).js文件中。

實(shí)際上囊扳,Vue Router 中吩翻,懶加載基本原理是:componentcomponents配置接收的是一個(gè)返回Promise組件的函數(shù)兜看,因此,我們也可以進(jìn)行自定義動(dòng)態(tài)導(dǎo)入仿野,其實(shí)就是創(chuàng)建一個(gè)返回Promise的函數(shù)铣减,該Promise返回一個(gè)組件,比如:

const UserDetails = () =>
  Promise.resolve({
    /* 組件定義 */
  })

動(dòng)態(tài)路由

一個(gè)很常見的場景脚作,比如葫哗,根據(jù)用戶id獲取用戶信息,通常對(duì)應(yīng)的 RESTFul API 為/user/{id}球涛,即匹配/user/1劣针、/user/2...

Vue Router 將這種形式的 URL 稱之為 動(dòng)態(tài)路由,其使用:進(jìn)行使能亿扁,形式如下所示:

const User = {
  template: '<div>User</div>',
}

// 這些都會(huì)傳遞給 `createRouter`
const routes = [
  // 動(dòng)態(tài)段以冒號(hào)開始
  { path: '/user/:id', component: User },
]

此時(shí)捺典,上述path可以匹配/user/1/user/username等等从祝。

動(dòng)態(tài)路由也支持正則匹配襟己,可以設(shè)置更加精細(xì)匹配規(guī)則,常見匹配設(shè)置如下:

const routes = [
  // /:id -> 僅匹配數(shù)字
  { path: '/:id(\\d+)' },

  // /:username -> 匹配其他任何內(nèi)容
  { path: '/:username' },

  // /:chapters ->  匹配 /one, /one/two, /one/two/three, 等
  { path: '/:chapters+' },

  // /:chapters -> 匹配 /, /one, /one/two, /one/two/three, 等
  { path: '/:chapters*' },

  // 匹配 /users 和 /users/posva
  { path: '/users/:userId?' },

  // 匹配 /, /1, /1/2, 等
  { path: '/:chapters(\\d+)*' },
]

動(dòng)態(tài)路由信息可以通過$route.params進(jìn)行獲取牍陌,一個(gè)示例代碼如下:
配置路徑/user/:id(\d+)映射到組件User.vue擎浴,并展示id具體值:

<!-- file: components/User.vue -->
<template>
  <!-- 模板獲取 route.params 屬性 -->
  <h1>User Component: {{ $route.params }}</h1>
</template>

<script>
import { onBeforeRouteUpdate } from 'vue-router';

export default {
  name: 'User',
  setup(props, context) {
    // Router 鉤子函數(shù)
    onBeforeRouteUpdate((to, from, next) => {
      // 代碼獲取 route.params 屬性
      console.log(to.params.id);
      next();
    });
  },
};
</script>

// file: router/index.js
const routes = [
  {
    path: '/user/:id(\\d+)',
    component: () => import('@/components/User.vue'),
  },
];

<!-- file: App.vue -->
<template>
  <h1>Main Page</h1>
  <div class="nav">
    <router-link :to="'/user/' + id" @click="randomId">User</router-link>
  </div>
  <router-view />
</template>

<script >
import { ref } from '@vue/reactivity';
export default {
  name: 'App',
  setup(props, context) {
    const id = ref(1);

    function randomInRange(min, max) {
      return Math.floor(Math.random() * (max - min)) + min;
    }

    const randomId = () => (id.value = randomInRange(0, 100));

    return {
      id,
      randomId,
    };
  },
};
</script>

:動(dòng)態(tài)路由如果使用可變參數(shù)進(jìn)行修飾,則:

  • /user/:id**表示匹配 0 個(gè)或多個(gè)毒涧,此時(shí)的$params.id為數(shù)組形式贮预,即{id: []}
  • /user/:id++表示匹配 1 個(gè)或多個(gè),此時(shí)的$params.id為數(shù)組形式契讲,即{id: []}
  • /user/:id??表示匹配 0 個(gè)或 1 個(gè)仿吞,此時(shí)的$params.id為值,即{id: 10}

:由于動(dòng)態(tài)路由實(shí)際上映射的是同一個(gè)組件捡偏,因此唤冈,在進(jìn)行動(dòng)態(tài)路由切換時(shí),會(huì)復(fù)用該組件實(shí)例霹琼,所以組件生命周期鉤子不會(huì)被調(diào)用务傲,如果想監(jiān)聽動(dòng)態(tài)路由改變,需要手動(dòng)watch當(dāng)前路由this.$route.params上對(duì)應(yīng)的屬性枣申,或者使用導(dǎo)航守衛(wèi)鉤子函數(shù),比如onBeforeRouteUpdate進(jìn)行監(jiān)聽看杭。

嵌套路由

  • 嵌套路由:就是一個(gè)路由內(nèi)部可以嵌套一些子路由忠藤。

比如,/user是一個(gè)路由楼雹,/user/one模孩、/user/two/user下的兩個(gè)子路由尖阔,所以/user是一個(gè)嵌套了/user/one/user/two的嵌套路由榨咐。

再簡單進(jìn)行理解介却,一個(gè)路由對(duì)應(yīng)一個(gè)組件,因此块茁,嵌套路由其實(shí)就是一個(gè)父組件內(nèi)部包含了多個(gè)子組件齿坷,且這些子組件也是通過路由進(jìn)行訪問。

嵌套路由的配置很簡單数焊,只需為父路由設(shè)置children屬性即可永淌,下面以一個(gè)例子進(jìn)行驅(qū)動(dòng),闡述嵌套路由佩耳。

示例:假設(shè)現(xiàn)在有一個(gè)新聞版塊遂蛀,該版塊內(nèi)部含有兩個(gè)子版塊,分別為財(cái)經(jīng)版塊和體育版塊干厚,用代碼進(jìn)行實(shí)現(xiàn)李滴。

分析:父路由對(duì)應(yīng)組件news.vue,其內(nèi)嵌套兩個(gè)子路由/news/finance/news/sports蛮瞄,分別對(duì)應(yīng)兩個(gè)組件Finance.vueSports.vue所坯。

嵌套路由搭建步驟如下:

  1. 首先創(chuàng)建所有對(duì)應(yīng)組件:

    <!-- file: components/nested_router/Finance.vue -->
    <template>
      <h3>Finance Component</h3>
    </template>
    
    <!-- file: components/nested_router/Sports.vue -->
    <template>
      <h3>Sports Component</h3>
    </template>
    
    <!-- file: components/nested_router/News.vue -->
    <template>
      <h1>News Component</h1>
    
      <div class="nav">
        <router-link to="/news/finance">Finance</router-link>
        <router-link to="/news/sports">Sports</router-link>
      </div>
      <router-view />
    </template>
    
    <style scoped>
    /* router-link 最終會(huì)被轉(zhuǎn)換為 a 標(biāo)簽 */
    .nav a {
      margin-left: 10px;
    }
    </style>
    

    News.vue由于是父組件,因此其內(nèi)部包含router-view標(biāo)簽用于展示嵌套子路由頁面組件裕坊。

  2. 配置路由信息:

    // file: ./router/nested.js
    import { createRouter, createWebHistory } from 'vue-router';
    
    const routes = [
      {
        path: '/news',
        component: () => import('@/components/nested_router/News.vue'),
        // 配置嵌套路由
        children: [
          {
            // /news 重定向到 /news/finance
            path: '/news',
            redirect: '/news/finance',
          },
          {
            // /news/finace
            path: 'finance',
            component: () => import('@/components/nested_router/Finance.vue'),
          },
          {
            // /news/sports
            path: 'sports',
            component: () => import('@/components/nested_router/Sports.vue'),
          },
        ],
      },
    ];
    
    export default createRouter({
      // 使用 History 模式
      history: createWebHistory(),
      routes,
    });
    
  3. 主頁面添加展示/news映射的組件New.vue

    // file: main.js
    import { createApp } from 'vue';
    import App from './App.vue';
    
    import router from './router/nested.js';
    
    const app = createApp(App);
    app.use(router);
    app.mount('#app');
    
    <!-- file: App.vue -->
    <template>
      <h1>Main Page</h1>
      <router-link to="/news">News</router-link>
      <!-- 路由出口:匹配組件最終被渲染位置 -->
      <router-view />
    </template>
    

編程式導(dǎo)航

前面我們都是通過<router-link>標(biāo)簽實(shí)現(xiàn)導(dǎo)航鏈接功能包竹,實(shí)際上當(dāng)我們點(diǎn)擊<router-link>時(shí),其內(nèi)部會(huì)調(diào)用Router#push方法實(shí)現(xiàn)真正的路由導(dǎo)航籍凝,因此周瞎,我們也可以直接通過編程方式,即調(diào)用Router相關(guān)方式饵蒂,手動(dòng)實(shí)現(xiàn)導(dǎo)航跳轉(zhuǎn)声诸。

Vue Router 主要提供了以下幾個(gè)方法供我們實(shí)現(xiàn)路由跳轉(zhuǎn):

  • Router#push:該方法會(huì)向歷史堆棧添加一個(gè)新記錄,可供我們導(dǎo)航到指定的 URL退盯。

    Router#push<router-link>底層默認(rèn)調(diào)用的導(dǎo)航方法:

    聲明式 編程式
    <router-link :to="..."> router.push(...)

    Router#push支持多種參數(shù)類型彼乌,其常見調(diào)用方式如下所示:

    // 字符串路徑
    router.push('/users/eduardo')
    
    // 帶有路徑的對(duì)象
    router.push({ path: '/users/eduardo' })
    
    // 命名的路由,并加上參數(shù)渊迁,讓路由建立 url
    router.push({ name: 'user', params: { username: 'eduardo' } })
    
    // 帶查詢參數(shù)慰照,結(jié)果是 /register?plan=private
    router.push({ path: '/register', query: { plan: 'private' } })
    
    // 帶 hash,結(jié)果是 /about#team
    router.push({ path: '/about', hash: '#team' })
    

    <router-link>中的to屬性與Router#push方法接收的參數(shù)類型一致琉朽,所以上述配置也適用于to屬性毒租。

    :如果同時(shí)提供了pathparams,則params會(huì)被忽略箱叁。建議使用name屬性替換path墅垮,避免潛在問題:

    router.push({ name: 'Me' });
    
  • Router#replace:該方法同樣支持路由導(dǎo)航惕医,但是與Router#push不同的是,該方法不會(huì)向歷史堆棧中添加導(dǎo)航記錄算色,而是直接替換當(dāng)前導(dǎo)航記錄抬伺。
    一般只有當(dāng)明確禁止跳轉(zhuǎn)回前一個(gè)路由時(shí),才會(huì)使用該方法灾梦。

    <router-link>可通過添加replace屬性峡钓,使能Router#replace

    聲明式 編程式
    <router-link :to="..." replace> router.replace(...)

    Router#push也可以實(shí)現(xiàn)replace功能,只需為路由添加replace: true屬性:

    router.push({ path: '/home', replace: true })
    // 相當(dāng)于
    router.replace({ path: '/home' })
    
  • Router#go:該方法可以橫跨跳轉(zhuǎn)歷史堆棧:

    // 向前移動(dòng)一條記錄斥废,與 router.forward() 相同
    router.go(1)
    
    // 返回一條記錄椒楣,與router.back() 相同
    router.go(-1)
    
    // 前進(jìn) 3 條記錄
    router.go(3)
    
    // 如果沒有那么多記錄,靜默失敗
    router.go(-100)
    router.go(100)
    

下面還是通過一個(gè)示例驅(qū)動(dòng)進(jìn)行講解牡肉。

例子:比如主頁有兩個(gè)按鈕捧灰,要求點(diǎn)擊兩個(gè)按鈕顯示Home.vueMe.vue兩個(gè)頁面。

思路:/home路由映射組件Home.vue统锤,/me路由映射組件Me.vue毛俏,然后為按鈕添加點(diǎn)擊事件,通過調(diào)用Router相關(guān)方式實(shí)現(xiàn)路由跳轉(zhuǎn)饲窿。
具體步驟如下:

  1. 創(chuàng)建路由頁面Home.vueMe.vue煌寇。內(nèi)容參考上文

  2. 配置路由信息:

    // file: router/index.js
    import { createRouter, createWebHistory } from 'vue-router';
    
    export default createRouter({
      history: createWebHistory(),
      routes: [
        {
          name: 'Home',
          path: '/home',
          component: () => import('@/components/Home.vue'),
        },
        {
          name: 'Me',
          path: '/me',
          component: () => import('@/components/Me.vue'),
        },
      ],
    });
    
  3. 加載 Vue Router 并配置主頁面:

    // file: main.js
    import { createApp } from 'vue';
    import App from './App.vue';
    
    import router from './router/index.js';
    
    const app = createApp(App);
    // 裝載 Vue Router 實(shí)例,確保整個(gè) Vue 應(yīng)用全局支持路由
    app.use(router);
    app.mount('#app');
    
    <!-- file: App.vue -->
    <template>
      <h1>Main Page</h1>
    
      <div class="nav">
          <button @click="nav2Home">Home</button>
          <button @click="nav2Me">Me</button>
      </div>
    
      <router-view />
    </template>
    
    <script setup>
    import { useRouter } from "vue-router"
    
    const router = useRouter();
    const nav2Home = () => router.push('/home');
    const nav2Me = () => router.push('/me');
    
    </script>
    
    <style scoped>
    .nav button {
        margin-left: 10px;
    }
    </style>
    

運(yùn)行結(jié)果如下圖所示:


programmatic_navigation_demo

命名路由

前面很多處都提到了 命名路由逾雄,其實(shí)就是為路由配置一個(gè)name屬性:

const routes = [
  {
    name: 'user', # 命名路由
    path: '/user/:username',
    component: User
  }
]

使用命名路由阀溶,除了避免了手動(dòng)硬編碼 URL 外,最大的好處就是它會(huì)對(duì)params屬性自動(dòng)進(jìn)行編碼/解碼鸦泳。

具體使用命名路由時(shí)银锻,只需為<router-link>to屬性指定一個(gè)命名對(duì)象即可:

<router-link :to="{ name: 'user', params: { username: 'erina' }}"> User </router-link>

命名視圖

一個(gè)<router-view>只能顯示一個(gè)組件頁面,即使是嵌套路由做鹰,同一時(shí)刻也只是顯示一個(gè)組件頁面击纬。但是如果一個(gè)路由需要同時(shí)顯示兩個(gè)及以上組件頁面,此時(shí)就需要同時(shí)提供多個(gè)<router-view>钾麸,并且為<router-view>設(shè)置相應(yīng)名稱更振,路由配置時(shí)會(huì)指定相應(yīng)組件顯示到對(duì)應(yīng)名稱的<router-view>上,這種具備名稱的的<router-view>稱之為 命名視圖饭尝。

只需為<router-view>設(shè)置name屬性肯腕,即為 命名視圖

<router-view name="sidebar" />

:實(shí)際上,所有的<router-view>都是命名視圖钥平,未配置name屬性時(shí)乎芳,其默認(rèn)名為default蘸际。

舉個(gè)例子:比如現(xiàn)在主頁上有兩個(gè)組件頁面:導(dǎo)航欄sidebar和主區(qū)域main取刃,同時(shí)呈現(xiàn)在主頁上,要求使用命名視圖完成陌选。

思路:主頁需要配置兩個(gè)命名視圖的<router-view>睡汹,然后路由配置時(shí)肴甸,指定相應(yīng)組件顯示到對(duì)應(yīng)的命名視圖上即可。
具體步驟如下:

  1. 創(chuàng)建導(dǎo)航欄組件和主區(qū)域組件:

    <!-- components/named_view/SideBar.vue -->
    <template>
        <nav>
            <u>
                <li>Nav 1</li>
                <li>Nav 2</li>
            </u>
        </nav>
    </template>
    
    <style scoped>
    nav {
        background-color: green;
    }
    </style>
    
    
    <!-- components/named_view/Main.vue -->
    <template>
        <p>Main Content</p>
    </template>
    
    <style scoped>
    p {
        background-color: yellow;
    }
    </style>
    
  2. 配置路由信息:根路由需要配置兩個(gè)子組件囚巴,并指定各自要顯示到的命名視圖:

    // file: router/index.js
    import { createRouter, createWebHistory } from 'vue-router';
    
    export default createRouter({
      history: createWebHistory(),
      routes: [
        {
          path: '/',
          // 主頁面同時(shí)顯示多個(gè)路由映射組件
          components: {
            // Main.vue 顯示到 default 視圖上
            default: () => import('@/components/named_view/Main.vue'),
            // SideBar.vue 顯示到 sidebar 視圖上
            sidebar: () => import('@/components/named_view/SideBar.vue'),
          },
        },
      ],
    });
    
  3. 主頁配置兩個(gè)命名視圖原在,分別渲染對(duì)應(yīng)的組件:

    // file: main.js 參考上文
    
    <!-- file: App.vue -->
    <template>
      <h1>Main Page</h1>
      
      <!-- 點(diǎn)擊跳轉(zhuǎn)到根路由 -->
      <router-link to="/">Main</router-link>
      
      <router-view name="sidebar" />
      <router-view />
      
    </template>
    

效果如下:


Named View Demo

重定向

  • 重定向:就是當(dāng)訪問一個(gè)路由時(shí),會(huì)被攔截并重新導(dǎo)航到另一個(gè)路由中彤叉。

重定向只需通過配置$route即可庶柿,Vue Router 大致提供如下幾種類型重定向配置:

  • path:直接配置重定向路徑:

    // 將 /home 重定向到 /
    const routes = [{ path: '/home', redirect: '/' }]
    
  • 命名路由:命名路由本質(zhì)是一個(gè)路由,因此也可直接命名路由秽浇,最終重定向到該命名路由對(duì)應(yīng)的path

    // 將 /home 重定向到命名路由 homepage 
    const routes = [{ path: '/home', redirect: { name: 'homepage' } }]
    
  • 函數(shù):可以將redirect設(shè)置會(huì)一個(gè)函數(shù)浮庐,動(dòng)態(tài)返回重定向地址信息:

    const routes = [
      {
        path: '/a',
        redirect: (to) => {
          // 參數(shù) to 是源路由地址實(shí)例對(duì)象
          const { hash, params, query } = to;
          if (query.to === 'search') {
            // 返回一個(gè)路由映射配置信息
            return { path: '/search', query: { q: params.searchText }};
          }
          if (params.id) {
            // 返回動(dòng)態(tài)路由
            return '/with-params/:id';
          } else {
            // 返回路由地址
            return '/bar';
          }
        },
      },
    ];
    

別名

  • 別名:Vue Router 中,別名 指的是一個(gè)路由對(duì)應(yīng)兩個(gè)路徑柬焕,即訪問這兩個(gè)路徑都能跳轉(zhuǎn)到該路由审残。

比如對(duì)于下面的配置:

const routes = [
  {
    path: '/user_one', // 路徑
    alias: '/user_1',  // 別名
    component: User,
  },
];

其實(shí)就是為/user_one設(shè)置了一個(gè)別名/user_1,此時(shí)訪問/user_one/user_1都可以導(dǎo)航到User.vue組件斑举。

:如果想同時(shí)指定多個(gè)別名搅轿,則需進(jìn)行如下配置:

const routes = [
  {
    path: '/user_one', 
    component: User,
    alias: ['/user_1', '/user_yi'], // 使用數(shù)組即可
  },
];

路由組件傳參

  • 路由組件傳參:其實(shí)就是跳轉(zhuǎn)時(shí),給路由映射組件傳遞參數(shù)富玷。

前面內(nèi)容璧坟,在模板中,我們都是通過$route直接獲取路由信息:

<!-- file: components/User.vue -->
<template>
  <h1>User Component: {{ $route.params.name }}</h1>
</template>

// file: router/index.js
const routes = [
  {
    path: '/user/:name',
    component: () => import('@/components/User.vue'),
  },
];

這種做法其實(shí)緊耦合了路由與組件赎懦,對(duì)組件復(fù)用性產(chǎn)生消極影響雀鹃。

一個(gè)更靈活的解決辦法是通過為組件動(dòng)態(tài)傳遞參數(shù),Vue Router 大致提供了如下幾種路由參數(shù)傳遞方法:

  • 布爾模式:為路由地址映射配置一個(gè)props: true铲敛,此時(shí)route.params會(huì)被傳遞給組件的props

    比如褐澎,上面的例子使用參數(shù)傳遞,可修改為如下:

    // file: router/index.js
    const routes = [
      {
        path: '/user/:name',
        component: () => import('@/components/User.vue'),
        props: true, // 使能路由參數(shù)傳遞
      },
    ];
    
    <!-- file: components/User.vue -->
    <template>
      <!-- 顯示傳遞的參數(shù) -->
      <h1>User Component: {{ name }}</h1>
    </template>
    
    <script>
    export default {
      name: 'User',
      props: {
        name: String, // 接收傳遞的參數(shù)
      },
    };
    </script>
    
  • 命名視圖:對(duì)于有命名視圖的路由伐蒋,必須顯示為每個(gè)命名視圖定義props配置:

    const routes = [
      {
        path: '/user/:name',
        components: { default: User, sidebar: Sidebar },
        // default 視圖使能參數(shù)傳遞工三,sidebar 視圖關(guān)閉參數(shù)傳遞
        props: { default: true, sidebar: false }
      }
    ]
    
  • 對(duì)象模式:將props設(shè)置為對(duì)象,直接傳遞該對(duì)象給組件:

    const routes = [
      {
        path: '/user/:name',
        components: { default: User, sidebar: Sidebar },
        // 直接傳遞對(duì)象
        props: { name: 'Whyn' }
      }
    ]
    

    :對(duì)象模式此時(shí)直接傳遞props對(duì)象先鱼,與路由params沒有關(guān)系俭正。當(dāng)我們需要傳遞靜態(tài)內(nèi)容給到路由組件時(shí),對(duì)象模式就很合適焙畔。

  • 函數(shù)模式:可以將props設(shè)置為一個(gè)函數(shù)掸读,該函數(shù)參數(shù)是路由地址信息$route,因此可以在函數(shù)內(nèi)部提取當(dāng)前路由相關(guān)信息,結(jié)合自己一些靜態(tài)內(nèi)容儿惫,組合進(jìn)行設(shè)置澡罚,更加靈活:

    const routes = [
      {
        path: '/user',
        component: () => import('@/components/User.vue'),
        props: (route) => ({ query: route.query.name }),
      },
    ];
    

    上述配置中,比如此時(shí)我們跳轉(zhuǎn)到/user?name=Whyn時(shí)肾请,則會(huì)傳遞{ query: 'Whyn' }給到User.vue組件:

    <!-- file: components/User.vue -->
    <template>
      <h1>User Component: {{ query }}</h1>
    </template>
    
    <script>
    export default {
      name: 'User',
      props: {
        query: String,
      },
    };
    </script>
    

導(dǎo)航守衛(wèi)

  • 導(dǎo)航守衛(wèi):所謂 導(dǎo)航守衛(wèi)留搔,其實(shí)就是一些路由鉤子,在進(jìn)行路由跳轉(zhuǎn)或取消時(shí)铛铁,會(huì)觸發(fā)相應(yīng)鉤子隔显,我們可以在這些鉤子中,檢測(cè)路由跳轉(zhuǎn)及獲取相關(guān)數(shù)據(jù)饵逐,植入我們自己的操作括眠。

Vue Router 總共提供了如下三種類型導(dǎo)航守衛(wèi):

  • 全局守衛(wèi):可以監(jiān)控所有路由跳轉(zhuǎn)的導(dǎo)航守衛(wèi)。具體可在細(xì)分為如下三種類型:

    1. 全局前置守衛(wèi):當(dāng)觸發(fā)一個(gè)導(dǎo)航跳轉(zhuǎn)時(shí)倍权,全局前置守衛(wèi)會(huì)被觸發(fā)調(diào)用(多個(gè)全局前置守衛(wèi)會(huì)按照創(chuàng)建順序依次回調(diào))掷豺。

      可通過Router#beforeEach注冊(cè)一個(gè)全局前置守衛(wèi):

      const router = createRouter({ ... })
      
      router.beforeEach((to, from, next) => {
        // ...
      })
      

      全局前置守衛(wèi)是異步解析執(zhí)行的,即回調(diào)函數(shù)與asyncPromise工作方式一樣:

      // 上述代碼相當(dāng)于如下
      router.beforeEach(async (to, from, next) => {
        // canUserAccess() 返回 `true` 或 `false`
        return await canUserAccess(to)
      })
      

      全局前置守衛(wèi)每個(gè)守衛(wèi)方法可接受三個(gè)參數(shù):

      • to:表示即將要進(jìn)入的路由目標(biāo)
      • from:當(dāng)前導(dǎo)航正要離開的路由對(duì)象
      • next:可選參數(shù)账锹,用于觸發(fā)并傳遞額外數(shù)據(jù)給下一個(gè)路由對(duì)象:
      router.beforeEach((to, from, next) => {
          // 進(jìn)行管道的下一個(gè)鉤子
          next(); 
      
          // 中斷當(dāng)前導(dǎo)航萌业,URL 重置為 from 路由路徑
          next(false);
      
          // 跳轉(zhuǎn)到指定路由 /home
          next('/home');
      
          // 同 next('/home')
          next( {path: '/home'} );
      
          // 如果 next 參數(shù)是一個(gè) Error 實(shí)例,則導(dǎo)航會(huì)被終止奸柬,
          // 且參數(shù) error 會(huì)被傳遞給 Router#onError() 回調(diào)
          next(error);
      })
      

      全局前置守衛(wèi)每個(gè)守衛(wèi)方法返回值有如下幾種可選:

      • true|undefined:返回trueundefined生年,表示導(dǎo)航有效,并自動(dòng)調(diào)用下一個(gè)導(dǎo)航守衛(wèi):

        router.beforeEach((to, from) => {
            // 沒有 return廓奕,則表示 return undefined
            return false;
        });
        

        :如果顯示聲明了第三個(gè)參數(shù)next抱婉,則必須手動(dòng)調(diào)用next進(jìn)行跳轉(zhuǎn):

        router.beforeEach((to, from, next) => {
            // false
            next(true);
            // 或者 undefined
            next();
        });
        
      • false:表示取消導(dǎo)航跳轉(zhuǎn),即當(dāng)前 URL 重置到from路由地址

        router.beforeEach((to, from) => {
            // 取消導(dǎo)航桌粉,停留在 from 路由頁面
            return false;
        });
        
      • 一個(gè)路由地址:指定導(dǎo)航跳轉(zhuǎn)地址蒸绩,相當(dāng)于調(diào)用了Router#push

        const routes = [
          // ...
          { path: '/user', component: () => import('@/components/User.vue') },
        ],
        
        router.beforeEach((to, from) => {
          if (to.path === '/user') {
              return true;
            return '/user';
        });
        
      • Error:拋出異常,此時(shí)會(huì)取消導(dǎo)航并回調(diào)Router#onError全局錯(cuò)誤鉤子:

        router.beforeEach((to, from, next) => {
          // 手動(dòng)拋異常铃肯,會(huì)被 onError 捕獲到
          throw 'error occured!!';
        });
        
        router.onError((error, to, from) => {
          console.log(error, to, from);
        });
        
    2. 全局解析守衛(wèi):全局解析守衛(wèi)與全局前置守衛(wèi)類似患亿,都是在 每次導(dǎo)航 時(shí)都會(huì)被觸發(fā),但是全局解析守衛(wèi)會(huì)確保在 所有組件內(nèi)守衛(wèi)和異步路由組件被解析后押逼,才會(huì)被正確調(diào)用步藕。

      可通過Router#beforeResolve方法注冊(cè)一個(gè)全局解析守衛(wèi):

      router.beforeResolve((to, from, next) => {
        console.log('Router beforeResolve');
      });
      

      Router#beforeResolve是獲取數(shù)據(jù)或執(zhí)行任何其他操作(如果用戶無法進(jìn)入頁面時(shí)你希望避免執(zhí)行的操作)的理想位置。

    3. 全局后置鉤子:全局后置鉤子是在導(dǎo)航被確認(rèn)后挑格,才進(jìn)行調(diào)用咙冗,因此,該鉤子不會(huì)攜帶next函數(shù)漂彤,也不會(huì)改變導(dǎo)航狀態(tài)雾消。

      可通過Router#afterEach注冊(cè)一個(gè)全局后置鉤子:

      router.afterEach((to, from, failure) => {
        console.log('Router afterEach');
      });
      

      Router#afterEach對(duì)于分析灾搏、更改頁面標(biāo)題、聲明頁面等輔助功能以及許多其他事情都很有用立润。

  • 路由獨(dú)享守衛(wèi):如果只關(guān)注特定路由導(dǎo)航跳轉(zhuǎn)事件狂窑,那么只需為相應(yīng)路由添加導(dǎo)航守衛(wèi)即可。

    只需在路由配置上定義beforeEnter函數(shù)即可注冊(cè)一個(gè)路由獨(dú)享導(dǎo)航守衛(wèi):

    const routes = [
      {
        path: '/home',
        component: () => import('@/components/Home.vue'),
        // 路由獨(dú)享守衛(wèi)
        beforeEnter: (to, from, next) => {
          console.log('Home: Route beforeEnter');
          next();
        },
        // 支持傳遞多個(gè)鉤子函數(shù)
        // beforeEnter: [(..)=>{..}, (..)=>{..}],
      },
    ];
    

    beforeEnter只在進(jìn)入路由時(shí)觸發(fā)范删,更改params蕾域、queryhash時(shí),不會(huì)觸發(fā)beforeEnter到旦。

  • 組件內(nèi)守衛(wèi):一個(gè)路由最終映射為一個(gè)組件,因此我們也可以在組件內(nèi)定義導(dǎo)航守衛(wèi)巨缘,捕獲路由跳轉(zhuǎn)導(dǎo)航相關(guān)信息添忘。

    組件內(nèi)守衛(wèi)在 Options API 中可通過為組件添加beforeRouteEnterbeforeRouteUpdatebeforeRouteLeave函數(shù)進(jìn)行注冊(cè):

    const UserDetails = {
      template: `...`,
      beforeRouteEnter(to, from) {
        // 在渲染該組件的對(duì)應(yīng)路由被驗(yàn)證前調(diào)用
        // 不能獲取組件實(shí)例 `this` 若锁!
        // 因?yàn)楫?dāng)守衛(wèi)執(zhí)行時(shí)搁骑,組件實(shí)例還沒被創(chuàng)建!
      },
      beforeRouteUpdate(to, from) {
        // 在當(dāng)前路由改變又固,但是該組件被復(fù)用時(shí)調(diào)用
        // 舉例來說仲器,對(duì)于一個(gè)帶有動(dòng)態(tài)參數(shù)的路徑 `/users/:id`,在 `/users/1` 和 `/users/2` 之間跳轉(zhuǎn)的時(shí)候仰冠,
        // 由于會(huì)渲染同樣的 `UserDetails` 組件乏冀,因此組件實(shí)例會(huì)被復(fù)用。而這個(gè)鉤子就會(huì)在這個(gè)情況下被調(diào)用洋只。
        // 因?yàn)樵谶@種情況發(fā)生的時(shí)候辆沦,組件已經(jīng)掛載好了,導(dǎo)航守衛(wèi)可以訪問組件實(shí)例 `this`
      },
      beforeRouteLeave(to, from) {
        // 在導(dǎo)航離開渲染該組件的對(duì)應(yīng)路由時(shí)調(diào)用
        // 與 `beforeRouteUpdate` 一樣识虚,它可以訪問組件實(shí)例 `this`
      },
    }
    

    組件內(nèi)守衛(wèi)在 Composition API 中可通過在setup函數(shù)中定義onBeforeRouteUpdateonBeforeRouteLeave分別注冊(cè) update 和 leave 守衛(wèi):

    <script>
    import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router';
    export default {
      name: 'Home',
    
      setup(props, context) {
        console.log('setup = onBeforeRouteEnter');
        // update 守衛(wèi)確認(rèn)導(dǎo)航跳轉(zhuǎn)肢扯,因此沒有 next 參數(shù)
        onBeforeRouteUpdate((fto, from) => {
          console.log('onBeforeRouteUpdate');
        });
    
        // leave 守衛(wèi)同樣沒有 next 參數(shù)
        onBeforeRouteLeave((to, from) => {
          console.log('onBeforeRouteLeave');
        });
      },
    };
    </script>
    

    Composition API 中,setup等于beforeRouteEnter担锤,在路由進(jìn)入時(shí)被觸發(fā)蔚晨;onBeforeRouteUpdate在第一次路由進(jìn)入時(shí),不會(huì)被觸發(fā)肛循,只有在該路由重復(fù)進(jìn)入铭腕,組件被復(fù)用時(shí)才會(huì)被觸發(fā)(比如params的改變);onBeforeRouteLeave在離開當(dāng)前路由時(shí)會(huì)被觸發(fā)育拨。

最后谨履,全局導(dǎo)航守衛(wèi)、路由獨(dú)享守衛(wèi)和組件內(nèi)守衛(wèi)完整的導(dǎo)航解析流程如下圖所示:

:流程圖來源于網(wǎng)上熬丧,侵刪笋粟。

路由導(dǎo)航完整解析流程

附錄

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末怀挠,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子害捕,更是在濱河造成了極大的恐慌绿淋,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尝盼,死亡現(xiàn)場離奇詭異吞滞,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)盾沫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門裁赠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人赴精,你說我怎么就攤上這事佩捞。” “怎么了蕾哟?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵一忱,是天一觀的道長。 經(jīng)常有香客問我谭确,道長帘营,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任逐哈,我火速辦了婚禮芬迄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鞠眉。我一直安慰自己薯鼠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布械蹋。 她就那樣靜靜地躺著出皇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪哗戈。 梳的紋絲不亂的頭發(fā)上郊艘,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音唯咬,去河邊找鬼纱注。 笑死,一個(gè)胖子當(dāng)著我的面吹牛胆胰,可吹牛的內(nèi)容都是我干的狞贱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼蜀涨,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼瞎嬉!你這毒婦竟也來了蝎毡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤氧枣,失蹤者是張志新(化名)和其女友劉穎沐兵,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體便监,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扎谎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了烧董。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片毁靶。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖解藻,靈堂內(nèi)的尸體忽然破棺而出老充,到底是詐尸還是另有隱情,我是刑警寧澤螟左,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站觅够,受9級(jí)特大地震影響胶背,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜喘先,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一钳吟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧窘拯,春花似錦红且、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至思喊,卻和暖如春壁酬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背恨课。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國打工舆乔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人剂公。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓希俩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親纲辽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子颜武,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Technology vue 3 安裝 npm install @vue/cli vue-router 4 安裝 ...
    行者深藍(lán)閱讀 1,230評(píng)論 0 0
  • 1. 后端路由階段 早期的網(wǎng)站開發(fā)整個(gè)HTML頁面是由服務(wù)器來渲染的璃搜。服務(wù)器直接生產(chǎn)渲染好對(duì)應(yīng)的HTML頁面, 返...
    itlu閱讀 531評(píng)論 0 3
  • 一、vue-router實(shí)現(xiàn)原理 SPA(single page application):單一頁面應(yīng)用程序盒刚,只有...
    walycode閱讀 1,042評(píng)論 1 3
  • 怎么重定向頁面腺劣? 第一種方法: 第二種方法:const router = new VueRouter({route...
    chendalei閱讀 1,177評(píng)論 0 0
  • 學(xué)習(xí)目的 學(xué)習(xí)Vue的必備技能,必須 熟練使用 Vue-router因块,能夠在實(shí)際項(xiàng)目中運(yùn)用橘原。 Vue-rout...
    _1633_閱讀 91,677評(píng)論 3 58