惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
O
OpenAI News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 三生石上(FineUI控件)
Webroot Blog
Webroot Blog
GbyAI
GbyAI
S
SegmentFault 最新的问题
Cyberwarzone
Cyberwarzone
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
J
Java Code Geeks
Google DeepMind News
Google DeepMind News
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
博客园 - 【当耐特】
S
Secure Thoughts
酷 壳 – CoolShell
酷 壳 – CoolShell
AWS News Blog
AWS News Blog
Engineering at Meta
Engineering at Meta
S
Security Affairs
H
Help Net Security
Microsoft Security Blog
Microsoft Security Blog
D
DataBreaches.Net
云风的 BLOG
云风的 BLOG
Hugging Face - Blog
Hugging Face - Blog
Google DeepMind News
Google DeepMind News
Spread Privacy
Spread Privacy
T
Threatpost
Forbes - Security
Forbes - Security
C
Cisco Blogs
Scott Helme
Scott Helme
Attack and Defense Labs
Attack and Defense Labs
Simon Willison's Weblog
Simon Willison's Weblog
腾讯CDC
The Last Watchdog
The Last Watchdog
Cloudbric
Cloudbric
Last Week in AI
Last Week in AI
Recorded Future
Recorded Future
小众软件
小众软件
V
Vulnerabilities – Threatpost
美团技术团队
人人都是产品经理
人人都是产品经理
有赞技术团队
有赞技术团队
Apple Machine Learning Research
Apple Machine Learning Research
Hacker News - Newest:
Hacker News - Newest: "LLM"
I
Intezer
月光博客
月光博客
C
Cyber Attacks, Cyber Crime and Cyber Security
博客园 - 司徒正美
C
Cybersecurity and Infrastructure Security Agency CISA
Martin Fowler
Martin Fowler
博客园 - 聂微东

博客园 - 骨月枫🍁

使用vLLM部署Qwen/Qwen3.5-35B-A3B-FP8并且在DIFY中调用 记录个人数组、字符串自己常忘记的方法,以及ES常用处理方式 解决webpack vue 项目打包生成的文件,资源文件均404问题 js 复制粘贴功能记录 记录下工作中使用的pdf.js 记录下jplayer的简单demo js 函数节流 用ajax与fetch调用阿里云免费接口 简要谈谈javascript bind 方法 h5启动原生APP总结 mac上安装mongoDb以及简单使用 mac快捷键整理以及node的基本使用 html5视频video积累 整理下PC和移动获取点击、移动坐标的代码和坑 canvas基础学习(四) canvas基础学习(三) canvas基础学习(二) canvas基础学习(一) 移动端使用百度分享代码
html5 实现简单的上传
骨月枫🍁 · 2016-01-20 · via 博客园 - 骨月枫🍁

简单记录下今早做H5上传中一些代码还有坑

一、展示

因为前端上传文件是必须通过form表单的,不能使用ajax,这样的话一个移动页面放入一个type为file的input真心不怎么好看,如下图,很挫有没有

解决办法找了下,PC上有些是把这个input换成flash,采用jquery的工具库比如uploadify来做,但是移动端大部分浏览器是不支持flash的。所以最后采用的办法还是用form表单的形式,只是把这个form和input的透明度设置为0,让它们和准备显示的内容同时在一个div中,显示的内容可以做成自己想要的样子。代码如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
        <title></title>
        <style>
            div{width: 100%;}
            .logo img{display:block; margin:0 auto;}
            .upload{position: relative;width: 80px;height: 18px;line-height: 18px;background: #2fc7c9;text-align: center;
                    color: #FFF;padding: 0px 5px;-webkit-border-radius: 2px;border-radius: 2px;
                    margin: 0 auto;
                    }
            .upload form{width:100%;position:absolute; left:0; top:0;opacity:0; filter:alpha(opacity=0);}
            .upload form input{width: 100%;}
        </style>
    </head>
    <body>
        <div class="logo">
            <img src="img/1.jpg" />
        </div>
        <div class="upload">
            <p>上传图片</p>
            <form>
                <input type="file" />
            </form>
        </div>
    </body>
</html>

样子如左图,这样展现就在“上传图片”这个p标签中,点击它就有选择file的效果

