封装一个基础的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;


结语


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



相关文章
|
2月前
|
JSON JavaScript 前端开发
【Vue面试题二十四】、Vue项目中有封装过axios吗?主要是封装哪方面的?
这篇文章讨论了在Vue项目中封装axios的最佳实践,包括设置接口请求前缀、请求头、状态码、请求方法的封装,以及如何使用请求和响应拦截器来处理token和响应状态,从而简化HTTP请求的配置和错误处理,提高代码的可维护性。
【Vue面试题二十四】、Vue项目中有封装过axios吗?主要是封装哪方面的?
|
2月前
|
设计模式 JavaScript 前端开发
Vue.js组件设计模式:构建可复用组件库
在Vue.js中,构建可复用组件库是提升代码质量和维护性的核心策略。采用单文件组件(SFC),定义props及默认值,利用自定义事件和插槽进行灵活通信,结合Vuex或Pinia的状态管理,以及高阶组件技术,可以增强组件的功能性和灵活性。通过合理的抽象封装、考虑组件的可配置性和扩展性,并辅以详尽的文档和充分的测试,能够打造出既高效又可靠的组件库。此外,采用懒加载、按需导入技术优化性能,制定设计系统和风格指南确保一致性,配合版本控制、CI/CD流程和代码审查机制,最终形成一个高品质、易维护且具有良好社区支持的组件库。
54 7
|
5月前
|
JavaScript API
Vue实现简单的接口封装
Vue实现简单的接口封装
|
5月前
|
存储 资源调度 JavaScript
vue怎样封装接口
vue怎样封装接口
37 0
|
5月前
vue3封装接口
vue3封装接口
59 0
|
12月前
|
JSON JavaScript 前端开发
「Vue面试题」Vue项目中有封装过axios吗?主要是封装哪方面的?
「Vue面试题」Vue项目中有封装过axios吗?主要是封装哪方面的?
61 0
|
JavaScript API
vue3如何封装框架
vue3如何封装框架
78 0
|
JavaScript
vue3 axios接口封装
vue3 axios接口封装
255 0
vue3如何将一个功能封装起来
vue3如何将一个功能封装起来
77 0