前端路由简介以及vue-router实现原理

作者:muwoo
来源:
后端路由简介路由这个概念最先是后端出现的 。 在以前用模板引擎开发页面时 , 经常会看到这样
大致流程可以看成这样:

  1. 浏览器发出请求
  2. 服务器监听到80 端口(或443)有请求过来 , 并解析 url 路径
  3. 根据服务器的路由配置 , 返回相应信息(可以是 html 字串 , 也可以是 json 数据 , 图片等)
  4. 浏览器根据数据包的 Content-Type 来决定如何解析数据
【前端路由简介以及vue-router实现原理】简单来说路由就是用来跟后端服务器进行交互的一种方式 , 通过不同的路径 , 来请求不同的资源 , 请求不同的页面是路由的其中一种功能 。
前端路由
  1. hash 模式
随着 ajax 的流行 , 异步数据请求交互运行在不刷新浏览器的情况下进行 。 而异步交互体验的更高级版本就是 SPA —— 单页应用 。 单页应用不仅仅是在页面交互是无刷新的 , 连页面跳转都是无刷新的 , 为了实现单页应用 , 所以就有了前端路由 。
类似于服务端路由 , 前端路由实现起来其实也很简单 , 就是匹配不同的 url 路径 , 进行解析 , 然后动态的渲染出区域 html 内容 。 但是这样存在一个问题 , 就是 url 每次变化的时候 , 都会造成页面的刷新 。 那解决问题的思路便是在改变 url 的情况下 , 保证页面的不刷新 。 在 2014 年之前 , 大家是通过 hash 来实现路由 , url hash 就是类似于:
#/login这种#。 后面 hash 值的变化 , 并不会导致浏览器向服务器发出请求 , 浏览器不发出请求 , 也就不会刷新页面 。 另外每次 hash 值的变化 , 还会触发 hashchange 这个事件 , 通过这个事件我们就可以知道 hash 值发生了哪些变化 。 然后我们便可以监听 hashchange来实现更新页面部分内容的操作:
unction matchAndUpdate () {// todo 匹配 hash 做 dom 更新操作}window.addEventListener('hashchange', matchAndUpdate)Vue router 实现我们来看一下vue-router 是如何定义的:
import VueRouter from 'vue-router'Vue.use(VueRouter)const router = new VueRouter({mode: 'history',routes: [...]})new Vue({router...})可以看出来 vue-router 是通过Vue.use 的方法被注入进 Vue 实例中 , 在使用的时候我们需要全局用到 vue-router 的router-view 和 router-link 组件 , 以及 this.$router/$route 这样的实例对象 。 那么是如何实现这些操作的呢?下面我会分几个章节详细的带你进入 vue-router的世界 。
造轮子 -- 动手实现一个数据驱动的 router经过上面的阐述 , 相信您已经对前端路由以及vue-router 有了一些大致的了解 。 那么这里我们为了贯彻无解肥 , 我们来手把手撸一个下面这样的数据驱动的 router:
new Router({id: 'router-view', // 容器视图mode: 'hash', // 模式routes: [{path: '/',name: 'home',component: 'Home',beforeEnter: (next) => {console.log('before enter home')next()},afterEnter: (next) => {console.log('enter home')next()},beforeLeave: (next) => {console.log('start leave home')next()}},{path: '/bar',name: 'bar',component: 'Bar',beforeEnter: (next) => {console.log('before enter bar')next()},afterEnter: (next) => {console.log('enter bar')next()},beforeLeave: (next) => {console.log('start leave bar')next()}},{path: '/foo',name: 'foo',component: 'Foo'}]})思路整理首先是数据驱动 , 所以我们可以通过一个 route 对象来表述当前路由状态 , 比如:
current = {path: '/', // 路径query: {}, // queryparams: {}, // paramsname: '', // 路由名fullPath: '/', // 完整路径route: {} // 记录当前路由属性}