Vue Router 4 的使用户秤,一篇文章給你講透徹

Vue 3.X 使用Vue Router 4.x 進(jìn)行路由配置,本文我們就來(lái)研究下如何使用Vue Router 4.x咪鲜,本文中所有的使用方式都是使用 Composition API的方式东亦。

本文通過(guò)一步步介紹Vue Router 4.x的使用急鳄,來(lái)搭建一個(gè)簡(jiǎn)單的博客系統(tǒng)悼吱,讓你對(duì)新版的Vue Router 4.x有一個(gè)完整的認(rèn)識(shí)银酗,然后能夠非常輕松滴將Vue Router 4.x應(yīng)用在自己的項(xiàng)目中辆影。

項(xiàng)目初始化

項(xiàng)目搭建

項(xiàng)目使用vite進(jìn)行創(chuàng)建。

npm init vite@latest vue-router-blog
npm install
npm run dev

目前安裝的是Vue 3.2.25

配置vite.config.js

我們配置@別名黍特,這樣就比較方便書寫引入文件的路徑

// 引入文件
const path = require("path");

export default defineConfig({
  // 添加 @
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
  plugins: [vue()],
});

配置jsconfig.json

jsconfig.json可以讓VSCode更加智能

{
  "include": [
    "./src/**/*",
  ],
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

Vue Router 4初體驗(yàn)

安裝Vue Router 4
npm i vue-router@4

目前安裝的是Vue Router 4.0.12

創(chuàng)建兩個(gè)頁(yè)面Home.vueAbout.vue
<!-- Home.vue -->
<template>
  <div>
    主頁(yè)
  </div>
</template>
<!-- About.vue -->
<template>
  <div>
    關(guān)于頁(yè)
  </div>
</template>

這兩個(gè)頁(yè)面很簡(jiǎn)單蛙讥,每個(gè)頁(yè)面僅僅就是顯示一行文字

創(chuàng)建router

我們?cè)?strong>src目錄下新建router目錄,在router目錄下創(chuàng)建index.js文件, 在里面進(jìn)行路由的信息配置衅澈。

import { createRouter, createWebHistory } from "vue-router";

// 引入
import Home from "@/views/Home.vue";
import About from "@/views/About.vue";

// 路由信息
let routes = [
  {
    path: "/",
    name: 'home',
    component: Home,
  },
  {
    path: "/about",
    name: 'about',
    component: About,
  },
];

// 路由器
const router = createRouter({
  history: createWebHistory(), // HTML5模式
  routes,
});

export default router;

安裝router

將路由安裝router安裝到app上键菱。

import { createApp } from 'vue'
import App from './App.vue'

// 引入插件
import router from "@/store/index";
// 安裝router插件
createApp(App).use(router).mount('#app')
使用 router-linkrouter-view

修改App.vue

<template>
  <img alt="Vue logo" src="./assets/logo.png" /><br />
  <div>
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link><br />
  </div>
  <router-view></router-view>
</template>

至此谬墙,我們的就實(shí)現(xiàn)了頁(yè)面間的切換功能了今布。

basic

幾個(gè)重要的概念

router-link組件和a標(biāo)簽的區(qū)別?

router-link組件底層也是渲染的a標(biāo)簽经备,但是router-link的頁(yè)面切換只是更新了頁(yè)面的部分內(nèi)容,不會(huì)進(jìn)行整個(gè)頁(yè)面的刷新部默,而a標(biāo)簽跳轉(zhuǎn)(例如:<a href="/about">調(diào)到Home標(biāo)簽</a><br>)是對(duì)整個(gè)頁(yè)面進(jìn)行刷新侵蒙。

底層原理是router-link劫持了元素的點(diǎn)擊事件,添加了處理頁(yè)面更新的邏輯傅蹂。

Hash模式和HTML5模式的區(qū)別?

