vue全家桶之-0-router源码分析-及实现

简介: 挑战下自己,看能不能梳理个头绪哈哈首先通过 3x以上的脚手架 (目前我使用的是4.5.13)创建vue项目 创建的时候配置好 router和vuex

1.前言


挑战下自己,看能不能梳理个头绪哈哈

首先通过 3x以上的脚手架 (目前我使用的是4.5.13)

创建vue项目 创建的时候配置好 routervuex


2. vue-router----router.js分析 3件事情


2.1 作为插件引入 VueRouter

Vue.use(VueRouter)

插件的形式:  一般是对象或者函数

这行代码其实会调用 install方法

如果写过插件这块应该会很清楚

也可以 通过查看 vue add axios 生成的文件

LG]ZBX95M6X6O4%RIEV3S~N.png


2.2 路由表的配置

主要就是 path和组件的对应关系

2.3 创建实例并导出


3. 准备工作


  1. 复制 router目录 为 zrouter/index.js     zrouter/zvue-router.js
  2. main.js文件修改引入


import router from './zrouter'



4. zrouter/index 实现上述基础的3个步骤结构


  1. 不用import 导入 Vue因为我们现在写的是个第三方库,把Vue打包进去,耦合性太高,所有用参数传进来


//ZVueRouter 类  对比 VueRouter类
class ZVueRouter{
}
// 形参1是Vue的构造函数
ZVueRouter.install = function(_Vue,options){
    // 传入构造函数 修改原型,起到扩展作用
    // 保存一下Vue实例 便于其他地方使用
    Vue = _Vue
    // install中  this是  ZVueRouter
}
export default ZVueRouter



5.  $router注册


因为path 跳转 都是 this.$router.push()的写法,所以需要注册 $router

通常的方法 是 原型挂载 例如事件总线 Vue.prototype.$bus

main.js


new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

所以  Vue.prototype.$router = this.$options.router,

但是在这install函数里面 this指向的是ZVueRouter,所以拿不到 路由的配置信息

5.1 顺序问题


Vue.use(VueRouter)
const router = new VueRouter({
  routes
})

仔细分析这段代码其实 use的时候  router还没有创建呢,

所以自己模拟这块的话,也需要延迟执行

也就是需要等到router的实例创建完成之后在,执行,我们的挂载代码

嘿嘿这里怎么办呢 ,应该有不少人脑子里 蹦出来 定时器  ,或者 钩子了

5.2 解决方案 全局混入

混入文档


6.注册全局router-link  router-view组件


6.1 基本结构

顺便把上面的代码一起贴下


// 形参1是Vue的构造函数
ZVueRouter.install = function (_Vue, options) {
    // 传入构造函数 修改原型,起到扩展作用
    // 保存一下Vue实例 便于其他地方使用
    Vue = _Vue
    // install中  this是  ZVueRouter
    // 1. 注册 router
    Vue.mixin({
        beforeCreate() {
            if (this.$options.router) {
                Vue.prototype.$router = this.$options.router
            }
        }  
    })
    // 2. 注册全局组件 routerLink routerView
    Vue.component("router-link",{
        template:'<a> 跳吧</a>'
    })
    Vue.component("router-view",{
        template:'<div> 出来吧 ,神龙</div>'
    })
}


6.2  终于 可以查看界面效果了,但是报错了 哈哈

HDB{TV@@_NMM}MS`2107V6S.png


渲染函数 render

6.3 render函数结构


// 2. 注册全局组件 routerLink routerView
    Vue.component("router-link", {
        render(h) {
            return h(
                "a",
                {
                    attrs: {
                        href: '#/yzs'
                    }
                },
                "随便写点"
            )
        }
    })
    Vue.component("router-view", {
        render(h) {
            return h(
                "div",
                {},
                "神龙这次出来了吧"
            )
        }
    })

6.4 界面效果

F74`_9}0PFH8@Y@RVCA93~L.png

6.5 render函数 介绍

h就是createElement 创建 VNode 虚拟节点

h(参数1,参数2,参数3)

参数1: 渲染的 标签 ,这标签其实也可以是 组件名哦 ,

