Vue Router 是 Vue.js 的官方插件,用来快速实现单页应用。
单页应用
SPA(Single Page Application)单页面应用程序,简称单页应用。指的是网站的 “所有” 功能都在单个页面中进行呈现。具有代表性的有后台管理系统、移动端、小程序等。
优点:
- 前后端分离开发,提高了开发效率。
- 业务场景切换时,局部更新结构。
- 用户体验好,更加接近本地应用。
缺点:
- 不利于 SEO。
- 初次首屏加载速度较慢。
- 页面复杂度比较高。
前端路由
前端路由,指的是 URL 与内容间的映射关系,有 Hash 和 History 两种实现方式。
Hash 方式
Hash 方式就是通过 hashchange 事件监听 hash 变化,并进行网页内容更新。
<body>
<div>
<a href="#/">首页</a>
<a href="#/category">分类页</a>
<a href="#/user">用户页</a>
</div>
<div id="container">
这是首页功能
</div>
</body>
window.onhashchange = function () {
var hash = location.hash.replace('#', '')
var str = ''
switch (hash) {
case '/':
str = '这是首页功能'
break
case '/category':
str = '这是分类功能'
break
case '/user':
str = '这是用户功能'
break
}
document.getElementById('container').innerHTML = str
}
封装以备用
// 准备对象,用于封装 hash 功能
var router = {
// 路由存储位置:保存了 url 与 内容处理函数 的对应关系
routes: {},
// 定义路由规则的方法
route: function (path, callback) {
this.routes[path] = callback
},
// 初始化路由的方法
init: function () {
var that = this
window.onhashchange = function () {
// 当 hash 改变,我们需要得到当前新的 hash
var hash = location.hash.replace('#', '')
// 根据 hash 触发 routes 中对应的 callback
that.routes[hash] && that.routes[hash]()
}
}
}
var container = document.getElementById('container')
// 定义路由
router.rote('/', function () {
container.innerHTML = '这就是首页功能'
})
router.rote('/category', function () {
container.innerHTML = '这就是分类功能'
})
router.rote('/user', function () {
container.innerHTML = '这就是用户功能'
})
// 初始化路由
router.init()
特点总结:
- Hash 方式兼容性好。
- 地址中具有 #,不太美观。
- 前进后退功能较为繁琐。
History 方式
History 方式采用 HTML5 提供的新功能实现前端路由。在操作时需要通过 history.pushState()
变更 URL并执行对应操作。
<body>
<div>
<a href="/">首页</a>
<a href="/category">分类页</a>
<a href="/user">用户页</a>
</div>
<div id="container">
这是首页功能
</div>
</body>
var router = {
// 存储路由的对象
routes: {},
// 定义路由的方法
route (path, callback) {
this.routes[path] = callback
},
// 用于触发指定的路由操作
go (path) {
// 更改 url
// 参数1:与当前路径相关的状态对象 state(暂时不需要)
// 参数2:标题 title (浏览器不支持)
// 参数3:需要修改的地址路由
history.pushState(null, null, path)
// 触发路由对应的回调函数
this.routes[path] && this.routes[path]()
}
};
// 设置 a 标签的功能
var links = document.querySelectorAll('a')
var container = document.querySelector('#container')
links.forEach(function (ele) {
ele.addEventListener('click', function (event) {
router.go(this.getAttribute('href'))
event.preventDefault()
});
});
// 路由规则
router.route('/', function () {
container.innerHTML = '首页功能';
});
router.route('/category', function () {
container.innerHTML = '分类功能';
});
router.route('/user', function () {
container.innerHTML = '用户功能';
});
前进后退功能,首先需要在更改 url 时保存路由标记。
go: function (path) {
histroy.pushState({ path: path }, null, path)
...
}
通过 popstate 事件监听前进后退按钮操作,并检测 state。
init: function () {
var that = this
window.addEventListener('popstate', function (e) {
var path = e.state ? e.state.path : '/'
that.routes[path] && that.routes[path]()
})
}
调用初始化方法监听前进后退操作并处理。
...
router.init()
...
Vue Router
Vue Router 是 Vue.js 官方的路由管理器,让构建单页面应用变得易如反掌。
基本使用
- 直接下载 / CDN
- npm
- npm install vue-router
Vue Router 提供了用于进行路由设置的组件 <router-link> 与 <router-view>。
<router-link> 默认是一个 a 标签,如果想要改成其他形式可以使用 tag 属性更改。
<router-view> 用来显示路由匹配到的组件。
<div id="app">
<router-link to="/">首页</router-link>
<router-link to="/category">分类</router-link>
<router-link to="/user">用户</router-link>
<router-view></router-view>
</div>
定义路由中需要的组件,并进行路由规则设置。
var Index = {
template: `<div>这是首页的功能</div>`
}
var Category = {
template: `<div>这是分类的功能</div>`
}
var User = {
template: `<div>这是用户的功能</div>`
}
var routes = [
{ path: '/', component: Index },
{ path: '/category', component: Category },
{ path: '/user', component: User }
]
创建 Vue Router 实例,通过 routes 属性配置路由。
var router = new VueRouter({
routes: routes
})
创建 Vue 实例,通过 router 属性注入路由。
var vm = new Vue({
el: '#app',
router: router
})
命名视图
如果导航后,希望同时在同级展示多个视图(组件),这时就需要进行命名视图。
<div id="app">
<router-link to="/">首页</router-link>
<router-link to="/user">用户</router-link>
<router-view name="sidebar"></router-view>
<!-- 未通过 name 命名的,默认名为 default -->
<router-view></router-view>
</div>
路由中通过 components 属性进行设置不同视图的对应组件。
var SideBar = {
template: `<div>这是侧边栏功能</div>`
}
..
{
path: '/',
components: {
sidebar: SideBar,
default: Index
}
}
..
动态路由
当我们需要将某一类 URL 都映射到同一个组件,就需要使用动态路由。
定义路由规则时,将路径中的某个部分使用 :
进行标记,即可设置为动态路由。
var User = {
template: `<div>这是用户的功能</div>`
}
var routes = [
{ path: '/user/:id', component: User }
]
设置为动态路由后,动态部分为任意内容均跳转到同一组件。
<div id="app">
<router-link to="/user/1">用户1</router-link>
<router-link to="/user/2">用户2</router-link>
<router-link to="/user/3">用户3</router-link>
<router-view></router-view>
</div>
:
部分对应的信息称为路径参数,存储在 vm.$route.params 中。
var User = {
template: `
<div>
这是用户 {{ $route.params.id }} 的功能
</div>
`
}
如果要响应路由的参数变化,可以通过 watch 监听 $route。
var User = {
template: `<div>这是用户 {{ $route.params.id }} 的功能</div>`,
watch: {
$route (route) {
console.log(route)
}
}
}
路由参数还可以通过路由的 props 设置数据,并通过组件 props 接收。
var routes = [
{
path: '/user/:id',
component: User
},
{
path: '/category/:id',
component: Category,
props:true
}
]
var User = {
template: `<div>这是用户 {{ $route.params.id }} 的功能</div>`,
}
var Category = {
props: ['id'],
template: `<div>这是 {{ id }} 的功能</div>`
}
包含多个命名视图时,需要将路由的 props 设置为对象。
var SideBar = {
template: `<div>这是侧边栏功能</div>`
}
{
path: '/category/:id',
components: {
defualt: Category,
sidebar: SideBar
}
props: {
default: true,
sidebar: false
}
}
如果希望设置静态数据,可将 props 中的某个组件对应的选项设置为对象,内部属性会绑定给组件的 props。
var SideBar2 = {
props: ['a', 'b'],
template: `
<div>
这是右侧侧边栏功能: {{ a }} {{ b }}
</div>
`
}
{
path: '/category/:id',
components: {
defualt: Category,
sidebar: SideBar,
sidebar2: SideBar2
}
props: {
default: true,
sidebar: false,
sidebar2: { a: '状态1', b:'状态2' }
}
}
嵌套路由
实际场景中,路由通常由多层嵌套的组件组合而成,这时需要使用嵌套路由配置。
使用 children 来进行嵌套路由中的子路由设置。
var routes = [
{
path: '/path',
component: User,
children: [
{
path: 'hobby',
component: UserHobby
},
{
path: 'info',
component: UserInfo,
children: [
{ path: 'age', component: UserInfoAge },
{ path: 'school', component: UserInfoSchool }
]
}
]
}
]
编程式导航
编程式导航,指的是通过方法设置导航。
router.push() 用来导航到一个新 URL。
vm.$router.push('/user')
vm.$router.push({path: '/user'})
vm.$router.push({path: '/user/123'})
<router-link> 的 to 属性使用绑定方式时也可属性对象结构。
<router-link :to="{ path: 'user/10' }" >用户10</router-link>
设置路由时添加 name 属性来命名路由。
var School = {
template: `<div>School 组件:{{ $route.params }}</div>`
}
var routes = [
{
path: 'user/:id/info/school',
name: 'school',
component: School
}
]
在 push() 中通过 name 导航到对应路由,参数通过 params 设置。
vm.$router.push({ name: 'school', prarams: { id: 20, demo: '其他数据' } })
也可以在 <router-link> 中使用。
<router-link :to="{ name='school', params: { id: 1 } }">用户学校</router-link>
重定向
示例如下:
var routes = [
{ path: '/', component: Index },
{ path: '/category/:id', component: Category },
{ path: '/category', redirect: '/' }
]
别名
示例如下
var routes = [
{
path: '/user/:id/info/school/intro/:date',
name: 'school',
component: School,
alias: '/:id/:date'
}
]
<router-link :to="{ name: 'school', params: { id: 1, date: 0101 } }">用户学校</router-link>
<router-link to="/10/0612">用户学校</router-link>
导航守卫
当路由发生改变的时候,可以通过跳转或者取消的方式进行守卫处理。
示例如下:
// beforeEach 在每条路由触发之前进行操作
// to 表示跳转到的路由的相关信息
// from 表示从哪个路由跳转的相关信息
// next 根据 to 和 from 的情况判断是否执行
router.beforeEach(function (to, from, next) {
console.log(to, from)
next()
})
History 模式
History 模式需要通过 Vue Router 实例的 mode 选项来设置,这样 URL 会更加美观,但同样需要后端支持避免问题。
var router = new VueRouter({
mode: 'history',
routes: [
...
]
})