vue-router 源码之实现一个简单的 vue-router


Posted in Javascript onJuly 02, 2018

前言

通过上篇,我们知道前端理由的两种实现方法,Hash 路由与 History 路由,并且用它们分别实现了一个前端路由。

接下来我们就将 Vue 与 Hash 路由结合,实现一个非常简单的 vue-router 吧。

开始实现

想象一下,如果自己实现了一个 vue-router,会怎么去使用呢?参考 vue-router 官方的使用方式,看看 html 的使用:

<div id="app">
 <p>
  <router-link to="#/">home</router-link>
  <router-link to="#/book">book</router-link>
  <router-link to="#/movie">movie</router-link>
 </p>
 <router-view></router-view>
</div>

这里会有 router-link 和 router-view 两个组件需要我们来实现。再来看 js 的:

const Home = { template: '<div>home</div>' };
const Book = { template: '<div>book</div>' };
const Movie = { template: '<div>movie</div>' };

const routes = [
 { path: '/', component: Home },
 { path: '/book', component: Book },
 { path: '/movie', component: Movie }
];

const router = new VueRouter(Vue, {
 routes
});

new Vue({
 el: '#app'
});

这里会有我们自己定义的组件 Home、Book 和 Movie,并且有它们各自对应的路由。我们实现的 VueRouter 跟官方的有些区别,在 VueRouter 被 new 时是将 Vue 作为参数传入,而不是注入挂载到根实例下。

接下来就是 VueRouter 的实现了。

VueRouter

要怎么来实现 VueRouter 呢,先提供一下实现的思路:

  1. 绑定 hashchange 事件,实现前端路由;
  2. 将传入的路由和组件做一个路由映射,切换哪个路由即可找到对应的组件显示;
  3. 需要 new 一个 Vue 实例还做响应式通信,当路由改变的时候,router-view 会响应更新;
  4. 注册 router-link 和 router-view 组件。

先创建一个 VueRouter:

class VueRouter {
 constructor (Vue, options) {
  this.$options = options;
 }
}

绑定事件

给 VueRouter 添加一个绑定事件的方法,一旦路由发生改变,会触发 onHashChange 方法。

constructor (Vue, options) {
 this.init();
}

// 绑定事件
init () {
 window.addEventListener('load', this.onHashChange.bind(this), false);
 window.addEventListener('hashchange', this.onHashChange.bind(this), false);
}

路由映射表

将传入的 options 设置成一张路由映射表,以便于通过路由查找到对应的组件。

constructor (Vue, options) {
 this.$options = options;
 this.routeMap = {};
 this.createRouteMap(this.$options);
}

// 路由映射表
createRouteMap (options) {
 options.routes.forEach(item => {
  this.routeMap[item.path] = item.component;
 });
}

options 之中,路由与组件的关系:

const routes = [
 { path: '/', component: Home },
 { path: '/book', component: Book },
 { path: '/movie', component: Movie }
];

生成的路由映射表:

this.routeMap = {
 '/': Home,
 '/book': Book,
 '/movie': Movie
};

响应

我们需要 new 一个新的 Vue 实例,将当前路由 current 储存在其 data 之中,当修改了 current 时,router-view 就会自己去更新视图。

constructor (Vue, options) {
 this.app = new Vue({
  data: {
   current: '#/'
  }
 });
}

// 获取当前 hash 串
getHash () {
 return window.location.hash.slice(1) || '/';
}


// 设置当前路径
onHashChange () {
 this.app.current = this.getHash();
}

只要在 router-view 里使用到了 this.app.current,一旦更新它,便会更新。

注册组件

router-link 实际上就是一个 <a> 标签,点击它便能触发 hashchangerouter-view 会实现一个 render 方法,将当前路由对应的组件取出,进行渲染。

constructor (Vue, options) {
 this.initComponent(Vue);
}

// 注册组件
initComponent (Vue) {
 Vue.component('router-link', {
  props: {
   to: String
  },
  template: '<a :href="to" rel="external nofollow" rel="external nofollow" ><slot></slot></a>'
 });

 const _this = this;
 Vue.component('router-view', {
  render (h) {
   var component = _this.routeMap[_this.app.current];
   return h(component);
  }
 });
}

完整代码

至此,一个简单的 vue-router 就出来了,全部代码是这样的:

class VueRouter {
 constructor (Vue, options) {
  this.$options = options;
  this.routeMap = {};
  this.app = new Vue({
   data: {
    current: '#/'
   }
  });

  this.init();
  this.createRouteMap(this.$options);
  this.initComponent(Vue);
 }

 // 绑定事件
 init () {
  window.addEventListener('load', this.onHashChange.bind(this), false);
  window.addEventListener('hashchange', this.onHashChange.bind(this), false);
 }

 // 路由映射表
 createRouteMap (options) {
  options.routes.forEach(item => {
   this.routeMap[item.path] = item.component;
  });
 }

