【Vue】 前端上传图片时限制只可以按文件夹上传图片( webkitdirectory )

简介: 【Vue】 前端上传图片时限制只可以按文件夹上传图片( webkitdirectory )

一、webkitdirectory

   撸代码之前还是先了解一下 input 标签的【webkitdirectory】属性,今天也是主要依赖 这个属性来帮助我们实现需求!

20210527153548522.png

A Boolean indicating whether or not to only allow the user to choose a directory (or directories, if multiple is also present)


一个布尔值,指示是否只允许用户选择一个目录(如果同时存在多个目录,则为一个或多个目录)


这是 MDN 上对 【 webkitdirectory 】属性的解释。一句话,非常通透!

20210527153548522.png

这段话就不做翻译了,大概我们可以看出来,【webkitdirectory 】属性的兼容性不是特别好,所以对【ie6,ie7.....】兼容的小伙伴要慎用....

二、具体实现

   因为用的是 【Vue2.0】的技术栈,所以演示就直接用 Vue 来做演示了!

20210527153548522.png

1. Template 设计

唯一的注意点就是:这里通过【v-show 隐藏 DOM 节点,然后用 ref 获得节点去调用原生 input 的方法】,然后通过 input change 是获取的 e.target 去进行解析;

<template>
  <div class="receive-img">
    <input
      v-show="false"
      type="file"
      ref="inputFile"
      accept="image/*"
      webkitdirectory
      @change="receiveImg"
    />
    <div class="btn">
      <button @click="chooseImgList">点击选择文件夹</button>
    </div>
    <div class="image-list-container">
      <div v-for="item in imageList" :key="item.imgUrl">
        <div class="image-list-item">
          <el-image fit="cover" :src="item.imgUrl"></el-image>
        </div>
        <div class="image-list-text">
          <div>{{ item.imgName }}</div>
          <div>{{ item.size + "KB" }}</div>
        </div>
      </div>
    </div>
  </div>
</template>
<style lang="scss">
.receive-img {
  width: 100%;
  height: 100%;
  .btn {
    margin: 100px auto 0 auto;
  }
  .image-list-container {
    width: 100%;
    height: 250px;
    display: flex;
    align-items: flex-start;
    justify-content: flex-start;
    border: 1px solid #d2d2d2;
    padding: 0 10px;
    .image-list-item {
      width: 210px;
      height: 210px;
      margin-left: 15px;
      text-align: center;
    }
    .image-list-text {
      width: 210px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      text-align: center;
    }
    .image-list-item:hover {
      cursor: pointer;
    }
  }
}
</style>

2. JavaScript 执行

通过 【 FileReader 】去读取文件的 进而读取出图片的name/path/size ;不过需要注意这里需要手动调用 【API】上传图片,演示的图片是 base64

import uploadFormData from "@/utils/uploadFormData.js"
<script>
export default {
  name: "ReceiveImage",
  data() {
    return {
      imageList: [],
    };
  },
  methods: {
    chooseImgList() {
      if (this.imageList.length == 0) {
        this.$refs["inputFile"].click();
      }
    },
    receiveImage (e) {
      var fmDataList = [];
      var count = e.target.files.length;
      for (let item in e.target.files) {
        let reader = new FileReader();
        const file = e.target.files[item];
        if (typeof file == 'object' && (file.name.indexOf('jpg') > -1 || file.name.indexOf('png') || file.name.indexOf('jpeg'))) {
          reader.readAsDataURL(e.target.files[item]);
          reader.onloadend = (e) => {
            // 这里的e.target就是reader
            let base64 = e.target.result;
            fmDataList.push({ file: base64, fileName: file.name })
            this.imageList.push({ imgName: file.name, size: Math.ceil(file.size / 1000) })
            count--;
            if (count == 0) {
              uploadFormData(fmDataList).then(result => {
                if (result.fileNames) {
                  this.imageList.forEach((t, index) => {
                    t['fileName'] = result.fileNames[index]
                  })
                }
                this.imageListStatus = true;
              })
            }
          }
        }
      }
    },
  },
};
</script>

3. 原生方式实现上传

值得介绍的是上述代码中的封装好的 uploadFormData 方法,因为我们用原生的方式去上传,且上传的是一个二进制流的 formData ,所以我们就不能再用项目里面已经封装好的 request 去发起请求,而是要用 new XMLHttpRequest(),具体怎么实现,可以看下面实现步骤( 当然具体要看后端 API 怎么去做),以下面为例:

封装 uploadFormData.js

/**
 * @param {string} file base64格式的图片
 * @param {string} imgFormat 需要转化为 formData 的图片格式
 */
