# 功能组件

# 组件概述

传统的开发模式中,我们常常需要在页面或模块独立的JS文件中抒写大量的JS去实现我们页面的功能,常常为了实现一个功能需要写复杂而又冗余的JS,整个模块下来整个JS文件不仅打而且显得很臃肿,如果只是个小项目还可以接收,但是如果是一个中大型的项目模块多,每个模块都采用这种实现方式,那可想而知需要写多少重复性繁琐的JS代码,那么是否有更高级、更便捷的方法简化开发,提交开发效率,降低开发和维护的成本呢?其实有很多办法,目前主流的开发模式都是采用模块化、功能解耦、开箱即用,为此我们从框架的整体架构出发,解决行业的痛点同时也为了简化开发,我们结合长期的项目经验专门定制化开发了JS组件,组件本身基于Layui开箱即用的思想编写,下面我们做详细的介绍。

# 功能分析

对于模块开发而言,其实主要的还是需要实现增删改查的功能,主要涉及表单渲染表单提交网络请求弹框显示表单校验事件处理等等,同样,组件也是为了解决模块的管理而撰写的功能实现,我们只需要在需要的时候进行调用即可,不需要再写大量的JS代码,复杂的事件和表单处理全部交由组件去处理。

# 窗体弹框

弹框的功能不管是在传统开发中还是如今比较流行的前后端分离开发中都是比较常见的功能,如:添加编辑确认框提示等等(当前页可以直接打开新页面不弹框),为了解决这个问题,我们封装了弹框组件,根据使用场景的不同,框架做了继承开发,调用时只需要传入相应的参数即可。

函数主体:

