1. 介绍
Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。包含的功能有:
- 嵌套的路由/视图表
- 模块化的、基于组件的路由配置
- 路由参数、查询、通配符
- 基于 Vue.js 过渡系统的视图过渡效果
- 细粒度的导航控制
- 带有自动激活的 CSS class 的链接
- HTML5 历史模式或 hash 模式,在 IE9 中自动降级
- 自定义的滚动条行为
vue-router路由模式:
- hash: 使用 URL hash 值来作路由。支持所有浏览器,包括不支持 HTML5 History的浏览器。
- history: 依赖 HTML5 History API 和服务器配置。
- abstract: 支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式。
2. Vue Router 和 Vue 项目集成
安装:
如果在vue-cli创建项目时没有勾选上vue-router选项,此时就需要手动的来安装它:
npm i -S vue-router@3
注意在 Vue2 中要安装3的版本。
使用步骤:
-
在项目中的
src
目录下创建router
文件夹,并在router
文件夹下创建index.js
文件: -
编写新创建的
index.js
文件,并且在入口文件main.js
中注入路由这一步可以分为以下几小步:
- 引入相关库文件
- 以插件的方式添加,将VueRouter引入到Vue类中
- 定义渲染的组件
- 实例化路由对象及配置路由表
- 导出路由配置
- 在入口文件注入路由
- 在父组件
App.vue
文件中定义路由匹配成功后渲染的挂载点
index.js:
// 1.引入相关库文件 import Vue from 'vue' import VueRouter from 'vue-router' // 3.定义渲染的组件 === 视图组件 容器组件 import Home from '@/views/Home.vue' // 2.以插件的方式添加,将VueRouter引入到Vue类中 Vue.use(VueRouter) // 配置路由表 const routes = [ { // 匹配的路由 path: '/home', // 匹配成功后要渲染的组件,这些组件会放在 src/views 目录下 component: Home } ] // 4.实例化路由对象及配置路由表 const router = new VueRouter({ // 路由模式 mode: 'history', // 路由规则表 routes }) // 5.导出 export default router
main.js:
import Vue from 'vue' import App from './App.vue' import router from './router' new Vue({ // 要通过 router 配置参数注入路由,从而让整个应用都有路由功能 // router:router // 简写 router, render: h => h(App) }).$mount('#app')
App.vue:
<template> <div> <!-- 定义路由匹配成功后渲染的挂载点 --> <router-view /> </div> </template> <script> export default { components: {}, data() { return {} }, methods: {} } </script> <style lang="scss" scoped></style>
3. 声明式导航
描述:
它就是先在页面中定义好跳转的路由规则,vueRouter中通过 router-link组件来完成。
语法:
<router-link to="path"></router-link>
# router-link声明式导航,它编译成html的标签为a,在vue-router3版本中可以自定义设置
# router-link 标签中有三个参数
+ to: string|{path:string,query:{},params:{}} 表示要跳转到的路由规则,这个参数是必填选项
+ tag: 默认编译生成的为a标签,可以自定义
+ activeClass 指定激活样式名称,默认名称为:router-link-active
使用:
首先在配置路由表,我们配置 home 页面和 about 页面:
index.js:
// 1.引入相关库文件
import Vue from 'vue'
import VueRouter from 'vue-router'
// 3.定义渲染的组件 === 视图组件 容器组件
import Home from '@/views/Home.vue'
import About from '@/views/About.vue'
// 2.以插件的方式添加,将VueRouter引入到Vue类中
Vue.use(VueRouter)
// 配置路由表
const routes = [
{
// 匹配的路由
path: '/home',
// 匹配成功后要渲染的组件,这些组件会放在 src/views 目录下
component: Home
},
{
path: '/about',
component: About
}
]
// 4.实例化路由对象及配置路由表
const router = new VueRouter({
// 路由模式
mode: 'history',
// 路由规则表
routes
})
// 5.导出
export default router
然后在父组件中定义路由跳转规则:
App.vue:
<template>
<div>
<ul>
<li>
<router-link to="/home" tag="h3" activeClass="active">home</router-link>
</li>
<li>
<router-link to="/about" activeClass="active">about</router-link>
</li>
</ul>
<hr>
<!-- 定义路由匹配成功后渲染的挂载点 -->
<router-view />
</div>
</template>
<script>
export default {
components: {},
data() {
return {}
},
methods: {}
}
</script>
<style lang="scss" scoped>
.active {
color: red;
}
</style>
上面的案例中,我们在 router-link 标签中给入 to 参数的数据为字符串类型,我们还可以给入对象类型:
父组件(App.vue):
<template>
<div>
<ul>
<li>
<!-- 给入对象传参 -->
<router-link :to="{ path: '/home', query: { id: 100 } }" activeClass="active">home</router-link>
</li>
<li>
<!-- 给入字符串传参 -->
<router-link to="/about?id=100" activeClass="active">about</router-link>
</li>
</ul>
<hr>
<!-- 定义路由匹配成功后渲染的挂载点 -->
<router-view />
</div>
</template>
<script>
export default {
components: {},
data() {
return {}
},
methods: {}
}
</script>
<style lang="scss" scoped>
.active {
color: red;
}
</style>
注意:
- 给 to 参数传入对象类型的数据时,必须在 to 前面加冒号
:
- 给 to 参数传入对象类型的数据中 query 类型是给地址栏传参用的,当然在给出字符串类型数据时也可以直接写入地址栏数据
4. 编程式导航
描述:
编程式导航就是通过js来实现路由跳转。
语法:
# 能回退 参数:String|Object
+ this.$router.push("/login");
+ this.$router.push({ path:"/login",query:{username:"jack"} });
# 不能回退 参数:String|Object
+ this.$router.replace("/login");
+ this.$router.replace({ name:'user' , params: {id:123} });
# n为数字,正数为前进,负数为回退
+ this.$router.go( n );//
使用:
在上文声明式导航的基础上,用编程式导航如果要实现在 about 页面中点击按钮,3秒钟之后跳转到 home 页面,我们只需要修改 about 页面。
About.vue:
<template>
<div>
<h3>关于我们</h3>
<button @click="goHome">点击到home</button>
</div>
</template>
<script>
export default {
methods: {
goHome() {
// 要求3秒钟之后跳转到 home 页面
setTimeout(() => {
// 通过this.$router对象中的push/replace方法完成路由切换
// push/replace string|object
// push/push string|object
// this.$router.push('/home')
this.$router.push({
path: '/home',
query: { id: 200 }
})
}, 3000)
}
}
}
</script>
<style lang="scss" scoped></style>
案例——登录成功实现页面跳转:
配置路由(index.js):
// 1.引入相关库文件
import Vue from 'vue'
import VueRouter from 'vue-router'
// 3.定义渲染的组件 === 视图组件 容器组件
import Home from '@/views/Home.vue'
import About from '@/views/About.vue'
import Login from '@/views/Login.vue'
// 2.以插件的方式添加,将VueRouter引入到Vue类中
Vue.use(VueRouter)
// 配置路由表
const routes = [
{
// 匹配的路由
path: '/home',
// 匹配成功后要渲染的组件,这些组件会放在 src/views 目录下
component: Home
},
{
path: '/login',
component: Login
}
]
// 4.实例化路由对象及配置路由表
const router = new VueRouter({
// 路由模式
mode: 'history',
// 路由规则表
routes
})
// 5.导出
export default router
父组件(App.vue):
<template>
<div>
<router-link to="/login">login</router-link>
<hr />
<!-- 定义路由匹配成功后渲染的挂载点 -->
<router-view />
</div>
</template>
<script>
export default {
components: {},
data() {
return {};
},
methods: {},
};
</script>
<style lang="scss" scoped></style>
登录页面(Login.vue):
<template>
<div>
<h3>用户登录</h3>
<hr />
<div>
<input v-model="username" />
</div>
<div>
<input v-model="password" />
</div>
<div>
<button @click="login">进入系统</button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
username: 'admin',
password: 'admin'
}
},
methods: {
login() {
if (this.username === 'admin') {
this.$router.replace('/home')
} else {
alert('登录失败')
}
}
}
}
</script>
<style lang="scss" scoped></style>
5. 重定向和404
描述:
重定向:用户在访问地址A的时候,强制用户跳转到地址C ,从而展示特定的组件页面。
404:用户访问的页面不存在时,显示的页面
实现方法:
配置路由表(index.js):
// 1.引入相关库文件
import Vue from 'vue'
import VueRouter from 'vue-router'
// 3.定义渲染的组件 === 视图组件 容器组件
import Home from '@/views/Home.vue'
import About from '@/views/About.vue'
import Login from '@/views/Login.vue'
import Notfound from '@/views/Notfound.vue'
// 2.以插件的方式添加,将VueRouter引入到Vue类中
Vue.use(VueRouter)
// 配置路由表
const routes = [
{
// 匹配的路由
path: '/home',
// 匹配成功后要渲染的组件,这些组件会放在 src/views 目录下
component: Home
},
{
path: '/about',
component: About
},
{
path: '/login',
component: Login
},
// 路径为根时,重定向到 home 页面
{
path: '/',
// 重定向
redirect: '/home'
},
// 以上的规则都没有匹配成功,则返回404
{
path: '*',
component: Notfound
}
]
// 4.实例化路由对象及配置路由表
const router = new VueRouter({
// 路由模式
mode: 'history',
// 路由规则表
routes
})
// 5.导出
export default router
父组件(App.vue):
<template>
<div>
<ul>
<li>
<router-link to="/home">home</router-link>
</li>
<li>
<router-link to="/about">about</router-link>
</li>
<li>
<router-link to="/login">login</router-link>
</li>
</ul>
<hr />
<!-- 定义路由匹配成功后渲染的挂载点 -->
<router-view />
</div>
</template>
<script>
export default {
components: {},
data() {
return {};
},
methods: {},
};
</script>
<style lang="scss" scoped>
.active {
color: red;
}
</style>
404页面(Notfound.vue):
注意:这个页面我们想要实现展示本页面之后 3 秒,路由重定向到 home 页面
<template>
<div>404</div>
</template>
<script>
export default {
// 在挂载完毕的生命周期函数中执行 3 秒钟后重定向到 home 页面
mounted() {
// setTimeout(() => {
// // 这种写法会让浏览器直接刷新,会结束上一个页面的所有任务,不用考虑销毁,工作中常用
// location.href = "/home";
// }, 3000);
let n = 1;
this.timer = setInterval(() => {
if (n++ >= 3) {
this.$router.push("/home").catch(() => {});
}
console.log(n);
}, 1000);
},
beforeDestroy() {
// 如果计时器存在就清除计时器,防止浏览器卡顿
this.timer && clearInterval(this.timer);
},
};
</script>
<style lang="scss" scoped></style>
注意:
注意编程式导航跳转到与当前地址一致的URL时会报错,但是这个报错不影响功能。
Vue Router 版本是3,这是版本 bug,可以修复,也可以不用管。
6. 嵌套路由
描述:
嵌套路由最关键在于理解子级路由的概念:
比如我们有一个/users的路由,那么/users下面还可以添加子级路由,如:
/users/index、/users/add等等,这样的路由情形称之为嵌套路由。
语法:
routes: [
{
path: "/user",
component: User,
//通过 children 属性为 /user 添加子路由规则
children:[
{ path: "/user/index", component: Index },
{ path: "/user/add", component: Add },
]
}
]
# 需要在 User组件中定义一个router-view 用于嵌套路由的渲染显示
<router-view></router-view>
案例:
-
需求:
登陆成功后会在 localStorage 中写入 token 值,并且跳转到后台管理页(admin),将后台汇总页和用户页作为子路由嵌套在后台管理页里。如果登录失败,后台管理页检测不到 localStorage 中的 token 值,会重新返回到登录页面,即登录失败,不会显示后台管理页。
-
实现
配置路由:
// 1.引入相关库文件 import Vue from 'vue' import VueRouter from 'vue-router' // 3.定义渲染的组件 === 视图组件 容器组件 import Login from '@/views/Login.vue' import Admin from '@/views/Admin' import Dashboard from '@/views/Dashboard' import User from '@/views/User' // 2.以插件的方式添加,将VueRouter引入到Vue类中 Vue.use(VueRouter) // 配置路由表 const routes = [ { path: '/login', component: Login }, // 嵌套路由 { path: '/admin', component: Admin, // 重定向 redirect: '/admin/dashboard', // 嵌套路由 children: [ { // 这里访问的是这个路径:/admin/dashborad path: 'dashboard', component: Dashboard }, { path: 'user', component: User } ] } ] // 4.实例化路由对象及配置路由表 const router = new VueRouter({ // 路由模式 mode: 'history', // 路由规则表 routes }) // 5.导出 export default router
父组件(App.vue):
<template> <div> <!-- 定义路由匹配成功后渲染的挂载点 --> <router-view /> </div> </template> <script> export default { components: {}, data() { return {}; }, methods: {}, }; </script> <style lang="scss" scoped></style>
登录页(Login.vue):
<template> <div> <h3>用户登录</h3> <hr /> <div> <input v-model="username" /> </div> <div> <input v-model="password" /> </div> <div> <button @click="login">进入系统</button> </div> </div> </template> <script> export default { data() { return { username: 'admin', password: 'admin' } }, methods: { login() { if (this.username === 'admin') { localStorage.setItem('token','fewfewlfewlkfewlkfelfew') // this.$router.replace('/admin/dashboard') this.$router.replace('/admin') // this.$router.replace('/home') } else { alert('登录失败') } } } } </script> <style lang="scss" scoped></style>
后台管理页(admin.vue):
<template> <div> <h3>后台管理</h3> <hr /> <menus /> <!-- 嵌套路由,一定要在父路由中添加对应的 挂载点 --> <router-view /> </div> </template> <script> import menu from './ui/menu.vue' export default { components: { menus: menu }, // 在嵌套路由的父级中书写业务代码,可以实现登录跳转 // 如果登录不成功就无法获取token值,此时重定向到登录页面 created() { if (!localStorage.getItem('token')) { this.$router.replace('/login') } } } </script> <style lang="scss" scoped></style>
7. 动态路由匹配
描述:
所谓动态路由就是路由规则中有部分规则是动态变化的,不是固定的值,需要去匹配取出数据(即路由参数)。
比如我们有这样一个场景,在页面中有新闻 1 、新闻 2 、新闻 3 三个选项,点击不同的选项会显示不同的新闻详情页,那么我们要如何实现这个功能呢?
我们可以通过?
在地址栏传入 id 值,通过参数控制跳转。但是这种方式不够安全,有可能会暴露后台数据。而且当地址栏中出现?
时,浏览器会判定当前页面为动态网站,动态网站在 SEO 搜索引擎中权重比静态网站要低,不利于 SEO 优化。
所以,当我们需要一个唯一标识来控制显示哪个页面时,就需要用到动态路由匹配。
动态路由匹配安全性更高,且会被浏览器判定为静态页,在搜索引擎中排名较高。
语法:
// 传递参数id
var router = new VueRouter({
// routes是路由规则数组
routes: [
{ path: '/user/:id', component: User },
]
})
// 组件中获取id值
const User = {
template: '<div>User ID is {{$route.params.id}}</div>'
}
使用:
路由配置(index.js):
// 1.引入相关库文件
import Vue from 'vue'
import VueRouter from 'vue-router'
// 3.定义渲染的组件 === 视图组件 容器组件
import News from '@/views/News'
import Detail from '@/views/Detail'
// 2.以插件的方式添加,将VueRouter引入到Vue类中
Vue.use(VueRouter)
// 配置路由表
const routes = [
{
path: '/news',
component: News
},
// 动态路由参数,一定要先定义,后使用
{
// :名称 定义动态路由参数的方式,可以定义N个 /:a/:b/:c
// path: '/detail/:nid',
// 可选路由参数,即没有参数也可以访问到详情页面
path: '/detail/:nid?',
component: Detail
}
]
// 4.实例化路由对象及配置路由表
const router = new VueRouter({
// 路由模式
mode: 'history',
// 路由规则表
routes
})
// 5.导出
export default router
新闻页面(index.vue):
<template>
<div>
<li>
<!-- 这里也可以传入 query 数据 -->
<router-link to="/detail/1?name=abc">新闻1</router-link>
</li>
<li>
<router-link to="/detail/2">新闻2</router-link>
</li>
<li>
<router-link to="/detail/3">新闻3</router-link>
</li>
</div>
</template>
<script>
export default {}
</script>
<style lang="scss" scoped></style>
新闻详情页(index.vue):
<template>
<div>
<h3>详情页面 --- {{ $route.params.nid || 0 }} == {{ nid }}</h3>
</div>
</template>
<script>
export default {
computed: {
nid() {
// 返回动态路由参数
return this.$route.params.nid || 0
}
},
mounted() {
// 获取动态路由传过来的 query 数据
// 注意:这里获取的数据是个对象,对象的属性值是字符串,如果要参与数值运算需要先转化为数值
console.log(this.$route.query)
},
}
</script>
<style lang="scss" scoped></style>
注意:
如果不使用动态路由参数,而使用 query 的方式(即在地址栏中传入
?
)向地址栏中传入数据:优点:不需要提前定义,只要传入字符串即可,操作方便。
缺点:不利于 SEO 优化;地址栏不优雅;暴露了敏感字段,安全性低。
如果使用动态路由参数,使用 params 的方式匹配动态路由:
优点:地址栏很优雅,没有问号;搜索引擎权重高;隐藏了字段名,安全性更高。
缺点:必须要先定义后使用,如果是对于很多项不确定的参数使用这种方式的话,定义起来会变得很麻烦。