# WebUploader - 文件上传组件

WebUploader 是百度开源的一个强大的文件上传组件，支持 HTML5 和 Flash 两种上传方式，自动根据浏览器环境选择最佳方案。

## 特性

- ✅ HTML5 + Flash 双模式，自动降级
- ✅ 多文件上传
- ✅ 拖拽上传
- ✅ 图片预览
- ✅ 上传进度条
- ✅ 文件类型/大小限制
- ✅ 分片上传（大文件）
- ✅ 断点续传

## 加载方式

```javascript
// 加载 CSS
Wind.css('webuploader');

// 加载 JS
Wind.use('webuploader', function() {
    // WebUploader 加载完成，可以使用了
});
```

## 基础用法

### 1. 基础文件上传

```html
<div id="uploader">
    <div id="picker">选择文件</div>
    <div id="fileList"></div>
</div>
```

```javascript
Wind.use('webuploader', function() {
    var uploader = WebUploader.create({
        // 选完文件后，是否自动上传
        auto: true,
        
        // swf文件路径
        swf: '/public/static/js/webuploader/Uploader.swf',
        
        // 文件接收服务端
        server: '/upload/file',
        
        // 选择文件的按钮
        pick: '#picker',
        
        // 文件上传域的name
        fileVal: 'file'
    });
    
    // 文件加入队列时
    uploader.on('fileQueued', function(file) {
        $('#fileList').append('<div id="' + file.id + '" class="item">' +
            '<h4 class="info">' + file.name + '</h4>' +
            '<p class="state">等待上传...</p>' +
        '</div>');
    });
    
    // 上传成功时
    uploader.on('uploadSuccess', function(file, response) {
        $('#' + file.id).find('p.state').text('已上传');
    });
    
    // 上传失败时
    uploader.on('uploadError', function(file) {
        $('#' + file.id).find('p.state').text('上传出错');
    });
});
```

### 2. 图片上传（带预览）

```html
<div id="uploader">
    <div id="picker">选择图片</div>
    <div id="preview"></div>
</div>
```

```javascript
Wind.use('webuploader', function() {
    var uploader = WebUploader.create({
        auto: true,
        swf: '/public/static/js/webuploader/Uploader.swf',
        server: '/upload/image',
        pick: '#picker',
        
        // 只允许选择图片
        accept: {
            title: 'Images',
            extensions: 'gif,jpg,jpeg,bmp,png',
            mimeTypes: 'image/*'
        },
        
        // 缩略图配置
        thumb: {
            width: 110,
            height: 110,
            quality: 70,
            allowMagnify: true,
            crop: true
        },
        
        // 压缩图片（仅对支持的图片）
        compress: {
            width: 1600,
            height: 1600,
            quality: 90,
            allowMagnify: false,
            crop: false,
            preserveHeaders: true,
            noCompressIfLarger: false,
            compressSize: 0
        }
    });
    
    // 生成缩略图预览
    uploader.on('fileQueued', function(file) {
        uploader.makeThumb(file, function(error, src) {
            if (error) {
                $('#preview').append('<p>不能预览</p>');
                return;
            }
            $('#preview').append('<img src="' + src + '" />');
        });
    });
    
    // 上传成功
    uploader.on('uploadSuccess', function(file, response) {
        console.log('上传成功', response);
    });
});
```

### 3. 拖拽上传

```html
<div id="uploader">
    <div id="dndArea" class="placeholder">
        <p>或将照片拖到这里，单次最多可选300张</p>
    </div>
    <div id="fileList"></div>
    <div id="picker">选择文件</div>
</div>
```

```javascript
Wind.use('webuploader', function() {
    var uploader = WebUploader.create({
        auto: true,
        swf: '/public/static/js/webuploader/Uploader.swf',
        server: '/upload/file',
        pick: '#picker',
        
        // 拖拽区域
        dnd: '#dndArea',
        
        // 禁用全局拖拽
        disableGlobalDnd: true,
        
        // 文件数量限制
        fileNumLimit: 300,
        
        // 文件大小限制（单位：字节）
        fileSizeLimit: 200 * 1024 * 1024, // 200M
        
        // 单文件大小限制
        fileSingleSizeLimit: 50 * 1024 * 1024 // 50M
    });
});
```

## 高级配置

### 完整配置示例