二、JS代码

我这边写的蛮简单的,只是用了下h5上传的的基本功能

html代码如下,action为要请求的路径,我这边做的是当文件发生改变时就上传修改头像,input标签的name属性不能省去,具体跟后端接口有关

<form id="uploadForm" enctype="multipart/form-data" method="post" action="XXXXXX">
     <input type="file" name="imageFile" id="imageFile" onchange="fileSelected()" />
</form>
var iMaxFilesize = 2097152; //2M
window.fileSelected = function() {
    var oFile = document.getElementById('imageFile').files[0];    //读取文件
    var rFilter = /^(image\/bmp|image\/gif|image\/jpeg|image\/png|image\/tiff)$/i;
    if (!rFilter.test(oFile.type)) {
        alert("文件格式必须为图片");
        return;
    }
    if (oFile.size > iMaxFilesize) {
        alert("图片大小不能超过2M");
        return;
    }
    var vFD = new FormData(document.getElementById('uploadForm')),    //建立请求和数据
        oXHR = new XMLHttpRequest();
    oXHR.addEventListener('load', function(resUpload) {
        //成功
    }, false);
    oXHR.addEventListener('error', function() {
        //失败
    }, false);
    oXHR.addEventListener('abort', function() {
        //上传中断
    }, false);
    oXHR.open('POST', actionUrl);
    oXHR.send(vFD);
};

三、图片压缩

在开发中,特别是在移动端往往一张图片大小在3,4M左右,这样的图片上传会给服务器带来不少压力,同时也有不少接口对img的大小有所要求,比如不能超过200K,那手机相册的照片大多是见了鬼的,都上传不了。在html5的功能中,可以将图片压缩大小(尺寸)放到canvas画布上,然后截取canvas画布上的图片,转变为二进制的数据,通过blob进行再次压缩生成图片文件,这样手机上4M左右图片传到服务器上也就100K左右了。

<input type="file" name="imageFile" id="imageFile" onchange="fileSelected()" />
<form id="uploadForm" enctype="multipart/form-data" method="post" action="XXXXXX">
     <input hidden="hidden" name="param" value="test" />
</form>

当文件改变时,对图片进行压缩上传

window.fileSelected = function() {
    var _this = $(this);
    var file = this.files[0];
    var rFilter = /^(image\/bmp|image\/gif|image\/jpeg|image\/png|image\/tiff)$/i;
    if(!rFilter.test(file.type)) {
        alert("文件格式必须为图片");
        return;
    }
    /*开始进行网络加载*/
    _this.css("display", "none");    //目的是为了屏蔽点击事件
    var reader = new FileReader() , image = new Image() ,
        canvas = document.createElement("canvas") , ctx = canvas.getContext("2d");
    reader.onload = function() {        //文件加载完成
        var url = reader.result;
        image.src = url;
    };
    image.onload = function() {        //图片加载完成
        var w = image.naturalWidth , h = image.naturalHeight ,
            scale = 3;        //图片缩放比例,这里是把图片大小高宽均缩小3倍
        canvas.width = w / scale;
        canvas.height = h / scale;
        ctx.drawImage(image, 0 , 0 , w , h ,
            0 , 0 , canvas.width , canvas.height);
        fileUpload();    
    };
    reader.readAsDataURL(file);        //用文件加载器加载文件
    function fileUpload() {        //文件上传方法
        var quality = 0.3;        //图片的质量,这里设置的是0.3
        var data = canvas.toDataURL("image/jpeg", quality);//获取画布图片,并且要jpg格式
        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);
        }
        var blob = new Blob([ia], {            //以上均为二进制参数处理,从而获取一个blob对象
            type: "image/jpeg"
        });
        var fd = new FormData(document.getElementById("uploadForm"));
        fd.append("XXX"  , blob , "upload.jpg");    //向form中加入图片数据,name属性是XXX,文件名是upload.jpg
        var xhr = new XMLHttpRequest();
        xhr.addEventListener('load', function(resUpload) {
            _this.css("display", "");
            //请求成功
        }, false);
        xhr.addEventListener('error', function(){
            _this.css("display", "");
            //请求失败
        }, false);
        xhr.addEventListener('abort', function(){
            _this.css("display", "");
            //上传终止
        }, false);
        xhr.open('POST', "http://XXXXXXXXXXXXX");//请求地址
        xhr.send(fd);//发送
    }
};