Hash模式的URL中有一個(gè)#號(hào)纷闺,eg:http://localhost:3000/#/about, #號(hào)后面的就是Hash地址,這個(gè)模式以前是SPA的常用模式份蝴,但是鏈接有一個(gè)#號(hào)比較丑犁功。

HTML5模式和正常的鏈接地址一樣的,eg:http://localhost:3000/about, 這個(gè)地址很優(yōu)雅婚夫,但是有一個(gè)問(wèn)題浸卦,需要服務(wù)器支持。 原因是瀏覽器中輸入http://localhost:3000/about支持案糙,服務(wù)器以為要訪問(wèn)根路勁下的about目錄的HTML文件限嫌,而不是訪問(wèn)根路勁下的HTML文件。

webpackvite啟動(dòng)的服務(wù)器是支持HTML5模式的时捌,所以開發(fā)環(huán)境使用HTML5模式?jīng)]有問(wèn)題怒医。

router-link組件和router-view組件為什么能直接使用?

安裝router插件的時(shí)候注冊(cè)了這兩個(gè)全局組件奢讨,所以能直接使用稚叹。

install(app: App) {
    app.component('RouterLink', RouterLink)
    app.component('RouterView', RouterView)
}

路由懶加載

上面寫法有一個(gè)嚴(yán)重的問(wèn)題,router中所有的組件都會(huì)被一次加載拿诸。我們的例子中就是 HomeAbout組件入录,即使有時(shí)候不會(huì)用到About組件, 也要加載,這對(duì)首頁(yè)的顯示會(huì)有很大的影響佳镜。

改造如下:

<!--// 刪除 import Home from "@/views/Home.vue";-->
<!--// 刪除 import About from "@/views/About.vue";-->

let routes = [
  {
    path: "/",
    name: 'home',
    <!--// 改成如下的寫法-->
    component: () => import("@/views/Home.vue"),
  },
  {
    path: "/about",
    name: 'about',
    <!--// 改成如下的寫法-->
    component: () => import("@/views/About.vue"),
  },
];

這樣在開發(fā)環(huán)境中只有使用到組件才會(huì)加載進(jìn)來(lái)僚稿,在生產(chǎn)環(huán)境中異步組件會(huì)分開文件進(jìn)行打包。

修改代碼(創(chuàng)建博客的框架)

為了方便介紹其他內(nèi)容蟀伸,我們修改一下代碼內(nèi)容:

新建模擬博客列表數(shù)據(jù)
[
  {
    "id": 1,
    "catId": 1,
    "catName": "iOS",
    "subCatId": 1,
    "subcatName": "推薦",
    "name": "RxSwift實(shí)現(xiàn)MVVM架構(gòu)",
    "image": "https://images.xiaozhuanlan.com/photo/2018/2f5dff865155d756dfe04f2909cd1a36.png",
    "description": "在本文中蚀同,我將介紹iOS編程中的MVVM設(shè)計(jì)模式,當(dāng)然還有RxSwift的介紹啊掏。本文分為兩部分蠢络。在第1部分中簡(jiǎn)要介紹了RxSwift的設(shè)計(jì)模式和基礎(chǔ)知識(shí),在第2部分中 迟蜜,我們有一個(gè)使用RxSwift的MVVM的示例項(xiàng)目刹孔。"
  },
  
  //省略...
]

命名為data.json將其放置在src文件夾下

創(chuàng)建路由信息
// 路由信息
let routes = [
  {
    path: "/",
    name: 'home',
    component: () => import("@/views/All.vue"),
  },
  {
    path: "/iOS",
    name: 'iOS',
    component: () => import("@/views/iOS.vue"),
  },
  {
    path: "/android",
    name: 'android',
    component: () => import("@/views/Android.vue"),
  },
  {
    path: "/flutter",
    name: 'flutter',
    component: () => import("@/views/Flutter.vue"),
  },
  {
    path: "/web",
    name: 'web',
    component: () => import("@/views/Web.vue"),
  },
];

設(shè)置5個(gè)路由:全部iOS娜睛,Android髓霞,Flutter卦睹,Web

