封装一个基础的vue-router

偏执的太偏执、 2021-08-14 00:06 471阅读 0赞

前言

主要知识点:

  • 路由原理
  • Hash与History
  • 实现路由

一、一个vue路由的工作原理

前端路由与后端路由的区别:

后端路由:
输入url>请求发送到服务器>服务器解析请求的路径>拿取对应的页面>返回回去
前端路由:
输入url>js解析地址>找到对应的地址的页面>执行页面生成的js>看到页面

vue-router工作流程

在这里插入图片描述

二、Hash与history的使用

hash:

  • #号后的就是hash的内容
  • 可以通过location.hash拿到
  • 可以通过onhashchange监听hash的改变
  • 可以在#号后面加路径不会向服务器请求

history:

  • history即正常的路径
  • location.pathname
  • 可以用onpopstate监听history变化

三、Vue插件基础知识

如:vue-router、vuex、element-ui都是插件

插件基础点:

  • Vue.use去使用一个插件,并且去执行install方法
  • Vue.mixin往vue的全局混入自定义的操作
  • 可以通过this.$options拿到new Vue时的参数

示例:

以下都是在main.js执行

1、初始Vue.use()

  1. Vue.use({
  2. console.log('use') //会打印出use
  3. })

2、install属性

  1. let a = function() {
  2. console.log(a)
  3. }
  4. //或 let a ={}
  5. a.install=function(){
  6. console.log('install')
  7. }
  8. Vue.use(a) // 会打印install,而不会打印a。
  9. // 如果你给他一个方法,他就执行这个方法,
  10. // 但是无论你给他的任何东西,只要给他一个install属性,他就会执行install。

3、Vue.mixin()

  1. let a = function() {
  2. console.log(a)
  3. }
  4. //或 let a ={}
  5. a.install=function(vue){
  6. // Vue.mixin 全局混入自定义操作。上面的vue是作为参数传进来的,而不是import Vue from 'vue'中的Vue
  7. vue.mixin({
  8. data () {
  9. return {
  10. c:123456 // 在其他页面this.c
  11. }
  12. },
  13. methods:{
  14. globalMethods(){
  15. console.log('我是全局方法') // 在其它页面this.globalMethods()
  16. }
  17. },
  18. created() {
  19. console.log(this)
  20. }
  21. })
  22. }
  23. Vue.use(a)

4、Vue工具类(Vue.util)
vue 工具类: defineReactiveextendmergeOptionswarn

  1. let obj = {
  2. key:'KEY'
  3. }
  4. setTimeout(function () {
  5. obj.key='KEY2' // 3s改变{ {this.obj1.key}}
  6. },3000)
  7. let a = function() {
  8. console.log(a)
  9. }
  10. //或 let a ={}
  11. a.install=function(vue){
  12. console.log(vue.util) // vue 工具类: defineReactive、extend、mergeOptions、warn
  13. vue.util.defineReactive(obj,'key') // 监听。源码使用的是Object.defineProperty()
  14. vue.mixin({
  15. beforeCreate(){
  16. this.obj1=obj //在其他页面{ {this.obj1.key}},值为KEY。
  17. }
  18. })
  19. }

vue.extend() 与 vue.util.extend() 区别:

  1. vue.extend() // 单元测试
  2. const home = Vue.extend(home)
  3. // 新建这个组件的构造函数,也就是组件的this
  4. const vm = new home().$mount()
  5. vue.util.extend() // 浅拷贝对象

四、 封装基础vue-router

准备完了前面几个知识点,我们下面来整代码,需要注意的是,下面只是个基础的vue-router,只可以页面切换。本篇只是为了熟悉源码,不为实际需要。
src文件夹下新建一个文件夹myrouter,里面再新建一个index.js文件。
在原来的router文件夹里的index.js中把原来引入router的路径换为import VueRouter from '../myrouter'

编辑myrouter文件夹下的index.js

  1. // 记录history对象
  2. class HistoryRoute{
  3. constructor(){
  4. // 要监听的路径
  5. this.current=null;
  6. }
  7. }
  8. // vuerouter本身
  9. class vueRouter{
  10. constructor(options){
  11. this.mode=options.mode||'hash'; //配置模式
  12. this.routes=options.routes||[]; // routes路由表
  13. this.routesMap=this.createMap(this.routes); // 调用 createMap,参数是路由表routes
  14. this.history=new HistoryRoute;// 实例化history
  15. this.init(); // 初始化
  16. }
  17. init(){
  18. if(this.mode=='hash'){ // 判断是否是hash模式
  19. location.hash?'':location.hash='/'; // 自动加#号。如果有hash返回空字符串。否则返回/
  20. window.addEventListener('load',()=>{ // 监听页面加载完成
  21. this.history.current=location.hash.slice(1); //拿到hash值,把#去掉。赋给实例化的history的current路径。
  22. })
  23. window.addEventListener('hashchange',()=>{ // 监听hash改变
  24. this.history.current=location.hash.slice(1);
  25. })
  26. }
  27. }
  28. // 路径对应组件。新组合一个对象。如:{'/':Home},也就是映射。
  29. createMap(routes){
  30. return routes.reduce((memo,current)=>{ // current 就是路由表routes
  31. memo[current.path]=current.component;
  32. return memo
  33. },{ })
  34. }
  35. }
  36. vueRouter.install=function(Vue){
  37. // 写插件要注意判断插件是否注册
  38. if(vueRouter.install.installed)return
  39. vueRouter.install.installed=true;
  40. // 向vue里面混入操作
  41. Vue.mixin({
  42. beforeCreate(){
  43. if(this.$options&&this.$options.router){ // 在App.vue文件里如果有router选项的话
  44. this._root=this; // 这里的this指向当前Vue实例,缓存下自身。
  45. this._router=this.$options.router; // 挂载下选项里传进来的router.
  46. Vue.util.defineReactive(this,'current',this._router.history); //监听this.current,并且传入第三个参数。相当于children。
  47. }else{
  48. this._root=this.$parent._root; //如果没有就向上查找一级,直到查到App.vue里new Vue({router})为止。
  49. }
  50. // 这个方法只是说明this.$router只读,私有变量思想
  51. Object.defineProperty(this,"$router",{ //this指当前组件实例
  52. get(){
  53. return this._root._router; // 返回挂载后的router
  54. }
  55. })
  56. }
  57. })
  58. // 定义组件
  59. Vue.component('router-view',{
  60. render(h){
  61. let current=this._self._root._router.history.current;// 拿到当前存进去的router实例里的current
  62. let routerMap=this._self._root._router.routesMap;//拿到当前存进去的router实例里的routesMap
  63. return h(routerMap[current]); // 拿到routerMap,调用h方法。渲染routerMap对应关系。放到router-view组件里面。
  64. }
  65. })
  66. }
  67. // 暴露vuerouter
  68. export default vueRouter;

结语

前端的路上我们一起前行。

发表评论

表情:
评论列表 (有 0 条评论,471人围观)

还没有评论,来说两句吧...

相关阅读