飞道的博客

手写vue-router源码

244人阅读  评论(0)

一、项目准备

创建vue项目

vue create projectName

进入项目

cd projectName

安装vue-router

vue add router

手写vue-router:在router文件夹中创建jvue-router.js文件。

将index.js文件中引入VueRouter地址改为jvue-router.js的地址


  
  1. // import VueRouter from "vue-router";
  2. import VueRouter from "./jvue-router";

 

二、手写vue-router源码

1在router/index.js中使用VueRouter时是new VueRouter(),所以要创建一个VueRouter类并暴露出来,同时vue插件都要有一个install进行初始化,install中的参数为vue,保存起来以便后面使用。


  
  1. let Vue;
  2. class VueRouter {
  3. constructor() {}
  4. }
  5. VueRouter.install = function(_vue) {
  6. Vue = _vue;
  7. }
  8. export default VueRouter;

2.在组件中,我们是直接使用<router-link>和<router-view>两个组件,所以install方法中注册这两个组件


  
  1. let Vue;
  2. class VueRouter {
  3. constructor() {}
  4. }
  5. VueRouter.install = function(_vue) {
  6. Vue = _vue;
  7. // 注册router-view和router-link
  8. Vue.component( 'router-view', {
  9. render(h) {
  10. return h( 'div', 'router-view')
  11. }
  12. })
  13. Vue.component( 'router-link', {
  14. render(h) {
  15. return h( 'a', 'router-link')
  16. }
  17. })
  18. }
  19. export default VueRouter;

3.先分析router-link组件:

使用时我们会传入一个to属性表示链接路径:

<router-link to="/about">About组件</router-link>

 编译后是一个a标签和href属性,href属性的值为上面to属性的值:

<a href="/about">About组件</a>

所以我们注册router-link组件时应先用props获取to属性值,用$slots获取插值文本


  
  1. let Vue;
  2. class VueRouter {
  3. constructor() {}
  4. }
  5. VueRouter.install = function(_vue) {
  6. Vue = _vue;
  7. // 注册router-view
  8. Vue.component( 'router-view', {
  9. render(h) {
  10. return h( 'div', 'router-view')
  11. }
  12. })
  13. // 注册router-link
  14. Vue.component( 'router-link', {
  15. props: {
  16. to: {
  17. type: String,
  18. required: true
  19. }
  20. },
  21. render(h) {
  22. return h( "a", { attrs: { href: "#" + this.to } }, this.$slots.default);
  23. }
  24. })
  25. }
  26. export default VueRouter;

4.分析router-view组件:

获取当前hash并将其设为响应式数据,监听url变化。由于是响应式数据,所以当hash变化时,相应的组件会重新渲染。

获取路由映射表,根据当前hash在映射表中找到对应的组件,并渲染。

由于组件中使用router时是this.$router形式,所以要将router挂载到Vue原型链上。此时可以在Vue组件中获取到router和routes。

因为VueRouter执行install时Vue实例还没有创建(详见main.js),所以要使用混入的方式,在beforeCreate时再挂载。

路由映射表是在创建路由实例时传入(./router/index.js):


  
  1. const routes = [
  2. {
  3. path: "/",
  4. name: "Home",
  5. component: Home
  6. },
  7. {
  8. path: "/about",
  9. name: "About",
  10. // route level code-splitting
  11. // this generates a separate chunk (about.[hash].js) for this route
  12. // which is lazy-loaded when the route is visited.
  13. component: () =>
  14. import( /* webpackChunkName: "about" */ "../views/About.vue")
  15. }
  16. ];
  17. const router = new VueRouter({
  18. routes
  19. });

对应代码:


  
  1. // 设置vue以便后面使用
  2. let Vue;
  3. class VueRouter {
  4. constructor(options) {
  5. this.options = options;
  6. // 初始化current,设置current为响应式数据,当current改变时重新渲染页面
  7. Vue.util.defineReactive(
  8. this,
  9. "current",
  10. window.location.hash.slice( 1) || "/"
  11. );
  12. console.log(Vue.util);
  13. // 监听url变化,重置current
  14. window.addEventListener( "hashchange", () => {
  15. this.current = window.location.hash.slice( 1);
  16. console.log( this.current);
  17. });
  18. }
  19. }
  20. // vue插件都要有install方法:注册router-link和router-view两个组件 使得我们在组件中使用时可以<router-view>,将router挂载到Vue原型链上,使得我们在组件中使用时可以this.$router
  21. VueRouter.install = function(_vue) {
  22. Vue = _vue;
  23. console.log(_vue);
  24. // 将router挂载到Vue原型链上
  25. // 因为VueRouter执行install时Vue实例还没有创建(详见main.js),所以要使用混入的方式,在beforeCreate时再挂载
  26. Vue.mixin({
  27. beforeCreate() {
  28. // 判断当前组件是否为根组件,只有根组件有$router
  29. // 因为根组件的vue实例创建时传入了vueRouter实例,vue组件中获取传入的参数可使用this.$options,所以获取传入的vueRouter实例可以用this.$options.router
  30. if ( this.$options.router) {
  31. Vue.prototype.$router = this.$options.router;
  32. }
  33. }
  34. });
  35. // 注册router-view
  36. // 根据当前hash找到对应component
  37. // hash:window.location.hash.slice(1)
  38. // 获取路由映射表:VueRouter在创建实例时传入了路由映射表,所以从VueRouter初始化中获取
  39. Vue.component( "router-view", {
  40. render(h) {
  41. const { current, options } = this.$router;
  42. let component = null;
  43. const route = options.routes.find( route => route.path === current);
  44. if (route) {
  45. component = route.component;
  46. }
  47. return h(component);
  48. }
  49. });
  50. // 注册router-link
  51. Vue.component( "router-link", {
  52. props: {
  53. to: {
  54. type: String,
  55. required: true
  56. }
  57. },
  58. render(h) {
  59. return h( "a", { attrs: { href: "#" + this.to } }, this.$slots.default);
  60. }
  61. });
  62. };
  63. export default VueRouter;

 


转载:https://blog.csdn.net/MiemieWan/article/details/116456199
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场