vue-router 源码实现前端路由的两种方式


Posted in Javascript onJuly 02, 2018

在学习 vue-router 的代码之前,先来简单了解一下前端路由。

前端路由主要有两种实现方法:

  • Hash 路由
  • History 路由

先来看看这两种方法的实现原理。

接着我们将用它们来简单实现一个自己的前端路由。

前端路由

Hash 路由

url 的 hash 是以 # 开头,原本是用来作为锚点,从而定位到页面的特定区域。当 hash 改变时,页面不会因此刷新,浏览器也不会向服务器发送请求。

http://www.xxx.com/#/home

同时, hash 改变时,并会触发相应的 hashchange 事件。所以,hash 很适合被用来做前端路由。当 hash 路由发生了跳转,便会触发 hashchange 回调,回调里可以实现页面更新的操作,从而达到跳转页面的效果。

window.addEventListener('hashchange', function () {
 console.log('render');
});

History 路由

HTML5 规范中提供了 history.pushStatehistory.replaceState 来进行路由控制。通过这两个方法,可以实现改变 url 且不向服务器发送请求。同时不会像 hash 有一个 # ,更加的美观。但是 History 路由需要服务器的支持,并且需将所有的路由重定向到根页面。

History 路由的改变不会去触发某个事件,所以我们需要去考虑如何触发路由更新后的回调。

有以下两种方式会改变 url:

  • 调用 history.pushState 或 history.replaceState;
  • 点击浏览器的前进与后退。

第一个方式可以封装一个方法,在调用 pushState(replaceState)后再调用回调。

function push (url) {
 window.history.pushState({}, null, url);
 handleHref();
}

function handleHref () {
 console.log('render');
}

第二个方式,浏览器的前进与后退会触发 popstate 事件。

window.addEventListener('popstate', handleHref);

路由实现

我们通过 <a> 标签来进行切换路由,通过一个 <div> 标签来装载各路由对应的页面内容。

参考 vue-router 的调用,我们会这么地调用一个 Router ,将路由与对应组件作为参数传入:

const router = new Router([
 {
  path: '/',
  component: 'home'
 },
 {
  path: '/book',
  component: 'book'
 },
 {
  path: '/movie',
  component: 'movie'
 }
]);

数组里是各路由对应的要显示的内容,接下来就来开始实现这个 Router

Hash 路由实现

Hash 路由 <a> 标签都需要带上 #

<div>
 <a href="#/" rel="external nofollow" >home</a>
 <a href="#/book" rel="external nofollow" >book</a>
 <a href="#/movie" rel="external nofollow" >movie</a>
  
 <div id="content"></div>
</div>

Router 的代码实现如下:

class Router {
 constructor (options) {
  this.routes = {};
  
  this.init();
  
  // 遍历,绑定视图更新
  options.forEach(item => {
   this.route(item.path, () => {
   	document.getElementById('content').innerHTML = item.component;
   });
  });
 }
 
 // 绑定监听事件
 init () {
  window.addEventListener('load', this.updateView.bind(this), false);
  window.addEventListener('hashchange', this.updateView.bind(this), false);
 }
 
 // 更新试图
 updateView () {
  const currentUrl = window.location.hash.slice(1) || '/';
  this.routes[currentUrl] && this.routes[currentUrl]();
 }
 
 // 将路由与回调函数关联
 route (path, cb) {
  this.routes[path] = cb;
 }
}

实现效果如下:

vue-router 源码实现前端路由的两种方式 

History 路由实现

History 路由需要服务器的支持,可以点击这里 的代码参考。

<div>
 <a href="javascript:void(0);" rel="external nofollow" rel="external nofollow" rel="external nofollow" data-href="/" rel="external nofollow" >home</a>
 <a href="javascript:void(0);" rel="external nofollow" rel="external nofollow" rel="external nofollow" data-href="/book" rel="external nofollow" >book</a>
 <a href="javascript:void(0);" rel="external nofollow" rel="external nofollow" rel="external nofollow" data-href="/movie" rel="external nofollow" >movie</a>
  
 <div id="content"></div>
</div>

Router 的代码实现如下:

class Router {
 constructor (options) {
  this.routes = {};

  this.init();
  this.bindEvent();

  // 遍历,绑定视图更新
  options.forEach(item => {
   this.route(item.path, () => {
    document.getElementById('content').innerHTML = item.component;
   });
  });
 }

 // 绑定点击事件
 bindEvent () {
  const _this = this;
  const links = document.getElementsByTagName('a');

  [].forEach.call(links, link => {
   link.addEventListener('click', function () {
    const url = this.getAttribute('data-href');
    _this.push(url);
   });
  });
 }

 // 绑定监听事件
 init () {
  window.addEventListener('load', this.updateView.bind(this), false);
  window.addEventListener('popstate', this.updateView.bind(this), false);
 }

