关于layui的一些故事(二):文件上传


一、普通form表单上传图片

通过ajax上传图片到图床,以下实例为七牛云

<form id="formLogoID1" method="post" enctype="multipart/form-data" style="display: none;">
    <input name="token" type="hidden" value="" id="shopTokenId" class="tokenClass" />
    <input id="imagefile1" name="file" type="file" class="userfileClass" />
</form>
<label class="uploadImageClass" for="imagefile1">
    <img
        class="layui-upload-img upload-default-img"
        src="./images/photo.png"
        id="shopLogoImageID1"
    />
</label>
var uploadUrl1 = "";
$("#imagefile1").live("change", function () {
    if (this.files.length != 0) {
        var imgSize = this.files[0].size / 1024 / 1024;
        console.log(imgSize);
        if (imgSize <= 3) {
            ImageHandle1($("#shopLogoImageID1"), $("#formLogoID1").attr("id"));
        } else {
            layer.msg("图片大小超过3M,请重新选择", {
                icon: 5,
            });
        }
    }
});
/**图片上传*/
function ImageHandle1(imgUrl, formID) {
    var id = new FormData(document.getElementById(formID));
    console.log(id);
    $.ajax({
        url: "http://up.qiniu.com/",
        type: "POST",
        data: id,
        processData: false,
        contentType: false,
        success: function (res) {
            console.log(res);
            console.log("成功:" + JSON.stringify(res));
            var srcUrl = domain + res.key;
            console.log(srcUrl);
            uploadUrl1 = srcUrl;
            imgUrl.attr("src", srcUrl);
            imgUrl.css("width", "100%");
            imgUrl.css("height", "100%");
            console.log(uploadUrl1);
        },
        error: function (res) {
            console.log("失败:" + JSON.stringify(res));
        },
    });
    return false;
}

二、layui和七牛云

七牛云不支持批量上传图片,但是可以根据layui图片上传组件的异步功能,实现批量上传,但是图片上传是异步上传,当图片大小有过大差距的时候,存在图片上传顺序错乱的情况,可以在done()中根据index进行排序,然后在allDone()一起提交

<!-- 上传组件是在form表单里的-->
<div class="layui-form-item">
    <label class="layui-form-label upload goods-desc" id="details">
        商品详情图:<span class="tips">不超过3M,格式为jpg,png</span></label
    >
    <div class="layui-upload" style="height:auto">
        <button type="button" class="layui-btn" id="ImageDetails">上传图片</button>
        <div class="layui-upload-list multipleDetail showDetailsImg"></div>
    </div>
</div>
var DetailImg = new Array();
layui.use(["form", "upload"], function () {
    var form = layui.form;
    var $ = layui.jquery;
    var upload = layui.upload;
    /*商品详情图片上传*/
    var ImageDetails = upload.render({
        elem: "#ImageDetails", //绑定元素
        size: 3072,
        multiple: true,
        number: 30,
        acceptMime: "image/*",
        url: "http://up.qiniu.com", //该处为七牛云的上传接口
        method: "post",
        data: {
            //主要是通过后台请求七牛云的url,获取token
            key: function () {
                //自定义文件名
                return "aaa.png";
            },
            token: function () {
                var token;
                $.ajax({
                    async: false, //ajax 非异步获取taken
                    type: "post",
                    url: url + "type=third&method=qiniutoken&time=3600&space=images", //后台接口
                    success: function (res) {
                        if (DetailImg.length == 30) {
                            layer.msg("最多只能上传30张", {
                                icon: 5,
                            });
                        } else {
                            console.log(res);
                            token = JSON.parse(res).token;
                        }
                    },
                });
                return token;
            },
        },
        before: function (obj) {
            //预读本地文件示例,不支持ie8
            obj.preview(function (index, file, result) {
                // console.log(file) //{name: "1.jpg" size: 140000}
                // console.log(result) //{data:image/jpeg;base64,}
                if (DetailImg.length == 30) {
                    layer.msg("最多只能上传30张", {
                        icon: 5,
                    });
                } else {
                    let imgList = `
<div class="img-box">
<img class="layui-upload-img upload-default-img" src="${result}" alt="${file.name}">
<div class="mb"></div>
<div class="remove">+</div>
</div>`;
                    $(".showDetailsImg").append(imgList);
                }
            });
        },
        done: function (res, index, upload) {
            console.log(res);
            if (DetailImg.length == 30) {
                layer.msg("最多只能上传30张", {
                    icon: 5,
                });
            } else {
                //由于图片上传是异步上传,所以存在图片上传顺序错乱的情况,可以根据index,进行重新排序
                var index = index.split("-")[1];
                console.log(index);
                if (index == 0) {
                    sortArr = new Array();
                }
                var url = domain + res.key;
                sortArr.push({
                    index: index,
                    url: url,
                });
                console.log(sortArr);
            }
        },
        allDone: function (obj) {
            //当文件全部被提交后,才触发
            console.log(obj);
            if (sortArr.length > 1) {
                sortArr.sort(compare);
                for (var i = 0; i < sortArr.length; i++) {
                    DetailImg.push(sortArr[i].url);
                }
            } else {
                DetailImg.push(sortArr[0].url);
            }
            console.log(DetailImg);
        },
        error: function () {
            //演示失败状态,并实现重传
            // return layer.msg('error');
            return;
        },
    });
});
/*
 *  详情图 图片删除
 */
