封装一个基础的vue-router

简介: 主要知识点:路由原理Hash与History实现路由

前言


主要知识点:


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


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


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


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


vue-router工作流程


微信截图_20220427142559.png


二、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()


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


2、install属性


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


3、Vue.mixin()


let a = function() {
  console.log(a)
}
//或 let a ={}
a.install=function(vue){
   // Vue.mixin 全局混入自定义操作。上面的vue是作为参数传进来的,而不是import Vue from 'vue'中的Vue
   vue.mixin({
    data () {
      return {
        c:123456 // 在其他页面this.c
      }
    },
    methods:{
      globalMethods(){
        console.log('我是全局方法') // 在其它页面this.globalMethods()
      }
    },
    created() {
      console.log(this)
    }
  })
}
Vue.use(a) 


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


let obj = {
  key:'KEY'
}
setTimeout(function () {
  obj.key='KEY2' // 3s改变{{this.obj1.key}}
},3000)
let a = function() {
  console.log(a)
}
//或 let a ={}
a.install=function(vue){
  console.log(vue.util) // vue 工具类: defineReactive、extend、mergeOptions、warn
  vue.util.defineReactive(obj,'key')  // 监听。源码使用的是Object.defineProperty()
  vue.mixin({
    beforeCreate(){
      this.obj1=obj //在其他页面{{this.obj1.key}},值为KEY。
    }
  })
}


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


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


四、 封装基础vue-router


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

编辑myrouter文件夹下的index.js


// 记录history对象
class HistoryRoute{
    constructor(){
        // 要监听的路径
        this.current=null;
    }
}
// vuerouter本身
class vueRouter{
    constructor(options){
        this.mode=options.mode||'hash'; //配置模式
        this.routes=options.routes||[]; // routes路由表
        this.routesMap=this.createMap(this.routes); // 调用 createMap,参数是路由表routes
        this.history=new HistoryRoute;// 实例化history
        this.init(); // 初始化
    }
    init(){
        if(this.mode=='hash'){ // 判断是否是hash模式
            location.hash?'':location.hash='/'; // 自动加#号。如果有hash返回空字符串。否则返回/
            window.addEventListener('load',()=>{ // 监听页面加载完成
                this.history.current=location.hash.slice(1); //拿到hash值,把#去掉。赋给实例化的history的current路径。
            })
            window.addEventListener('hashchange',()=>{ // 监听hash改变
                this.history.current=location.hash.slice(1);
            })
        }
    }
    // 路径对应组件。新组合一个对象。如:{'/':Home},也就是映射。
    createMap(routes){
        return routes.reduce((memo,current)=>{ // current 就是路由表routes
            memo[current.path]=current.component;
            return memo
        },{})
    }
}
vueRouter.install=function(Vue){
    // 写插件要注意判断插件是否注册
    if(vueRouter.install.installed)return
    vueRouter.install.installed=true;
    // 向vue里面混入操作
    Vue.mixin({
        beforeCreate(){
            if(this.$options&&this.$options.router){ // 在App.vue文件里如果有router选项的话
                this._root=this; // 这里的this指向当前Vue实例,缓存下自身。
                this._router=this.$options.router; // 挂载下选项里传进来的router.
                Vue.util.defineReactive(this,'current',this._router.history); //监听this.current,并且传入第三个参数。相当于children。
            }else{
                this._root=this.$parent._root; //如果没有就向上查找一级,直到查到App.vue里new Vue({router})为止。
            }
            // 这个方法只是说明this.$router只读,私有变量思想
            Object.defineProperty(this,"$router",{ //this指当前组件实例
                get(){ 
                    return this._root._router; // 返回挂载后的router
                }
            })
        }
    })
    // 定义组件
    Vue.component('router-view',{
        render(h){
           let current=this._self._root._router.history.current;// 拿到当前存进去的router实例里的current
           let routerMap=this._self._root._router.routesMap;//拿到当前存进去的router实例里的routesMap
           return h(routerMap[current]); // 拿到routerMap,调用h方法。渲染routerMap对应关系。放到router-view组件里面。
        }
    })
}
// 暴露vuerouter
export default vueRouter;


结语


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



相关文章
|
7月前
|
JavaScript
|
8月前
|
JavaScript API
Vue实现简单的接口封装
Vue实现简单的接口封装
|
8月前
|
JavaScript 前端开发 API
在VUE项目中做一个简单的Axios二次封装及使用
在VUE项目中做一个简单的Axios二次封装及使用
120 0
|
8月前
|
存储 资源调度 JavaScript
vue怎样封装接口
vue怎样封装接口
45 0
|
8月前
vue3封装接口
vue3封装接口
73 0
|
JSON JavaScript 前端开发
「Vue面试题」Vue项目中有封装过axios吗?主要是封装哪方面的?
「Vue面试题」Vue项目中有封装过axios吗?主要是封装哪方面的?
80 0
|
JavaScript
Vue之封装二次axios
Vue之封装二次axios
|
JavaScript API
vue3如何封装框架
vue3如何封装框架
103 0
|
JavaScript
如何在vue中封装一个功能
如何在vue中封装一个功能
47 0
vue3如何将一个功能封装起来
vue3如何将一个功能封装起来
85 0