頂部導(dǎo)航組件
<!-- TheNavigation.vue -->
<template>
  <div id="nav">
    <router-link to="/" class="nav-link">全部</router-link>
    <router-link to="/ios" class="nav-link">iOS</router-link>
    <router-link to="/android" class="nav-link">Android</router-link>
    <router-link to="/flutter" class="nav-link">Flutter</router-link>
    <router-link to="/web" class="nav-link">Web</router-link>
  </div>
</template>

TheNavigation導(dǎo)航組件中有5個(gè)router-link,分別切換到全部方库,iOS结序,AndroidFlutter纵潦,Web徐鹤。

5個(gè)頁(yè)面組件
<template>
  <div class="container">
    <!-- 博客列表 -->
    <div v-for="blog in arrs" class="item" :key="blog.id">
      <!-- 圖片 -->
      <img class="thumb" :src="blog.image" />
      <!-- 信息 -->
      <div class="info">
        <div class="title">{{ blog.name }}</div>
        <div class="message"> {{ blog.description }} </div>
      </div>
    </div>
  </div>
</template>

<script setup>

// 數(shù)據(jù)
import sourceData from "@/data.json";
let arrs = sourceData;

</script>
APP.vue
<script setup>
import TheNavigation from "@/components/TheNavigation.vue";
</script>

<template>
  <TheNavigation />
  <router-view></router-view>
</template>

至此,博客框架就完成了邀层,實(shí)現(xiàn)了5個(gè)博客分類返敬,效果如下圖:

博客分類

設(shè)置linkActiveClass

路由器可以設(shè)置router-link激活的類:

const router = createRouter({
  history: createWebHistory(),
  routes,
  <!--// 添加激活的類-->
  linkActiveClass: "blog-active-link"
});

然后設(shè)置樣式:

#nav .blog-active-link  {
  color: red;
  border-bottom: 2px solid red;
}
linkActiveClass

命名路由

我們?cè)陧敳繉?dǎo)航組件使用的跳轉(zhuǎn)都是路徑跳轉(zhuǎn)例如:to="/", 我們可以給路由設(shè)置一個(gè)名稱name,這樣可以通過(guò)路由的名稱name進(jìn)行跳轉(zhuǎn)寥院。

<template>
  <div id="nav">
    <router-link to="/" class="nav-link">全部</router-link>
    <!-- 修改 to 屬性為 name -->
    <router-link :to="{name: 'ios'}" class="nav-link">iOS</router-link>
    <router-link :to="{name: 'android'}" class="nav-link">Android</router-link>
    <router-link :to="{name: 'flutter'}" class="nav-link">Flutter</router-link>
    <router-link :to="{name: 'web'}" class="nav-link">Web</router-link>
  </div>
</template>

路由的query

前面提到的5個(gè)博客分類是固定的救赐,我們點(diǎn)擊博客列表的每條數(shù)據(jù)進(jìn)入博客詳情,此時(shí)由于不同的博客內(nèi)容是不同的只磷,所以不能固定寫死经磅。實(shí)現(xiàn)方法一是通過(guò)路由傳參實(shí)現(xiàn)。

添加博客詳情的路由
let routes = [
  //...
  {
    path: '/blogdetail',
    name: "blogdetail",
    component: () => import("@/views/BlogDetail.vue")
  }
];
query傳參
<template>
  <div class="container">
    <!-- 傳參 -->
    <router-link v-for="blog in arrs" class="item" :key="blog.id" :to="{ name: 'blogdetail', query: { id: blog.id } }">
      // 省略
    </router-link>
  </div>
</template>

設(shè)置query: { id: blog.id } }給路由傳參

接收query傳參
<template>
  <div class="container">
    <h2>{{ blog.name }}</h2>
    <p>{{ blog.description }}</p>
  </div>
</template>