关键代码

reader.readAsDataURL(file);

将文件读取为DataURL

canvas.toDataURL(type, encoderOptions); 

实际上就是读取canvas画布上图片的数据。其默认是png格式,如果第一个参数type是image/jpeg的话,第二个参数encoderOptions就可以用来设置图片的压缩质量。

var quality = 0.3;        //图片的质量,这里设置的是0.3
var data = canvas.toDataURL("image/jpeg", quality);//获取画布图片,并且要jpg格式
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);
}
var blob = new Blob([ia], {            //以上均为二进制参数处理,从而获取一个blob对象
    type: "image/jpeg"
});

这一段代码的的目的是为了解码图片数据,然后返回一个Blob对象,对象的格式是jpg。aton其作用是做解码,因为图片格式的base64,该方法解码出来可能是一堆乱码,Uint8Array返回的是8进制整型数组。

Blob是存储二进制文件的容器,典型的Blob对象是一个图片或者声音文件,其默认是PNG格式。最后的blob就可以传给服务端了。

整理成一个插件,代码如下

(function(window,undefind){
    function imgUpLoad(options){
        var defaults = {
            inputId : "" ,        //输入框ID
            formId : "" ,        //表单ID
            paramName : "" ,        //输入框的name
            requestUrl : "" ,     //请求的URL
            imgSizeScale : 3 ,     //图片缩放比例
            imgQuality : 0.3 ,    //图片质量
            sucFun : undefind , //成功的回调函数
            errFun : undefind , //失败的回调函数
            abortFun : undefind     //上传取消的回调函数
        };
        var opts = $.extend(true , defaults , options || {}) ,
            _this = document.getElementById(opts.inputId);
        _this.addEventListener('change' , fileChange , false);    
        function fileChange() {
            var file = _this.files[0];
            var rFilter = /^(image\/bmp|image\/gif|image\/jpeg|image\/png|image\/tiff)$/i;
            if(!rFilter.test(file.type)) {
                alert("文件格式必须为图片");
                return;
            }
            var reader = new FileReader() , image = new Image() ,
                canvas = document.createElement("canvas") , ctx = canvas.getContext("2d");
            startFileLoad(reader , image , canvas , ctx);
        }
        function startFileLoad(reader , image , canvas , ctx){    //文件加载
            reader.onload = function() {        //文件加载完成
                var url = reader.result;
                image.src = url;
            };
            image.onload = function() {        //图片加载完成
                var w = image.naturalWidth , h = image.naturalHeight;
                canvas.width = w / opts.imgSizeScale;
                canvas.height = h / opts.imgSizeScale;
                ctx.drawImage(image, 0 , 0 , w , h ,
                    0 , 0 , canvas.width , canvas.height);
                fileUpload(canvas);    
            };
            reader.readAsDataURL(file);    
        }
        function fileUpload(canvas){        //文件上传
            var blob = getBlob(canvas);
            var fd = new FormData(document.getElementById(opts.formId));
            fd.append(opts.paramName  , blob , "upload.jpg");
            var xhr = new XMLHttpRequest();
            xhr.addEventListener('load', function(resUpload) {    //请求成功
                _this.style.display = "";
                if(opts.sucFun && typeof opts.sucFun === "function")        opts.sucFun(resUpload.currentTarget.response);
            }, false);
            xhr.addEventListener('error', function(){    //请求失败
                _this.style.display = "";
                if(opts.errFun && typeof opts.errFun === "function")        opts.errFun();
            }, false);
            xhr.addEventListener('abort', function(){    //上传终止
                _this.style.display = "";
                if(opts.abortFun && typeof opts.abortFun === "function")        opts.abortFun();
            }, false);
            xhr.open('POST', opts.requestUrl);//请求地址
            xhr.send(fd);//发送
        }
        function getBlob(canvas){        //获取blob对象
            var data = canvas.toDataURL("image/jpeg", opts.imgQuality);
            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: "image/jpeg"
            });
        }
    }
    window.imgUpLoad = imgUpLoad;
})(window);