阅读 1866

前端路由那些事

树酱希望将前端的乐趣带给大家 本文已收录 github.com/littleTreem… 喜欢就star✨

谈到路由,一般分为前端路由和后端路由两种,后端路由指的当用户通过浏览器切换不同URL时,都会向服务器发起资源请求,服务器通过后端路由匹配之后根据不同URL返回不同页面,而前端路由则将浏览器与服务器交互(页面跳转的URL规则匹配)的任务交给前端来做

1.前端路由模式

目前单页应用(SPA)成为目前前端应用的主流,而大型单页应用的一个大特征是,由前端路由来控制页面的跳转,通过url的切换,在不请求服务器的前提,更新页面视图,这里以vue-router为例分析,前端路由模式主要包括两种:hash模式和history模式

1.1 hash 模式

hash模式即是通过 hash 值(类似锚点)的变化,浏览器不用向服务器发起请求,也就无需刷新页面。而浏览器是怎么监听变化的呢?就是通过url中hash 值的变化,此时还好触发 hashchange 事件,通过此事件的触发我们就可以清晰知道hash发生了什么变化

假设你浏览器访问的url地址是 http://127.0.0.1/#/test 那么通过 location.hash 获取的hash值为 #/test

导致路由的变化无非是三种情况:刷新页面、浏览器返回操作、新链接跳转,下面是具体流程图👇

那hash模式下监听路由变化实现的原理是怎么样的呢?


window.addEventListener('hashchange', this.onHashChange.bind(this))
window.addEventListener('load', this.onHashChange.bind(this))
function onHashChange(){
// todo 匹配 hash 做 dom 更新操作
}
复制代码

有兴趣的童鞋可以研究vue-router关于hash类的具体源码实现 点我到达火箭

1.2 history 模式

自HTML5新标准出台,pushState和replaceState是HTML5的新接口,通过这两个 API 可以改变 url 地址且不会发送请求,前端路由从此了多了另外一种模式History,而且通过这种模式不再需要在URL添加#符号,也能让URL显得更加优美

我们先看看window.history对象里面有什么

History.pushState

在不刷新浏览器的情况下,创建新的浏览记录并插入浏览记录队列中,当刷新页面,页面内容不变但地址发生了变化,该API可传入三个参数,分别是

  • 状态对象(stateObject): 可以通过pushState方法可以将stateObject(对象)内容传递到新页面中
  • 标题(title):可不传
  • 地址(url):新的历史记录条目的地址(url不支持跨域);
window.history.pushState({data: "test"}, "", 'http://127.0.0.1/test');
复制代码

History.replaceState:

的使用与 history.pushState() 类似,区别在于pushState会增加一条新的历史记录,而replaceState则会替换当前的历史记录,把当前的历史记录改成目标地址

window.history.replaceState({data: "test"}, "", 'http://127.0.0.1/test');
复制代码

popstate

当用户发起返回操作或者执行history.go()或history.forward()等操作时,才会触发popstate

 window.addEventListener('popstate', e => {
    //todo 
 });
复制代码

讲完history模式涉及到接口,树酱聊聊配置history模式需要注意的事项,这种模式相比hash模式还需要配置后端,如果后台没有正确的配置,当用户在浏览器直接刷新 http://127.0.0.1/#/test 就会返回 404,那如何解决这个问题呢 🤔️

你需要在Nginx配置文件添加重定向 附上 history vue-router官方文档

location / {
  try_files $uri $uri/ /index.html;
}
复制代码

Vue-router History模式下的流程图如下所示

有兴趣Vue-router关于history类的具体源码实现 点我到达火箭

2.路由应用

聊聊vue-router的一些应用场景

2.1 路由拦截

路由拦截可以用来作为前端鉴权入口,比如判断是否是已登录状态

mport Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
const router = new Router({
 routes: [
 {
  path: '/home',''
  component: () => import('@/components/Home')
  }
 },{
  path: '/login',
  name: 'login',
  component: (resolve) => {
  component: () => import('@/components/Login')
  }
 }}]
})
// 判断是否需要登录权限 以及是否登录
router.beforeEach((to, from, next) => {
 if (to.matched.some(res => res.meta.requireAuth)) { // 判断路由是否需要登录权限
 if (localStorage.getItem('item')) { //判断是否有token
  next()
 } else {// 没登录则跳转到登录界面
  next({
  path: '/login',
  query: {redirect: to.fullPath}
  })
 }
 } else {
 next()
 }
})
复制代码

export default router

2.2 路由懒加载

懒加载,顾名思义就是等需要再加载,在SPA应用中,如果不通过懒加载加载组件的方式,会导致webpack打包出来的文件体制过大,进而影响用户体验

export default new Router({                                
  routes: [
    {
      path: '/home',                                            
      name: 'home',
      component: () => import('@/components/Home') # 懒加载引入组件
    }
  ]
});
复制代码

2.3 路由模块化管理

你是否还在烦恼如何按不同模块不同功能管理不同路由,这里要推荐使用 require.context()

不同功能模块区分,再通过require.context 导出所有路由

require.context() 它允许传入一个目录进行搜索,一个标志表示是否也应该搜索子目录,以及一个正则表达式来匹配文件,当你构建项目时,webpack会处理require.context的内容

require.context()可传入三个参数分别是:

  • directory :读取文件的路径

  • useSubdirectories :是否遍历文件的子目录

  • regExp: 匹配文件的正则

实际应用如下👇

routes导出来结果是这样

当然原本的定义路由的方式也变了

/*
 * 个人中心路由模块(user)
 * @Author: tree
 * @Date: 2019-11-06 20:20:51
 */
export default [
  {
    path: '/user/info',
    name: 'personalInfo',
    component: () => import('@/views/user/info.vue'),
    meta: { title: '账号信息', keepAlive: false, showHeader: true },
  },
  {
    path: '/user/security',
    name: 'security',
    component: () => import('@/views/user/security.vue'),
    meta: { title: '安全设置', keepAlive: false, showHeader: true },
  },
];
复制代码

2.4 其他常见路由 API

  • window.history.back() : 加载 history 列表中的前一个 URL
  • window.history.forward() : 加载 history 列表中的下一个 URL
  • window.history.back(n) : 加载 history 列表中的某个页面
  • window.location.href: 返回完整的URL
  • window.location.hash: 返回URL的锚部分
  • window.location.pathname: 返回URL路径名

2.5 koa-router 待补充