8月更文挑战 | 前端路由模式分析---实现vue-router

447 阅读3分钟

这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战

介绍

来自百度百科:单页Web应用(single page web application,SPA),就是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序,其实和以前的前后端不分离的应用区别就是在切换页面的时候不会有刷新页面的反应,而这会大大的提高用户的体验感目前浏览器有两种常用的模式分别是HashHistory路由的方式

单页面应用和多页面应用

单页面

  • 无刷新更新页面提升用户体验
  • seo优化较差,因为seo可以识别html中的内容,不能识别js中的内容,但是页面都是js渲染的
  • 首屏加载会慢一些,因为首次需要加载对应的html和js全部完成之后才会显示页面,可以通过一些优化手段解类似拆分资源服务端渲染等

多页面

  • 首屏加载速度会快一些,当访问一个页面的时候服务端返回一个html然后直接会展示出来整个过程只经历了一个html请求的过程
  • seo优化效果会好一些
  • 页面切换效果没有单页面应用体验好

两种路由的区别

Hash

  • hash模式背后的原理主要依赖hashChange事件进行监听更新
  • hash路由在url会展示一个#看起来不太美观
  • 我们用回车刷新路由hash会加载到地址栏对应的页面,而history路由一般就报404了,原因是history刷新是网络请求如果后端没有准备就会报错
  • hash路由支持低版本的浏览器并兼容性比history模式强,history是HTML5新增的api
  • hash传参是基于url传参的有长度限制

History

  • history路由利用了浏览器历史记录栈,之前有back、forward、go方法,之后又新增了pushStaterepleaseState方法
  • 目前这两个方法有兼容性需要特定浏览器支持,会对浏览器历史记录修改的功能,虽然改变了当前的url,但你的浏览器不会立即向后端发送请求

说明

现在比较流行的框架ReactVue内部的路由模式都是基于我上面说的两种实现的,今天就以vue-router当做例子来实现一下,实现一个基础版的vue-router路由

开始

我们需要创建一个基本架子使用vue官方提供的生成工具就可以,之后创建两个基础页面用来展示切换的内容,和以前一样代码中会有大量的注释

创建home.vue和list.vue

//home.vue
<template>
  <div>
  home
  </div>
</template>
​
<script>
​
export default {
 
};
</script>
<style scoped></style>
//list.vue
<template>
  <div>
  list
  </div>
</template>
<script>
export default {
​
};
</script>
<style scoped></style>

在vue根目录main.js挂载一下router

//main.jsimport Vue from 'vue'
import App from './App.vue'
import router from './lrouter'//这是我们要实现的路由Vue.config.productionTip = falsenew Vue({
  router,
  render: h => h(App),
}).$mount('#app')
​

在lrouter下创建index.js用来写路由列表

//index.js
import Vue from 'vue'
import vueRouter from './lvue-router'
import Home from '../views/home.vue'
import List from '../views/list.vue'//执行内部 install 方法 
Vue.use(vueRouter)
​
const routes = [{
    path: "/",
    name: "Home",
    component: Home
}, {
    path: "/list",
    name: "List",
    component: List
}]
​
export default new vueRouter({ routes })

接着在当前目录下创建lvue-router.js用来编写我们的主要逻辑,之后写的逻辑都是属于当前页面的

//lvue-router.jslet Vue = null//外层的Vue.use会调用install方法
VueRouter.install = function (_vue) {
    //获取Vue在之后的类VueRouter中使用
    Vue = _vue
    //1.挂载实例 保证全局使用this调用$router 
    //使用全局mixin进行混入
    Vue.mixin({
        beforeCreate() {
            if (this.$options.router) {
                //首次实例化的时候会调用一次在main.js里面
                Vue.prototype.$router = this.$options.router
            }
        }
    })
}
​

1.在install中注册全局组件router-link

VueRouter.install = function (_vue) {
    //2.注册全局组件
    Vue.component('router-link', {
        props: {
            to: {
                type: String,
                required: true
            }
        },
        //执行渲染函数
        render(h) {
            return h('a', { attrs: { href: `#${this.to}` } }, this.$slots.default)
        }
    })
}
​

2.在install中注册全局组件router-view

Vue.component('router-view', {
  render(h) {
    let Component = null
    //监听到this.$router.current变化执行当前方法更新页面
    let res = this.$router.$options.routes.find(v => v.path === this.$router.current)
    if (res.component) {
      Component = res.component
    }
    return h(Component)
  }
})

创建VueRouter类

class VueRouter {
    constructor(options) {
        this.$options = options
        let initial = window.location.hash.slice(1) //截取#后面的参数
        Vue.util.defineReactive(this, 'current', initial) //将current变量变为响应式
        window.addEventListener('hashchange', this.hashChange.bind(this)) //注册hashChange方法监听变化
    }
    hashChange() {
        this.current = window.location.hash.slice(1) //截取#后面的参数
    }
}
​
export default VueRouter

页面效果

save.gif

结束

vue-router基础功能到这里就实现的差不多了,有什么问题可以评论区讨论一下☕️