 // 注册组件
 initComponent (Vue) {
  Vue.component('router-link', {
   props: {
    to: String
   },
   template: '<a :href="to" rel="external nofollow" rel="external nofollow" ><slot></slot></a>'
  });

  const _this = this;
  Vue.component('router-view', {
   render (h) {
    var component = _this.routeMap[_this.app.current];
    return h(component);
   }
  });
 }

 // 获取当前 hash 串
 getHash () {
  return window.location.hash.slice(1) || '/';
 }

 // 设置当前路径
 onHashChange () {
  this.app.current = this.getHash();
 }
}

最后

将 Vue 与 Hash 路由结合,监听了 hashchange 事件,再通过 Vue 的 响应机制 和 组件,便有了上面实现好了一个 vue-router。

全部源码参考这里。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js DataSet数据源处理代码
Mar 29 Javascript
js解析与序列化json数据(二)序列化探讨
Feb 01 Javascript
javascript删除元素节点removeChild()用法实例
May 26 Javascript
JavaScript使用RegExp进行正则匹配的方法
Jul 11 Javascript
javaScript中的原型解析【推荐】
May 05 Javascript
Bootstrap BootstrapDialog使用详解
Feb 17 Javascript
react开发中如何使用require.ensure加载es6风格的组件
May 09 Javascript
jQuery轮播图实例详解
Aug 15 jQuery
微信小程序拍照和摄像功能实现方法示例
Feb 01 Javascript
Vue快速实现通用表单验证功能
Dec 05 Javascript
详解vue-template-admin三级路由无法缓存的解决方案
Mar 10 Javascript
vue实现水波涟漪效果的点击反馈指令
May 31 Vue.js
JavaScript设计模式之单例模式简单实例教程
Jul 02 #Javascript
JavaScript设计模式之建造者模式实例教程
Jul 02 #Javascript
JS实现的JSON序列化操作简单示例
Jul 02 #Javascript
JS内部事件机制之单线程原理
Jul 02 #Javascript
JS将网址url转化为JSON格式的方法
Jul 02 #Javascript
原生JS实现列表子元素顺序反转的方法分析
Jul 02 #Javascript
JS限制输入框输入的实现代码
Jul 02 #Javascript
You might like
php中关于普通表单多文件上传的处理方法
2011/03/25 PHP
PHP实现异步调用方法研究与分享
2011/10/27 PHP
基于PHP读取csv文件内容的详解
2013/06/18 PHP
PHP错误Parse error: syntax error, unexpected end of file in test.php on line 12解决方法
2014/06/23 PHP
php实现可用于mysql,mssql,pg数据库操作类
2014/12/13 PHP
PHP基于phpqrcode生成带LOGO图像的二维码实例
2015/07/10 PHP
PHP的RSA加密解密方法以及开发接口使用
2018/02/11 PHP
jquery animate 动画效果使用说明
2009/11/04 Javascript
JavaScript利用正则表达式去除日期中的-
2014/06/09 Javascript
jQuery中eq()方法用法实例
2015/01/05 Javascript
jquery增加和删除元素的方法
2015/01/14 Javascript
JavaScript中实现键值对应的字典与哈希表结构的示例
2016/06/12 Javascript
ActiveX控件的使用-js实现打印超市小票功能代码详解
2017/11/22 Javascript
快速搭建vue2.0+boostrap项目的方法
2018/04/09 Javascript
vue实现虚拟列表功能的代码
2020/07/28 Javascript
[01:27:44]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Aster BO3 第一场 1月24日
2021/03/11 DOTA
python实现人脸识别经典算法(一) 特征脸法
2018/03/13 Python
Python遍历某目录下的所有文件夹与文件路径
2018/03/15 Python
python实现合并多个list及合并多个django QuerySet的方法示例
2019/06/11 Python
django 数据库连接模块解析及简单长连接改造方法
2019/08/29 Python
8段用于数据清洗Python代码(小结)
2019/10/31 Python
Tensorflow 实现将图像与标签数据转化为tfRecord文件
2020/02/17 Python
神经网络训练采用gpu设置的方式
2021/03/03 Python
美国最大的团购网站:Groupon
2016/07/23 全球购物
华为智利官方商店:Huawei Chile
2020/05/09 全球购物
华硕新加坡官方网上商店:ASUS Singapore
2020/07/09 全球购物
信息技术毕业生自荐信范文
2014/03/13 职场文书
媒体宣传策划方案
2014/05/25 职场文书
客户答谢会活动方案
2014/08/31 职场文书
2014年小学教师工作自我评价
2014/09/22 职场文书
2014年最新个人对照检查材料范文
2014/09/25 职场文书
个人政风行风自查自纠报告
2014/10/21 职场文书
勇敢的心观后感
2015/06/09 职场文书
如何书写读后感?(附范文)
2019/07/26 职场文书
java泛型通配符详解
2021/07/25 Java/Android
python可视化大屏库big_screen示例详解
2021/11/23 Python