JS分片上传

JS分片上传

//分片上传

function ScarecrowPatchUpload (uploadPath, isPatch,onePackSize=1024*1024) {

    //是否分片上传

    isPatch = isPatch == undefined ? false : Boolean(isPatch);

    if (uploadPath == undefined) {

        throw new Error("ScarecrowPatchUpload obj must parameter 1:uploadPath");

    }

    this.__init__(uploadPath, isPatch, onePackSize);

}

ScarecrowPatchUpload.prototype={

    constructor: ScarecrowPatchUpload,

    fileObj:null,

    fileName:"",

    fileSize:0,

    uploadPath:"./",

    onePackSize:1024*1024*8,

    blockData:null,

    blockNum:0,

    blockNumSum:0,

    isPatch:false,

    startIndex:0,

    endIndex:0,

    formData:null,

    ajaxObj:null,

    isSend:false,

    isSendTemp:true,

    __iCnt:0,

    //上传完成回调函数

    funcUploadSuccess:function () {},

    //每个分片上传成功回调函数

    funcUploadStateChange:function () {},

    __init__:function (uploadPath, isPatch, onePackSize) {

        this.isPatch = isPatch;

        this.formData = new FormData();

        this.ajaxObj = new XMLHttpRequest();

        this.uploadPath = uploadPath;

        if (this.isPatch) {

            this.onePackSize = onePackSize;

        }

    },

    addFile:function (fileInfo) {

        if (fileInfo.files.length < 1) {

            console.error("没有找到对应的文件");

            return false;

        }

        console.log(fileInfo.files);

        this.fileObj = fileInfo.files[0];

        this.fileName = this.fileObj.name;

        this.fileSize = this.fileObj.size;

        if (this.isPatch) {

            this.blockNumSum = Math.ceil(this.fileSize / this.onePackSize)

        }

        this.isSend = true;

        this.isSendTemp = false;

        if (this.isPatch) {

            this.__iCnt = setInterval(()=>{

                console.log(this.blockNum);

                if (this.blockNum >= this.blockNumSum) {

                    clearInterval(this.__iCnt);

                    return ;

                }

                if (this.isSendTemp) {

                    this.sendFile();

                }

            }, 500);

        }

    },

    //发送文件

    sendFile:function () {

        this.isSendTemp = false;

        if (!this.isSend) {

            console.error("请先使用addFile添加文件对象");

            return false;

        }

        if (this.isPatch) {

            if(!this.cutFile()){

                return ;

            }

        } else {

            this.blockNum = 1;

            this.blockNumSum = 1;

            this.blockData = this.fileObj;

        }

        this.clearFormData();

        this.formData.append('file', this.blockData);

        this.formData.append('blockNum', this.blockNum);

        this.formData.append('blockNumSum', this.blockNumSum);

        this.formData.append('fileName', this.fileName);

        this.formData.append('isPatch', this.isPatch);

        this.ajaxObj.open('POST',this.uploadPath,false);

        this.ajaxObj.onreadystatechange =  () => {

            if (this.ajaxObj.status == 500 && this.isPatch) {

                clearInterval(this.__iCnt);

            }

            if (this.ajaxObj.readyState == 4 && this.ajaxObj.status == 200) {

                this.funcUploadStateChange.call(this);

                if (this.blockNum >= this.blockNumSum) {

                    this.funcUploadSuccess.call(this);

                    this.__resetObj();

                }

                this.ajaxObj.readyState = 1;

                this.isSendTemp = true;

            }

        }

        this.ajaxObj.send(this.formData);

    },

    //分割文件

    cutFile:function () {

        this.endIndex = this.startIndex + this.onePackSize;

        if (this.startIndex > this.fileSize) {

            this.startIndex = 0;

            return false;

        }

        this.blockNum += 1;

        this.blockData = this.fileObj.slice(this.startIndex, this.endIndex);

        this.startIndex = this.endIndex;

        return true;

    },

    clearFormData:function () {

        this.formData.has('file') ? this.formData.delete("file"): null;

        this.formData.has('blockNum') ? this.formData.delete("blockNum"): null;

        this.formData.has('blockNumSum') ? this.formData.delete("blockNumSum"): null;

        this.formData.has('fileName') ? this.formData.delete("fileName"): null;

        this.formData.has('isPatch') ? this.formData.delete("isPatch"): null;

    },

    setFuncUploadSuccess:function (func) {

        if (typeof func == "function") {

            this.funcUploadSuccess = func;

        } else {

            throw new Error("setFuncUploadSuccess parameter 1 must is function");

        }

    },

    //设置上传状态改变函数

    setFuncUploadStateChange:function (func) {

        if (typeof func == "function") {

            this.funcUploadStateChange = func;

        } else {

            throw new Error("setFuncUploadStateChange parameter 1 must is function");

        }

    },

    //重置参数

    __resetObj:function () {

        this.fileObj = null;

        this.blockNumSum = 0;

        this.blockNum = 0;

        this.endIndex = 0;

        this.formData = new FormData();

    }

}



