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操纵Cookie实现购物车程序
Feb 15 Javascript
一个XML格式数据转换为图表的例子
Feb 09 Javascript
JavaScript 参数中的数组展开 [译]
Sep 21 Javascript
js简单实现HTML标签Select联动带跳转
Oct 23 Javascript
一个JS函数搞定网页标题(title)闪动效果
May 13 Javascript
jQuery中append()方法用法实例
Dec 25 Javascript
jquery插件Jplayer使用方法简析
Apr 22 Javascript
让DIV的滚动条自动滚动到最底部的3种方法(推荐)
Sep 24 Javascript
详解JS对象封装的常用方式
Dec 30 Javascript
一个例子轻松学会Vue.js
Jan 02 Javascript
vue解决一个方法同时发送多个请求的问题
Sep 25 Javascript
深入探索VueJS Scoped CSS 实现原理
Sep 23 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_num_rows VS COUNT 效率问题分析
2011/04/23 PHP
用C/C++扩展你的PHP 为你的php增加功能
2012/09/06 PHP
解析php中的fopen()函数用打开文件模式说明
2013/06/20 PHP
PHP Laravel中的Trait使用方法
2019/01/20 PHP
php设计模式之中介者模式分析【星际争霸游戏案例】
2020/03/23 PHP
firefox 和 ie 事件处理的细节,研究,再研究 书写同时兼容ie和ff的事件处理代码
2007/04/12 Javascript
javascript 强制刷新页面的实现代码
2009/12/13 Javascript
通过$(this)使用jQuery包装后的方法或属性
2014/05/18 Javascript
jquery实现标签支持图文排列带上下箭头按钮的选项卡
2015/03/14 Javascript
jQuery实现加入购物车飞入动画效果
2015/03/14 Javascript
jQuery-1.9.1源码分析系列(十)事件系统之事件体系结构
2015/11/19 Javascript
xcode中获取js文件的路径方法(推荐)
2016/11/05 Javascript
JS排序之冒泡排序详解
2017/04/08 Javascript
vue.js通过路由实现经典的三栏布局实例代码
2018/07/08 Javascript
vue.js实现的经典计算器/科学计算器功能示例
2018/07/11 Javascript
原生js封装的ajax方法示例
2018/08/02 Javascript
Vue.js点击切换按钮改变内容的实例讲解
2018/08/22 Javascript
JS中的变量作用域(console版)
2020/07/18 Javascript
vue仿携程轮播图效果(滑动轮播,下方高度自适应)
2021/02/11 Vue.js
Python 中的with关键字使用详解
2016/09/11 Python
Python使用numpy实现BP神经网络
2018/03/10 Python
Python去除、替换字符串空格的处理方法
2018/04/01 Python
使用Python通过win32 COM打开Excel并添加Sheet的方法
2018/05/02 Python
用vue.js组件模拟v-model指令实例方法
2019/07/05 Python
WxPython实现无边框界面
2019/11/18 Python
python数据预处理 :数据抽样解析
2020/02/24 Python
python对批量WAV音频进行等长分割的方法实现
2020/09/25 Python
python爬虫判断招聘信息是否存在的实例代码
2020/11/20 Python
Everything But Water官网:美国泳装品牌
2019/03/17 全球购物
Osklen官方在线商店:巴西服装品牌
2019/04/25 全球购物
师范应届生求职信
2013/11/15 职场文书
精彩自我鉴定
2014/01/16 职场文书
机修工工作职责
2014/02/21 职场文书
六一节目主持词
2014/04/01 职场文书
安全生产宣传标语
2014/06/06 职场文书
八一建军节慰问信
2015/02/14 职场文书