{"id":25098369,"url":"https://github.com/supercll/cvue-router","last_synced_at":"2025-04-02T04:10:43.077Z","repository":{"id":124739240,"uuid":"300542867","full_name":"supercll/cvue-router","owner":"supercll","description":"learn how to implement vue-router","archived":false,"fork":false,"pushed_at":"2020-10-02T07:58:19.000Z","size":82,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-07T18:51:36.181Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/supercll.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-10-02T07:57:34.000Z","updated_at":"2020-10-02T07:58:22.000Z","dependencies_parsed_at":null,"dependency_job_id":"a778cdf8-34c9-48e9-ae50-0b95458d373d","html_url":"https://github.com/supercll/cvue-router","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supercll%2Fcvue-router","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supercll%2Fcvue-router/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supercll%2Fcvue-router/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supercll%2Fcvue-router/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/supercll","download_url":"https://codeload.github.com/supercll/cvue-router/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246752656,"owners_count":20827987,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-02-07T18:31:16.568Z","updated_at":"2025-04-02T04:10:43.065Z","avatar_url":"https://github.com/supercll.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# vue-router源码实现\n\nVue Router 是 Vue.js 官⽅的路由管理器。\n它和 Vue.js 的核⼼深度集成，让构建单⻚⾯应⽤变得容易\n单⻚⾯应⽤程序中，url发⽣变化时候，不能刷新，显示对应视图内容\n# 需求分析\n\n1. spa ⻚⾯不能刷新\n1. hash模式： #/about\n1. History模式 api /about\n1. 根据url显示对应的内容\n1. router-view\n1. 数据响应式：current变量持有url地址，⼀旦变化，动态重新执⾏render\n\n# vue-router的基本使用\n\n1. 安装vue-router插件\n```javascript\nimport Router from 'vue-router'\nVue.use(Router)\n```\n\n2. 创建Router实例\n```javascript\nexport default new Router({...})\n```\n\n3. 在根组件添加Router实例\n```javascript\nimport router from './router'\nnew Vue({\n router,\n}).$mount(\"#app\");\n```\n\n4. 添加路由视图\n```vue\n\u003crouter-view\u003e\u003c/router-view\n```\n\n5. 添加路由导航\n```vue\n\u003crouter-link to=\"/\"\u003eHome\u003c/router-link\u003e\n\u003crouter-link to=\"/about\"\u003eAbout\u003c/router-link\u003e\n```\n\n6. 使用路由信息\n```javascript\nthis.$router.push('/')\nthis.$router.push('/about'\n```\n# 插件的实现\n## use方法的过程\n\n1. 调用install方法\n1. 给vue原型挂载插件属性\n1. 注册需要的组件\n## 创建VueRouter类和install⽅法\n```javascript\nconst Vue; // 声明一个全局变量，存储构造函数，VueRouter中要用\n\nclass VueRouter {\n    constructor(options) {\n        this.$options = options\n    }\n}\n\n// 插件：实现install方法，注册$router\n// 为什么要⽤混⼊⽅式写？主要原因是use方法执行在Router实例创建之前，⽽install逻辑⼜需要⽤到该实例\nVueRouter.install = function(_Vue) {\n    // 引用构造函数，VueRouter中使用\n    Vue = _Vue;\n\n    // 1. 挂载$router\n    Vue.mixin({\n        beforeCreate() {\n            // 只有根组件有router选项\n            if (this.$options.router) {\n                Vue.prototype.$router = this.$options.router;\n            }\n        },\n    })\n\n}\n```\n### 为什么要使用混入mixin？\n主要原因是use方法执行在Router实例创建之前，⽽install逻辑⼜需要⽤到该实例，所以作用就是延迟逻辑到router创建完毕并且挂载到选项时才执行use\n### 为什么只有根组件有router选项？\n当根组件具备router的时候，才会将这个组件的所有实例都赋予路由信息（赋给vue的原型）\n### 为什么需要全局变量Vue\n\n\n\n\n## 实现全局组件router-link、router-view\n### router-link\n```javascript\nvue.component(\"router-link\", {\n    props: {\n        to: {\n            type: String,\n            required: true,\n        },\n    },\n    render(h) {\n        // 可以使用jsx，但是不推荐，因为性能低于render渲染成虚拟dom\n        return h(\n            \"a\",\n            {\n                attr: {\n                    href: \"#\" + this.to,\n                },\n            },\n            this.$slots.default\n        );\n    },\n});\n```\n\n\n### 监控**url**变化\n```javascript\nclass VueRouter {\n    constructor(options) {\n        // 保存当前选项\n        this.$options = options;\n        this.current = \"/\";\n        window.addEventListener(\"hashchange\", () =\u003e {\n            console.log(this.current);\n            this.current = window.location.hash.slice(1);\n        });\n    }\n}\n```\n### router-view动态获取路由对应组件\n```javascript\n    Vue.component(\"router-view\", {\n        render(h) {\n            // 获取当前路由对应的组件\n            let component = null;\n            const route = this.$router.$options.routes.find(\n                route =\u003e route.path === this.$router.current\n            );\n            if (route) {\n                component = route.component;\n            }\n            console.log(this.$router.current, component);\n\n            return h(component);\n        },\n    });\n```\n如何将数据与视图变为响应式的？\n### 利用 Vue.util.defineReactive方法将路由数据变为响应式\n\n\n```javascript\nclass VueRouter {\n    constructor(options) {\n        // 保存当前选项\n        this.$options = options;\n        const initial = window.location.hash.slice(1) || \"/\";\n        Vue.util.defineReactive(this, \"current\", initial);\n        window.addEventListener(\"hashchange\", () =\u003e {\n            console.log(this.current);\n            this.current = window.location.hash.slice(1);\n        });\n    }\n```\n### 要点\n\n1. router-link组件中使用this.$slots.default插入对应路由\n1. 利用hashchange监听路由变化\n1. router-view动态获取对应组件\n1. 利用**Vue.util.defineReactive**将路由属性变为响应式属性\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsupercll%2Fcvue-router","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsupercll%2Fcvue-router","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsupercll%2Fcvue-router/lists"}