<script>
import sourceData from "@/data.json";
import { useRoute } from "vue-router";
export default {
  setup(props) {
    // 獲取路由
    let route = useRoute();
    // 獲取query參數(shù)
    let blogId = route.query.id;

    return {
      blog: sourceData.find((blog) => blog.id == blogId),
    };
  },
};
</script>

通過(guò)route.query.id就能獲取到傳遞的博客id, 然后就能顯示對(duì)應(yīng)的博客信息了钮追。

query

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

博客詳情的頁(yè)面邏輯预厌,也可以用動(dòng)態(tài)路由去實(shí)現(xiàn)。

修改博客詳情的路由
<!-- router.js -->
let routes = [
  //...
  {
    <!-- 動(dòng)態(tài)路由路徑 -->
    path: '/blogdetail/:id',
    name: "blogdetail",
    component: () => import("@/views/BlogDetail.vue")
  }
];

:id 表示 路由的路徑是動(dòng)態(tài)的元媚,路徑最后表示博客id.

傳參
<template>
  <div class="container">
    <!-- 傳參 -->
    <router-link v-for="blog in arrs" class="item" :key="blog.id" :to="{ name: 'blogdetail', params: { id: blog.id } }">
      // 省略
    </router-link>
  </div>
</template>

設(shè)置params: { id: blog.id } }給動(dòng)態(tài)路由傳參

接收參數(shù)
let blogId = route.params.id;

通過(guò)route.params.id就能獲取到傳遞的博客id, 然后就能顯示對(duì)應(yīng)的博客信息了轧叽。

重命名路由

知道了動(dòng)態(tài)路由的邏輯后,我們當(dāng)然可以把iOS, Android, Flutter, Web四個(gè)頁(yè)面合并為一個(gè)頁(yè)面刊棕。

合并router
<!-- router.js -->
let routes = [
  {
    path: "/",
    name: 'home',
    component: () => import("@/views/All.vue"),
  },
  <!-- 將/ios,/android,/flutter,/web四個(gè)合并為/category/:catId -->
  {
    path: "/category/:catId",
    name: 'category',
    component: () => import("@/views/All.vue"),
  },
  {
    path: '/blogdetail/:id',
    name: "blogdetail",
    component: () => import("@/views/BlogDetail.vue")
  }
];
修改導(dǎo)航
<template>
  <div id="nav">
    <router-link to="/" class="nav-link">全部</router-link>
    <!-- 動(dòng)態(tài)路由 -->
    <router-link :to="{name: 'category', params: { catId: 1 }}" class="nav-link">iOS</router-link>
    <router-link :to="{name: 'category', params: { catId: 2 }}" class="nav-link">Android</router-link>
    <router-link :to="{name: 'category', params: { catId: 3 }}" class="nav-link">Flutter</router-link>
    <router-link :to="{name: 'category', params: { catId: 4 }}" class="nav-link">Web</router-link>
  </div>
</template>

列表
<script setup>
import { useRoute } from 'vue-router';

// 獲取路由
let route = useRoute();
// 獲取params參數(shù)
let catId = route.params.catId;

// 數(shù)據(jù)
import sourceData from "@/data.json";
let arrs = sourceData.filter((blog) => blog.catId == catId);

</script>

這樣我就可以把iOS.vue,Android.vue,Flutter.vue,Web.vue四個(gè)組件文件刪除了炭晒。

你應(yīng)該有個(gè)疑問(wèn),home路由的內(nèi)容其實(shí)和category路由的內(nèi)容也是一樣的甥角,是否可以合并呢网严?

重命名"/"

可以將"/"重命名為'/category/0',這樣所有的5個(gè)路由都將訪問(wèn)"/category/:catId"這個(gè)路由了嗤无。

<!-- router.js -->
let routes = [
  {
    path: "/",
    <!-- 重命名 -->
    redirect: '/category/0'
  },
  {
    path: "/category/:catId",
    name: 'category',
    component: () => import("@/views/All.vue"),
  },
  {
    path: '/blogdetail/:id',
    name: "blogdetail",
    component: () => import("@/views/BlogDetail.vue")
  }
];
import sourceData from "@/data.json";
let arrs = catId != '0' ? sourceData.filter((blog) => blog.catId == catId) : sourceData;

