• Vue源码学习(十九):router基本原理


    好家伙,

     

    0.什么是路由?

    路由就是匹配到对应路径显示对应的组件

    那么我们要如何去实现?

     

    我们来回忆一下这router怎么用的

    1. 声明式路由配置:在路由配置对象中,定义路径与组件的映射关系。例如:
    复制代码
    import AboutComponent from '../views/AboutComponent.vue'
    
    const routes = [
      { path: '/', component: HomeComponent },
      { path: '/about', component: AboutComponent },
      { path: '/user/:id', component: UserComponent },
    ];
    复制代码

     

    2. 安装路由插件:在 Vue 根实例中,使用 `Vue.use()` 方法安装 vue-router 插件,
    并将路由实例注入到根实例中。
    复制代码
    import Vue from 'vue';
    import VueRouter from 'vue-router';
    
    
    Vue.use(VueRouter);
    复制代码

     

    3. 创建 router 实例:根据路由配置对象创建一个 VueRouter 实例。
    复制代码
    const router = new VueRouter({
      routes,
      mode: 'history',
      base: '',
    });
    复制代码

     

    4. 挂载路由:将创建的 router 实例挂载到 Vue 应用上。
    new Vue({
      router,
      render: (h) => h(App),
    }).mount('#app');

     

    5. 在组件中使用 ``:在需要显示路由组件的页面中,
    使用 `` 标签。该标签会根据当前路由自动渲染对应的组件。
    复制代码
    复制代码

     

    
    6. 导航:通过调用 router 实例的方法(如 `router.push()`)实现页面跳转。当用户访问不同的路径时,vue-router 会根据路由配置自动渲染对应的组件。

    图例:

     也就是说如果我点击了about,就对应跳到/about,并在下方展示这个路径对应的组件

    于是我们目标明确了,事实上,我们只需要解决三个问题

    1.router-link的实现

    2.router-view的实现

    3.路径到组件的映射关系的实现

     

     

     目录结构如下:

    1.router-link的实现

    routerLink.jsx

    复制代码
      //组件
      export default{
        props:{ //组件的属性
          to:{
            type:String,
            required:true
          },
          tag:{
            type:String
          }
        },
        
      //jsx  
      render(){
        let tag = this.tag || 'a'
        //跳转
        console.log(tag,666)
        let handler = ()=>{
           this.$router.push(this.to)
        }
          return {this.$slots.default}//jsx  {变量}
      }
    }
    复制代码

     

    2.router-view的实现

    routerView.js

    复制代码
    export default {
        functional: true,
        // 函数式组件
        render(h, { parent, data }) { // 1 h  2 属性
            //1 获取到组件
            let route = parent.$route // 获取到route
            // this match  component
            // 2问题  嵌套  /about/a :[about, a]  routerView
            data.routerView = true
            let depath = 0
            while (parent) {
                // $vnode 相当于一个 占位符   
                if (parent.$vnode && parent.$vnode.data.routerView) {
                    depath++
                }
                parent = parent.$parent //一直寻找父亲
            }
            let recode = route.metched[0].metched[depath]
    
            if (!recode) {
                return h() //
            }
            return h(recode.component, data)
        }
    }
    复制代码

     

    3.路径到组件的映射关系的实现

    index.js

    复制代码
    export default class VueRouter {
        constructor(options = {}) {
            //   vue-router 核心 1 match核心  [{},{}]  => {'/':{组件相关信息},'/about':{}}
            console.log(options.routes,'this is options.routes')
            this.match = createMatch(options.routes || [])
            this.beforeHooks= []
            // 核心二:浏览器路由管理  
            // 1;获取模式
            options.mode = options.mode || 'hash'
            //进行判断
            switch (options.mode) {
                case 'hash':
                    this.history = new HashHistory(this)
                    break;
                case 'history':
                    this.history = new HtmlHistory(this)
                    break
            }
            console.log(this.history)
        }
    复制代码

     

    createMatch.js

    复制代码
    export function createMatch(routes) { //匹配器
       //1变成一个路由映射表   [{},{}]  => {'/':{组件相关信息},'/about':{},/about/c:{}}
       const  pathMap  = createRouterMap(routes)
       //2addRoutes 动态添加路由
       // addRoutes(routes)
       function addRoutes(routes) { // 1:用户自己动态的路由  2
          // 注意需要合并在一起
    
          createRouterMap(routes, pathMap)
       }
    
    /.
    .
    .
    ./
    }
    复制代码

     

    createRouterMap.js

     

    `createRouterMap` 函数用于创建路径映射对象

     

    复制代码
    export function createRouterMap(routes,routerOptions={}) {
        // console.log(routes,5556)
        let pathMap = routerOptions
        routes.forEach(router => {
            //[{path:'/},{}]  => {'/':{组件相关信息},'/about':{},/about/a:{}}
            console.log(router, pathMap,'||this is router, pathMap')
            addRouterRecode(router, pathMap)
        })
        //  console.log(pathMap)
         //问题 路由嵌套 /about/a
         return pathMap
    }
    
    
    function addRouterRecode(router, pathMap,parent) {
        // 1路径 /  记录
    
        let path = parent ?`${parent.path}/${router.path}`:router.path
        let recode = {
            path: router.path,
            name: router.name,
            component: router.component,
            parent
        }
        //添加
        if (!pathMap[path]) {
            pathMap[path] = recode
        }
        //有没有儿子
        if(router.children){
            //递归
            router.children.forEach(child=>{
                //注意 parent 
                addRouterRecode(child, pathMap,recode)
            })
        }
    }
    复制代码

    对于以上createRouterMap方法,举个例子
    复制代码
    const routes = [
      {
        path: '/',
        name: 'Home',
        component: HomeComponent
      },
      {
        path: '/about',
        name: 'About',
        component: AboutComponent,
        children: [
          {
            path: 'contact',
            name: 'Contact',
            component: ContactComponent
          }
        ]
      }
    ];
    
    const routerOptions = {
      base: '/'
    };
    
    const pathMap = createRouterMap(routes, routerOptions);
    
    得到结果
    
    {
      '/': {
        path: '/',
        name: 'Home',
        component: HomeComponent,
        parent: null
      },
      '/about': {
        path: '/about',
        name: 'About',
        component: AboutComponent,
        parent: '/'
      },
      '/about/contact': {
        path: '/about/contact',
        name: 'Contact',
        component: ContactComponent,
        parent: '/about'
      }
    }
    复制代码

     












  • 相关阅读:
    【HTML5】调查问卷制作简约版
    关于服装ERP,你想知道的都在这里了
    PCM格式图解
    IntelliJ IDEA 本地springBoot项目导入到gitlab管理
    设计模式:适配器模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)
    【ICer的脚本练习】tcl语法熟悉和工具tcl的实例
    vue3的生命周期
    面试系列多线程:核心参数设置多少合适
    Gitea 仓库事件触发Jenkins远程构建
    虽然webpack4以后。webpack 可以不用再引入一个配置文件来打包项目,但还是梳理常用配置信息
  • 原文地址:https://www.cnblogs.com/FatTiger4399/p/17958178