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代码
Sep 22 Javascript
JS正则验证邮箱的格式详细介绍
Nov 19 Javascript
js自动查找select下拉的菜单并选择(示例代码)
Feb 26 Javascript
js控制iframe的高度/宽度让其自适应内容
Apr 09 Javascript
jQuery简单实现隐藏以及显示特效
Feb 26 Javascript
使用C++为node.js写扩展模块
Apr 22 Javascript
JavaScript动态添加css样式和script标签
Jul 19 Javascript
Node.js 使用命令行工具检查更新
Jun 08 Javascript
微信小程序url与token设置详解
Sep 26 Javascript
一文了解Vue中的nextTick
May 06 Javascript
Vue3新特性之在Composition API中使用CSS Modules
Jul 13 Javascript
Vue使用鼠标在Canvas上绘制矩形
Dec 24 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 JSON数组与对象
2016/07/19 PHP
PHP使用JpGraph绘制折线图操作示例【附源码下载】
2019/10/18 PHP
JqGrid web打印实现代码
2011/05/31 Javascript
javascript学习笔记(五) Array 数组类型介绍
2012/06/19 Javascript
jQuery实现可以控制图片旋转角度效果(附demo源码下载)
2016/01/27 Javascript
Angular的Bootstrap(引导)和Compiler(编译)机制
2016/06/20 Javascript
再谈javascript注入 黑客必备!
2016/09/14 Javascript
关于js二维数组和多维数组的定义声明(详解)
2016/10/02 Javascript
jQuery模拟实现的select点击选择效果【附demo源码下载】
2016/11/09 Javascript
深入理解Vuex 模块化(module)
2017/09/26 Javascript
JavaScript树的深度优先遍历和广度优先遍历算法示例
2018/07/30 Javascript
JavaScript日期工具类DateUtils定义与用法示例
2018/09/03 Javascript
element-ui上传一张图片后隐藏上传按钮功能
2019/05/22 Javascript
Vue-cli3多页面配置详解
2020/03/22 Javascript
Vue项目中使用mock.js的完整步骤
2021/01/12 Vue.js
Vue实现多页签组件
2021/01/14 Vue.js
[02:34]DOTA2英雄基础教程 幽鬼
2014/01/02 DOTA
Python的条件语句与运算符优先级详解
2015/10/13 Python
python3.4下django集成使用xadmin后台的方法
2017/08/15 Python
Python有序查找算法之二分法实例分析
2017/12/11 Python
[原创]windows下Anaconda的安装与配置正解(Anaconda入门教程)
2018/04/05 Python
对python程序内存泄漏调试的记录
2018/06/11 Python
对pandas中时间窗函数rolling的使用详解
2018/11/28 Python
浅谈pycharm使用及设置方法
2019/09/09 Python
adidas美国官网:adidas US
2016/09/21 全球购物
中科前程Java笔试题
2016/11/20 面试题
社区党总支书记先进事迹材料
2014/01/24 职场文书
幼儿教师考核制度
2014/01/25 职场文书
放飞蜻蜓反思
2014/02/05 职场文书
学习方法演讲稿
2014/05/10 职场文书
物业管理专业求职信
2014/06/11 职场文书
国庆宣传标语
2014/06/30 职场文书
工商管理本科生求职信
2014/07/13 职场文书
推普周活动总结
2014/08/28 职场文书
2014年销售内勤工作总结
2014/12/01 职场文书
sql server偶发出现死锁的解决方法
2022/04/10 SQL Server