这里可以自定义组件渲染哦,所以在 iviewelementUI等框架的表格组件 经常自己写 render

参数2:主要就是标签 属性配置信息

参数3: 是标签内容, 那系统组件的话,写的时候内容又要显示我们自己的,就需要用到slot 插槽啦

6.6 render 实现 组件

Home


Vue.component("router-link", {
        // 这就是组件的传值 to属性是 使用 router-link的时候传过来的
        props:{
            to:{
                type:String,
                required:true,
            }
        },
        render(h) {
            return h(
                "a",
                {
                    attrs: {
                        href: '#'+this.to
                    }
                },
                // 标签内容是 用户传过来的 默认插槽
                this.$slots.default
            )
        }
    })

6.6.1 效果

HDB{TV@@_NMM}MS`2107V6S.png


6.6.2 扩展 jsx用法

也可以使用 JSX 支持 JSX语法就行


return  <a href={'#' + this.to}> {this.$slots.default}</a>



7 render 实现 router-view组件


7.1作用

  1. 获取路由实例
  2. 获取hash 部分 也就是path
  3. 根据path,从路由表中获取组件

7.2. 获取路由实例

1.先前 已经把路由实例 通过混入的方式 挂载到了实例上

  1. 获取路由配置信息


const router = new VueRouter({
  routes
})
  1. 这路由配置信息是通过 创建 路由实例挂载上去的
  2. 所以我们可以通过路由的 构造函数获取这个配置信息


class ZVueRouter {
    constructor(options){
        //选项中 包含路由配置信息 ,保存下 ,后边使用
        // 挂载到了 ZVueRouter
        this.$options = options;
    }
}
  1. 测试获取 路由配置信息

`@XKE@AIZX[EDFF)H}R5GRD.png


Vue.component("router-view", {
        render(h) {
            //  0获取路由实例
            console.log("配置信息",this.$router.$options)
            return h(
                "div",
                {},
                "神龙这次出来了吧"
            )
        }
    })

7.3. 获取hash 部分 也就是path

  1. 监听hashchange事件并且在变化的时候响应

1.截取下 因为 获取的是 #about 这种形式

2.初识话的 第一次进来也可能没有 哈希 所有给个默认的/

3.赋值给ZVueRouter 实例


class ZVueRouter {
    constructor(options){
        //选项中 包含路由配置信息 ,保存下 ,下边使用
        // 挂载到了 ZVueRouter
        this.$options = options;
        // 2.监听hashchange事件并且在变化的时候响应
        window.addEventListener("hashchange",()=>{
            // 1.截取下 因为 获取的是 #about 这种形式
            // 2.初识话的 第一次进来也可能没有 哈希 所有给个默认的/
            // 3.赋值给ZVueRouter 实例 
           this.current = window.location.hash.slice(1) ||"/"
           console.log("监听 hash",this.current);
        })
    }
}
7.3.1, 问题可以监听到 但是 下方的路由router-view并不会切换
7.3.2. 数据响应式

数据变化可侦听

使用这些数据的组件就会和数据产生依赖关系

当响应式数据变化的时候,组件也会变化

数据响应式的方式

1,使用new Vue() 里面的data

2.Vue.util.defineReactive()

注意 Vue.set()不行

其实set这里的第一个参数 要求就是必须是响应式的


class ZVueRouter {
    constructor(options) {
        this.$options = options;
        //  需要将current 设置为响应式的
        Vue.util.defineReactive(
            this, 
            "current", 
            window.location.hash.slice(1) || "/"
            )
        // 2.监听hashchange事件并且在变化的时候响应
            this.current = window.location.hash.slice(1) || "/"
            console.log("监听 hash", this.current);
        })
    }
}

7.3.4 router 打印


Vue.component("router-view", {
        render(h) {
            //  0获取路由实例
            console.log("配置信息-view",this.$router.current, this.$router.$options)
         return h(
                "div",
                {},
                "神龙这次出来了吧"
            )
        }
    })

7.3.5运行查看效果

来回切换 已经可以 每次都触发 router-view

