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 相关文章推荐
Javascript Jquery 遍历Json的实现代码
Mar 31 Javascript
基于jquery的图片懒加载js
Jun 30 Javascript
jquery 如何动态添加、删除class样式方法介绍
Nov 07 Javascript
js实现可折叠展开的手风琴菜单效果
Sep 07 Javascript
微信小程序自定义toast实现方法详解【附demo源码下载】
Nov 28 Javascript
分析JS中this引发的bug
Dec 12 Javascript
vue组件传递对象中实现单向绑定的示例
Feb 28 Javascript
JavaScript生成指定范围的时间列表
Mar 19 Javascript
JavaScript ES6中的简写语法总结与使用技巧
Dec 30 Javascript
vue实现微信二次分享以及自定义分享的示例
Mar 20 Javascript
vue 调用 RESTful风格接口操作
Aug 11 Javascript
vue项目里面引用svg文件并给svg里面的元素赋值
Aug 17 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
mysql_fetch_row,mysql_fetch_array,mysql_fetch_assoc的区别
2009/04/24 PHP
30个php操作redis常用方法代码例子
2014/07/05 PHP
ThinkPHP类似AOP思想的参数验证的实现方法
2019/12/18 PHP
javascript 函数使用说明
2010/04/07 Javascript
javascript 四则运算精度修正函数代码
2010/05/31 Javascript
深入理解javascript学习笔记(一) 编写高质量代码
2012/08/09 Javascript
jQuery 关于伪类选择符的使用说明
2013/04/24 Javascript
用模版生成HTML的的框架jquery.tmpl使用详解
2015/01/07 Javascript
jQuery UI结合Ajax创建可定制的Web界面
2016/06/22 Javascript
巧用jQuery选择器提高写表单效率的方法
2016/08/19 Javascript
JSONP基础知识详解
2017/03/19 Javascript
JavaScript实现隐藏省略文字效果的方法
2017/04/27 Javascript
vue项目中导入swiper插件的方法
2018/01/30 Javascript
vue-cli项目修改文件热重载失效的解决方法
2018/09/19 Javascript
vue中js判断长时间不操作界面自动退出登录(推荐)
2020/01/22 Javascript
vue实现淘宝购物车功能
2020/04/20 Javascript
Python使用代理抓取网站图片(多线程)
2014/03/14 Python
Python自动扫雷实现方法
2015/07/25 Python
在java中如何定义一个抽象属性示例详解
2017/08/18 Python
ubuntu环境下python虚拟环境的安装过程
2018/01/07 Python
django2.0扩展用户字段示例
2019/02/13 Python
python路径的写法及目录的获取方式
2019/12/26 Python
Python统计学一数据的概括性度量详解
2020/03/03 Python
matplotlib之pyplot模块之标题(title()和suptitle())
2021/02/22 Python
HTML5时代CSS设置漂亮字体取代图片
2014/09/04 HTML / CSS
CSS3 毛玻璃效果
2019/08/14 HTML / CSS
毕业生求职信的经典写法
2014/01/31 职场文书
葛优非诚勿扰搞笑征婚台词
2014/03/17 职场文书
喷漆工的岗位职责
2014/03/17 职场文书
让生命充满爱演讲稿
2014/05/10 职场文书
禁毒宣传活动总结
2014/08/26 职场文书
民主生活会对照检查材料(统计局)
2014/09/21 职场文书
个人职业及收入证明
2014/10/13 职场文书
高二化学教学反思
2016/02/22 职场文书
Pygame Rect区域位置的使用(图文)
2021/11/17 Python
Python 中面向接口编程
2022/05/20 Python