首页 > 其他分享 >layui upload 分块上传实现

layui upload 分块上传实现

时间:2022-12-01 11:15:42浏览次数:45  
标签:分块 layui number upload let file progress

由于项目需要上传超大文件,当然现在的条件好了,1-3百M的文件没多大问题,但是超过1G的还是有问题的。(当然oss单个文件最高可以5g)对于大额文件上传存在上传缓慢甚至失败的问题

所有研究了一下layui怎么实现分块上传(layui没有提供,不过大部分需求满足所有,还有各家的云储存减少一定需求)。

实现逻辑就是利用ajax技术做循环提交文件。

先把文件对象(二进制)分割成多分,然后分多次提交

后端接受后,在合成一个完整的文件。大致流程如此,实现的方式有差异

前端代码:(哈哈,半吊子前端,也是参考别人的)

<!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">
    <!-- 注意:如果你直接复制所有代码到本地,上述css路径需要改成你本地的 -->
    <?php include get_theme_path() . 'commom/head.php' ?>
    <style>
        .layui-progress {
            position: fixed;
            width: 300px;
            left: 50%;
            margin-left: -150px;
            top: 200px;
            height: 18px;
            border-radius: 10px;
            background: #fff;
            z-index: 99999999;
            overflow: hidden;
            display: none;
        }
    </style>
</head>
<body>
<form class="layui-form" method="post" action="">
    <input type="hidden" name="form_submit" value="ok"/>
    <div class="layui-form-item">
        <label class="layui-form-label">选择文件:</label>
        <div class="layui-input-block">
            <button type="button" class="layui-btn" id="file"><i class="layui-icon"></i>上传文件</button>
        </div>
    </div>
    <div class="layui-form-item">
        <label class="layui-form-label">文件名:</label>
        <div class="layui-input-block">
            <input type="text" name="name" id="name" value="" lay-verify="title" autocomplete="off" readonly="true"
                   class="layui-input">
        </div>
    </div>
    <div class="layui-form-item layui-form-text">
        <label class="layui-form-label">文件地址:</label>
        <div class="layui-input-block">
            <input type="text" name="path" id="path" value="" lay-verify="path" autocomplete="off"
                   readonly="true" placeholder="" class="layui-input">
        </div>
    </div>
    <div class="layui-form-item">
        <div class="layui-input-block">
            <button class="layui-btn" lay-submit="" lay-filter="submit">立即提交</button>
            <button type="reset" class="layui-btn layui-btn-primary">重置</button>
        </div>
    </div>
</form>

<div class="layui-progress layui-progress-big" lay-showpercent="true" lay-filter="Progress">
    <div class="layui-progress-bar layui-bg-blue" lay-percent="0%"></div>
</div>
<!-- 注意:如果你直接复制所有代码到本地,上述js路径需要改成你本地的 -->
<?php include get_theme_path() . 'commom/foot.php' ?>
<script>
    layui.use(['form', 'upload', 'element'], function () {
        let form = layui.form
            , upload = layui.upload
            , element = layui.element
            , $ = layui.jquery;

        let number, status, size, totalNum;// number控制数量,status状态,size 文件大小 totalNum总数
        upload.render({
            elem: '#file',
            url: apiDomain + '/test/file', //处理上传文件接口
            accept: 'file',
            auto: false,
            choose: function (obj) {
                layer.load(1,{shade: 0.3});
                element.progress('Progress', '0%');
                $('.layui-progress').show();
                let data = this.data;//请求上传接口的额外参数
                // let files = obj.pushFile();
                let LENGTH = 1024 * 1024 * 5; //每片文件大小
                obj.preview(function (index, file, result) {
                    size = file.size;
                    totalNum = Math.ceil(size / LENGTH);
                    number = 1;//初始化
                    status = 1;//初始化 1开始
                    let fileName = file.name;
                    $('#name').val(fileName);
                    let fileExt = fileName.substring(fileName.lastIndexOf('.') + 1);
                    // let uuidFileName = fileName.substring(0, fileName.lastIndexOf('.'));
                    let uuidFileName = ''//前端自己实现唯一或者后端实现就不用传参,
                    let progress = setInterval(function () {
                        if (totalNum === number && (status === 2 || status === -1)) {//当总数和分片数相等
                            clearInterval(progress);//结束循环
                        } else {
                            if (status === 1) {
                                status = 0;//改为0避免直接循环 一次循环一次返回结果避免异步或者后置
                                data.fileName = uuidFileName;
                                data.number = number;
                                data.totalNum = totalNum;
                                data.fileExt = fileExt;
                                data.type = file.type;
                                let blob = file.slice((number - 1) * LENGTH, number * LENGTH)//分割file(二进制blob)对象,但类似分页找到目标blob对象
                                obj.upload(index, blob);
                            }
                        }
                    }, 100);
                });
            },
            done: function (res) {
                if (res.code === 100) {
                    element.progress('Progress', Math.ceil(number * 100 / totalNum) + '%');//计算进度条
                    number = number + 1;
                    status = 1;//分片成功修改状态
                } else if (res.code === 200) { //上传完成
                    element.progress('Progress', '100%');
                    status = 2;
                    $('#path').val(res.upload);
                    layer.closeAll('loading'); //关闭loading
                    layer.msg('上传成功', {time: 1000, anim: 0}, function () {
                        $('.layui-progress').hide();
                    });
                } else { //上传错误
                    status = -1;
                    layer.closeAll('loading'); //关闭loading
                    element.progress('Progress', '0%');
                    if (typeof (res.upload) == "undefined") {
                    } else {
                        $('#path').val(res.upload);
                    }
                    layer.msg("上传失败,请重试", {time: 1500, anim: 0}, function () {
                        $('.layui-progress').hide();
                    });
                }
            },
            error: function () {
                $('.layui-progress').hide();
            }
        });
    });