判斷下震束,如果catId != '0'為分類篩選,否則就是顯示全部

監(jiān)聽路由變化

此時(shí)的代碼出現(xiàn)了問(wèn)題当犯,點(diǎn)擊頂部的導(dǎo)航切換不同的分類垢村,底下的列表將不會(huì)變化。這是因?yàn)榻M件復(fù)用了嚎卫。此時(shí)需要監(jiān)聽組件的路由的變化嘉栓,切換數(shù)據(jù)。

路由

可以通過(guò)watch函數(shù)監(jiān)聽route.params, 當(dāng)路由變化后,就可以重新獲取數(shù)據(jù)侵佃。

<!-- All.vue -->
<script setup>
import { ref } from '@vue/reactivity';
import { useRoute } from 'vue-router';
import sourceData from "@/data.json";
import { watch } from '@vue/runtime-core';

let arrs = ref([]);

let route = useRoute();
let params = route.params;

let initData = (catId) => {
  arrs.value = catId != '0' ? sourceData.filter((blog) => blog.catId == catId) : sourceData;
}

// 初始化的時(shí)候獲取數(shù)據(jù)
initData(params.catId);

// 監(jiān)聽paramas麻昼,更新數(shù)據(jù)
watch(() => route.params.catId, (value) => {
  initData(value);
})

</script>

禁止路由復(fù)用

解決上節(jié)問(wèn)題,還有一個(gè)更簡(jiǎn)單的方法趣钱,就是禁止路由的復(fù)用。

<template>
  <TheNavigation />
  <!-- 禁止路由復(fù)用 -->
  <router-view :key="$route.path"></router-view>
</template>

通過(guò)這個(gè)方法胚宦,動(dòng)態(tài)組件將不會(huì)復(fù)用首有,直接卸載舊組件,掛載新組件枢劝。所以性能上有丟丟的損耗井联。

給組件傳遞props

我們前面在組件中需要使用useRoute獲取到路由,然后獲取對(duì)應(yīng)的route.params, 我們可以通過(guò)另外一種方式獲取route.params您旁。

路由添加props屬性
<!-- router.js -->
{
    path: "/category/:catId",
    name: 'category',
    component: () => import("@/views/All.vue"),
    <!-- 路由添加`props`屬性 -->
    props: true,
}
組件中獲取props屬性
<script setup>
import { ref } from '@vue/reactivity';
import { useRoute } from 'vue-router';
import sourceData from "@/data.json";

// 定義props
const props = defineProps({
  catId: {
    type: String,
    required: true,
  }
})

let arrs = props.catId != '0' ? sourceData.filter((blog) => blog.catId == props.catId) : sourceData;

</script>

組件中可以直接獲取到catId參數(shù)烙常,個(gè)人認(rèn)為這種寫法更優(yōu)美。

路由props屬性支持函數(shù)
<!-- router.js -->
{
    path: "/category/:catId",
    name: 'category',
    component: () => import("@/views/All.vue"),
    props: route => ({ catId: parseInt(route.params.catId) }) ,
}

函數(shù)中鹤盒,可以對(duì)參數(shù)進(jìn)行處理蚕脏,我們的例子中是將catId從字符串變成了數(shù)字

// 定義props
const props = defineProps({
  catId: {
    type: Number,
    required: true,
  }
})

let arrs = props.catId !== 0 ? sourceData.filter((blog) => blog.catId === props.catId) : sourceData;

props catId的定義和使用也要進(jìn)行相應(yīng)的修改

編程式導(dǎo)航

除了使用<router-link> 來(lái)定義導(dǎo)航鏈接,我們還可以借助 router 的實(shí)例方法侦锯,通過(guò)編寫代碼來(lái)實(shí)現(xiàn)驼鞭。

