美文网首页Vue前端小程序
文件upload 文件上传深入

文件upload 文件上传深入

作者: Raral | 来源:发表于2020-11-04 13:24 被阅读0次

我记录这篇文章是因为开发过程中,发现上传业务有时候感觉不同平台自己有时一脸懵逼不知道咋样去优化这块业务,不同的后台实现咋样做不同的处理,以下介绍后台实现主要node和java为主,比如:手机端app图片上传,H5页面图片上传,后台管理系统不分离时的图片上传,分离后使用前端框架图片上传这里主要介绍vue,混合框架uni-app图片上传,还有多图片上传优化等

H5 页面文件上传

敬请期待

pc端文件上传(分离)

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Layui</title>
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <link rel="stylesheet" href="./layui//css/layui.css"
        tppabs="https://www.layui.site/layui/dist/css/layui.css" media="all">
    <!-- 注意:如果你直接复制所有代码到本地,上述css路径需要改成你本地的 -->
    <style>
        .layui-upload-img {
            height: 100px;
            width: 100px;
            position: relative;
        }
        .add {
            width: 100px;
            height: 100px;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 30px;
            color: #999;
            position: relative;
            transform: translateY(-100px);
        }

    </style>
</head>

<body>


    <div class="layui-upload">
        <!-- <button type="button" class="layui-btn" id="test1">上传图片</button> -->
        <div class="layui-upload-list" id="test1">
            <img class="layui-upload-img" id="demo1">
            <div class="add"><span>+</span></div>
        </div>
    </div>

    


    <script src="./layui//layui.js" charset="utf-8"></script>
    <script src="./js/upload_img.js"></script>
    <!-- 注意:如果你直接复制所有代码到本地,上述 JS 路径需要改成你本地的 -->
    <script>
        var url = "https://httpbin.org/post";
        var field = "picture";
        var val = "https://uat-res.gomezhe.com/as-res/public/64c15dd5-7d7e-4988-9499-915ab00e1d17.jpg";
        var nodeSelect = "#demo1";
        uploadImg(url, field, val, nodeSelect, function(val) {
            console.log(val);
        });



        // var imgUrl = "https://uat-res.gomezhe.com/as-res/public/64c15dd5-7d7e-4988-9499-915ab00e1d17.jpg";
    //     var imgUrl = "";


    //     layui.use(['upload', 'element', 'layer'], function () {
    //         var $ = layui.jquery
    //             , upload = layui.upload
    //             , element = layui.element
    //             , layer = layui.layer;

    //             if(imgUrl) {
    //                 $('#demo1').attr('src', imgUrl); //图片链接(base64)
    //             }
    

    //         //常规使用 - 普通图片上传
    //         var uploadInst = upload.render({
    //             elem: '#test1'
    //             , url: 'https://httpbin.org/post' //此处用的是第三方的 http 请求演示,实际使用时改成您自己的上传接口即可。
    //             , before: function (obj) {
    //                 //预读本地文件示例,不支持ie8
    //                 obj.preview(function (index, file, result) {
    //                     $('#demo1').attr('src', result); //图片链接(base64)
    //                 });

    //                 element.progress('demo', '0%'); //进度条复位
    //                 layer.msg('上传中', { icon: 16, time: 0 });
    //             }
    //             , done: function (res) {
    //                 console.log(res);
    //                 //如果上传失败
    //                 if (res.code > 0) {
    //                     return layer.msg('上传失败');
    //                 }
    //                 //上传成功的一些操作
    //                 imgUrl = res.files.file;
    //             }
    //             , error: function () {
    //                 //演示失败状态,并实现重传
    //                 // var demoText = $('#demoText');
    //                 // demoText.html('<span style="color: #FF5722;">上传失败</span> <a class="layui-btn layui-btn-xs demo-reload">重试</a>');
    //                 // demoText.find('.demo-reload').on('click', function () {
    //                 //     uploadInst.upload();
    //                 // });
    //             }
    //             //进度条
    //             , progress: function (n, elem, e) {
    //                 element.progress('demo', n + '%'); //可配合 layui 进度条元素使用
    //                 if (n == 100) {
    //                     layer.msg('上传完毕', { icon: 1 });
    //                 }
    //             }
    //         });
    //     });
    // </script>

</body>

</html>

上传js基于layui

