• 手写vue路由


    一、简易demo
    // routes注册
    import Vue from "vue";
    // import VueRouter from "vue-router";
    import VueRouter from "./vueRouter"; // 自定义路由 js
    import Home from "../views/Home.vue";
    
    Vue.use(VueRouter);
    
    const routes = [
      {
        path: "/",
        name: "Home",
        component: Home,
      },
      {
        path: "/about",
        name: "About",
        // route level code-splitting
        // this generates a separate chunk (about.[hash].js) for this route
        // which is lazy-loaded when the route is visited.
        component: () =>
          import(/* webpackChunkName: "about" */ "../views/About.vue"),
      },
    ];
    
    const router = new VueRouter({
      mode: "history",
      routes,
    });
    
    export default router;
    
    // vueRouter
    var _Vue = null
    
    export default class VueRouter {
      // 一、 install方法
      static install(Vue) {
        // 1、判断插件是否注册
        if (VueRouter.install.installed) return
        VueRouter.install.installed = true
    
        // 2、将Vue构造函数记录到全局变量
        _Vue = Vue
    
        // 3、把创建Vue实例的时候传入的router对象注入到Vue实例上
        // _Vue.prototype.$router = this.$options.router;
        // 混入
        _Vue.mixin({
          beforeCreate() {
            if (this.$options.router) {
              _Vue.prototype.$router = this.$options.router
              this.$options.router.init() // ?
            }
          }
        })
      }
    
      //  二、构造函数
      constructor(options) {
        this.options = options
        this.routeMap = {}
        this.data = _Vue.observable({
          current: '/'
        })
      }
    
      init() {
        this.createRouteMap()
        this.initComponents(_Vue)
        this.initEvent()
      }
    
      //   三、createRouteMap
      createRouteMap() {
        //   遍历所有的路由规则,把路由规则解析成键值对,保存在routeMap中
        this.options.routes.forEach(route => {
          this.routeMap[route.path] = route.component
        })
      }
    
      //   四、initComponents
      initComponents(Vue) {
        Vue.component('router-link', {
          props: {
            to: String
          },
          //   template: '<a :href="to"><slot></slot></a>'
          render(h) {
            return h(
              'a',
              {
                attrs: {
                  href: this.to
                },
                on: {
                  click: this.clickHandler
                }
              },
              [this.$slots.default]
            )
          },
          methods: {
            clickHandler(e) {
              history.pushState({}, '', this.to) // 修改地址栏 - 不会发送请求
              this.$router.data.current = this.to // 重新加载响应的组件
              e.preventDefault() // 阻止发送请求
            }
          }
        })
    
        const self = this
        Vue.component('router-view', {
          render(h) {
            let component = self.routeMap[self.data.current]
            return h(component)
          }
        })
      }
    
      //   五、返回按钮、前进按钮问题
      initEvent() {
        window.addEventListener('popstate', () => {
          this.data.current = window.location.pathname
        })
      }
    }
    
    二、Vue-Router传参方式

    一、普通、动态路由传参方式

    // 路由代码传参
    import About from 'about'
    // routes 配置
    {
      path: '/about/:id', // 动态路由
      component: About,
      props: true // ①布尔模式
    }
    
    {
      path: '/about', // 普通路由
      component: 'About',
      props: { id: 19 } // ②对象模式
    }
    
    // 接收方式 props
    props;['id'] 或者
    props: {
      id: { type: Number, default: 12}
    }
    // ③函数模式
    routes:[
      {
        path: '/about',
        component: About,
        // props: route => ({id:route.query.id}) // url='/about?id="89"' 或者
        props: route => ({id: route.params.id}) // url='/about/:id' => '/about/89'
      }
    ]
    

    二、动态路由:将给定匹配模式的路由映射到同一个组件,复用一个组件,相对与销毁后重建更高效。

    • Keep-alive包括时,组件的声明周期钩子函数不会被重复调用。

    • 要对同一个组件中参数变化做出响应的话,可以通过watch 侦听$route对象上的任意属性

      watch: {
        $route: {
          immediate: true,
          handler(route) {
            // 处理事件 对路由变化做出响应
          }
        }
      }
      
    • 或者使用导航守卫,beforeRouteUpdate,也可以取消导航

    三、捕获所有路由或404路由

    四、路由的匹配语法

    • 自定义正则 像可以区分 /list/100 和/list/xsk 等路由

      • routes: [ { path: '/list/:id(\\d+)'}, {path: '/list/:name'} ]
    • 可以重复的参数 匹配多个部分的路由,可以用 * 号和 +号将参数标记为重复

    • 也可通过使用?号修饰符(0个或1个)将一个参数标记为可选

    五、嵌套路由、命名路由

    六、编程式导航

    • 声明式()\编程式路由 router.push(...)

    • Router.push(params):

      • Params: 字符串路径、路径对象、命名的路由并加上参数、带查询参数、带hash

      •   '/users/detail'
          { path: '/users/detail' }
          { name: 'detail', params: {id: '0'}}
          { path: '/users/detail', query: {id: '0'} }
        
    • 替换当前位置 router.replace({path: '/users'}) 或者router.push({path:'users', replace: true}); 导航时不会向history添加记录

    • history.go()横跨历史

    七、命名视图:

    八、重定向配置

    // 通过routes配置来完成
    const routes = [{ path: '/home', redirect: '/'}]
    // 重定向的目标也可以是一个命名的路由  redirect: { name: 'Details'}
    // 一个方法动态返回重定向目标
    const routes = [
      {
        path: '/home/:id',
        redirect: to => {
          return {path:'Details', query: { q: to.params.searchText}}
        }
      }
    ]
    // 别名
    alias: '/home'
    

    九、路由组件传参 props、$route.query$route.params

    • 布尔模式 routes配置时 props:true设置即可

    • 对象模式 props: { id: '0' } 当props为静态的时候很有用

    • 函数模式 创建一个返回props的函数,允许你将参数转换为其他类型,将静态值与基于路由的值相结合等操作

      props: route => ({ query: route.query.id })
      props: route => ({ params: route.params.id})
      
    • 对于命名视图的路由,必须为每个命名视图定义props配置

      const routes = [{
        path: '/home',
        components: { default: Home, sidebar: Sidebar},
        props: { default: true, sidebar: true}
      }]
      

    十、不同的历史模式

    • Hash模式:history: createWebHashHistory() SEO受影响
    • HTML5模式:history:createWbeHistory() 如果没有适当的服务器配置,就会404,需要在服务器上添加一个简单的回退路由
    三、进阶-路由导航

    一、导航守卫:vue-router提供的主要是通过跳转或取消的方式守卫导航。

    • 方式:全局、单个路由独享、组件

    • 全局前置守卫:beforeEnter:

      • 每个守卫都接收两个__参数__:to\from\next(可选)
      • 返回值 ①false:取消当前导航、②一个路由地址:通过一个路由地址跳转到不同的地址,类似于router.push()可配置,当前的 导航被中断然后进行一个新的导航。
      • next可选参数
    • 全局后置守卫:afterEach 不接受next函数也不会改变导航本身

    • 全局解析守卫:beforeResolve

    • 路由独享守卫:在routes中配置

    • 组件内的守卫 可用配置API:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave

      • beforeRouteEnter:唯一可传递next回调守卫;解决不可访问this;
      • next()里的内容执行时机在组件mounted周期之前;
      • beforeRouteUpdate: 该组件复用时被调用
  • 相关阅读:
    通信行业的必备网站
    资源变现小程序开通流量主教程
    CI/CD 编译golang项目依赖包使用自建的gitlab仓库 免密码配置
    C专家编程 第5章 对链接的思考 5.1 函数库、链接和载入
    flutter 常用组件:列表ListView
    npm 与 yarn 命令比较
    设计模式:外观模式 导诊台。空指针异常
    API调用,淘宝天猫、1688、京东、拼多多各平台获得淘宝商品详情
    Web前端入门(十三)CSS复合选择器
    浅谈模拟退火
  • 原文地址:https://www.cnblogs.com/xsk-walter/p/16275016.html