例如:可以在詳情頁(yè)加一個(gè)按鈕,點(diǎn)擊返回上一個(gè)頁(yè)面

<button @click="$router.back()">返回</button>

轉(zhuǎn)場(chǎng)動(dòng)畫

Vue Router4 的轉(zhuǎn)場(chǎng)動(dòng)畫的實(shí)現(xiàn) 和 以前的版本有些不一致尺碰。需要將transition 包含在router-view挣棕, 如下所示:

  <router-view v-slot="{ Component }">
    <transition name="fade" mode="out-in">
      <component :is="Component" :key="$route.path" />
    </transition>
  </router-view>

加上對(duì)應(yīng)的css樣式

/* fade 模式 name="fade" mode="out-in" */
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

這樣切換就有淡入淡出的效果了。效果自定義亲桥,很方便洛心。

路由未匹配上

有時(shí)候用戶可能輸入一個(gè)根本不存在的路勁(例如:http://localhost:3000/categorys),此時(shí)最好是給顯示個(gè)默認(rèn)的404頁(yè)面题篷,這樣用戶體驗(yàn)更好词身。

404頁(yè)面
定義路由
<!-- router.js -->
{
    path: '/:pathMatch(.*)*',
    name: "NotFound",
    component: () => import("@/views/404.vue"),
}

注意,這個(gè)路由一定要放在最后番枚,否則就有問(wèn)題了偿枕。

404頁(yè)面
<template>
  <div class="container">
    <h2>未找到頁(yè)面</h2>
  <router-link to="/">回到首頁(yè)</router-link>
  </div>
</template>

這個(gè)頁(yè)面內(nèi)容隨意

路由守衛(wèi)

路由獨(dú)享的守衛(wèi)

想象下用戶瀏覽器地址欄輸入http://localhost:3000/category/6, 其實(shí)也會(huì)出現(xiàn)一些問(wèn)題,因?yàn)椴淮嬖谶@個(gè)分類户辫。這時(shí)候需要進(jìn)行處理, 當(dāng)分類不存在的時(shí)候跳轉(zhuǎn)到404頁(yè)面渐夸。

<!-- router.js -->
  {
    path: "/category/:catId",
    name: 'category',
    component: () => import("@/views/All.vue"),
    props: route => ({ catId: parseInt(route.params.catId) }),
    <!-- 添加路由守衛(wèi) -->
    beforeEnter: (to, from) => {
      // 如果不是正確的分類,跳轉(zhuǎn)到NotFound的頁(yè)面
      console.log(to.params.catId);
      if (!["0", "1", "2", "3", "4"].includes(to.params.catId)) { 
        return {
          name: "NotFound",
          // 這個(gè)是在地址欄保留輸入的信息渔欢,否則地址欄會(huì)非常的丑
          params: { pathMatch: to.path.split("/").slice(1) },
          query: to.query,
          hash: to.hash,
        };
      }
    }
  },

判斷如果不是正確的分類墓塌,跳轉(zhuǎn)到NotFound的頁(yè)面

路由全局守衛(wèi)

在某些路由中需要一些特定的操作,譬如訪問(wèn)前必須是登錄用戶。這時(shí)候可以通過(guò)使用meta屬性和全局守衛(wèi)來(lái)實(shí)現(xiàn)苫幢。

譬如有一個(gè)課程專欄我們?cè)O(shè)置為需要用戶登錄才能訪問(wèn)访诱。我們可以如下設(shè)置

<!-- router.js -->
  {
    path: '/course',
    name: "course",
    component: () => import("@/views/Course.vue"),
    <!-- 需要登錄 -->
    meta: {needLogin: true}
  },
  {
    path: '/login',
    name: "login",
    component: () => import("@/views/Login.vue"),
  },
  

添加一個(gè)全局守衛(wèi), 需要登錄但是沒(méi)有登錄的情況下就跳轉(zhuǎn)到登錄頁(yè)面