(function(window,layui) {
    
    
    function uploadImg(url,field, val,nodeSelect,cb) {
        
        layui.use(['upload', 'element', 'layer'], function () {
            var $ = layui.jquery
                , upload = layui.upload
                , element = layui.element
                , layer = layui.layer;

                if(val) {
                    $(nodeSelect).attr('src', val); //图片链接(base64)
                }


            var uploadInst = upload.render({
                elem: '#test1'
                , url: url 
                , before: function (obj) {
                    obj.preview(function (index, file, result) {
                        $(nodeSelect).attr('src', result); //图片链接(base64)
                    });

                    element.progress('demo', '0%'); //进度条复位
                    layer.msg('上传中', { icon: 16, time: 0 });
                }
                , done: function (res) {
                    console.log(res);
                    //如果上传失败
                    if (res.code > 0) {
                        return layer.msg('上传失败');
                    }
                    //上传成功的一些操作
                    val = res.files.file;
                    cb(val);

                }
                , error: function () {
                    //演示失败状态,并实现重传
                    // var demoText = $('#demoText');
                    // demoText.html('<span style="color: #FF5722;">上传失败</span> <a class="layui-btn layui-btn-xs demo-reload">重试</a>');
                    // demoText.find('.demo-reload').on('click', function () {
                    //     uploadInst.upload();
                    // });
                }
                //进度条
                , progress: function (n, elem, e) {
                    element.progress('demo', n + '%'); //可配合 layui 进度条元素使用
                    if (n == 100) {
                        layer.msg('上传完毕', { icon: 1 });
                    }
                }
            });
        });

    }



    window.uploadImg = uploadImg;

})(window,layui)

pc端文件上传(不分离)

1. node+ejs

  • nodejs中在上传文件时,我们通常会使用到Multer中间件用于处理multipart/form-data 类型的表单数据。
cnpm install multer --save
  • 视图ejs使用form表单提交,enctype为:multipart/form-data表单类型

ejs

 <form action="http://localhost:8080/" method="post" enctype="multipart/form-data">
    <input type="file" name="files" value="指定文件">
    <br><br>
    <input type="submit" value="上传">
</form>

node

const express=require("express");
const multer=require('multer');
//初始化上传对象
var upload=multer({dest:'./upload/'});//目录要存在
var fs = require('fs');


var app=express();

app.use("/",upload.single("files"),function(req,res){   //files为input type="file"的name值
    var oldFile=req.file.destination+req.file.filename; //指定旧文件
    var newFile=req.file.destination + req.file.originalname;   //指定新文件
    fs.rename(oldFile,newFile,function(err){
        if(err){
            res.send('上传失败!');
        }else{
            res.send('上传成功!');
        }
    });
});

app.listen(8080);
  • 上传多个文件
    1. 首先要在ejs中form的input 加上 multiple
    2. 使用multer中间的方法 变为 array("files",5),通过遍历处理数据
  • 总结
    1. 在HTML找中input type="file"需要加上multiple来实现过滤,multiple不写参数则可以读取·所有文件。而在服务端上,我们需要将single()改为array(“name”,num);的形式来接收多个文件的上传请求。最后对他们全部进行重命名。在这之前我们首先看看multer支持哪些文件上传方式:
        .single(fieldname)  //接受一个以 fieldname 命名的文件。.fields(fields)
        .array(fieldname[, maxCount])   //接受一个以 fieldname 命名的文件数组。可以配置 maxCount 来限制上传的最大数量。
        .fields(fields) //接受指定 fields 的混合文件。fields是一个拥有name和maxCount的数组对象。
        .none()     //只接受文本域。如果任何文件上传到这个模式,将发生 "LIMIT_UNEXPECTED_FILE" 错误。
        .any()  //接受一切上传的文件。
    
    1. 通过limits来限制上传文件
        var upload=multer({dest:'./upload/',limits:{fileSize: 1024 * 1024 * 20,files: 5}});
    
    limits参数
        Key Description Default
        fieldNameSize   field 名字最大长度    100 bytes
        fieldSize   field 值的最大长度    1MB
        fields  非文件 field 的最大数量 无限
        fileSize    在 multipart 表单中,文件最大长度 (字节单位)   无限
        files   在 multipart 表单中,文件最大数量  无限
        parts   在 multipart 表单中,part 传输的最大数量(fields + files)    无限
        headerPairs 在 multipart 表单中,键值对最大组数 2000
        如果你上传的文件超出这些设定,MulterError模块将会启用,该模块在node_modules/multer/lib/multer-error.js上:
    

2. java + themlef

敬请期待