2]F1%R}NK01_A`5]Y(T`{_E.png


7.4. 根据path,从路由表中获取组件


Vue.component("router-view", {
        render(h) {
            console.log("配置信息-view",this.$router.current, this.$router.$options)
            let component = null 
            const route = this.$router.$options.routes.find(
                (route)=>route.path === this.$router.current
            )
            if(route){
                component = route.component
            }
            return h(component)
        }
    })



8.纸上得来终觉浅呀


最好的学习,最好的检测自己 ,就是输出, 受益匪浅,

  1. 目录结构

    `@XKE@AIZX[EDFF)H}R5GRD.png
  2. index.js 修改下引用


import VueRouter from './zvue-router'
  1. 主文件 zvue-router.js


let Vue
class ZVueRouter {
    constructor(options) {
        //选项中 包含路由配置信息 ,保存下 ,下边使用
        // 挂载到了 ZVueRouter
        this.$options = options;
        //  需要将current 设置为响应式的
        Vue.util.defineReactive(
            this, 
            "current", 
            window.location.hash.slice(1) || "/"
            )
        // 2.监听hashchange事件并且在变化的时候响应
        window.addEventListener("hashchange", () => {
            this.current = window.location.hash.slice(1) || "/"
            console.log("监听 hash", this.current);
        })
    }
}
// 形参1是Vue的构造函数
ZVueRouter.install = function (_Vue, options) {
    // 传入构造函数 修改原型,起到扩展作用
    // 保存一下Vue实例 便于其他地方使用
    Vue = _Vue
    // install中  this是  ZVueRouter
    Vue.mixin({
        beforeCreate() {
            if (this.$options.router) {
                Vue.prototype.$router = this.$options.router
            }
        }
    })
    // 2. 注册全局组件 routerLink routerView
    Vue.component("router-link", {
        // 这就是组件的传值 to属性是 使用 router-link的时候传过来的
        props: {
            to: {
                type: String,
                required: true,
            }
        },
        render(h) {
            // 这里也支持JSX语法
            // return  <a href={'#' + this.to}> {this.$slots.default}</a>
            return h(
                "a",
                {
                    attrs: {
                        href: '#' + this.to
                    }
                },
                // 标签内容是 用户传过来的
                // <router-link to="/">Home</router-link> |
                this.$slots.default
            )
        }
    })
    Vue.component("router-view", {
        render(h) {
            console.log("配置信息-view",this.$router.current, this.$router.$options)
            let component = null 
            const route = this.$router.$options.routes.find(
                (route)=>route.path === this.$router.current
            )
            if(route){
                component = route.component
            }
            return h(component)
        }
    })
}
export default ZVueRouter




相关文章
|
1天前
|
JavaScript
vue知识点
vue知识点
14 6
|
22小时前
|
分布式计算 资源调度 JavaScript
程序员必知:vue项目创建和启动、ElementUI的安装和快速学习
程序员必知:vue项目创建和启动、ElementUI的安装和快速学习
|
22小时前
|
JavaScript
vue基础概念(1)
vue基础概念(1)
6 0
|
1天前
|
JavaScript API 网络架构
Vue3路由机制router(2)
Vue3路由机制router(2)
7 0
|
1天前
|
安全 定位技术 数据安全/隐私保护
Vue3路由机制router(1)
Vue3路由机制router(1)
4 0
|
1天前
|
JavaScript
vue父子组件传值,父组件内容更新子组件内容不实时更新
vue父子组件传值,父组件内容更新子组件内容不实时更新
5 0
|
1天前
|
前端开发 JavaScript
vue+el-select下拉多选实现,全选,反选,清空功能源码
vue+el-select下拉多选实现,全选,反选,清空功能源码
4 0
|
1天前
|
JavaScript 前端开发
脚手架vue-cli自定义创建Vue项目,完整详细步骤!
脚手架vue-cli自定义创建Vue项目,完整详细步骤!
|
1天前
|
JavaScript 网络架构
vue路由跳转之【编程式导航与传参】
vue路由跳转之【编程式导航与传参】
|
1天前
|
JavaScript
vue路由从入门到进阶 --- 路由重定向与404等问题
vue路由从入门到进阶 --- 路由重定向与404等问题