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 相关文章推荐
JQuery CSS样式控制 学习笔记
Jul 23 Javascript
js实现图片轮换效果代码
Apr 16 Javascript
js sort 二维数组排序的用法小结
Jan 24 Javascript
返回上一页并自动刷新的JavaScript代码
Feb 19 Javascript
jquery实现鼠标拖拽滑动效果来选择数字的方法
May 04 Javascript
在React框架中实现一些AngularJS中ng指令的例子
Mar 06 Javascript
详谈jQuery.load()和Jsp的include的区别
Apr 12 jQuery
浅析Visual Studio Code断点调试Vue
Feb 27 Javascript
angular组件间通讯的实现方法示例
May 07 Javascript
如何在微信小程序中使用骨架屏的步骤
Jun 12 Javascript
解决vue 退出动画无效的问题
Aug 09 Javascript
vue 实现图片懒加载功能
Dec 31 Vue.js
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
基于HTTP长连接的&quot;服务器推&quot;技术的php 简易聊天室
2009/10/31 PHP
php实现通用的从数据库表读取数据到数组的函数实例
2015/03/21 PHP
PHP+MySql实现一个简单的留言板
2020/07/19 PHP
解析javascript 数组以及json元素的添加删除
2013/06/26 Javascript
jQuery+slidereveal实现的面板滑动侧边展出效果
2015/03/14 Javascript
jQuery平滑旋转幻灯片特效代码分享
2015/09/07 Javascript
跟我学习javascript解决异步编程异常方案
2015/11/23 Javascript
浅谈jquery中的each方法$.each、this.each、$.fn.each
2016/06/23 Javascript
详解js中Json的语法与格式
2016/11/22 Javascript
EasyUI Combobox设置默认值 获取text的方法
2016/11/28 Javascript
React根据宽度自适应高度的示例代码
2017/10/11 Javascript
vue+element实现批量删除功能的示例
2018/02/28 Javascript
JavaScript EventEmitter 背后的秘密 完整版
2018/03/29 Javascript
vue裁切预览组件功能的实现步骤
2018/05/04 Javascript
angular6开发steps步骤条组件
2019/07/04 Javascript
Vue动态生成表格的行和列
2019/07/18 Javascript
微信小程序实现点击空白隐藏的方法示例
2019/08/13 Javascript
vue获取验证码倒计时组件
2019/08/26 Javascript
VUE:vuex 用户登录信息的数据写入与获取方式
2019/11/11 Javascript
Vue使用screenfull实现全屏效果
2020/09/17 Javascript
Python cookbook(数据结构与算法)找出序列中出现次数最多的元素算法示例
2018/03/15 Python
Python if语句知识点用法总结
2018/06/10 Python
Python模拟百度自动输入搜索功能的实例
2019/02/14 Python
Tensorflow实现在训练好的模型上进行测试
2020/01/20 Python
使用tensorboard可视化loss和acc的实例
2020/01/21 Python
基于Python数据结构之递归与回溯搜索
2020/02/26 Python
keras得到每层的系数方式
2020/06/15 Python
基于opencv的selenium滑动验证码的实现
2020/07/24 Python
详解用 python-docx 创建浮动图片
2021/01/24 Python
CSS3的文字阴影—text-shadow的使用方法
2012/12/25 HTML / CSS
使用HTML5 Canvas绘制直线或折线等线条的方法讲解
2016/03/14 HTML / CSS
自动化专业毕业生自荐信
2013/11/01 职场文书
入学申请自荐信范文
2014/02/26 职场文书
保险内勤岗位职责
2015/04/13 职场文书
教师旷工检讨书
2015/08/15 职场文书
驾驶员安全责任协议书
2016/03/22 职场文书