Vue-Router是Vue全家桶中至关重要的一个扩展化插件,使用它能够让我们的组件切换更加的方便,更加容易的开发前后端分离项目,目前Vue-Router版本已更新到4.x,我们就以4.x为例了解它的用法。
学习Vue-Router之前,我们有必要了解一下什么是后端路由。
在早期前后端混合开发时,前端具体所展示的内容是由后端负责的,也就是说用户在浏览器中的一次请求操作会直接传递到后端服务器上,后端服务器会根据这个请求内容返回给浏览器不同的页面,如下所示:
现在的项目越来越大,前后端混合的开发模式并不适用于大型项目,于是出现了前后端分离的开发模式,即用户在页面上所有静态资源请求大部分都是面向前端服务器发起的,然后再由前端服务器动态请求后端服务器的API接口获得所需要展示的数据最终结合前端服务器中的静态资源反馈给浏览器:
用户与Web服务器之间是经由浏览器通过url打交道的,因此在学习Vue-Router插件之前你应该掌握一些必要的url相关知识。
下面是url的组成部分,截图自Node.js官网中对url的描述:
值得注意的是,auth部分是对身份权限的认证,目前在绝大多数应用中已经极少看到了,因此这里不再进行介绍。
我们以下面这个url进行说明:
https://localhost/book/1?page=2#caption_01
释义如下:
Vue单页面开发的原理实际上就是利用标签的锚点切换来完成的,举个例子。
访问下面的这个url就是主页:
http://loclhost/#/index
跳转时只需要修改锚点的定位即可,如从首页跳转到新闻页面:
http://loclhost/#/news
下面我们基于此原理利用原生的HTML+CSS来实现一个单页面应用:
代码示例:
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
list-style: none;
}
.components {
display: none;
}
:target {
display: block;
}
body header {
background-color: #565656;
height: 48px;
}
body header ul {
height: 100%;
display: flex;
flex-flow: row wrap;
align-items: center;
padding: 1rem;
}
body header ul li:first-of-type,
body header ul li:nth-of-type(2) {
margin-right: 2rem;
}
body header ul li:last-of-type {
margin-left: auto;
}
body header ul li a {
color: #fff;
text-decoration: none;
}
body main {
display: flex;
justify-content: center;
align-items: center;
margin-top: 68px;
font-size: 5rem;
}
</style>
<body>
<header>
<ul>
<li><a href="#/index">主页</a></li>
<li><a href="#/news">新闻</a></li>
<li><a href="#/backend">后台</a></li>
</ul>
</header>
<main>
<!-- 主页 -->
<div id="/index" class="components">
<span>HELLO INDEX</span>
</div>
<!-- 新闻 -->
<div id="/news" class="components">
<span>HELLO NEWS</span>
</div>
<!-- 后台 -->
<div id="/backend" class="components">
<span>HELLO BACKEND</span>
</div>
</main>
<footer></footer>
</body>
Vue-Router中对于组件的切换有2种模式,分别是hash模式和history模式。
当使用hash模式时,若你访问/index页面则浏览器地址栏中的url是这个样子的:
http://loclhost/#/index
而使用history模式时,url看起来会正常许多:
http://loclhost/index
使用hash模式的优缺点如下:
而使用history模式的优缺点如下:
hash模式是我们在开发时建议使用的,尽管history模式让url看起来美观了许多,但是你需要做一些额外的配置,过程比较繁琐,你可以参阅官方文档寻找这部分的资料。
hash和history其实都是window的2个子对象,使用location.hash可修改当前url中#后的部分,比如我们在浏览器的控制台中输入以下命令:
location.hash = "/index"
你会发现浏览器的地址栏中url会变更为:
http://localhost:5500/#/index
同理,history模式也提供了一些链接跳转的方法支持。
如,在浏览器的控制台中输入以下命令:
history.pushState({}, "", "/index")
你会发现浏览器的地址栏中url会变更为:
http://localhost:5500/index
如果你想了解更多,请参照之前JavaScript中的widnow对象章节。
当浏览一个网页时,只要地址栏中的url发生改变都会被浏览器记录到一个“栈”中。
如下所示,我们先浏览了index.html、然后又浏览了news.html、最后浏览了backend.html:
当你点击back按钮或者调用router.back()以及history.back()方法后,它会向后回退一格,同时图中左侧的计数器也会发生变化:
同理,当你点击forward按钮或者调用router.forward()以及history.forward()方法后,它又会向前推进一格,回到图1的状态:
如果你通过router.go()或者history.go()方法,并且填入的参数是-2时,那么它会向后回退2格,变成下面这种状态:
而router.replace()的意思是,跳转至新的页面,并且清空整个栈,如下所示,它等同于history.replaceState()方法:
使用Vite生成项目,跟随指引一步一步的进行初始化:
$ npm init @vitejs/app <project-name>
进入到项目根目录下,安装Vue-Router插件,输入以下命令后它将会安装Vue-Router 4.x的最新版本:
$ npm install vue-router@4
在src下新建一个router目录,并在其中新建一个index.js文件,该文件将作为Vue-Router插件的配置文件存在:
$ mkdir ./src/router
$ touch ./src/router/index.js
删除.src/components/HelloWorld.vue:
$ rm -rf ./src/components/HelloWorld.vue
清空.src/App.vue中的代码,并粘贴下面的代码:
<template>
<div>hello world</div>
</template>
<script setup>
</script>
<style>
</style>
接下来你就可以启动这个Vue项目了,默认项目的端口是3000:
$ npm run dev
我们需要先准备3个组件、分别是Index、Book、Hot,代码基本一致:
<template>
<div>
<h1>Hello Index</h1>
</div>
</template>
<script setup>
</script>
<style scoped>
h1 {
font-size: 8rem;
}
</style>
要想使用Vue-Router插件,我们就必须在.src/router/index.js文件中对其进行引入:
// 1. 导入使用hash模式、使用history模式、以及创建全局路由对象的方法
import { createWebHashHistory, createWebHistory, createRouter } from "vue-router";
// 2. 导入组件
import Index from "../components/Index.vue"
import Book from "../components/Book.vue"
import Hot from "../components/Hot.vue"
// 3.配置路由映射表
const routes = [
{ path: "/index", component: Index },
{ path: "/book", component: Book },
{ path: "/hot", component: Hot },
]
// 4.创建全局路由对象,并且使用hash模式初始化这个全局路由对象
const router = createRouter({
routes,
history: createWebHashHistory()
})
// 5.导出全局路由对象
export default router
然后需要到.src/main.js中为当前的Vue应用加载这个插件:
import { createApp } from 'vue'
import App from './App.vue'
import router from "./router/index"
const app = createApp(App);
// 加载插件
app.use(router);
app.mount('#app');
最后修改一下App.vue的代码,我们要在App.vue中使用
<template>
<div>
<header id="header">
<!-- 路由入口,相当于a标签 -->
<router-link :to="{ path: '/index' }">主页</router-link>
<router-link :to="{ path: '/book' }">书籍</router-link>
<router-link :to="{ path: '/hot' }">热门</router-link>
</header>
<main id="main">
<!-- 路由出口,当点击<router-link>后,路由表中的组件会在此处显示 -->
<router-view></router-view>
</main>
</div>
</template>
<script setup>
// 注册组件
import Index from "./components/Index.vue";
import Book from "./components/Book.vue";
import Hot from "./components/Hot.vue";
</script>
<style>
/* 全局样式设置 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
list-style: none;
}
header#header {
height: 50px;
padding: 1rem;
background: #565656;
display: flex;
justify-content: flex-start;
align-items: center;
box-shadow: #aaa 0 5px 5px;
}
header#header a {
text-decoration: none;
margin-right: 2rem;
color: #fff;
}
main#main {
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
height: 80vh;
}
</style>
实际上
<!-- 不推荐 -->
<router-link to="/index">主页</router-link>
<!-- 推荐 -->
<router-link :to="{ path: '/index' }">主页</router-link>
对.src/index.js里routes中每一条rule对象,我们都可以为它们加上一个name属性:
const routes = [
{ path: "/index", name: "index", component: Index },
{ path: "/book", name: "book", component: Book },
{ path: "/hot", name: "hot", component: Hot },
]
这样在为模板中的
<header id="header">
<!-- 路由入口,相当于a标签 -->
<router-link :to="{ name: 'index' }">主页</router-link>
<router-link :to="{ name: 'book' }">书籍</router-link>
<router-link :to="{ name: 'hot' }">热门</router-link>
</header>
对.src/index.js里routes中每一条rule对象,我们都可以为它们加上一个alias属性:
const routes = [
{
path: "/index",
name: "index",
alias: ["/index.htm", "/index.html"],
component: Index
}
]
配置好之后不管你访问下面那个url,它都会跳转至Index组件中:
http://localhost:3000/index
http://localhost:3000/index.htm
http://localhost:3000/index.html
如果想在路由中定义重定向,则只需要配置redirect属性即可:
const routes = [
{
path: "/",
redirect: { name: "index" }
},
{
path: "/index",
name: "index",
alias: ["/index.htm", "/index.html"],
component: Index
},
]
这样当你访问 localhost:3000 时,它会自动跳转到Index中。
对.src/index.js里routes中每一条rule对象,我们都可以为它们加上一个meta属性:
const routes = [
{
path: "/index",
name: "index",
alias: ["/index.htm", "/index.html"],
meta: { title: "主页", verify: false },
component: Index
}
]
在后续开发时,我们能通过一些方式拿到这些内容,因此你可以将meta属性定义成这个route的附加信息:
<script setup>
import { onMounted } from "vue";
import { useRoute } from "vue-router";
const route = useRoute();
onMounted(() => {
console.log(route.meta.verify);
console.log(route.meta.title);
});
</script>
默认的
.router-link-active {
text-shadow: #ddd 2px 5px 5px !important;
}
最终结果:
你也可以为每个
// template
<router-link to="/index" active-class="choice_index">主页</router-link>
// style
.choice_index{
color : red !important;
}
useRouter()是Vue-Router中提供的一个构造方法,调用它可以得到一个全局的Router对象,即整个routes路由映射表。
如果想在模板中使用这个全局路由对象,你可以直接像下面这样操作:
{{$router}}
要想在脚本中使用这个全局路由对象你必须先对其进行导入:
import { useRouter } from "vue-router";
接下来需要进行实例化操作:
const router = useRouter();
全局路由对象中可以调用很多方法、如push()、back()等,如下表所示:
方法
描述
push()
等同于window.history.pushState(),打开一个新的url
replace()
等同于window.history.replaceState(),打开一个新的url,并清空当前活动窗口的历史记录
back()
等同于window.history.back(),执行页面回退操作
forward()
等同于window.history.forward(),执行页面前进操作
go(±n)
等同于window.history.go(),执行页面回退或前进n个操作
useRoute()是Vue-Router中提供的一个构造方法,调用它可以得到一个当前活动的Route对象,即当前所匹配到的rule。
如果想在模板中使用这个活动路由对象,你可以直接像下面这样操作:
{{$route}}
要想在脚本中使用这个活动路由对象你必须先对其进行导入:
import { useRoute } from "vue-router";
接下来需要进行实例化操作:
const route = useRoute();
活动路由对象中可以调用很多属性、如path、name等,如下表所示:
属性
描述
path
获取当前活动路由的path
name
获取当前活动路由的name
params
获取当前活动路由的params
query
获取当前活动路由的query
meta
获取当前活动路由的meta
hash
获取当前活动路由的hash
redirectedFrom
获取当前活动路由的前一个跳转链接
如果你想在