$(".showDetailsImg").on("mouseenter mouseleave", ".img-box", function () {
    $(this).find(".remove").css({
        opacity: 0.5,
    });
    $(this).find(".mb").css({
        opacity: 1,
    });
});
$(".showDetailsImg").on("mouseleave", ".img-box", function () {
    $(this).find(".remove").css({
        opacity: 0,
    });
    $(this).find(".mb").css({
        opacity: 0,
    });
});
$(".showDetailsImg").on("click", ".remove", function () {
    var parents = $(this).parent()[0];
    var index = $(".showDetailsImg .img-box").index(parents);
    console.log(index);
    console.log(DetailImg);
    DetailImg.splice(index, 1);
    console.log(DetailImg);
    $(this).parent().remove();
});
/*排序*/
function compare(obj1, obj2) {
    var a = obj1.index;
    var b = obj2.index;
    return a - b;
}

三、动态渲染数据表格时,添加图片上传组件

先上图片

重点:在渲染数据表格的时候,需要一起把上传按钮的点击事件一起渲染


<div class="layui-form-item ">
    <label class="layui-form-label goods-desc">商品规格:</label>
    <div class="specs">
        <div class="box">
            <div class="layui-input-block" style="margin-left: 15px;display: flex;">
                <input
                    type="text"
                    name="network"
                    autocomplete="off"
                    placeholder="网络"
                    class="layui-input"
                    id="network"
                    style="width: 50px;margin-right: 20px;"
                />
                <input
                    type="text"
                    name="newNetwork"
                    autocomplete="off"
                    class="layui-input"
                    id="newNetwork"
                    style="width: 150px;margin-right: 20px;"
                />
                <button
                    type="button"
                    class="layui-btn layui-btn-primary"
                    style="width: 50px;padding: 0;"
                    id="addNewNetwork"
                >
                    新增
                </button>
            </div>
            <div class="showAddNewNetwork showAdd"></div>
        </div>
        <div class="box">
            <div class="layui-input-block" style="margin-left: 15px;display: flex;">
                <input
                    type="text"
                    name="memory"
                    autocomplete="off"
                    placeholder="内存"
                    class="layui-input"
                    id="memory"
                    style="width: 50px;margin-right: 20px;"
                />
                <input
                    type="text"
                    name="newMemory"
                    autocomplete="off"
                    class="layui-input"
                    id="newMemory"
                    style="width: 150px;margin-right: 20px;"
                />
                <button
                    type="button"
                    class="layui-btn layui-btn-primary"
                    style="width: 50px;padding: 0;"
                    id="addNewMemory"
                >
                    新增
                </button>
            </div>
            <div class="showAddNewMemory showAdd"></div>
        </div>
        <div class="box">
            <div class="layui-input-block" style="margin-left: 15px;display: flex;">
                <input
                    type="text"
                    name="color"
                    autocomplete="off"
                    placeholder="颜色"
                    class="layui-input"
                    id="color"
                    style="width: 50px;margin-right: 20px;"
                />
                <input
                    type="text"
                    name="newColor"
                    autocomplete="off"
                    class="layui-input"
                    id="newColor"
                    style="width: 150px;margin-right: 20px;"
                />
                <button
                    type="button"
                    class="layui-btn layui-btn-primary"
                    style="width: 50px;padding: 0;"
                    id="addNewColor"
                >
                    新增
                </button>
            </div>
            <div class="showAddNewColor showAdd"></div>
        </div>
        <button type="button" class="layui-btn" id="save">保存</button>
    </div>
