|

Aimee

Write the Code. Change the World.

vue2.0 router及简易实现

· 分享镜#vue

分类

hash

  • URL中 # 后面的内容作为路径地址
  • hash的模式是基于锚点,以及onhashchange 事件
  • 根据当前路由地址找到对应组件重新渲染

history

  • history 模式是基于html5中的history api
  • history.pushState() ie10 以后才支持
  • history.replaceState()
  • 通过history.pushState()方法改变地址栏
  • 监听popstate 事件
  • 根据当前路由地址找到对应组件重新渲染

服务端配置history

express配置

const path = require('path')
const history = require('connect-history-api-fallback')
const express = require('express')

const app = express()
// 注册处理history 模式的中间件
app.use(history())
// 处理金泰资源的中间件,网站根目录 ../web
app.use(express.static(path.join(__dirname, '../web')))

app.listen(3000, ()=>{
 console.log('服务器开启,端口:3000')
})

nginx 配置

server{
 ...
 location / {
 	 root html;
   index index.html index.html;
   try_files $uri $uri/ index.html;
 }
 ...
}

history 实现

简易版说明

  • 只支持routes 参数
  • 只支持router-link 和router-view 组件
  • 不支持push replace 等功能

实现

  • 写一个VueRouter class类
  • 提供静态 install 方法
    • 接受一个Vue参数
    • 判断当前 router是否已经被安装
    • 把Vue的构造函数记录在全局
    • 把创建Vue的实例传入的router对象 注入到Vue实例中
      • 使用mixin的方式注入
      • 在beforeCreate 钩子中注入
  • 提供构造函数constructor 处理参数和初始化
    • 初始化参数options
    • 将routes存放在routeMap中
    • 记录当前的current, 并设置为响应式
      • 通过Vue.observable来实现
    • 初始化组件信息
  • 处理组件 router-link 和router-view 注册为全局组件
    • router-link
      • 处理router-link 组件 接受一个参数to
      • router-link即为a标签,to即为href的参数
      • 拦截a标签的onClick事件,将history中pushState 记录跳转记录
      • 设置当前的current为to的值
    • router-view
      • 处理router-view 组件
      • router-view组件,用于展示当前路由的对应的component内容
      • 获取当前的current,通过routerMap获取对应的component
      • render 函数中return component vnode
      • 由于current 是响应式的,router-view中的render 会实时 获取最新的component来渲染
  • 处理监听事件
    • 由于router-link中 点击的时候,在history中添加了state,浏览器会根据hsitory的state自动处理前进和后退箭头
    • 箭头浏览器的前进后退事件及popstate,重新设置对应的current
    • 触发了router-view中component的渲染
let _Vue = null;
export default class VueRouter {
  static install(Vue) {
    //1 判断当前插件是否被安装
    if (VueRouter.install.installed) {
      return
    }

    VueRouter.install.installed = true
    //2 把Vue的构造函数记录在全局
    _Vue = Vue
    //3 把创建Vue的实例传入的router对象注入到Vue实例
    _Vue.mixin({
      beforeCreate() {
        if (this.$options.router) {
          _Vue.prototype.$router = this.$options.router
        }
      },
    })

  }
  constructor(options) {
    // 初始化参数
    this.options = options;
    // 将routes 存放在routeMap中
    this.routeMap = {}
    // 记录当前的current,并设置为响应式
    this.data = _Vue.observable({
      current: '/'
    })
    this.init()
  }
  init() {
    this.createRouteMap()
    this.initComponent(_Vue)
    this.initEvent()
  }
  // 创建routeMap的数据
  createRouteMap() {
    this.options.routes.forEach(item => {
      this.routeMap[item.path] = item.component
    })
  }
  // 处理组件
  initComponent(Vue) {
    Vue.component('router-link', {
      props: {
        to: String
      },
      render(h) {
        console.log('this.$slots.default', this.$slots.default)
        return h('a', {
          attrs: {
            href: this.to
          },
          on: {
            click: this.clickhander
          }
        }, [this.$slots.default])
      },
      methods: {
        clickhander(e) {
          e.preventDefault();
          history.pushState({}, '', this.to)
          this.$router.data.current = this.to
        }
      }
    })


    Vue.component("router-view", {
      render: (h) => {
        const cm = this.routeMap[this.data.current]
        return h(cm)
      }
    })
  }
  // 监听事件 替换的current
  initEvent() {
    window.addEventListener('popstate', () => {
      this.data.current = window.location.pathname
    })
  }
}

hash实现

简易版说明

  • 只支持routes参数
  • 只支持router-link和router-view组件
  • 不支持push replace等功能

实现

  • 和history实现整理类似, 可以继续使用history的模式
  • 或者通过hashchange监听路由变化,设置current的值
 window.addEventListener('hashchange', () => {
   this.data.current = window.location.hash
 })
let _Vue = null;
export default class VueRouter {
  static install(Vue) {
    //1 判断当前插件是否被安装
    if (VueRouter.install.installed) {
      return
    }

    VueRouter.install.installed = true
    //2 把Vue的构造函数记录在全局
    _Vue = Vue
    //3 把创建Vue的实例传入的router对象注入到Vue实例
    _Vue.mixin({
      beforeCreate() {
        if (this.$options.router) {
          _Vue.prototype.$router = this.$options.router
        }
      },
    })

  }
  constructor(options) {
    // 初始化参数
    this.options = options;
    // 将routes 存放在routeMap中
    this.routeMap = {}
    // 记录当前的current,并设置为响应式
    this.data = _Vue.observable({
      current: '#/'
    })
    this.init()
  }
  init() {
    this.createRouteMap()
    this.initComponent(_Vue)
    this.initEvent()
  }
  // 创建routeMap的数据
  createRouteMap() {
    this.options.routes.forEach(item => {
      this.routeMap[item.path] = item.component
    })
  }
  // 处理组件
  initComponent(Vue) {
    Vue.component('router-link', {
      props: {
        to: String
      },
      render(h) {
        return h('a', {
          attrs: {
            href: this.to
          },
          on: {
            click: this.clickhander
          }
        }, [this.$slots.default])
      },
      methods: {
        clickhander() {
          this.$router.data.current = this.to
        }
      }
    })


    Vue.component("router-view", {
      render: (h) => {
        const cm = this.routeMap[this.data.current]
        return h(cm)
      }
    })
  }
  // 监听事件 替换的current
  initEvent() {
    // window.addEventListener('popstate', () => {
    //   this.data.current = window.location.hash
    // })

    window.addEventListener('hashchange', () => {
      console.log(window.location)
      this.data.current = window.location.hash
    })

  }
}

评论1

登录后参与评论。

  • 游客

    解决

回到顶部