阅读 151

ElementUI图片上传前如何对尺寸进行验证并且上传到新浪SCS?

这是我参与更文挑战的第3天,活动详情查看: 更文挑战

ElementUI图片上传前对尺寸进行验证的方法

一.ElementUI的upload组件用法

具体的属性可以查看官方文档,这里用到的是:before-upload="beforeAvatarUpload" 这个钩子函数,看名字就知道这是在图片上传前执行的方法,在此可以进行一些验证,官方给出了对图片类型以及大小的验证,接下来将实现对图片尺寸的验证.

<template>
  <div class="blog-main-views">
    <el-upload
      class="avatar-uploader"
      action="https://jsonplaceholder.typicode.com/posts/"
      :show-file-list="false"
      :on-success="handleAvatarSuccess"
      :before-upload="beforeAvatarUpload">
      <img v-if="imageUrl" :src="imageUrl" class="avatar">
      <i v-else class="el-icon-plus avatar-uploader-icon"></i>
        </el-upload>
  </div>
</template>
 methods: {
    beforeAvatarUpload(file) {
      const isJPG = file.type === 'image/jpeg';
      const isLt2M = file.size / 1024 / 1024 < 2;
      if (!isJPG) {
        this.$message.error('上传头像图片只能是 JPG 格式!');
      }
      if (!isLt2M) {
        this.$message.error('上传头像图片大小不能超过 2MB!');
      }
      return isJPG && isLt2M;
    }
  }
}
复制代码

这里我们把file参数打印出来看一下

image.png

可以看到里面包含了文件名称,大小,类型,但是没有图片的宽高.

要实现对图片宽高的验证,我这里是借助了javascript原生API FileReader

二.javascript原生API FileReader

先来学习一下这个api的使用方法,然后再结合elementUI进行验证

1、FileReader接口的方法

FileReader接口有4个方法,其中3个用来读取文件,另一个用来中断读取。

微信截图_20210608153953.png

  • readAsText:该方法有两个参数,其中第二个参数是文本的编码方式,默认值为 UTF-8。这个方法非常容易理解,将文件以文本方式读取,读取的结果即是这个文本文件中的内容。

  • readAsBinaryString:该方法将文件读取为二进制字符串,通常我们将它传送到后端,后端可以通过这段字符串存储文件。

  • readAsDataURL:这个方法将文件读取为一段以data:开头的字符串,这段字符串的实质就是 Data URLData URL是一种将小文件直接嵌入文档的方案。我这里就使用这个方法.

2、FileReader接口事件

FileReader接口包含了一套完整的事件模型,用于捕获读取文件时的状态。

微信截图_20210608154142.png

3、FileReader 属性

无论读取成功或失败,方法并不会返回读取结果,这一结果存储在result属性中。

4、FileReader 使用

FileReader接口的使用方式非常简单,在不考虑浏览器兼容的情况下直接创建实例就可以了

let reader = new FileReader();
复制代码

如果考虑浏览器,可以先检查一下

if(window.FileReader) {
    let reader = new FileReader();
}
else {
    alert("浏览器不支持 换个吧!!");
}
复制代码

三.ElementUI与FileReader的结合实现验证

既然是获取图片的宽高,那么我这里也是借助了图片来进行验证,既然是图片,我们就要用到FileReader接口的readAsDataURL方法,

beforeAvatarUpload(file) {
  let reader = new FileReader();
  reader.onload = function () {
    let txt = this.result;
    let img = document.createElement("img");
    img.src = txt;
    img.onload = function () {
      console.log(img.width);
      console.log(img.height);
    }
  };
  reader.readAsDataURL(file);
}
复制代码

我们通过readAsDataURL获取到的结果,刚好可以赋给img标签作为src属性,然后我们就可以通过最简单的img.width以及img.height来获取宽高了,最后再进行验证就好了

看一下控制台打印结果,编码太长了,主要看一下红色框里的部分.看来获取到宽高是没问题的了

111.png

最后我们进行验证,由于FileReader接口的onload方法是异步方法,所以我们是拿不到img属性的,为此我们借助Promise

最后的验证代码如下

beforeAvatarUpload(file) {
      let _this = this;
      return new Promise(resolve => {
        let reader = new FileReader()
        reader.readAsDataURL(file);
        reader.onload = function () {
          resolve(this.result)
        }
      }).then((result) => {
        document.querySelector("#img").src = result;
        let img = document.querySelector("#img")
        img.onload = function () {
          console.log(img.width)
          console.log(img.height)
          const isWidth = img.width < 500
          const isHeight = img.height < 500
          console.log(isWidth)
          console.log(isHeight)
          if (!isWidth) {
            _this.$message.error('上传头像图片宽度不能超过500!');
          }
          if (!isHeight) {
            _this.$message.error('上传头像图高度不能超过500!');
          }
          return isWidth && isHeight;
        }
      })
    }
复制代码

先用一个不符合要求的图片,

image (1).png

换一个符合要求的图片

image (2).png

大功告成,这样就可以在上传图片前进行尺寸验证啦!

验证通过以后自然就是要上传了

基于express图片上传到新浪云

目标功能:图片上传

操作流程:点击上传按钮->把图片上传到服务器->返回图片URL

1.组件中使用elementUI的上传

<el-upload
      class="avatar-uploader"
      action="http://81.xx.xx.113:3000/blog/uploadArticleImg"
      :show-file-list="false"
      :on-success="handleAvatarSuccess"
      :before-upload="beforeAvatarUpload"
    >
      <img v-if="imageUrl" :src="imageUrl" class="avatar" />
      <i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
