大前端 - Vue-Router

编程式导航


// 将新的路由推入 history 中,history.length + 1
this.$router.push()


// 用新的路由替换掉当前 histroy 中的末尾项
this.$router.replace()

// 在 history 数组中,前进回退
// + 前进    - 后退
this.$router.go(-1)

hash 模式


  • URL中带有 # 标识,如:https://music.163.com/#/playlist?id=202
  • URL 中 # 后面的内容作为路径地址
  • 基于锚点,以及 onhashchange 事件
  • 当锚点变化时,触发 onhashchange 事件,根据当前路由地址找到对应组件,重新渲染、更新页面

history 模式


概述

  • 链接更为简洁,如:https://music.163.com/playlist/202
  • 基于 HTML5 中的 History API
    • history.pushState()
    • history.replaceState()
  • 监听 popstate 事件
  • 根据当前路由地址找到对应组件重新渲染

使用事项

  • 需要服务器的支持
  • 在服务端应该除了静态资源外都返回单页应用的 index.html
    • 单页应用中,服务端只有一个 index.html 页面
    • 单页应用中,服务端不存在 http://www.test.com/login 这样的地址,若未进行配置,则会因为找不到该页面对应的文件,返回 404

实现原理


分析

属性

options

记录构造函数中传入的对象

data

响应式对象

包含属性 current,用于记录当前地址

routeMap

记录路由地址和组件的对应关系

方法

Constructor(Options): VueRouter

install(Vue): void

静态方法,用于实现 Vue 的插件机制

init(): void

用于调用后边的 3 个方法

initEvent(): void

用于注册 popState(),监听浏览器历史变化

createRouteMap(): void

由于初始化 routeMap,将构造函数中的路由规则转化为键值对的形式,存储到 routeMap 中

initComponents(vue): void

用于创建 <route-link> 和 <route-view>

实现示例

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) { // 判断是组件还是实例,组件的 $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() {
        // 遍历所有的路由规则,将路由规则解析成键值对的形式,存储到 routeMap 中
        this.options.routes.forEach(route => {
            this.routeMap[route.path] = route.component
        })
    }

    initComponents(Vue) {
        Vue.component('router-link', {
            props: {
                to: String
            },
            // 运行时版本实现方案
            /*
            *   h() 有 Vue 传递进来
            *   h() 可传入 3个参数
            *       1、选择器,传入标签名
            *       2、为创建的对象添加设置,值为一个对象,通过对象中 attrs 来设置标签属性,通过 on 设置事件监听
            *       3、生成的标签里的内容,值为一个数组,通过 default 获取默认插槽的内容
            * */
            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()
                }
            }
            // 完整版,即配置携带编译器的情况下可用
            // template: '<a :href="to"><slot></slot></a>'
        })

        const _this = this
        Vue.component('router-view', {
            render(h) {
                const component = _this.routeMap[_this.data.current]
                return h(component)
            }
        })
    }

    initEvent() {
        window.addEventListener('popstate', () => {
            this.data.current = window.location.pathname
        })
    }
}

注意事项


修改配置

// router/index.js
import VueRouter from 'vue-router'
// ===>
import VueRouter from '../myrouter'

$router / $route

  • this.$router 中包含属性 currentRoute,该属性可以用来获取当前的路由信息
  • this.$route 是当前路由的信息

Hash 模式

因为本身是基于锚点的,因此刷新浏览器返回的始终是 SPA 的指定的 index.html,所以服务端不需要特殊配置

Vue 的构建问题

  • 运行时版
    • 不支持 template 模板,需要打包的时候提前编译
  • 完整版
    • 包含运行时和编译器,体积比运行时版大 10K 左右,程序运行时会把模板转换成 render 函数
  • 配置
// vue.config.js
module.exports = {
    runtimeCompiler: true // 是否带编译(完整)版本,默认为 false
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值