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 相关文章推荐
对采用动态原型方式无法展示继承机制得思考
Dec 04 Javascript
JavaScript 数组运用实现代码
Apr 13 Javascript
jQuery实现购物车数字加减效果
Mar 14 Javascript
JSP防止网页刷新重复提交数据的几种方法
Nov 19 Javascript
JavaScript实现自定义媒体播放器方法介绍
Jan 03 Javascript
JavaScript中offsetWidth的bug及解决方法
May 17 Javascript
vue 如何添加全局函数或全局变量以及单页面的title设置总结
Jun 01 Javascript
基于Bootstrap的标签页组件及bootstrap-tab使用说明
Jul 25 Javascript
深入理解ES6的迭代器与生成器
Aug 19 Javascript
vue初始化动画加载的实例
Sep 01 Javascript
初学node.js中实现删除用户路由
May 27 Javascript
JS前端使用canvas实现扩展物体类和事件派发
Aug 05 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
php中将指针移动到数据集初始位置的实现代码[mysql_data_seek]
2012/11/01 PHP
Zend Framework教程之Zend_Config_Xml用法分析
2016/03/23 PHP
PHP正则匹配反斜杠'\'和美元'$'的方法
2017/02/08 PHP
解决laravel groupBy 对查询结果进行分组出现的问题
2019/10/09 PHP
JavaScript 变量基础知识
2009/11/07 Javascript
DOM和XMLHttpRequest对象的属性和方法整理
2012/01/04 Javascript
js操作CheckBoxList实现全选/反选(在客服端完成)
2013/02/02 Javascript
JavaScript设置IFrame高度自适应(兼容各主流浏览器)
2013/06/05 Javascript
jquery属性选择器not has怎么写 行悬停高亮显示
2013/11/13 Javascript
jquery动态调整div大小使其宽度始终为浏览器宽度
2014/06/06 Javascript
JavaScript检测上传文件大小的方法
2015/07/22 Javascript
js插件Jcrop自定义截取图片功能
2016/10/14 Javascript
JS表单数据验证的正则表达式(常用)
2017/02/18 Javascript
JS实现按钮颜色切换效果
2020/09/05 Javascript
layer实现关闭弹出层刷新父界面功能详解
2017/11/15 Javascript
Layer弹出层动态获取数据的方法
2018/08/20 Javascript
微信小程序如何实现点击图片放大功能
2020/01/21 Javascript
[06:16]DOTA2守卫传承者——职业选手谈心路历程
2015/02/26 DOTA
python机器学习之神经网络(二)
2017/12/20 Python
Python中的defaultdict与__missing__()使用介绍
2018/02/03 Python
python线程池threadpool使用篇
2018/04/27 Python
Flask框架实现的前端RSA加密与后端Python解密功能详解
2019/08/13 Python
python线程里哪种模块比较适合
2020/08/02 Python
基于html5 DeviceOrientation 实现微信摇一摇功能
2015/09/25 HTML / CSS
迪卡侬英国官网:Decathlon英国
2017/04/08 全球购物
娇韵诗法国官网:Clarins法国
2019/01/29 全球购物
Moda Italia荷兰:意大利男士服装
2019/08/31 全球购物
代办委托书怎样写
2014/04/08 职场文书
病媒生物防治方案
2014/05/13 职场文书
统计专业自荐书
2014/07/06 职场文书
民事授权委托书范文
2014/08/02 职场文书
批评与自我批评发言稿
2014/10/15 职场文书
个人作风建设总结
2014/10/23 职场文书
大学毕业生自我鉴定范文
2019/06/21 职场文书
网络新闻该怎么写?这些写作技巧你都知道吗?
2019/08/26 职场文书
Java实现简易的分词器功能
2021/06/15 Java/Android