```javascript
Wind.use('webuploader', function() {
    var uploader = WebUploader.create({
        // 是否自动上传
        auto: false,
        
        // 选择文件按钮
        pick: {
            id: '#picker',
            label: '点击选择图片',
            multiple: true  // 是否允许多选
        },
        
        // swf文件路径
        swf: '/public/static/js/webuploader/Uploader.swf',
        
        // 文件接收服务端
        server: '/upload/file',
        
        // 文件上传域的name
        fileVal: 'file',
        
        // 发送给服务端的额外数据
        formData: {
            uid: 123,
            type: 'image'
        },
        
        // 文件数量限制
        fileNumLimit: 10,
        
        // 总文件大小限制
        fileSizeLimit: 500 * 1024 * 1024, // 500M
        
        // 单文件大小限制
        fileSingleSizeLimit: 50 * 1024 * 1024, // 50M
        
        // 允许的文件类型
        accept: {
            title: 'Images',
            extensions: 'gif,jpg,jpeg,bmp,png',
            mimeTypes: 'image/*'
        },
        
        // 拖拽配置
        dnd: '#dndArea',
        disableGlobalDnd: true,
        paste: '#uploader',
        
        // 缩略图配置
        thumb: {
            width: 110,
            height: 110,
            quality: 70,
            allowMagnify: true,
            crop: true
        },
        
        // 压缩配置
        compress: {
            width: 1600,
            height: 1600,
            quality: 90
        },
        
        // 是否允许重复上传同一文件
        duplicate: false,
        
        // 是否分片上传
        chunked: false,
        
        // 分片大小（字节）
        chunkSize: 5 * 1024 * 1024, // 5M
        
        // 上传并发数
        threads: 3,
        
        // 上传超时时间
        timeout: 0,
        
        // 上传方式（POST/GET）
        method: 'POST'
    });
});
```

## 常用方法

```javascript
Wind.use('webuploader', function() {
    var uploader = WebUploader.create({
        auto: false,
        swf: '/public/static/js/webuploader/Uploader.swf',
        server: '/upload/file',
        pick: '#picker'
    });
    
    // 手动上传
    $('#uploadBtn').on('click', function() {
        uploader.upload();
    });
    
    // 暂停上传
    $('#pauseBtn').on('click', function() {
        uploader.stop(true);
    });
    
    // 继续上传
    $('#continueBtn').on('click', function() {
        uploader.upload();
    });
    
    // 取消上传
    $('#cancelBtn').on('click', function() {
        uploader.stop(true);
    });
    
    // 移除文件
    $('#fileList').on('click', '.remove', function() {
        var fileId = $(this).data('id');
        uploader.removeFile(fileId, true);
    });
    
    // 获取文件数量
    console.log(uploader.getFiles().length);
    
    // 获取统计信息
    var stats = uploader.getStats();
    console.log('成功：' + stats.successNum);
    console.log('失败：' + stats.uploadFailNum);
    console.log('取消：' + stats.cancelNum);
    console.log('无效：' + stats.invalidNum);
    
    // 重置
    $('#resetBtn').on('click', function() {
        uploader.reset();
    });
    
    // 销毁
    $('#destroyBtn').on('click', function() {
        uploader.destroy();
    });
});
```

## 事件列表

```javascript
Wind.use('webuploader', function() {
    var uploader = WebUploader.create({
        auto: true,
        swf: '/public/static/js/webuploader/Uploader.swf',
        server: '/upload/file',
        pick: '#picker'
    });
    
    // 当文件被加入队列之前触发
    uploader.on('beforeFileQueued', function(file) {
        // 返回 false 则不加入队列
        if (file.size > 10 * 1024 * 1024) {
            alert('文件太大');
            return false;
        }
    });
    
    // 当文件被加入队列以后触发
    uploader.on('fileQueued', function(file) {
        console.log('文件加入队列', file.name);
    });
    
    // 当一批文件添加进队列以后触发
    uploader.on('filesQueued', function(files) {
        console.log('批量加入队列', files.length);
    });
    
    // 当文件被移除队列后触发
    uploader.on('fileDequeued', function(file) {
        console.log('文件移除队列', file.name);
    });
    
    // 当 uploader 被重置的时候触发
    uploader.on('reset', function() {
        console.log('重置');
    });
    
    // 当开始上传流程时触发
    uploader.on('startUpload', function() {
        console.log('开始上传');
    });
    
    // 当开始上传流程时触发
    uploader.on('stopUpload', function() {
        console.log('停止上传');
    });
    
    // 上传过程中触发，携带上传进度
    uploader.on('uploadProgress', function(file, percentage) {
        var percent = Math.round(percentage * 100);
        console.log('上传进度：' + percent + '%');
        $('#' + file.id).find('.progress .bar').css('width', percent + '%');
    });
    
    // 当文件上传成功时触发
    uploader.on('uploadSuccess', function(file, response) {
        console.log('上传成功', response);
    });
    
    // 当文件上传出错时触发
    uploader.on('uploadError', function(file, reason) {
        console.log('上传失败', reason);
    });
    
    // 不管成功或者失败，文件上传完成时触发
    uploader.on('uploadComplete', function(file) {
        console.log('上传完成', file.name);
    });
    
    // 当所有文件上传结束时触发
    uploader.on('uploadFinished', function() {
        console.log('所有文件上传完成');
    });
    
    // 当validate不通过时触发
    uploader.on('error', function(type) {
        switch(type) {
            case 'Q_TYPE_DENIED':
                alert('文件类型不允许');
                break;
            case 'Q_EXCEED_NUM_LIMIT':
                alert('文件数量超出限制');
                break;
            case 'Q_EXCEED_SIZE_LIMIT':
                alert('文件总大小超出限制');
                break;
            case 'F_EXCEED_SIZE':
                alert('单个文件大小超出限制');
                break;
            case 'F_DUPLICATE':
                alert('文件重复');
                break;
        }
    });
});
```