复制代码

action里面写上传图片的接口

2.配置静态资源文件夹

只有配置了静态资源文件夹才可以使用URL的方式访问图片,这里开放静态资源文件夹一定要在dist前面,不然的话就会走html从而访问不到图片

//开放静态资源文件
app.use(express.static(path.join(__dirname, "public")));

// 访问静态资源文件 这里是访问所有dist目录下的静态资源文件
app.use(express.static(path.resolve(__dirname, './dist')));
// 因为是单页应用 所有请求都走/dist/index.html
app.get('*', function(req, res) {
    const html = fs.readFileSync(path.resolve(__dirname, './dist/index.html'), 'utf-8');
    res.send(html);
})
复制代码

3.上传图片接口

服务器端使用的是multer模块来处理上传的图片,使用post方式,并添加upload.single('file')

//blog.js

//图片上传模块
const multer = require('multer')
//配置上传路径
const upload = multer({ dest: __dirname + '../../public/uploads' })
//upload.single()表示单个文件的上传 
blog.post('/uploadArticleImg', upload.single('file'), require("./blog/uploadArticleImg"));
复制代码

但是这个multer模块处理文件有个坑(更可能是我不懂配置),就是它会把上传的文件名更换成随机乱码,并且不会保留后缀,这就导致前端访问的时候直接下载了这个文件,而不是展示图片.为此 ,需要用path模块解析原文件后缀名,然后用fs的方法给文件添加后缀

//uploadArticleImg.js

//引入path模块
const path = require("path");
//引入fs模块
const fs = require("fs");
module.exports = async(req, res) => {
    //接收文件信息
    const file = req.file;
    //获取原文件名的后缀
    const suffix = path.parse(req.file.originalname).ext;
    //旧的文件名
    const oldname = req.file.path;
    //新的文件名
    const newname = req.file.path + suffix;
    //调用fs.renameSync()方法添加后缀
    fs.renameSync(oldname, newname);
    //获取图片的URL
    file.url = `http://81.70.96.113:3000/uploads/${file.filename}` + suffix;
    //返回文件信息
    res.send(file);
}
复制代码

到这里就可以正常上传图片,并且返回图片的URL

4.上传图片到新浪云

偶然间发现新浪云可以上传图片用,数据量在一定范围内还是免费的,减少了自己本来就不富裕的服务器内存压力.

/*
 * @Description: 图片上传接口
 * @Author: hanzhiwei
 * @Date: 2020-10-07 00:46:47
 * @LastEditTime: 2020-10-13 00:42:41
 * @FilePath: \blog\serve\route\blog\uploadArticleImg.js
 */
//引入path模块
const path = require("path");
//引入fs模块
const fs = require("fs");

//新浪sdk引用
const sinaCloud = require('scs-sdk');
//配置新浪云的accessKey和secretKey  我理解的就是账号密码
const config = new sinaCloud.Config({
    accessKeyId: '2wesaabmtYD4N3SwxkfM',
    secretAccessKey: 'e75005531b2e364d72efb8ee729f0825629a158a',
    sslEnabled: false
});

//实例化新浪云储存
var myBucket = new sinaCloud.S3({ params: { Bucket: 'duwanyu.com' } });
//当前实例生效:
myBucket.config = config;


module.exports = async(req, res) => {
    //接收文件信息
    const file = req.file;
    //获取原文件名的后缀
    const suffix = path.parse(req.file.originalname).ext;
    //旧的文件名(模块生成的乱码)
    const oldname = req.file.path;
    //新的文件名
    const newname = req.file.path + suffix;

    //调用fs.renameSync()方法添加后缀
    fs.renameSync(oldname, newname);
    //获取图片的URL
    // file.url = `http://81.70.96.113:3000/uploads/${file.filename}` + suffix;
    //原文件名(文件本身名字)
    const remoteFilename = req.file.originalname;
    //根据新文件名读取文件
    const fileBuffer = fs.readFileSync(newname);

    //上传文件
    myBucket.putObject({
        ACL: 'public-read', //权限
        Bucket: 'duwanyu.com/images', //上传至duwanyu.com文件夹里的images文件夹里
        Key: remoteFilename, //上传到新浪云的文件名
        Body: fileBuffer //文件
    }, function(error, response) {
        if (error) {
            res.json("上传新浪云失败");
        } else {
            //上传图片成功,将图片地址返回给前端
            file.sinaPath = "http://sinacloud.net/duwanyu.com/images/" + remoteFilename;
            //获取图片的URL
            file.url = `http://81.70.96.113:3000/uploads/${file.filename}` + suffix;
            //返回文件信息
            res.send(file);

        }
    });
}
复制代码

大功告成,此时新浪云就有我们上传的图片啦!

打个广告

16.gif 这是我一个开源的收藏网址的项目

项目地址👉👉点击进入,可以直接设置为浏览器主页或者桌面快捷方式进行使用,本人在用,长期维护。

完全开源,大家可以随意研究,二次开发。当然还是十分欢迎大家点个Star⭐⭐⭐
👉👉源码链接(gitee)       👉👉源码链接(github)

链接整合

🔊项目预览地址(GitHub Pages):👉👉alanhzw.github.io

🔊项目预览备用地址(自己的服务器):👉👉warbler.duwanyu.com

🔊源码地址(gitee):👉👉gitee.com/hzw_0174/wa…

🔊源码地址(github):👉👉github.com/alanhzw/War…

🔊我的博客:👉👉www.duwanyu.com

文章分类
前端
文章标签