</script>
</body>
</html>

可以用循环,for 来控制次数,也可以用递归 当然我这里用的  setInterval 定时器 更好些可以更好的控制

后端代码:

$code=100;
        // 用原生或者自己session实现 uuid自己实现或者原生(原生的有误差)
        if (empty(Session::get('fileUid'))){
            $uuid = create_guid();
            Session::set('fileUid',$uuid);
        } else {
            $uuid = Session::get('fileUid');
        }
        //占位符 upload的目录路径自己选
        $filename = sprintf('./upload/%s.%s',$uuid,$_POST['fileExt']);
        $data = file_get_contents($_FILES['file']['tmp_name']);
        if($_POST['number']==1){
            file_put_contents($filename,$data);//先生成一个文件
        } else {
            //其余文件追加到文件末尾
            file_put_contents($filename,$data,FILE_APPEND);
        }

         //最后一片文件
        if($_POST['totalNum']==$_POST['number']){
            Session::delete('fileUid');
            $code=200;
        }
        $res=['code'=>$code,'upload'=>$filename];
        echo json_encode($res);
    }

 

标签:分块,layui,number,upload,let,file,progress
From: https://www.cnblogs.com/yangshiyi/p/16940770.html

相关文章

  • 数论分块
    数论分块数论分块也叫整除分块是用于快速处理类似于\[\sum_{i=1}^n\lceil\frac{n}{i}\rceil\text{或者}\sum_{i=1}^n\lfloor\frac{n}{i}\rfloor\]式子的一......
  • vue a-upload组件上传图片,headers和data字段自定义
    <divclass="clearfix"><a-uploadlist-type="picture-card":file-list="fileList"@preview="handlePreview"@change="handleChange":before-upload="......
  • Upload-labs 18 条件竞争——通关
    访问目标站点,提示如下图所示查看源码思路:上传shell.php.7z图片木马配合解析漏洞进行getshell实验步骤:图片中php一句话木马代码:​​<?phpfputs(fopen('shell2.php','w'),'......
  • 使用appuploader工具如何生成发布证书和描述性文件教程
     之前用AppCan平台开发了一个应用,平台可以同时生成安卓版和苹果版,想着也把这应用上架到AppStore试试,于是找同学借了个苹果开发者账号,但没那么简单,还要用到Mac电脑的钥......
  • 基于SpringBoot+Layui的物业管理系统【完整项目源码】
    使用建议业务逻辑简略,需要细化业务,增加业务开发,如未交费提醒等技术架构数据库:MySQL8.X后端技术:SpringBoot2.3.0,MyBatisPlus数据连接池:Druid前端技术:La......
  • layui合并单元格
    在别人的基础上解决了多列合并和同一个页面多个表格的问题1//合并单元格2functionmerge(id,res,columsName,columsIndex){34var......
  • layui行转列的偷懒写法
     vartempCols=[];//转换后的列头vartempData=[]; varentcount={};//转换后的第一行,也就是原来的第一列......
  • layui10
    1.table数据表格文档1.三种初始化渲染方式方式机制适用场景 01.方法渲染用JS方法的配置完成渲染(推荐)无需写过多的HTML,在JS中指定原始元素,再设定各项参数......
  • layui6
    列边距​经过“列间距”的预设类,来设定列之间的间距。且一行中最左的列不会出现左边距,最右的列不会出现右边距。列间距在保证排版美观的同时,还能够进一步保证分列的宽度......
  • layui7
    列偏移​对列追加相似 layui-col-md-offset* 的预设类,从而让列向右偏移。其中 号表明的是偏移占据的列数,可选中为1-12。​如:layui-col-md-offset3*,即表明在“中......