<!-- router.js -->
// 全局守衛(wèi)
router.beforeEach((to, from) => {
  if (to.meta.needLogin && !userLogin) {
    // need to login
    return { name: "login" };
  }
});
組件內(nèi)的路由守衛(wèi)

前面的切換分類的章節(jié)的問(wèn)題其實(shí)還有第三種解決方案,就是用組件內(nèi)的路由守衛(wèi)韩肝。

<script setup>
import { ref } from '@vue/reactivity';
import { useRoute, onBeforeRouteUpdate } from 'vue-router';
import sourceData from "@/data.json";

// 定義props
const props = defineProps({
  catId: {
    type: Number,
    required: true,
  }
})

let arrs = ref([]);

let fetchData = (id) => {
  return id !== 0 ? sourceData.filter((blog) => blog.catId == id) : sourceData;
}

<!-- 組件內(nèi)的路由守衛(wèi) -->
onBeforeRouteUpdate((to, from, next) => {
  arrs.value = fetchData(to.params.catId)
});

arrs.value = fetchData(props.catId);

</script>

對(duì)于一個(gè)帶有動(dòng)態(tài)參數(shù)的路徑 /category/:catId触菜,在 /category/1/category/2 之間跳轉(zhuǎn)的時(shí)候, 會(huì)觸發(fā)onBeforeRouteUpdate的路由鉤子函數(shù),在鉤子函數(shù)中可以進(jìn)行數(shù)據(jù)的更新哀峻。

擴(kuò)展 RouterLink

router-link可以實(shí)現(xiàn)路由的跳轉(zhuǎn)涡相,此外為了更加豐富功能,可以對(duì)其進(jìn)行擴(kuò)展剩蟀。譬如我們可以擴(kuò)展實(shí)現(xiàn)能夠跳轉(zhuǎn)到外部鏈接催蝗。

<!--AppLink.vue-->
<template>
  <!-- 如果是外部鏈接,跳轉(zhuǎn)(<slot />表示router-link組件中的slot內(nèi)容)  -->
  <a v-if="isExternal" :href="to"><slot /></a>
  <!-- 如果是APP內(nèi)的鏈接育特,路由跳轉(zhuǎn) (<slot />表示router-link組件中的slot內(nèi)容) -->
  <router-link v-else v-bind="$props"><slot /></router-link>
</template>

<script>
import { computed, defineComponent } from "@vue/runtime-core";
import { RouterLink } from "vue-router";

export default {
  props: {
    // 繼承RouterLink的props
    ...RouterLink.props,
  },
  setup(props) {
    
    // 如果`to`屬性值是字符串類型丙号,并且以`http`開頭,我們認(rèn)為它是外部鏈接
    let isExternal = computed(() => typeof props.to === 'string' && props.to.startsWith('http'));

    return {
      isExternal
    }
  }
};
</script>

使用:

<AppLink to="https://www.domain.cn" />

總結(jié)

Vue Router 4.x 的使用基本上介紹完了缰冤,最重要的特性是能和Composition API的搭配使用犬缨,此外使用上也還是有一些不小的變化。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末棉浸,一起剝皮案震驚了整個(gè)濱河市遍尺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌涮拗,老刑警劉巖乾戏,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異三热,居然都是意外死亡鼓择,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門就漾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)呐能,“玉大人,你說(shuō)我怎么就攤上這事抑堡“诔觯” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵首妖,是天一觀的道長(zhǎng)偎漫。 經(jīng)常有香客問(wèn)我,道長(zhǎ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
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼获讳!你這毒婦竟也來(lái)了阴颖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤丐膝,失蹤者是張志新(化名)和其女友劉穎量愧,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體帅矗,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡偎肃,尸身上長(zhǎng)有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
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)躺苦。三九已至身腻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間匹厘,已是汗流浹背嘀趟。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留愈诚,地道東北人她按。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像炕柔,于是被迫代替她去往敵國(guó)和親酌泰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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