前端路由与Vue Router
Vue Router 是Vue.js的官方插件,用来快速实现单页应用
单页应用
- SPA(Single Page Application)单页面应用程序,简称单页应用
- 指的是网站的“所有”功能都在单个页面中进行呈现
最有代表性的有:后台管理系统,移动端,小程序等等 - 优点:
- 前后端分离开发,提高了开发效率
- 业务场景切换时,局部更新结构
- 用户体验度更好,更加接近本地应用
- 缺点
- 不利于SEO(搜索引擎)
- 初次首屏加载速度较慢
- 页面复杂度比较高
前端路由
前端路由,指的是URL与内容之间的映射关系
必备的条件
URL,内容,映射关系
Hash方式
通过 hashchange 事件监听 hash 变化,并进行网页内容更新
基本实现步骤:
<body>
<div>
<a href="#/">首页</a>
<a href="#/category">分类页</a>
<a href="#/user">用户页</a>
</div>
<div id="container">
这是首页功能
</div>
<script>
var container = document.getElementById('container');
window.onhashchange = function () {
// 获取 url 中的 hash,清除#号
var hash = location.hash.replace('#', '');
// 根据不同 hash 值,更改网页内容(功能)
var str = '';
switch (hash) {
case '/':
str = '这是首页的功能';
break;
case '/category':
str = '这是分类的功能';
break;
case '/user':
str = '这是用户的功能';
break;
}
container.innerHTML = str;
};
</script>
</body>
封装以备复用:
<body>
<div>
<a href="#/">首页</a>
<a href="#/category">分类页</a>
<a href="#/user">用户页</a>
</div>
<div id="container">
这是首页功能
</div>
<script>
// 准备对象,用于封装 hash 功能。
var router = {
// 路由存储位置: 保存了 url 与 内容处理函数的对应关系。
routes: {},
// 定义路由规则的方法
route: function (path, callback) {
// path是字符串,要通过以键的方式访问就要用中括号
this.routes[path] = callback;
},
// 初始化路由的方法
init: function () {
// this指向的window,所以要通过that保存this查询外部的数据
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.route('/', function () {
container.innerHTML = '这是首页功能';
});
router.route('/category', function () {
container.innerHTML = '这是分类功能';
});
router.route('/user', function () {
container.innerHTML = '这是用户功能';
});
// 初始化路由
router.init();
</script>
</body>
Hash方式的特点总结
- Hash方式兼容性好
- 地址中有#,不太美观
- 前进后退功能较为繁琐
History 方式
History 方式采用 HTML5 提供的新功能实现前端路由
- 在操作时需要通过 history.pushState() 变更 URL并执行对应操作
前进后退功能
-
前进后退功能,首先需要在更改 url 时保存路由标记
-
通过 popstate 事件监听前进后退按钮操作,并检测 state
-
调用初始化方法监听前进后退操作并处理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<a href="/">首页</a>
<a href="/category">分类</a>
<a href="/user">用户</a>
</div>
<div id="container">
这是首页功能
</div>
<script>
var router = {
// 存储路由的对象
routes: {},
// 定义路由的方法
route (path, callback) {
this.routes[path] = callback;
},
// 用于触发指定的路由操作
go (path) {
// 更改 url
history.pushState({ path: path }, null, path);
// 触发路由对应的回调函数
this.routes[path] && this.routes[path]();
},
// 设置初始化方法,用来检测前进后退按钮的功能
init () {
var that = this;
window.addEventListener('popstate', function (e) {
var path = e.state ? e.state.path : '/';
that.routes[path] && that.routes[path]();
});
}
};
router.init();
// 设置 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 = '用户功能';
});
</script>
</body>
</html>
特点:
书写简便,格式美观,可存储量更大,兼容性差,刷新时需要后端支持
Vue Router
Vue.js官方的路由管理器,让构建单页面应用变得易如反掌
基本使用
- 直接下载/CDN
- 最新版本:
- 指定版本:
- npm
npm install vue-router
-
Vue Router 提供了用于进行路由设置的组件 <router-link> 与 <router-view>
-
定义路由中需要的组件,并进行路由规则设置
-
创建 Vue Router 实例,通过 routes 属性配置路由
-
创建 Vue 实例,通过 router 属性注入路由
综合所述,案例:
<body>
<div id="app">
<!-- 设置用于进行路由操作的组件 -->
<router-link to="/">首页</router-link>
<router-link to="/user">用户</router-link>
<router-link to="/category">分类</router-link>
<router-view></router-view>
</div>
<script src="lib/vue.js"></script>
<script src="lib/vue-router.js"></script>
<script>
var Index = {
template: `<div>首页功能</div>`
};
var User = {
template: `<div>用户功能</div>`
};
var Category = {
template: `<div>分类功能</div>`
};
// 定义路由规则
var routes = [
{ path: '/', component: Index },
{ path: '/user', component: User },
{ path: '/category', component: Category }
];
// 创建 Vue Router 实例
var router = new VueRouter({
// ES6语法
routes
});
// 创建 Vue 实例,注入 router
var vm = new Vue({
el: '#app',
router : router
});
console.log(vm);
</script>
</body>
命名视图
-
如果导航后,希望同时在同级展示多个视图(组件),这时就需要进行命名视图
-
路由中通过 components 属性进行设置不同视图的对应组件
命名视图总结案例:
<body>
<div id="app">
<router-link to="/">首页</router-link>
<router-link to="/user">用户</router-link>
<router-view name="sidebar"></router-view>
<!-- 没有设置 name 的 router-view 默认 name 为 default-->
<router-view></router-view>
</div>
<script src="lib/vue.js"></script>
<script src="lib/vue-router.js"></script>
<script>
var SideBar1 = {
template: `<div>侧边栏1功能</div>`
};
var SideBar2 = {
template: `<div>侧边栏2功能</div>`
};
var Index = {
template: `<div>首页功能</div>`
};
var User = {
template: `<div>用户功能</div>`
};
// 定义路由规则
var routes = [
{
path: '/',
components: {
// router-view 的 name : 组件配置对象
default: Index,
sidebar: SideBar1
}
},
{
path: '/user',
components: {
default: User,
sidebar: SideBar2
}
}
];
// 创建 Vue Router 实例
var router = new VueRouter({
routes
});
// 创建 Vue 实例
new Vue({
el: '#app',
router
});
</script>
</body>
动态路由
当我们需要将某一类 URL 都映射到同一个组 件,就需要使用动态路由
- 定义路由规则时,将路径中的某个部分使用
:
进行标记,即可设置为动态路由
比如说图书商品详细页,每本书的id不一样 -
设置为动态路由后,动态部分为任意内容均跳转到同一组件
-
: 部分对应的信息称为路径参数,存储在 vm.$route.params 中
侦听路由参数
-
如果要响应路由的参数变化,可以通过 watch 监听 $route
路由传参处理
- 这里通过路由的 props 设置数据,并通过组件 props 接收
为什么要进行这个路由参数处理的做法?
因为如果使用$route.params.id来访问,会导致当前组件和路由高度耦合,如果将组件放在其他地方,比如通过父组件传递,不通过路由,那么就不好修改,要解耦,当然如果这个组件只是要在当前路由中使用的话这一步是可以不用考虑的
路由传参处理的其他方式
-
包含多个命名视图时,需要将路由的 props 设置为对象
-
如果希望设置静态数据,可将 props 中的某个组件对应的选项设置为对象,内部属性会绑定给组件的 props
嵌套路由
实际场景中,路由通常由多层嵌套的组件组合而成,这时需要使用嵌套路由配置
-
使用 children 来进行嵌套路由中的子路由设置
案例:
<body>
<div id="app">
<router-link to="/user">用户功能</router-link>
<router-view></router-view>
</div>
<script src="./lib/vue.js"></script>
<script src="./lib/vue-router.js"></script>
<script>
var User = {
template: `
<div>
<h3>这是 User 组件的功能</h3>
<router-link to="/user/hobby">爱好功能</router-link>
<router-link to="/user/info">用户信息</router-link>
<router-view></router-view>
</div>
`
};
var UserHobby = {
template: `<div> UserHobby 组件</div>`
};
var UserInfo = {
template: `
<div>
UserInfo 组件
<router-link to="/user/info/school">学校信息</router-link>
<router-view></router-view>
</div>`
};
var UserInfoSchool = {
template: `<div> UserInfoSchool 组件</div>`
};
var routes = [
{
path: '/user',
component: User,
children: [
{
path: 'hobby',
component: UserHobby
},
{
path: 'info',
component: UserInfo,
children: [
{
path: 'school',
component: UserInfoSchool
},
]
}
]
}
];
var router = new VueRouter({ routes });
var vm = new Vue({
el: '#app',
router
});
</script>
</body>
编程式导航
编程式导航,指的是通过方法设置导航
-
router.push() 用来导航到一个新 URL
-
<router-link> 的 to 属性使用绑定方式时也可属性对象结构
命名路由
设置路由时添加 name 属性
在 push() 中通过 name 导航到对应路由,参数通过 params 设置
也可以在 <router-link> 中使用
重定向
示例如下:
别名
美化路由的其他方式,路径更简单
alias就是别名,访问一个id和日期组成的结构就可以了
导航守卫
路由发生改变的时候,通过跳转或者取消的方式进行守卫处理,比如有些网站需要用户登录才能看到的功能,没有登录时就要拦截住
每条路由触发之前都可以执行的守卫功能
to 表示要到达的路由
from 从哪个路由来的
next 表示下一个操作
判断to,from,然后判断是否可以调用next
<body>
<div id="app">
<router-link to="/">首页</router-link>
<router-link to="/user">用户</router-link>
<router-link to="/category">分类</router-link>
<router-view></router-view>
</div>
<script src="lib/vue.js"></script>
<script src="lib/vue-router.js"></script>
<script>
var Index = {
template: `<div>这是首页功能</div>`
};
var User = {
template: `<div>这是用户功能</div>`
};
var Category = {
template: `<div>这是分类功能</div>`
};
var router = new VueRouter({
routes: [
{ path: '/', component: Index },
{ path: '/user', component: User },
{ path: '/category', component: Category },
]
});
// 设置导航守卫
router.beforeEach(function (to, from, next) {
// console.log(to, from);
// next();
// next(false);
if (to.path === '/user') {
// 当路由为user,跳转到category上
next('/category');
} else {
// 路由为其他的,都可以顺利跳转
next();
}
});
var vm = new Vue({
el: '#app',
router
})
</script>
</body>
History模式
Vue-Router默认是Hash模式,因为兼容性更好,当然,也提供了History模式
-
需要通过 Vue Router 实例的 mode 选项来设置,这样 URL 会更加美观,但同样需要后端支持避免问题
history的问题就在于刷新之后会出现链接跳转问题,需要后端支持解决