 push (url) {
  window.history.pushState({}, null, url);
  this.updateView();
 }

 // 更新试图
 updateView () {
  const currentUrl = window.location.pathname || '/';
  this.routes[currentUrl] && this.routes[currentUrl]();
 }

 // 将路由与回调函数关联
 route (path, cb) {
  this.routes[path] = cb;
 }
}

实现效果如下:

vue-router 源码实现前端路由的两种方式

最后

前端路由实现方式有两种,分别是:

  1. Hash 路由
  2. History 路由

原理都是修改 url 的同时不刷新页面,不向服务器发送请求,通过监听特殊的事件来更新页面。

以上实现全部源码参考这里。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js window.onload 加载多个函数的方法
Nov 02 Javascript
JavaScript window.setTimeout() 的详细用法
Nov 04 Javascript
js setTimeout()函数介绍及应用以倒计时为例
Dec 12 Javascript
jquery预览图片实现鼠标放上去显示实际大小
Jan 16 Javascript
JS解析XML文件和XML字符串详解
Apr 17 Javascript
元素绑定click点击事件方法
Jun 08 Javascript
JavaScript实现点击单选按钮改变输入框中文本域内容的方法
Aug 12 Javascript
js实现点击文本框显示日期选择器特效代码分享
May 21 Javascript
纯js实现画一棵树的示例
Sep 05 Javascript
JS中实现隐藏部分姓名或者电话号码的代码
Jul 17 Javascript
JS散列表碰撞处理、开链法、HashTable散列示例
Feb 08 Javascript
使用JS实现动态时钟
Mar 12 Javascript
React Native基础入门之调试React Native应用的一小步
Jul 02 #Javascript
vue-router 源码之实现一个简单的 vue-router
Jul 02 #Javascript
JavaScript设计模式之单例模式简单实例教程
Jul 02 #Javascript
JavaScript设计模式之建造者模式实例教程
Jul 02 #Javascript
JS实现的JSON序列化操作简单示例
Jul 02 #Javascript
JS内部事件机制之单线程原理
Jul 02 #Javascript
JS将网址url转化为JSON格式的方法
Jul 02 #Javascript
You might like
通过ICQ网关发送手机短信的PHP源程序
2006/10/09 PHP
Thinkphp结合ajaxFileUpload实现异步图片传输示例
2017/03/13 PHP
js为鼠标添加右击事件防止默认的右击菜单弹出
2013/07/29 Javascript
jQuery实现字符串按指定长度加入特定内容的方法
2015/03/11 Javascript
JavaScript中的toUTCString()方法使用详解
2015/06/12 Javascript
javascript制作照片墙及制作过程中出现的问题
2016/04/04 Javascript
jquery过滤特殊字符',防sql注入的实现方法
2016/08/17 Javascript
javascript this详细介绍
2016/09/19 Javascript
Flask中获取小程序Request数据的两种方法
2017/05/12 Javascript
Bootstrap按钮组实例详解
2017/07/03 Javascript
详解基于Vue+Koa的pm2配置
2017/10/24 Javascript
基于vue中keep-alive缓存问题的解决方法
2018/09/21 Javascript
分享5个小技巧让你写出更好的 JavaScript 条件语句
2018/10/20 Javascript
Vue 递归多级菜单的实例代码
2019/05/05 Javascript
[02:18]《我与DAC》之工作人员:为了热爱DOTA2的玩家们
2018/03/28 DOTA
[01:03:37]Secret vs VGJ.S Supermajor小组赛C组 BO3 第二场 6.3
2018/06/04 DOTA
[41:05]Serenity vs Pain 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
Python中用post、get方式提交数据的方法示例
2017/09/22 Python
python如何创建TCP服务端和客户端
2018/08/26 Python
python对验证码降噪的实现示例代码
2019/11/12 Python
基于python和flask实现http接口过程解析
2020/06/15 Python
Html5导航栏吸顶方案原理与对比实现
2020/06/10 HTML / CSS
天猫国际进口超市直营:官方直采,一站购齐
2017/12/11 全球购物
伦敦剧院门票:From The Box Office
2018/06/30 全球购物
Rentalcars.com中国:世界上最大的在线汽车租赁服务
2019/08/22 全球购物
Jack Rogers官网:美国经典的女性鞋靴品牌
2019/09/04 全球购物
新闻专业个人自我评价
2013/09/21 职场文书
秋季红领巾广播稿
2014/01/27 职场文书
五年级语文教学反思
2014/01/30 职场文书
个人担保书格式范文
2014/05/12 职场文书
廉洁校园实施方案
2014/05/25 职场文书
民族学专业职业生涯规划范文:积跬步以至千里
2014/09/11 职场文书
2014年仓库管理员工作总结
2014/11/18 职场文书
工人先进事迹材料
2014/12/26 职场文书
教师个人发展总结
2015/02/11 职场文书
专项资金申请报告
2015/05/15 职场文书