前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >学习 Vue 3 全家桶 - vue-router

学习 Vue 3 全家桶 - vue-router

作者头像
Cellinlab
发布2023-05-17 16:58:57
发布2023-05-17 16:58:57
41600
代码可运行
举报
文章被收录于专栏:Cellinlab's BlogCellinlab's Blog
运行总次数:0
代码可运行

# 前端开发模式演变

在 jQuery 时代,对于大部分 Web 项目而言,前端都是不能控制路由的,而是需要依赖后端项目的路由系统。通常,前端项目也会部署在后端项目的模板里,对于每次的页面跳转,都由后端开发人员来负责重新渲染模板。

前端依赖后端,并且前端不需要负责路由的这种开发方式:

  • 优点
    • 开发速度会很快
    • 后端也可以承担部分前端任务等
  • 缺点
    • 前后端项目无法分离
    • 页面跳转由于需要重新刷新整个页面、等待时间较长等等,交互体验下降

目前的前端开发中,用户访问页面后代码执行的过程。

用户访问路由后,无论是什么 URL 地址,都直接渲染一个前端的入口文件 index.html,然后就会在 index.html 文件中加载 JS 和 CSS。之后,JavaScript 获取当前的页面地址,以及当前路由匹配的组件,再去动态渲染当前页面即可。用户在页面上进行点击操作时,也不需要刷新页面,而是直接通过 JS 重新计算出匹配的路由渲染即可。

在新架构下,前端获得了路由的控制权,在 JavaScript 中控制路由系统。也因此,页面跳转的时候就不需要刷新页面,网页的浏览体验也得到了提高。这种所有路由都渲染一个前端入口文件的方式,是单页面应用程序(SPA,single page application)应用的雏形。

通过 JavaScript 动态控制数据去提高用户体验的方式并不新奇,Ajax 让数据的获取不需要刷新页面,SPA 应用让路由跳转也不需要刷新页面。这种开发的模式在 jQuery 时代就出来了,浏览器路由的变化可以通过 pushState 来操作,这种纯前端开发应用的方式,以前称之为 Pjax (pushState+ Ajax)。之后,这种开发模式在 MVVM 框架的时代大放异彩,现在大部分使用 Vue/React/Angular 的应用都是这种架构。

SPA 应用相比于模板的开发方式,对前端更加友好,比如:前端对项目的控制权更大了、交互体验也更加丝滑,更重要的是,前端项目终于可以独立出来单独部署了。

单页应用在页面交互、页面跳转上都是无刷新的,这极大地提高了用户访问网页的体验。为了实现单页应用,前端路由的需求也变得重要了起来

类似于服务端路由,前端路由实现起来其实也很简单,就是匹配不同的 URL 路径,进行解析,然后动态地渲染出区域 HTML 内容。但是这样存在一个问题,就是 URL 每次变化的时候,都会造成页面的刷新。解决这一问题的思路便是在改变 URL 的情况下,保证页面的不刷新。

# 前端路由实现原理

通过 URL 区分路由的机制上,有两种实现方式:

  • hash 模式:通过 URL 中 # 后面的内容做区分
  • history 模式:这种方式下,路由看起来和正常的 URL 完全一致

在 vue-router 中对应两个函数,分别是 createWebHashHistory 和 createWebHistory:

# hash 模式

在 2014 年之前,大家是通过 hash 来实现前端路由,URL hash 中的 # 就是类似于下面代码中的这种 #

代码语言:javascript
代码运行次数:0
运行
复制
http://cellinlab.xyz/#/login

在进行页面跳转的操作时,hash 值的变化并不会导致浏览器页面的刷新,只是会触发 hashchange 事件。通过对 hashchange 事件的监听,就可以进行动态地页面切换:

代码语言:javascript
代码运行次数:0
运行
复制
window.addEventListener('hashchange',fn)

# history 模式

HTML5 标准发布,浏览器多了两个 API:pushState 和 replaceState。通过这两个 API ,可以改变 URL 地址,并且浏览器不会向后端发送请求,同时还会触发 popstate 事件。

通过这两个 API 和 popstate 事件,就能用另外一种方式实现前端路由。

代码语言:javascript
代码运行次数:0
运行
复制
window.addEventListener('popstate', fn)

# Toy Vue Router

src/router/ToyRouterView.vue

代码语言:javascript
代码运行次数:0
运行
复制
<template>
  <component :is="comp"></component>
</template>

<script setup>
import { computed } from 'vue';
import { useRouter } from './toyrouter';

let router = useRouter();

const comp = computed(() => {
  const route = router.routes.find((route) => {
    return route.path === router.current.value;
  });
  return route? route.component : null;
});
</script>

src/router/ToyRouterLink.vue

代码语言:javascript
代码运行次数:0
运行
复制
<template>
  <a :href="'#'+props.to">
    <slot />
  </a>
</template>

<script setup>
import { defineProps } from 'vue';
let props = defineProps({
  to: {
    type: String,
    required: true
  }
});
</script>

src/router/toyrouter.js

代码语言:javascript
代码运行次数:0
运行
复制
import { ref, inject } from 'vue';
import ToyRouterLinkVue from './ToyRouterLink.vue';
import ToyRouterViewVue from './ToyRouterView.vue';

const ROUTE_KEY = '__router__';

function createRouter(options) {
  return new Router(options);
}
function useRouter () {
  return inject(ROUTE_KEY);
}
function createWebHashHistory () {
  function bindEvents(fn) {
    window.addEventListener('hashchange', fn);
  }
  return {
    bindEvents,
    url: window.location.hash.slice(1) || '/',
  }
}
class Router {
  constructor(options) {
    this.history = options.history;
    this.routes = options.routes;
    this.current = ref(this.history.url);

    this.history.bindEvents(() => {
      this.current.value = window.location.hash.slice(1);
    });
  }
  install (app) {
    app.provide(ROUTE_KEY, this);
    app.component('ToyRouterLink', ToyRouterLinkVue);
    app.component('ToyRouterView', ToyRouterViewVue);
  }
}

export {
  createRouter,
  useRouter,
  createWebHashHistory,
};

src/App.vue 使用

代码语言:javascript
代码运行次数:0
运行
复制
<template>
  <div>
    <toy-router-link to="/">Home</toy-router-link>
    <toy-router-link to="/about">About</toy-router-link>
  </div>
  <toy-router-view></toy-router-view>
</template>

# 应用技巧

# 动态路由

在路由匹配的语法上,vue-router 支持动态路由。

例如有一个用户页面,这个页面使用的是 User 组件,但是每个用户的信息都不一样,需要给每一个用户配置单独的路由入口。

代码语言:javascript
代码运行次数:0
运行
复制
const routes = [
  {
    path: '/user/:id',
    component: User,
  },
]

# 导航守卫

对于有些页面来说,只有管理员才可以访问,普通用户访问时,会提示没有权限。可以使用 vue-router 的导航守卫功能了,在访问路由页面之前进行权限认证,这样可以做到对页面的控制。

# 动态导入

在项目庞大之后,如果首屏加载文件太大,那么就可能会影响到性能。可以使用 vue-router 的动态导入功能,把不常用的路由组件单独打包,当访问到这个路由的时候再进行加载。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022/2/6,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • # 前端开发模式演变
  • # 前端路由实现原理
    • # hash 模式
    • # history 模式
  • # Toy Vue Router
  • # 应用技巧
    • # 动态路由
    • # 导航守卫
    • # 动态导入
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档