</div>
<script type="text/html" id="showGoodsList">
    <table>
        <thead>
            <tr>
                <th>{{d.title1}}</th>
                <th>{{d.title2}}</th>
                <th>{{d.title3}}</th>
                <th>售价</th>
                <th>库存</th>
            </tr>
        </thead>
        <tbody>
            {{# layui.each(d.data, function(index, item){ }}
            <tr>
                <td>{{item.network}}</td>
                <td>{{item.memory}}</td>
                <td class="picBox">
                    <div class="color">
                        {{item.color}}
                    </div>
                    <div class="layui-upload addUpload">
                        <button type="button" class="layui-btn eachGoodsImgBtn" style="float: left;  margin: 35px 10px 0 0">上传图片</button>
                        <input class="layui-upload-file" type="file" accept="image/*" name="file">
                        <div class="layui-upload-list">
                            <img class="layui-upload-img ShowEachGoodsImg">
                        </div>
                    </div>
                </td>
                <td class="eachPrice">
                    <input type="text" autocomplete="off" class="layui-input" placeholder="999">
                </td>
                <td class="eachStock">
                    <input type="text" autocomplete="off" class="layui-input" placeholder="999">
                </td>
            </tr>
            {{# }); }}
        </tbody>
    </table>
<script>
var network = "";
var networkArr = new Array();
var memory = "";
var memoryArr = new Array();
var color = "";
var colorArr = new Array();
var goodsList = "";
var trIndex = "";
layui.use(["form", "upload", "laytpl"], function () {
    var form = layui.form;
    var layer = layui.layer;
    var $ = layui.jquery;
    var upload = layui.upload;
    var laytpl = layui.laytpl;
    //按钮保存生成规格表格
    $("#save").click(function () {
        var newArr = new Array();
        if (network == "") {
            network = "网络";
        }
        if (memory == "") {
            memory = "内存";
        }
        if (color == "") {
            color = "颜色";
        }
        if (
            networkArr == "" ||
            memoryArr == "" ||
            colorArr == "" ||
            network == "" ||
            memory == "" ||
            color == ""
        ) {
            layer.msg("请先添加内容,再保存", {
                icon: 5,
            });
        } else {
            for (var i = 0; i < networkArr.length; i++) {
                for (var j = 0; j < memoryArr.length; j++) {
                    for (var k = 0; k < colorArr.length; k++) {
                        newArr.push({
                            network: networkArr[i],
                            memory: memoryArr[j],
                            color: colorArr[k],
                            imgurl: "",
                            price: "",
                            stock: "",
                        });
                    }
                }
            }
            console.log(newArr);
            goodsList = {
                title1: network,
                title2: memory,
                title3: color,
                data: newArr,
            };
            console.log(goodsList);
            var getTpl = showGoodsList.innerHTML;
            var view = document.getElementById("goodslist");
            laytpl(getTpl).render(goodsList, function (html) {
                view.innerHTML = html;
            });
            //重点:在渲染表格的时候,需要渲染upload组件,否则按钮的点击事件是无效的
            uploadImgRender(".eachGoodsImgBtn");
        }
    });

    //获取tr的索引
    $("#goodslist").on("click", ".eachGoodsImgBtn", function () {
        var gettr = $(this).parent().parent().parent()[0];
        trIndex = $("#goodslist tbody tr").index(gettr);
        console.log(gettr);
        console.log(trIndex);
    });

    /*封装表格里单个图片上传*/
    function uploadImgRender(e) {
        var uploadEachGoods = upload.render({
            elem: e, //绑定元素
            size: 3072,
            acceptMime: "image/*",
            url: "http://up.qiniu.com/", //上传接口
            method: "post",
            data: {
                key: function () {
                    //自定义文件名
                    return "aaa.png";
                },
                token: function () {
                    var token;
                    $.ajax({
                        async: false, //ajax 非异步获取taken
                        type: "post",
                        url: url + "type=third&method=qiniutoken&time=3600&space=images",
                        success: function (res) {
                            console.log(res);
                            token = JSON.parse(res).token;
                        },
                    });
                    return token;
                },
            },
            before: function (obj) {
                //预读本地文件示例,不支持ie8
                obj.preview(function (index, file, result) {
                    $("#goodslist tbody tr").eq(trIndex).find(".layui-upload-list").css({
                        display: "block",
                    });
                    $("#goodslist tbody tr")
                        .eq(trIndex)
                        .find(".ShowEachGoodsImg")
                        .attr("src", result);
                });
            },
            done: function (res, index, upload) {
                console.log(res);
                for (var i = 0; i < goodsList.data.length; i++) {
                    if (i == trIndex) {
                        goodsList.data[i].imgurl = domain + res.key; //damain 来自qiniu/formdata.js
                    }
                }
                console.log(goodsList);
            },
            error: function () {
                //演示失败状态,并实现重传
                return layer.msg("error");
            },
        });
    }
});

三、layui 图片上传时,判断图片长宽和自定义名字

layui再上传图片时,若是需要判断上传图片的长宽,可以在上传前继续判断,选择choose: function(obj){},同时要关闭自动上传,即auto: false,批量上传图片时,图片渲染要放在choose中

<!-- 上传图片-->
<div class="layui-form-item">
    <label class="layui-form-label upload goods-desc"> 小程序logo:</label>
    <div class="layui-upload">
        <button type="button" class="layui-btn" id="appletsImg">上传图片</button>
        <label style="width: 500px;color: red;margin-left: 20px;"
            >注:小程序logo图标,格式必须为:png,jpeg,jpg,建议上传像素为180*180,图片最大为256KB</label
        >
        <div class="layui-upload-list">
            <img class="layui-upload-img" id="ShowThirdImg" />
        </div>
    </div>
</div>
var suffix = ""; //获取上传图片的后缀名
var img = ""; //需要获取的图片

// 图片尺寸
var imgSize = {
    width: 180,
    height: 180,
    size: 256,
};
//方法调用
uploadImgRender("#appletsImg", "#ShowThirdImg", imgSize, function (res) {
    img = res;
});
// 封装图片上传功能
function uploadImgRender(elemBtn, showImg, size, callback) {
    var ImageSingular = upload.render({
        elem: elemBtn, //绑定元素
        size: size.size,
        acceptMime: "image/jpg, image/jpeg, image/png",
        url: "http://up.qiniu.com/", //上传接口
        method: "post",
        auto: false, //要在choose中判断上传图片大小时,auto参数必须设置为false
        data: {
            key: function () {
                //自定义文件名
                return getNowFormatDate() + lastThree() + "." + suffix;
            },
            token: function () {
                var token;
                $.ajax({
                    async: false, //ajax 非异步获取taken
                    type: "post",
                    url: url + "type=third&method=qiniutoken&time=3600&space=images", //后台接口
                    success: function (res) {
                        console.log(res);
                        token = JSON.parse(res).token;
                    },
                });
                return token;
            },
        },
        choose: function (obj) {
            //上传前选择回调方法
            // var files = obj.pushFile();//将每次选择的文件追加到文件队列
            var flag = true;
            obj.preview(function (index, file, result) {
                //预读本地文件,如果是多文件,则会遍历。(不支持ie8/9)
                //obj.resetFile(index, file, '123.jpg'); //重命名文件名,layui 2.3.0 开始新增
                //这里还可以做一些 append 文件列表 DOM 的操作
                // obj.upload(index, file); //满足条件调用上传方法
                //delete files[index]; //删除列表中对应的文件,一般在某个事件中使用
                console.log(file);
                suffix = file.name.split(".")[1]; //获取上传图片的后缀名
                var img = new Image();
                img.src = result;
                img.onload = function (res) {
                    //初始化夹在完成后获取上传图片宽高,判断限制上传图片的大小。
                    if (size.width == 0 && size.height == 0) {
                        obj.upload(index, file); //满足条件调用上传方法
                    } else if (size.width != 0 && size.height != 0) {
                        if (img.width == size.width && img.height == size.height) {
                            obj.upload(index, file); //满足条件调用上传方法
                        } else {
                            flag = false;
                            layer.msg(`您上传的小图大小必须是${size.width}*${size.height}尺寸!`);
                            return false;
                        }
                    }
                };
                return flag;
            });
        },
        before: function (obj) {
            //预读本地文件示例,不支持ie8
            obj.preview(function (index, file, result) {
                //多张图片上传时,应该放在choose中
                $(showImg).attr("src", result); //图片链接(base64)
            });
        },
        done: function (res, index, upload) {
            console.log(res);
            var saveImg = domain + res.key; //damain 来自qiniu/formdata.js
            console.log(saveImg);
            callback(saveImg);
        },
        error: function () {
            //演示失败状态,并实现重传
            return layer.msg("error");
        },
    });
}

//生成图片的随机数
function getNowFormatDate() {
    var day = new Date();
    var Year = 0;
    var Month = 0;
    var Day = 0;
    var Hour = 0;
    var Minute = 0;
    var Second = 0;
    var CurrentDate = "";
    Year = day.getFullYear(); //支持IE和火狐浏览器.
    Month = day.getMonth() + 1;
    Day = day.getDate();
    Hour = day.getHours();
    Minute = day.getMinutes();
    Second = day.getSeconds();
    CurrentDate += Year; //CurrentDate =CurrentDate+ Year
    if (Month >= 10) {
        CurrentDate += Month;
    } else {
        CurrentDate += "0" + Month;
    }
    if (Day >= 10) {
        CurrentDate += Day;
    } else {
        CurrentDate += "0" + Day;
    }
    CurrentDate = CurrentDate + Hour + Minute + Second;
    return CurrentDate;
}

function lastThree() {
    var lastThree = "";
    for (var i = 0; i < 3; i++) {
        lastThree += Math.floor(Math.random() * 10);
    }
    return lastThree;
}

四、layui 图片上传

1.选择文件的回调

在文件被选择后触发,该回调会在 before 回调之前。一般用于非自动上传(即 auto: false )的场景,比如预览图片等。

upload.render({
    elem: "#id",
    url: "/api/upload/",
    auto: false, //选择文件后不自动上传
    bindAction: "#testListAction", //指向一个按钮触发上传
    choose: function (obj) {
        //将每次选择的文件追加到文件队列
        var files = obj.pushFile();

        //预读本地文件,如果是多文件,则会遍历。(不支持ie8/9)
        obj.preview(function (index, file, result) {
            console.log(index); //得到文件索引
            console.log(file); //得到文件对象
            console.log(result); //得到文件base64编码,比如图片

            //obj.resetFile(index, file, '123.jpg'); //重命名文件名,layui 2.3.0 开始新增

            //这里还可以做一些 append 文件列表 DOM 的操作

            //obj.upload(index, file); //对上传失败的单个文件重新上传,一般在某个事件中使用
            //delete files[index]; //删除列表中对应的文件,一般在某个事件中使用
        });
    },
});

2.文件上传前的回调

choose 回调之后、done/error 回调之前触发。返回的参数完全类似 choose 回调。一般用于上传完毕前的loading、图片预览等。

upload.render({
    elem: "#id",
    url: "/api/upload/",
    before: function (obj) {
        //obj参数包含的信息,跟 choose回调完全一致,可参见上文。
        layer.load(); //上传loading
    },
    done: function (res, index, upload) {
        layer.closeAll("loading"); //关闭loading
    },
    error: function (index, upload) {
        layer.closeAll("loading"); //关闭loading
    },
});

3.上传接口请求成功的回调

在上传接口请求完毕后触发,但文件不一定是上传成功的,只是接口的响应状态正常(200)。回调返回三个参数,分别为:服务端响应信息当前文件的索引重新上传的方法

upload.render({
    elem: "#id",
    url: "/api/upload/",
    done: function (res, index, upload) {
        //假设code=0代表上传成功
        if (res.code == 0) {
            //do something (比如将res返回的图片链接保存到表单的隐藏域)
        }

        //获取当前触发上传的元素,一般用于 elem 绑定 class 的情况,注意:此乃 layui 2.1.0 新增
        var item = this.item;

        //文件保存失败
        //do something
    },
});

4.上传请求失败的回调

当请求上传时出现异常时触发(如网络异常、404/500等)。回调返回两个参数,分别为:当前文件的索引重新上传的方法

upload.render({
    elem: "#id",
    url: "/api/upload/",
    error: function (index, upload) {
        //当上传失败时,你可以生成一个“重新上传”的按钮,点击该按钮时,执行 upload() 方法即可实现重新上传
    },
});

5.多文件上传完毕后的状态回调

只有当开启多文件时(即 multiple: true),该回调才会被触发。回调返回一个 object 类型的参数,包含一些状态数据:

upload.render({
    elem: "#id",
    url: "/api/upload/",
    multiple: true,
    allDone: function (obj) {
        //当文件全部被提交后,才触发
        console.log(obj.total); //得到总文件数
        console.log(obj.successful); //请求成功的文件数
        console.log(obj.aborted); //请求失败的文件数
    },
    done: function (res, index, upload) {
        //每个文件提交一次触发一次。详见“请求成功的回调”
    },
});

6.文件上传进度的回调

在网速一般的情况下,大文件的上传通常需要一定时间的等待,而浏览器并不会醒目地告知你它正在努力地上传中,此时为了提升用户体验,我们可以通过该回调制作一个进度条。

upload.render({
    elem: "#id",
    url: "/api/upload/",
    progress: function (n, elem) {
        var percent = n + "%"; //获取进度百分比
        element.progress("demo", percent); //可配合 layui 进度条元素使用

        //以下系 layui 2.5.6 新增
        console.log(elem); //得到当前触发的元素 DOM 对象。可通过该元素定义的属性值匹配到对应的进度条。
    },
});

文章作者: 弈心
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 弈心 !
评论
  目录