uni-app上传

  1. 通过官方文档我们掌握到图片上传核心的api,举个栗子:

    正常情况下:

uni.chooseImage({
    count: 1, //默认9
    sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有//不支持H5
    sourceType: ['album', 'camera'], //从相册选择 照相
    success: res => {
        console.log(res);//
        uni.showLoading({
            mask: true,
        })
        uni.uploadFile({
            url: 'http:/xxxx/api/common/image/upload', //仅为示例,非真实的接口地址
            filePath: res.tempFilePaths[0],
            name: 'file', //相当于formData提交key属性,后台可以根据key获取2进制数据
            success: (uploadFileRes) => {
                //根据后台返回的结果去获取对应的图片路径
                let imgUrl = JSON.parse(uploadFileRes.data).data,
            },
            complete: () => {
                uni.hideLoading()
                this.hideInputPopup()
            }
        });
    }
});
  1. 使用混合框架我们要注意选项的参数差异性

    [图片上传失败...(image-c47855-1604483474514)]

  2. 了解File类型到底是什么?

  • 计算机单位之间的转换:

    T(TB):我们所说的1个T
    G(GB):我们所说的1个G
    M(MB):万字节,也就是我们所说的兆
    K(KB):千字节
    B(Byte):字节 计算机显示的最小单位。
    bit:二进制位

    8bit == 1B(Byte)八个二进制位等于一个字节

    微软                                        计算机厂商
    

    1024B(Byte)= 1K(KB) 1000B(Byte)= 1K(KB)
    1024K(KB)= 1M(MB) 1000K(KB)= 1M(MB)
    1024M(MB)= 1G(GB) 1000M(MB)= 1G(GB)
    1024G(GB)= 1T(TB) 1000G(GB)= 1T(TB)

  • 打印通过uni.chooseImage获取的图片 内容是什么
    [图片上传失败...(image-3551bb-1604483474514)]

  1. H5中uni-app不支持H5压缩图片,那H5咋样进行图片压缩?
// 图片压缩
export function photoCompress(file,w,objDiv){
    var ready=new FileReader();
    /*开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容.*/
    ready.readAsDataURL(file);
    ready.onload=function(){
        var re=this.result;
        canvasDataURL(re,w,objDiv)
    }
}
// 通过canvas压缩得到base64
export function canvasDataURL(path, obj, callback){
    var img = new Image();
    img.src = path;
    img.onload = function(){
        var that = this;
        // 默认按比例压缩
        var w = that.width,
            h = that.height,
            scale = w / h;
        w = obj.width || w;
        h = obj.height || (w / scale);
        var quality = 0.7;  // 默认图片质量为0.7
        //生成canvas
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        // 创建属性节点
        var anw = document.createAttribute("width");
        anw.nodeValue = w;
        var anh = document.createAttribute("height");
        anh.nodeValue = h;
        canvas.setAttributeNode(anw);
        canvas.setAttributeNode(anh);
        ctx.drawImage(that, 0, 0, w, h);
        // 图像质量
        if(obj.quality && obj.quality <= 1 && obj.quality > 0){
            quality = obj.quality;
        }
        // quality值越小,所绘制出的图像越模糊
        var base64 = canvas.toDataURL('image/jpeg', quality);
        // 回调函数返回base64的值
        callback(base64);
    }
}
  1. 使用uni-app实现图片上传并压缩,并且在提交一步之前不与后台交互,目的用户体验更好上传时不用等待。
    核心js方法配合使用 utils.js
// 上传图片(不交互的)
export function showImg() {
    return new Promise((resolve, reject) => {
        uni.chooseImage({
            count: 1, //默认9
            sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
            sourceType: ['album', 'camera'], //从相册选择
            success: res => {
                console.log("chooseImage",res)
                let _thumbnail = res.tempFilePaths[0];
                let _file = res.tempFiles[0];
                let _temp = {
                    blob: _thumbnail,
                    file: _file
                }
                resolve(_temp);
            }
        });
    })
}
//上传图片(交互的)
export function uploadImg(filePath) {
    return new Promise((resolve, reject) => {
        uni.showLoading({
            mask: true,
        })
        uni.uploadFile({
            url: uploadUrl, 
            name: "file",
            filePath: filePath,
            success: (uploadFileRes) => {
                let _thumbnail = JSON.parse(uploadFileRes.data).data;
                resolve(_thumbnail)
            },
            complete: () => {
                uni.hideLoading()
                // this.hideInputPopup()
            }
        });
    })  
}