var uploadImgUrl = process.env.VUE_APP_BASE_API + "/common/upload"; // 上传的图片服务器地址
import data2blob from "@/lib/data2blob.js";
import mimes from "@/lib/mimes.js";
import { getToken } from "@/utils/auth";
export default function (files, imgFormat = 'png') {
  // files 就是上面 fmDataList 里的 base64 数组
  const allowImgFormat = ["jpg", "png"];
  const format = allowImgFormat.indexOf(imgFormat) > -1 ? 'jpg' : imgFormat;
  const fmData = new FormData();
  if (Array.isArray(files) && files.length > 0) {
    files.forEach(t =>
      // data2blob() 方法是通过 Blob 转化为二进制流
      fmData.append('file', data2blob(t.file, mimes[format]))
    )
  } else {
    fmData.append('file', data2blob(files, mimes[format]))
  }
  // XMLHttpRequest 去做具体请求
  return new Promise((resolve, reject) => {
    let client = new XMLHttpRequest();
    client.open("POST", uploadImgUrl, true);
    client.withCredentials = false; // 是否支持跨域
    client.onreadystatechange = function () {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200 || this.status === 201) {
        resolve(JSON.parse(this.responseText));
      } else {
        reject(this.status);
      }
    };
    client.setRequestHeader("Authorization", "Bearer " + getToken());
    client.send(fmData);
  })
}

base64 转 二进制 data2blob.js

/**
 * database64文件格式转换为2进制
 *
 * @param  {[String]} data dataURL 的格式为 “data:image/png;base64,****”,逗号之前都是一些说明性的文字,我们只需要逗号之后的就行了
 * @param  {[String]} mime [description]
 * @return {[blob]}      [description]
 */
export default function(data, mime) {
  data = data.split(',')[1];
  data = window.atob(data);
  var ia = new Uint8Array(data.length);
  for (var i = 0; i < data.length; i++) {
    ia[i] = data.charCodeAt(i);
  };
  return new Blob([ia], {
    type: mime
  });
};

文件格式 mimes.js

export default {
    'jpg': 'image/jpeg',
    'png': 'image/png',
    'gif': 'image/gif',
    'svg': 'image/svg+xml',
    'psd': 'image/photoshop'
};

边记录边学习边成长,加油加油加油~~~~


相关文章
|
5天前
|
前端开发 JavaScript API
阿珊比较Vue和React:两大前端框架的较量
阿珊比较Vue和React:两大前端框架的较量
|
6天前
|
缓存 JavaScript 前端开发
前端vue的性能优化都有那些方式?
【4月更文挑战第8天】 Vue.js 性能优化技巧包括:路由懒加载,按需加载路由以加快页面加载;组件优化,如用`v-show`替换`v-if`,使用计算属性代替方法;虚拟滚动提升大数据列表性能;图片优化,如使用懒加载;减少不必要的重渲染,借助`v-once`或`shouldComponentUpdate`;以及考虑使用服务端渲染(SSR)提升首屏加载速度。注意平衡优化与代码复杂性之间的关系。
34 0
|
6天前
|
缓存 安全 JavaScript
前端安全:Vue应用中防范XSS和CSRF攻击
【4月更文挑战第23天】本文探讨了在Vue应用中防范XSS和CSRF攻击的重要性。XSS攻击通过注入恶意脚本威胁用户数据,而CSRF则利用用户身份发起非授权请求。防范措施包括:对输入内容转义、使用CSP、选择安全的库;采用Anti-CSRF令牌、同源策略和POST请求对抗CSRF;并实施代码审查、更新依赖及教育团队成员。通过这些实践,可提升Vue应用的安全性,抵御潜在攻击。
|
2天前
|
存储 JavaScript 前端开发
使用Vue.js构建交互式前端界面的技术探索
【5月更文挑战第20天】Vue.js是一款渐进式JavaScript框架,擅长构建交互式前端界面。其核心特性包括响应式数据绑定、组件化开发、指令系统和虚拟DOM,简化开发并提升性能。通过Vue CLI创建项目,拆分组件,结合数据绑定和事件处理实现交互,使用Vue Router管理路由,Vuex进行状态管理,能高效构建现代Web应用。
|
4天前
|
前端开发 JavaScript Java
Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)五(前端页面
Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)五(前端页面
Java网络商城项目 SpringBoot+SpringCloud+Vue 网络商城(SSM前后端分离项目)五(前端页面
|
6天前
|
存储 JavaScript 前端开发
使用Vue.js构建交互式前端的技术探索
【5月更文挑战第12天】Vue.js是渐进式前端框架,以其简洁和强大的特性深受开发者喜爱。它聚焦视图层,采用MVVM模式实现数据与视图的双向绑定,简化开发。核心特性包括响应式数据绑定、组件化、模板系统和虚拟DOM。通过创建Vue实例、编写模板及定义方法,可以构建交互式前端,如计数器应用。Vue.js让复杂、交互式的前端开发变得更加高效和易维护。
|
6天前
|
JSON JavaScript 前端开发
vue的 blob文件下载文件时,后端自定义异常,并返回json错误提示信息,前端捕获信息并展示给用户
vue的 blob文件下载文件时,后端自定义异常,并返回json错误提示信息,前端捕获信息并展示给用户
|
6天前
|
JSON JavaScript 前端开发
vue前端运行时出现RangeError: Maximum call stack size exceeded
vue前端运行时出现RangeError: Maximum call stack size exceeded
18 4
|
6天前
|
JavaScript 前端开发
vue前端展示【1】
vue前端展示【1】
9 1
|
6天前
|
JSON JavaScript Java
从前端Vue到后端Spring Boot:接收JSON数据的正确姿势
从前端Vue到后端Spring Boot:接收JSON数据的正确姿势
26 0