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的eval()中使用函数的进一步讨论
Jul 26 Javascript
Extjs EditorGridPanel中ComboBox列的显示问题
Jul 04 Javascript
js点击页面其它地方将某个显示的DIV隐藏
Jul 12 Javascript
Extjs根据条件设置表格某行背景色示例
Jul 23 Javascript
JavaScript随机生成信用卡卡号的方法
Apr 07 Javascript
在JavaScript中操作数组之map()方法的使用
Jun 09 Javascript
jquery 将当前时间转换成yyyymmdd格式的实现方法
Jun 01 Javascript
jquery.tableSort.js表格排序插件使用方法详解
Aug 12 Javascript
Vue组件之Tooltip的示例代码
Oct 18 Javascript
webpack源码之loader机制详解
Apr 06 Javascript
浅析vue中的MVVM实现原理
Mar 04 Javascript
vue如何在项目中调用腾讯云的滑动验证码
Jul 15 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
yii的CURD操作实例详解
2014/12/04 PHP
PHP使用Redis实现Session共享的实现示例
2019/05/12 PHP
javascript 语法基础 想学习js的朋友可以看看
2009/12/16 Javascript
基于jquery的从一个页面跳转到另一个页面的指定位置的实现代码(带平滑移动的效果)
2011/05/24 Javascript
js中符号转意问题示例探讨
2013/08/19 Javascript
使用js在页面中绘制表格核心代码
2013/09/16 Javascript
javascript检查浏览器是否支持flash的实现代码
2014/08/14 Javascript
JavaScript父子窗体间的调用方法
2015/03/31 Javascript
js自定义回调函数
2015/12/13 Javascript
js判断某个字符出现的次数的简单实例
2016/06/03 Javascript
JavaScript中获取HTML元素值的三种方法
2016/06/20 Javascript
KnockoutJS 3.X API 第四章之数据控制流component绑定
2016/10/10 Javascript
关于vue中watch检测到不到对象属性的变化的解决方法
2018/02/08 Javascript
javascript少儿编程关于返回值的函数内容
2018/05/27 Javascript
javascript移动端 电子书 翻页效果实现代码
2019/09/07 Javascript
layui 监听select选择 获取当前select的ID名称方法
2019/09/24 Javascript
vue实现百度搜索功能
2020/12/28 Javascript
node.js通过url读取文件
2020/10/16 Javascript
nuxt 自定义 auth 中间件实现令牌的持久化操作
2020/11/05 Javascript
一篇文章入门Python生态系统(Python新手入门指导)
2015/12/11 Python
python实现学生管理系统
2018/01/11 Python
Python后台开发Django的教程详解(启动)
2019/04/08 Python
python连接PostgreSQL数据库的过程详解
2019/09/18 Python
Python3 filecmp模块测试比较文件原理解析
2020/03/23 Python
python中wheel的用法整理
2020/06/15 Python
菲律宾旅游网站:Expedia菲律宾
2017/10/11 全球购物
英国领先的汽车轮胎和快速健康中心:Kwik Fit
2017/10/29 全球购物
外企C语言笔试题
2013/11/10 面试题
迟到检讨书500字
2014/02/05 职场文书
社区庆中秋节活动方案
2014/02/07 职场文书
违反交通安全法检讨书
2014/10/24 职场文书
岳麓书院导游词
2015/02/03 职场文书
爱国主义教育主题班会
2015/08/13 职场文书
2016年小学“公民道德宣传日”活动总结
2016/04/01 职场文书
解决vue $http的get和post请求跨域问题
2021/06/07 Vue.js
详细聊聊vue中组件的props属性
2021/11/02 Vue.js