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实现的动态文字变换
Jul 28 Javascript
JS不间断向上滚动效果代码
Dec 25 Javascript
js+css实现的简单易用兼容好的分页
Dec 30 Javascript
javascript中通过arguments参数伪装方法重载
Oct 08 Javascript
jquery实现全选功能效果的实现代码
May 05 Javascript
jquery实现全选、不选、反选的两种方法
Sep 06 Javascript
BootStrap入门教程(二)之固定的内置样式
Sep 19 Javascript
Javascript中字符串和数字的操作方法整理
Jan 22 Javascript
微信小程序picker组件下拉框选择input输入框的实例
Sep 20 Javascript
Vue自定义toast组件的实例代码
Aug 15 Javascript
JavaScript 扩展运算符用法实例小结【基于ES6】
Jun 17 Javascript
Vue.js组件通信之自定义事件详解
Oct 19 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函数
2006/10/09 PHP
将一维或多维的数组连接成一个字符串的php代码
2010/08/08 PHP
通过缓存数据库结果提高PHP性能的原理介绍
2012/09/05 PHP
Yii框架用户登录session丢失问题解决方法
2017/01/07 PHP
laravel中命名路由的使用方法
2017/02/24 PHP
PHP判断是手机端还是PC端 PHP判断是否是微信浏览器
2017/03/15 PHP
Laravel 5.5 的自定义验证对象/类示例代码详解
2017/08/29 PHP
php中钩子(hook)的原理与简单应用demo示例
2019/09/03 PHP
在IE下获取object(ActiveX)的Param的代码
2009/09/15 Javascript
IE不支持getElementsByClassName最终完美解决方案
2012/12/17 Javascript
js中创建对象的几种方式示例介绍
2014/01/26 Javascript
详细探究ES6之Proxy代理
2016/07/22 Javascript
深入理解JavaScript中Ajax
2016/08/02 Javascript
JavaScript事件委托实现原理及优点进行
2020/08/29 Javascript
Vue中使用JsonView来展示Json树的实例代码
2020/11/16 Javascript
为什么JavaScript中0.1 + 0.2 != 0.3
2020/12/03 Javascript
[00:50]深扒TI7聊天轮盘语音出处6
2017/05/11 DOTA
[56:01]2018DOTA2亚洲邀请赛 3.31 小组赛 B组 Effect vs EG
2018/03/31 DOTA
Python函数式编程指南(三):迭代器详解
2015/06/24 Python
python中int与str互转方法
2018/07/02 Python
Python django使用多进程连接mysql错误的解决方法
2018/10/08 Python
python使用MQTT给硬件传输图片的实现方法
2019/05/05 Python
python实现拉普拉斯特征图降维示例
2019/11/25 Python
python统计字符串中字母出现次数代码实例
2020/03/02 Python
django中related_name的用法说明
2020/05/20 Python
Python+Kepler.gl实现时间轮播地图过程解析
2020/07/20 Python
关于django python manage.py startapp 应用名出错异常原因解析
2020/12/15 Python
深入浅析css3 中display box使用方法
2015/11/25 HTML / CSS
html5移动端价格输入键盘的实现
2019/09/16 HTML / CSS
数控机械专业个人的自我评价
2014/01/02 职场文书
安全承诺书范文
2014/03/26 职场文书
环保倡议书500字
2014/05/15 职场文书
张丽莉观后感
2015/06/16 职场文书
董事长开业致辞
2015/07/29 职场文书
JAVA API 实用类 String详解
2021/10/05 Java/Android
python绘制云雨图raincloud plot
2022/08/05 Python