# 项目讲解

# 大文件上传

# 应用场景

上传文件大小有限制,页面响应时间过长会超时

# 解决方案

切片上传

# 思路

  1. 前端负责分块,服务端负责整合

  2. 前端文件对象File的原型链上面有slice方法,可以对文件进行分块。

  3. 前端对文件切片时,要标记序号保证后端有序地整合资源。

    1. 前端对文件分块之后,原来的一个文件对应一个请求就变成了一个文件对应多个请求了。所以,前端可以基于 Promise.all 将这多个接口整合,上传完成在发送一个合并的请求,通知服务端进行合并。

    2. 通过spark-md5根据文件内容计算出文件的hash值,方便做其他优化,比如:当 hash 值不变时,服务端没有必要重复读写文件(秒传)等.

  4. 合并时可通过 nodejs 中的读写流(readStream/writeStream),将所有切片的流通过管道(pipe)输入最终文件的流中。

  5. 如果某个切片上传失败了,服务端会返回当前分块失败的信息,其中会包含文件名称、文件hash、分块大小以及分块序号等,前端拿到这些信息后可以进行重传。

# 进度条数据

分块进度数据利用 axios 中的 onUploadProgress 配置项获取数据,通过使用computed 根据分块进度数据的变化自动自动计算当前文件的总进度。

# 断点续传

断点续传其实就是让请求可中断,然后在接着上次中断的位置继续发送,此时要保存每个请求的实例对象,以便后期取消对应请求,并将取消的请求保存或者记录原始分块列表取消位置信息等,以便后期重新发起请求。

# 秒传

所谓的秒传就是不用传,在正式发起上传请求时,先发起一个检查请求,这个请求会携带对应的文件 hash 给服务端,服务端负责查找是否存在一模一样的文件 hash,如果存在此时直接复用这个文件资源即可,不需要前端在发起额外的上传请求。

# 权限管理

# 路由权限

# 菜单栏权限

# 场景

不同级别用户看到不同菜单栏

# 思路

前端在用户登录后,根据后端返回的路由列表,使用addRoute方法动态添加路由

# 如何解决刷新页面,动态路由丢失

通过监听路由的变化,当刷新时,添加动态路由并定位到管理页面

// src/App.vue
watch: {
    $route: {
      async handler(newVal) {
        console.log("newVal", newVal);
        const role = localStorage.getItem(ROLE);
        if (role && role === "admin") {
          /* 在4.x版本中需手动调用router.replace方法重定向,
          因为动态路由页面刷新时,matched的值为空;
          在3.x版本中,刷新页面添加异步路由,matched有值,不需要再重定向 */
          this.$router.addRoute("Layout", manage);
          /* 在动态路由页面刷新时,matched数组为空 */
          if (!newVal.matched.length && newVal.fullPath === "/manage") {
            await this.$router.replace("/manage");
          }
        }
      },
    },
  }

# 按钮权限

# 场景

根据不同的用户,一些页面功能进行显示或者隐藏

# 思路

在路由元信息上定义权限信息,通过自定义指令删除一些DOM节点

# 具体实现

  1. 定义路由元信息
{
  path: "/about",
  name: "About",
  component: About,
  meta: {
      btnPermissions: ['admin']
  },
}
  1. 增加判断方法
// src/utils/index.js
import { ROLE } from "../config/constant";

// 权限检查方法
export function has(value) {
  let isExist = false;
  // 获取用户按钮权限
  let btnPermissionsStr = localStorage.getItem(ROLE);

  if (btnPermissionsStr == undefined || btnPermissionsStr == null) {
    return false;
  }

  if (value.indexOf(btnPermissionsStr) > -1) {
    isExist = true;
  }
  return isExist;
}

  1. 新增自定义指令
// src/main.js
app.directive("has", {
  mounted(el) {
    // 获取页面按钮权限
    const btnPermissionsArr = router.currentRoute._value.meta.btnPermissions;
    if (!has(btnPermissionsArr)) {
      if (el.parentNode) {
        el.parentNode.removeChild(el);
      }
    }
  },
})

  1. 在需要的页面使用v-has
<template>
  <div class="about">
    <h1>This is an about page</h1>
    <button type="button" v-has>管理员按钮</button>
  </div>
</template>

# 前端水印

  1. 使用canvas绘制水印的内容。

  2. 水印的内容一般为登陆者的信息,这些信息从Vuex中读取。

  3. 将canvas导出为base64。

  4. 在body元素后面添加一个fixed布局的元素。该元素的background-image为刚刚导出的base64图片,将该元素的层级设置为9999,pointer-events:one。

Last Updated: 3/28/2022, 1:47:45 PM