## 实际应用场景

### 1. 多图上传（带预览和进度）

```html
<div id="uploader">
    <div class="queueList">
        <div id="dndArea" class="placeholder">
            <div id="filePicker"></div>
            <p>或将照片拖到这里，单次最多可选300张</p>
        </div>
    </div>
    <div class="statusBar" style="display:none;">
        <div class="progress">
            <span class="text">0%</span>
            <span class="percentage"></span>
        </div>
        <div class="info"></div>
        <div class="btns">
            <div id="filePicker2"></div>
            <div class="uploadBtn">开始上传</div>
        </div>
    </div>
</div>
```

```javascript
Wind.use('webuploader', function() {
    var $wrap = $('#uploader'),
        $queue = $('<ul class="filelist"></ul>').appendTo($wrap.find('.queueList')),
        $statusBar = $wrap.find('.statusBar'),
        $info = $statusBar.find('.info'),
        $upload = $wrap.find('.uploadBtn'),
        $progress = $statusBar.find('.progress').hide();
    
    var uploader = WebUploader.create({
        auto: false,
        pick: {
            id: '#filePicker',
            label: '点击选择图片'
        },
        dnd: '#dndArea',
        paste: '#uploader',
        swf: '/public/static/js/webuploader/Uploader.swf',
        server: '/upload/image',
        accept: {
            title: 'Images',
            extensions: 'gif,jpg,jpeg,bmp,png',
            mimeTypes: 'image/*'
        },
        fileNumLimit: 300,
        fileSizeLimit: 200 * 1024 * 1024,
        fileSingleSizeLimit: 50 * 1024 * 1024
    });
    
    // 添加文件到队列
    uploader.on('fileQueued', function(file) {
        var $li = $('<li id="' + file.id + '">' +
            '<p class="title">' + file.name + '</p>' +
            '<p class="imgWrap"></p>' +
            '<p class="progress"><span></span></p>' +
            '</li>');
        
        $queue.append($li);
        
        // 创建缩略图
        uploader.makeThumb(file, function(error, src) {
            if (error) {
                $li.find('.imgWrap').text('不能预览');
                return;
            }
            $li.find('.imgWrap').html('<img src="' + src + '">');
        });
        
        $statusBar.show();
    });
    
    // 上传进度
    uploader.on('uploadProgress', function(file, percentage) {
        var $li = $('#' + file.id),
            $percent = $li.find('.progress span');
        $percent.css('width', percentage * 100 + '%');
    });
    
    // 上传成功
    uploader.on('uploadSuccess', function(file, response) {
        $('#' + file.id).addClass('upload-state-done');
    });
    
    // 上传失败
    uploader.on('uploadError', function(file) {
        $('#' + file.id).addClass('upload-state-error');
    });
    
    // 点击上传
    $upload.on('click', function() {
        uploader.upload();
    });
});
```

### 2. 头像裁剪上传

```javascript
Wind.use('webuploader', 'jcrop', function() {
    var uploader = WebUploader.create({
        auto: true,
        swf: '/public/static/js/webuploader/Uploader.swf',
        server: '/upload/avatar',
        pick: '#avatarPicker',
        accept: {
            title: 'Images',
            extensions: 'jpg,jpeg,png',
            mimeTypes: 'image/*'
        },
        fileSingleSizeLimit: 2 * 1024 * 1024 // 2M
    });
    
    uploader.on('uploadSuccess', function(file, response) {
        if (response.code == 1) {
            var src = response.data.url;
            $('#avatarPreview').attr('src', src);
            
            // 初始化裁剪
            $('#avatarPreview').Jcrop({
                aspectRatio: 1,
                onSelect: function(c) {
                    // 保存裁剪坐标
                    $('#cropData').val(JSON.stringify(c));
                }
            });
        }
    });
});
```

## 浏览器兼容性

| 浏览器 | 上传方式 | 说明 |
|--------|----------|------|
| Chrome | HTML5 | 完整支持 |
| Firefox | HTML5 | 完整支持 |
| Safari | HTML5 | 完整支持 |
| Edge | HTML5 | 完整支持 |
| IE 11 | HTML5 | 完整支持 |
| IE 10 | HTML5 | 完整支持 |
| IE 9 | Flash | 需要 Flash 支持 |
| IE 8 | Flash | 需要 Flash 支持 |

## 更多文档

- 官方文档: https://fex.baidu.com/webuploader/
- GitHub: https://github.com/fex-team/webuploader
