2

文件上传

不借助第三方的插件的情况下进行文件上传可利用:

  1. Form表单

  2. FormData对象

Form表单是不存在浏览器的兼容性的,同时在js被禁用的情况下也能进行文件的传输,因此可以大胆使用。Form表单提交不同于Ajax,Ajax提交数据还需要利用脚本进行数据的处理,而Form是不需要进行任何数据处理的。

使用Form表单提交文件一个非常典型的应用场景就是上传图片,但是页面不刷新。

常用属性

  • target(数据提交完后,后台返回数据展示的位置,常用_blank, _self, 指定的iframe)

  • action(数据提交的接口)

  • enctype(设置上传数据编码类型,常用的application/x-www-form-urlencoded,multipart/form-data)

  • method(HTTP请求的方式,常用GET/POST)

示例

使用Form表单异步上传图片,获取后台返回的图片路径,页面不发生跳转。

    Html:
    
    <form action="/" enctype="multipart/form-data" target="test-ifr" method="post">
        <input type="file" name="key">
    </form>
    <button>点击上传</button>
    <div id="container"></div>

js:

    (function(window) {
        var win = window,
            btn = document.getElementsByTagName('button')[0],
            container = document.getElementById('container'),
            form = document.getElementsByTagName('form')[0];
            
            btn.addEventListener('click', function() {
                var ifr = document.createElement('iframe');
                    ifr.id = 'test-ifr';
                    ifr.name = 'test-ifr';
                    //隐藏iframe
                    ifr.style.display = 'none';

                    container.appendChild(ifr);
                    //iframe加载事件,获取到数据以前onload会触发一次,获取到数据后再触发一次,需要添加一个判断
                    ifr.onload = function () {
                       //后台尽量传JSON的字符串,这样可以确保一致性,同时可以调用innerHTML来获取DOM里面的内容
                        var _result = JSON.parse(this.contentDocument.getElementsByTagName('body')[0].innerHTML);
                    //iframe的body标签里面的内容就是从后台传输过来的数据。例如后台传输过来的是图片的url地址
                    var _img = new Image();
                    _img.src = _result.url;
                    container.appendChild(_img);//显示图片
        };

                    //调用Form表单事件
                    form.submit();
            })
    })(window);

server:

var express = require('express');
var bodyParser = require('body-parser');
var app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(express.static('./'));

app.get('/', function (req, res) {
    res.sendFile('index.html');
});

app.post('/', function (req, res) {
    setTimeout(function () {
        var str = JSON.stringify({url: './imgs/1.png'});
        res.send(str);
    }, 1000);
});

app.listen(3000, function () {
    console.log('The server has start up on port of 3000');
});

如果现在需求变化了,必须要求前端上传图片后需要立马在前端展示出来,而不是通过上传至服务器端,拿到Url后再展示。现在HTML5提供了3种API可以做到。

  • FileReader

  • canvas

  • ceateObjectURL()

FileReader

    <input type="file" multiple accept="image/*">
    //multiple属性支持多文件上传
    <div class="img-container"></div>
    var aInput = document.getElementByTagName('input')[0],
        imgContainer = document.getElementByClassName('img-container')[0];
    aInput.addEventListener('change', function() {
        for(var i = 0; i < this.files.length; i++) {
            var img = new Image(),
                reader = new FileReader(),
                url = reader.readAsDataURL(this.files[i]);
            
            imgContainer.appendChild(img);
            
            reader.onload = function(e) {
                img.src = e.target.result;
            }
        }
    });

这个API主要是是将Image转化成了base64,这样图片就能在不推送的服务器后才显示。
FileReader兼容性

canvas

canvas是在网页中生成一块画图,然后利用drawImage方法,将图片在画布中重新绘制。

    var img = new Image(),
            canvas;
    img.onload = function () {
        canvas = document.createElement('canvas');
        canvas.width = img.width;
        canvas.height = img.height;
        var context = canvas.getContext('2d');
        context.drawImage(img, 0, 0);
        console.log(canvas.toDataURL());
        document.body.appendChild(canvas);
        return canvas;
    };
    img.src = './images/1.png';
    
    //drawImage即将img画到画布区域内,接收三个参数,第一个是img对象,第二个是绘制的起始位置水平,第三个是绘制的垂直位置。

canvas兼容性


苹果小萝卜
5.1k 声望356 粉丝

Github: [链接]