// 图片压缩
export function photoCompress(file,w,objDiv){
    var ready=new FileReader();
    /*开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容.*/
    ready.readAsDataURL(file);
    ready.onload=function(){
        var re=this.result;
        canvasDataURL(re,w,objDiv)
    }
}
// 通过canvas压缩得到base64
export function canvasDataURL(path, obj, callback){
    var img = new Image();
    img.src = path;
    img.onload = function(){
        var that = this;
        // 默认按比例压缩
        var w = that.width,
            h = that.height,
            scale = w / h;
        w = obj.width || w;
        h = obj.height || (w / scale);
        var quality = 0.7;  // 默认图片质量为0.7
        //生成canvas
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        // 创建属性节点
        var anw = document.createAttribute("width");
        anw.nodeValue = w;
        var anh = document.createAttribute("height");
        anh.nodeValue = h;
        canvas.setAttributeNode(anw);
        canvas.setAttributeNode(anh);
        ctx.drawImage(that, 0, 0, w, h);
        // 图像质量
        if(obj.quality && obj.quality <= 1 && obj.quality > 0){
            quality = obj.quality;
        }
        // quality值越小,所绘制出的图像越模糊
        var base64 = canvas.toDataURL('image/jpeg', quality);
        // 回调函数返回base64的值
        callback(base64);
    }
}

template

<view class="upload-box" @tap="uploadImg">
    <view class="img-box">
        <image class="img" v-if="thumbnail" :src="thumbnail" mode="aspectFill"></image>
        <!-- <image class="add"  src="/static/add.png" mode="aspectFit"></image> -->
        <text class="add" v-else>缩略图</text>
    </view>
</view>
<view class="input-header">
    <input class="input-h" type="text" placeholder="输入标题" v-model="title">
</view>
<view class="editor-box">
<!-- 如果交互的可以之间传提交地址,如果不交互可以不传返回base64,在富文本显示 -->
<!--jinEdit 手机端富文本插件  -->
    <jinEdit placeholder="请输入编辑内容" @editOk="editOk" uploadFileUrl=""></jinEdit> 
</view>

jinEdit组件改写

uni.chooseImage({
    count: 9, //默认9
    sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
    sourceType: ['album', 'camera'], //从相册选择
    success: async(res) => {
        var file = res.tempFiles[0];
            //utils.js 压缩返回base64,直接渲染
            photoCompress(file, {
                quality: 0.3
                }, function(base64Codes){
                //这里可以一个图片预览 把base64Codes 赋值给img的src即可
                console.log(base64Codes);
                _this.editorCtx.insertImage({
                    src: base64Codes,  // 此处需要将图片地址切换成服务器返回的真实图片地址
                    alt: '图片',
                    success: function(e) {}
                });
            })
    }
})

场景应用:手机端新闻发布

相关文章

  • 文件upload 文件上传深入

    我记录这篇文章是因为开发过程中,发现上传业务有时候感觉不同平台自己有时一脸懵逼不知道咋样去优化这块业务,不同的后台...

  • NSURLConnection上传

    //上传用post请求文件较大 //上传文件 - (void)upload { //设置路径 NSURL*url ...

  • 文件上传upload

    f12在前端js判断函数中加上可以上传php文件 在本地写一个一句话木马后文件名改为jpg之类的,直接上传,抓包...

  • upload 文件上传

    ----、黑名单检测 黑名单的安全性比白名单的安全性低很多,攻击首发自然也比白的名单多,一般有专门的blackli...

  • 前端文件上传与下载(含 base64流文件)

    上传文件实现 elementUi el-upload + axios自定义上传实现:/*** 批量上传文件* @p...

  • iview上传多文件

    iView自带的文件上传功能为Upload组件,基本用法参考文档upload 文档中的示例都是选择文件后,直接上传...

  • 上传图片-限制尺寸大小

    1.图片upload之前做监听,>-- before-upload handleBeforeUpload:上传文件...

  • 2018-07-24react.js ant-design

    upload组件文件上传表格 参考:https://ant.design/components/upload-cn/

  • PHP文件上传

    1.创建一个文件上传表单 2.创建上传脚本 "upload_file.php" 文件含有供上传文件的代码:在这个脚...

  • 2020-05-15

    jeecgboot框架——文件(图片)上传下载代码 表单文件(图片)上传代码

网友评论

    本文标题:文件upload 文件上传深入

    本文链接:https://www.haomeiwen.com/subject/iwkgvktx.html