文档:


## 分页上传JS说明文档

## 方法:

### addFile(fileInfo):void

    添加一个文件对象

    fileInfo为input 中的file具体对象


### sendFile():void

    上传文件

### setFuncUploadSuccess(func):void

    设置上传成功后的回调函数

    func:callback 回调函数


### setFuncUploadStateChange(func):void

    设置分片上传每个分片上传成功时的回调函数

    func:callback 回调函数   




示例:

index.html

<!doctype html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport"

          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">

    <meta http-equiv="X-UA-Compatible" content="ie=edge">

    <title>Document</title>

    <style>

        #progress{

            width: 300px;

            height: 20px;

            background-color:#f7f7f7;

            box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);

            border-radius:4px;

            background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);

        }

        #finish{

            background-color: #149bdf;

            background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);

            background-size:40px 40px;

            height: 100%;

        }

        form{

            margin-top: 50px;

        }

    </style>

</head>

<body>

<div id="progress">

    <div id="finish" style="width: 0%;" progress="0"></div>

    <br>

    <span id="showjindu"></span>

</div>

<form>

    <input type="file" name="file" id="file">

    <input type="button" value="上传" id="sc">

</form>

<script src="ScarecrowPatchUpload.js"></script>

<script>

    var fileForm = document.getElementById("file");

    upload = new ScarecrowPatchUpload("./index.php", true);

    upload.setFuncUploadSuccess(function () {

        console.log(this.fileName+"上传成功");

        alert(this.fileName+"上传成功");

    });

    upload.setFuncUploadStateChange(function () {

        var progress;

        var progressObj = document.getElementById('finish');

        var showjindu = document.getElementById("showjindu");

        if(this.blockNumSum == 1){

            progress = '100%';

        }else{

            progress = Math.min(100,(this.blockNum/this.blockNumSum)* 100 ) +'%';

        }

        progressObj.style.width = progress;

        showjindu.innerHTML= progress;

    });

    fileForm.onchange = function(){

        upload.addFile(this);

        upload.sendFile();

    }

</script>

</body>

</html>



upload.php

<?php

class Upload{

    private $filepath = './upload'; //上传目录

    private $tmpPath; //PHP文件临时目录

    private $blobNum; //第几个文件块

    private $totalBlobNum; //文件块总数

    private $fileName; //文件名

    public function __construct($tmpPath,$blobNum,$totalBlobNum,$fileName){

        $this->tmpPath = $tmpPath;

        $this->blobNum = $blobNum;

        $this->totalBlobNum = $totalBlobNum;

        $this->fileName = $fileName;

    }

    //判断是否是最后一块,如果是则进行文件合成并且删除文件块

    private function fileMerge(){

        if($this->blobNum == $this->totalBlobNum){

            $file = fopen($this->filepath.'/'. $this->fileName, "a+");

            $blob = '';

            for($i=1; $i<= $this->totalBlobNum; $i++){

                $blob = file_get_contents($this->filepath.'/'. $this->fileName.'__'.$i);

                fwrite($file, $blob);

            }

            fclose($file);

            $this->deleteFileBlob();

        }

    }

    //删除文件块

    private function deleteFileBlob(){

        for($i=1; $i<= $this->totalBlobNum; $i++){

            @unlink($this->filepath.'/'. $this->fileName.'__'.$i);

        }

    }

    //移动文件

    private function moveFile(){

        $this->touchDir();

        $filename = $this->filepath.'/'. $this->fileName.'__'.$this->blobNum;

        if (is_uploaded_file($this->tmpPath)){

            move_uploaded_file($this->tmpPath,$filename);

        }

    }

    //建立上传文件夹

    private function touchDir(){

        if(!file_exists($this->filepath)){

            return mkdir($this->filepath);

        }

    }

    //开始接受上传

    public function start()

    {

        $this->moveFile();

        $this->fileMerge();

    }

}

//实例化并获取系统变量传参

$upload = new Upload($_FILES['file']['tmp_name'],$_POST['blockNum'],$_POST['blockNumSum'],$_POST['fileName']);

$upload->start();

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容

  • 单例模式 适用场景:可能会在场景中使用到对象,但只有一个实例,加载时并不主动创建,需要时才创建 最常见的单例模式,...
    Obeing阅读 2,045评论 1 10
  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些阅读 2,025评论 0 2
  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,674评论 0 38
  • 【0224 读书感悟】3078-Why小賢 书名:《干法》 作者:稻盛和夫 金句: 不是为了击败对手而拼命,而是为...
    Why小賢阅读 235评论 0 0
  • 本周已经是父母课堂的第四个学习主题了,转眼间,父母课堂已经开讲了一个月了,这一个月的收获还是很大的! 记得第一次讲...
    乐瞳妈咪阅读 507评论 0 1