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 相关文章推荐
JS JavaScript获取Url参数,src属性参数
Mar 09 Javascript
js类中的公有变量和私有变量
Jul 24 Javascript
jquery URL参数判断,确定菜单样式
May 31 Javascript
javascript实现英文首字母大写
Apr 23 Javascript
JS制作手机端自适应缩放显示
Jun 11 Javascript
javascript和jquery实现用户登录验证
May 04 Javascript
jQuery图片轮播(二)利用构造函数和原型创建对象以实现继承
Dec 06 Javascript
jQuery.ajax向后台传递数组问题的解决方法
May 12 jQuery
JS中利用FileReader实现上传图片前本地预览功能
Mar 02 Javascript
element-ui的回调函数Events的用法详解
Oct 16 Javascript
详解JavaScript数据类型和判断方法
Sep 04 Javascript
vue添加自定义右键菜单的完整实例
Dec 08 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
PHP学习资料汇总与网址
2007/03/16 PHP
php中对2个数组相加的函数
2011/06/24 PHP
PHP中include与require使用方法区别详解
2013/10/19 PHP
php图像处理类实例
2015/07/28 PHP
Laravel学习教程之model validation的使用示例
2017/10/23 PHP
推荐一些非常不错的javascript学习资源站点
2007/08/29 Javascript
jQuery+CSS 实现的超Sexy下拉菜单
2010/01/17 Javascript
Jquery实战_读书笔记2 选择器
2010/01/22 Javascript
jquery实现通用版鼠标经过淡入淡出效果
2014/06/15 Javascript
jquery操作 iframe的方法
2014/12/03 Javascript
jQuery老黄历完整实现方法
2015/01/16 Javascript
JavaScript定时器和优化的取消定时器方法
2015/07/03 Javascript
提高jQuery性能优化的技巧
2015/08/03 Javascript
JavaScript对象引用与赋值实例详解
2017/03/15 Javascript
AngularJS实现的省市二级联动功能示例【可对选项实现增删】
2017/10/26 Javascript
让bootstrap的carousel支持滑动滚屏的实现代码
2017/11/27 Javascript
Vue通过ref父子组件拿值方法
2018/09/12 Javascript
JavaScript 复制对象与Object.assign方法无法实现深复制
2018/11/02 Javascript
angular学习之动态创建表单的方法
2018/12/07 Javascript
Vue插件之滑动验证码
2019/09/21 Javascript
搭建Vue从Vue-cli到router路由护卫的实现
2019/11/14 Javascript
微信小程序利用云函数获取手机号码
2019/12/17 Javascript
vue 实现setInterval 创建和销毁实例
2020/07/21 Javascript
vue组件讲解(is属性的用法)模板标签替换操作
2020/09/04 Javascript
vue 根据选择的月份动态展示日期对应的星期几
2021/02/06 Vue.js
[04:48]DOTA2上海特锦赛小组赛第三日 TOP10精彩集锦
2016/02/28 DOTA
5个很好的Python面试题问题答案及分析
2018/01/19 Python
Python cookbook(数据结构与算法)找到最大或最小的N个元素实现方法示例
2018/02/13 Python
python利用后缀表达式实现计算器功能
2021/02/22 Python
行政专员工作职责
2013/12/22 职场文书
大学生党员自我批评思想汇报
2014/10/10 职场文书
校园会短篇的广播稿
2014/10/21 职场文书
幼儿园见习报告范文
2014/10/30 职场文书
2015庆祝七一建党节94周年活动总结
2015/03/20 职场文书
2019年共青团工作条例最新版
2019/11/12 职场文书
react使用antd的上传组件实现文件表单一起提交功能(完整代码)
2021/06/29 Javascript