showWin: function (title, url, width = 0, height = 0, param = [], type = 2, btn = [], callback = null) {
    var index = layui.layer.open({
        title: title,
        type: type,
        area: [width + "px", height + "px"],
        content: url,
        // closeBtn: false,
        shadeClose: true,// 点击遮罩关闭
        shade: 0.4,
        // maxmin: true, // 开启最大化最小化按钮
        // skin: 'layui-layer-rim', // 加上边框
        // skin: 'layui-layer-molv', // 加上边框
        skin: 'layui-layer-admin',
        // btn: btn,
        // btnAlign: 'c',
        success: function (layero, index) {

            // 窗体传值【支持多值传递】
            if (Array.isArray(param)) {
                for (var i in param) {
                    var item = param[i].split('=');
                    // console.log("传值:" + item[0] + "," + item[1]);
                    var body = layui.layer.getChildFrame('body', index);
                    body.find("#" + item[0]).val(item[1]);
                }
            }

            // 回调函数
            if (callback) {
                callback(layero, index);
            }
        },
        end: function () {
            // 加载结束
        }
    });

    if (width == 0) {
        // 全屏设置
        layui.layer.full(index);
        $(window).on("resize", function () {
            layui.layer.full(index);
        });
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

调用方式:

showWin(title, url, width, height, param, type, btn, function (layero, index) {
    if (callback) {
        callback(layero, index);
    }
});
1
2
3
4
5

参数说明:

  • title:弹窗标题,这个标题是在弹框的左上角显示的标题文字;
  • url:URL地址,这个是弹框调用的方法地址,比如添加、编辑时需要调用页面表单地址的方法;
  • width:弹窗宽度,一个数值(不传时默认弹窗全屏显示);
  • height:弹窗高度,一个数值(不传时默认弹窗全屏显示);
  • param:需要传给弹窗的自定义参数;
  • type:弹窗类型,
  • btn:自定义弹窗底部的按钮,如:确认取消
  • callback:回调函数,弹窗成功弹出之后会默认进行回调;

使用案例:

func.showWin("职级", 500, 300);
1

效果展示:

mixureSecure

# 添加、编辑

做过模块管理的开发者都知道添加、编辑其实主体的表单信息都是相同的,不同的只是个别参数,如编辑时记录ID是存在值的,添加时记录ID=0,避免代码的冗余,添加、编辑方法我们写一个共用的方法edit,下面我们详细的描述下,添加、编辑时是如何弹出窗体的。

edit: function (title, id = 0, width = 0, height = 0, param = []) {

    // 窗口标题
    var titleStr = id > 0 ? "修改" : "新增";
    if (base.isEmpty(title)) {
        titleStr += '内容';
    } else {
        titleStr += title;
    }

    // URL逻辑处理
    var url = cUrl + "/edit?id=" + id;
    if (Array.isArray(param)) {
        for (var i in param) {
            url += "&" + param[i];
        }
    }
    // 调用内部方法
    active.showWin(titleStr, url, width, height, param);

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

总结:edit方法里面进行了判断添加还是编辑,同时对URL参数进行动态解析,可以动态解析自定义参数param,最后一步进行调用弹窗操作,这就是为什么我们先介绍showWin的原因。

# 查看详情

查看记录数据的详情在我们项目研发中也是非常多见的,因此基于使用频率,我们也内置集成了查看详情的功能,如下:

detail: function (title, id, width = 0, height = 0) {
    // 调用内部方法
    var url = cUrl + "/detail?id=" + id;
    active.showWin(title + "详情", url, width, height);
}
1
2
3
4
5

总结::详情展示非常简单,内置的方法名为detail,id为记录数据的编号,最终也是调用系统内置JS方法showWin,关于showWin参数详解请看上节内容;

# 一键复制

一键复制在个别模块开发中会使用到,需要复制某一条现有的数据记录然后进行调整和修改生成一条新的记录,这时我们框架也提供了这一功能。

copy: function (title, id, width = 0, height = 0) {
    var url = cUrl + "/copy?id=" + id;
    active.showWin(title + "复制", url, width, height);
}
1
2
3
4

总结:可以看出一键复制所调用的JAVA端方法是copy,此时会自动查询我们所复制记录数据的信息并在弹窗中进行呈现,我们可以进行编辑修改后再次提交创建一条新的记录,一切的功能框架JS都内置,无需在模块JS或者页面中再去写额外的功能;

# 数据删除

删除功能我们并不陌生,在大多数的数据列表中,都会有删除按钮的出现,顾名思义就是在有权限的前提下我们可以删除这条数据,点击删除会弹出删除确认框,确定删除后才会发起网络请求,具体JS实现方法如下:

delete: function (id, callback = null) {
    layer.confirm('您确定要删除吗?删除后将无法恢复!', {
        icon: 3,
        skin: 'layer-ext-moon',
        btn: ['确认', '取消'] //按钮
    }, function (index) {

        // 调用内部方法
        var url = cUrl + "/delete";
        active.ajaxGet(url, {"id": id}, function (data, flag) {
            if (callback) {
                // 关闭弹窗
                layer.close(index);
                // 回调
                callback(data, flag);
            }
        }, '正在删除。。。');

    });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

调用方式:

common.delete(id, callback);
1

参数说明:

  • id:当前待删除数据的数据库记录ID;
  • callback:回调函数,删除成功之后会默认进行回调;

使用案例:

common.delete(id, function (data, res) {
    if (res) {
        // 从界面移除记录
        obj.del();
    } else {

    }
});
1
2
3
4
5
6
7
8

效果展示:

mixureSecure

# 批量操作

很好理解,批量操作就是可以选择多条记录数据进行批量处理的方法,如:批量删除批量启用批量禁用批量设置等等,在我们使用中批量删除算是最常用的了,删除多条数据时一条条删除非常耗时,那么批量删除可以很好的帮我解决此问题。

batchFunc: function (option, callback = null) {
    // 基础参数
    var url = option.url,
        title = option.title,
        form = option.form || '',
        confirm = option.confirm || false,
        show_tips = option.show_tips || '处理中...',
        item = option.data || [],
        param = option.param || [];

    if (item.length == 0) {
        layer.msg("请选择数据", {icon: 5});
        return false;
    }

    // 选择数据ID
    var ids = [];
    for (var i in item) {
        ids.push(item[i].id);
    }
    // 选择数据ID字符串(逗号‘,’分隔)
    var ids_str = ids.join(",");

    var data = {};
    data['id'] = ids_str;

    // 自定义参数解析
    if (Array.isArray(param)) {
        for (var i in param) {
            var subItem = param[i].split('=');
            data[subItem[0]] = subItem[1];
        }
    }

    if (confirm) {
        // 弹出确认
        layer.confirm('您确定要【' + title + '】选中的数据吗?', {icon: 3, title: '提示信息'}, function (index) {
            active.ajaxPost(url, data, callback, show_tips);
        });
    } else {
        // 直接请求
        active.ajaxPost(url, data, callback, show_tips);
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

以上便是实现批量删除实现,此方法会对数据进行处理及删除确认提示,确认无误后会正式发起网络请求。 调用方式:

common.batchFunc(options, callback);
1

参数说明:

  • options:参数集合,具体内容如下:
var options = {
    title: "批量删除",
    url: cUrl + "/batchDrop",
    data: data,
    confirm: true,
};
1
2
3
4
5
6
  • callback:回调函数,删除成功之后会默认进行回调;

使用案例:

common.batchFunc(options, function () {
    // 删除成功回调
});
1
2
3

效果展示:

mixureSecure

# 表单验证

表单提交时通常我们会通过前端JS先进行一些基本的为空或者数据类型校验,因此框架中也考虑到了这一点,编写了常规表单数据校验方法;

verify: function () {
    form.verify({
        // value:表单的值、item:表单的DOM对象
        required: function (value, item) {
            var title = $(item).data('title');
            if (!title) {
                // 自动获取
                title = $(item).parents('.layui-inline').find('.layui-form-label').text();
                if (title.indexOf(":") >= 0) {
                    title = title.substring(0, title.Length - 1);
                }
            }
            // 值为空时提示
            if (!value) {
                return $(item).attr('placeholder');
            }
        }
        , number: [/^[0-9]*$/, '请输入数字']
        , username: function (value, item) {
            // 特殊字符验证
            if (!new RegExp("^[a-zA-Z0-9_\u4e00-\u9fa5\\s·]+$").test(value)) {
                return title + '不能含有特殊字符';
            }
            // 下划线验证
            if (/(^\_)|(\__)|(\_+$)/.test(value)) {
                return title + '首尾不能出现下划线\'_\'';
            }
            // 数字验证
            if (/^\d+\d+\d$/.test(value)) {
                return title + '不能全为数字';
            }
        }
        // 数组的两个值分别代表:[正则匹配、匹配不符时的提示文字]
        , pass: [/^[\S]{6,12}$/, '密码必须6到12位,且不能出现空格']
    });
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

总结:基本都是数据类型及为空的常规正则验证;

# 表单提交

模块功能数据的录入少不了表单的提交,不管是添加、编辑最终都需要提交表单,因为框架JS底层写了表单提交的公共方法以及基础表单数据的处理,下面我们会详细描述;

submitForm: function (data, url = null, callback = null, isClose = true) {
    // 带[]中括号下标的字段特殊处理
    var nameArr = [];
    var itemArr = [];
    var param = data;
    $.each(param, function (key, val) {
        // 正则验证字段是否存在中括号[]
        var regex = /\/g
        if (!regex.test(key)) {
            return;
        }

        // 处理带括号[]的字段
        var regex1 = /\.+?)\]/g;   // [] 中括号及内容

        // 获取括号及括号内容
        var content = key.match(regex1);

        // 获取括号内容值
        var regex2 = "";
        var item = key.match(regex2);
        val = item[1];

        // 获取字段名
        var name = key.replace(content, "");
        // 字段名临时存储
        if ($.inArray(name, nameArr) < 0) {
            nameArr.push(name);
        }

        // 字段名数组初始化
        if (!itemArr[name]) {
            itemArr[name] = [];
        }
        itemArr[name].push(val);
    });

    // 请求地址
    if (url == null) {
        var url = cUrl;
        var action = $("form").attr("action");
        if (!base.isEmpty(action)) {
            // 自定义网络请求地址
            url = action;
        } else if (data.id != null) {
            // 根据常规表单提交判断是新增还是编辑
            if (data.id == 0) {
                url += "/add";
            } else if (data.id > 0) {
                url += "/update";
            }
        }
    }
    active.ajaxPost(url, param, function (res, success) {
        if (success) {
            // 延迟0.5秒
            if (isClose) {
                setTimeout(function () {
                    // 关闭窗体
                    layer.closeAll("iframe");
                    // 刷新父页面
                    parent.location.reload();
                }, 100);
            }

            // 数据回调
            if (callback) {
                callback(res, success);
            }
            return false;
        } else {
            // 网络请求异常处理
        }
    });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  • 逻辑代码看上去还是比较丰富的,其实表单提交的逻辑非常简单,获取表单数据,发起网络请求,但是复杂就在于需要对表单的一些特殊数据进行处理,正如前面章节汇总我们所描述的那这样,添加编辑我们走的同一个方法edit,同样表单提交的事件捕捉也是同一个方法,这就要求我们提交表单时判断本地提交到底是添加还是编辑以便动态生成网络请求地址;
  1. 自定义URL:表单提交时框架支持自定义URL地址,默认程序会判断form表单是否自定义了网络请求地址,取至表单属性action;
  2. 动态生成URL:当前不存在自定义表单提交地址时,程序会根据当前id隐藏域控件的值判断当前表单是添加提交还是编辑提交来动态生成网络请求地址;
  • 鉴于表单特殊控件的差异,对个别特性控件的取值进行分析处理,如checkbox表单控件,当我们多选时,所获取到的值是带中括号[]下标的数组,我们需要对其进行拆解,取出下标值并使用逗号,拼接成一个字符串重新赋值给参数;

调用方式:

form.on('submit(submitForm)', function (data) {
    // 查询调用方式
    common.submitForm(data.field, null, function (res, success) {
        console.log("保存成功回调");
    });
    return false;
});
1
2
3
4
5
6
7

# 搜索功能

对于大量的数据列表而言,我们常常需要根据条件获得我们所需要的数据源,这是条件搜索就可以帮助我们实现,正如很多模块我们所看到的那样在数据列表上方有很多的条件筛选框,这是我们可以选择我们所需要查询的条件,然后去定向搜索,鉴于此框架也做了常规的集成,如下所示:

searchForm: function (table, data, tableList = 'tableList') {
    // 执行重载
    table.reload(tableList, {
        page: {
            curr: 1
        },
        where: data.field
    });
}
1
2
3
4
5
6
7
8
9

调用方式:

form.on("submit(searchForm)", function (data) {
    // 查询调用方式
    common.searchForm(table, data);
    return false;
});
1
2
3
4
5

# 日期组件

在表单中我们会使用到大量的选择日期的空间,如出生日期根据日期筛选数据活动时间等等,每次需要使用时需要引入控件的同时还需要写对应的JS来进行交互,如时间区间段的选择等等,如果表单中只有一个日期控件还可以勉强写一下,但是如果想商品之类的模块往往需要不止一个日期控件,这时就会多出很多重复率高的冗余代码,不仅页面显得很庞大,同时后期的维护成本也比较高,因此我们对日期控件进行了多场景情况下的封装,形成了独立的日期组件,JS组件是对UI组件的补充和配合,UI组件调用JS组件时只需要传入一些特定的参数即可帮我们完美的实现想要的功能;

initDate: function (item, callback = null) {
    if (Array.isArray(item)) {
        for (var i in item) {
            var subItem = item[i].split('|');
            if (subItem[2]) {
                var param = subItem[2].split(',');
            }

            // 日期组件数据重组
            var options = {};
            options.elem = "#" + subItem[0];
            options.type = subItem[1];
            options.theme = 'molv';// 主题颜色[molv,#393D49,grid]
            options.range = subItem[3] === "true" ? true : subItem[3];// 开启左右面板
            options.calendar = true;// 是否显示公历节日
            options.show = false;// 默认显示
            options.position = 'absolute';// [fixed,absolute,static]
            options.trigger = 'click';// 定义鼠标悬停时弹出控件[click,mouseover]
            options.btns = ['clear', 'now', 'confirm'];// 工具按钮 默认值['clear', 'now', 'confirm']
            options.mark = {'0-06-25': "生日", '0-12-31': "跨年"};// 自定义标注重要日子
            // 控件在打开时触发,回调返回一个参数
            options.ready = function (date) {
                // console.log("组件面板打开:" + date);
            }
            // 日期时间被切换后的回调
            options.change = function (value, date, endDate) {
                // console.log(value); // 得到日期生成的值,如:2017-08-18
                // console.log(date); // 得到日期时间对象:{year: 2017, month: 8, date: 18, hours: 0, minutes: 0, seconds: 0}
                // console.log(endDate); // 得结束的日期时间对象,开启范围选择(range: true)才会返回。对象成员同上。
            }
            // 控件选择完毕后的回调
            options.done = function (value, date, endDate) {
                if (callback) {
                    callback(value, date);
                }
            }
            if (param) {
                // 最小值
                var minV = param[0];
                if (minV) {
                    var isNum = !isNaN(minV);
                    if (isNum) {
                        // 数字
                        options.min = parseInt(minV);
                    } else {
                        // 非数字
                        options.min = minV;
                    }
                }
                // 最大值
                var maxV = param[1];
                if (maxV) {
                    var isNum2 = !isNaN(maxV);
                    if (isNum2) {
                        // 数字
                        options.max = parseInt(maxV);
                    } else {
                        // 非数字
                        options.max = maxV;
                    }
                }
            }

            // 日期选择组件
            laydate.render(options);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

备注:日期组件具体的使用方法请查看《UI组件(日期组件)》,文档中详细的阐述了日期组件的几种常见的使用模式;

# 网络请求

目前我们的数据都是经过网络请求跟后端服务进行交互的,获取数据和提交数据,都需要经过网络请求,以前我们开发项目时都需要单独在页面或者模块JS文件中写一堆AJAX网络请求,传入特定的参数,功能我们都可以实现,但是项目做的多了,模块开发多了,就会觉得写这些千篇一律的重复率搞的代码牵扯了我们太多的精力,往往为了实现一个小功能需要我们写大量的代码进行交互,那么我们是否可以进行封装、简化、增强呢?为此我们特地封装了网络请求,鉴于常规请求,框架底层目前只封装了两种常见的当时POSTGET,下面我们详细的说明;

  • POST请求
ajaxPost: function (url, data, callback = null, msg = '处理中,请稍后...') {
    var index = null;
    $.ajax({
        type: "POST",
        url: url,
        data: JSON.stringify(data),
        contentType: "application/json",
        dataType: "json",
        beforeSend: function () {
            index = layer.msg(msg, {
                icon: 16
                , shade: 0.01
                , time: 0
            });
        },
        success: function (res) {
            if (res.code == 0) {
                //0.5秒后关闭
                layer.msg(res.msg, {icon: 1, time: 500}, function () {
                    layer.close(index);
                    if (callback) {
                        callback(res, true);
                    }
                });
            } else {
                layer.close(index);
                layer.msg(res.msg, {icon: 5});
                return false;
            }
        },
        error: function () {
            layer.close(index);
            layer.msg("AJAX请求异常");
            if (callback) {
                callback(null, false);
            }
        }
    });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

调用方式:

common.ajaxPost(url, data, callback, msg)
1

参数说明:

  1. url:URL请求地址;
  2. data:请求参数,要求JSON格式;
  3. callback:回调函数,删除成功之后会默认进行回调;
  4. msg:网络请求时界面的提示语,如请求中。。。

使用案例:

func.ajaxPost(url, data, function (res, success) {
    // 网络请求回调
    if (success) {
        // 成功
    } else {
        // 失败
    }
}, "处理中。。。");
1
2
3
4
5
6
7
8
  • GET请求
ajaxGet: function (url, data, callback = null, msg = '处理中,请稍后...') {
    var index = null;
    $.ajax({
        type: "GET",
        url: url,
        data: data,
        contentType: "application/json",
        dataType: "json",
        beforeSend: function () {
            index = layer.msg(msg, {
                icon: 16
                , shade: 0.01
                , time: 0
            });
        },
        success: function (res) {
            if (res.code == 0) {
                //0.5秒后关闭
                layer.msg(res.msg, {icon: 1, time: 500}, function () {
                    layer.close(index);
                    if (callback) {
                        callback(data, true);
                    }
                });
            } else {
                layer.msg(res.msg, {icon: 5});
                return false;
            }
        },
        error: function () {
            layer.msg("AJAX请求异常");
            if (callback) {
                callback(data, false);
            }
        }
    });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

调用方式:

common.ajaxGet(url, data, callback, msg)
1

参数说明:

  1. url:URL请求地址;
  2. data:请求参数,要求JSON格式;
  3. callback:回调函数,删除成功之后会默认进行回调;
  4. msg:网络请求时界面的提示语,如请求中。。。

使用案例:

func.ajaxGet(url, data, function (res, success) {
    // 网络请求回调
    if (success) {
        // 成功
    } else {
        // 失败
    }
}, "处理中。。。");
1
2
3
4
5
6
7
8

# 开关事件

UI组件中我们详细的阐述了开关组件这一节,对开关组件有了一定的了解,这里我们来讲解另一种JS开关组件,顾名思义就是在开关进行开启和关闭的过程中可以发起响应的网络请求并且进行一系列业务处理,比如常见的在数据列表中会显示一栏开关按钮,当前我们点击开关时就可以正常的开启和关闭这条数据,这时就是我们刚刚所说的开关事件了,下面我们详细的阐述:

formSwitch: function (name, url = '', callback = null) {
    form.on('switch(' + name + ')', function (obj) {
        // 开关的值
        var value = this.checked ? '1' : '2';

        // URL自定义
        if (base.isEmpty(url)) {
            url = cUrl + "/set" + name.substring(0, 1).toUpperCase() + name.substring(1);
        }

        // JSON数据
        var json_data = {};
        json_data['id'] = this.value;
        json_data[name] = value;
        // JSON字符串
        var json_str = JSON.stringify(json_data);
        // JSON数据
        var json = JSON.parse(json_str);
        // 发起POST请求
        active.ajaxPost(url, json_data, function (data, res) {
            if (callback) {
                callback(data, res);
            }
        });

    });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

调用方式:

func.formSwitch(name, url, callback);
1

参数说明:

  1. name:name值是开关组件的参数名称;
  2. url:URL请求地址;
  3. callback:回调函数,删除成功之后会默认进行回调; 备注:开关组件默认传的值就是:1和2,至于对于数字12的定义自由发挥;

使用案例:

func.formSwitch('status', null, function (data, res) {
    console.log("开关回调成功");
})
1
2
3

总结:开关组件发起的网络请求方法正如上面所示,如果url传了自定义的网路请求地址则会按照给定的地址进行请求,否则程序会动态生成请求地址,方法名称生成规则是set组件参数名(组件参数名首字母大写),举例,当组件参数名为status时,则方法名为setStatus;

# 上传文件

上传文件并不陌生,大多数情况下我们都是需要上传文件时初始化上传控件,然后编写JS进行业务处理,当然我们前面的《图片上传组件》,《文件上传组件》都对上传部分进行了很友好的封装,很方便的实现了上传功能,其实这里还可以进行简化,就是把上述UI组件部分的JS代码进行JS组件化封装,然后嵌入到UI组件中去,这样是不是更加完美了(这个提议后期会在版本迭代中升级),根据实际的使用场景,我们封装了JS上传组件,如下所示:

uploadFile: function (elem_id, callback = null, url = '', exts = 'xls|xlsx', size = 10240, data = {}) {
    if (base.isEmpty(url)) {
        url = cUrl + "/uploadFile";
    }
    upload.render({
        elem: '#' + elem_id
        , url: url
        , auto: false
        , exts: exts
        , accept: 'file' // 允许上传的文件类型
        , size: size // 最大允许上传的文件大小
        , method: 'post' // 可选项。HTTP类型,默认post
        , data: data // 可选项。额外的参数,如:{id: 123, abc: 'xxx'}
        , before: function (obj) {
            // 预读本地文件
            layer.msg('上传并处理中。。。', {
                icon: 16
                , shade: 0.01
                , time: 0
            });
        }
        , done: function (res) {
            // 上传完毕回调

            // 关闭所有弹窗
            layer.closeAll();

            // 上传成功
            if (res.code == 0) {
                layer.alert(res.msg, {
                    title: "上传反馈"
                    , skin: 'layui-layer-molv' //样式类名  自定义样式
                    , closeBtn: 1    // 是否显示关闭按钮
                    , anim: 0 //动画类型
                    , btn: ['确定', '取消'] //按钮
                    , icon: 6    // icon
                    , yes: function () {
                        // 回调
                        if (callback) {
                            callback(res, true);
                        }
                    }
                    , btn2: function () {
                    }
                });
            } else {
                layer.msg(res.msg, {icon: 5});
            }
            return false;
        }
        , error: function () {
            // 请求异常回调
            return layer.msg('数据请求异常');
        }
    });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

调用方式:

common.uploadFile(elemId,callback,url, exts, data);
1

参数说明:

  1. elemId:组件的唯一标识名;
  2. callback:回调函数,删除成功之后会默认进行回调;
  3. url:URL请求地址;
  4. exts:允许上传的文件后缀,如:xls|xlsx|doc|docx|zip|rar等等;
  5. data:自定义参数;

使用案例:

common.uploadFile('file', function (data, res) {
    console.log("开关回调成功");
}, "xls|xlsx|doc|docx|zip|rar", "type=1&category=2")
1
2
3

# 结语

上述内容就是偏底层的功能组件的大部分内容,大概的给大家介绍到这里,在项目开发过程中可能大家使用不到这些内容,因为真正对外提供API接口服务的是《业务组件》部分,这里的内容都是在为他做嫁衣,给他提供支持而已,所以大家只需要了解即可,不必过多去研究