• [入门到吐槽系列] Webix 10分钟入门 二 表单Form的使用


    前言

    继续接着上一篇的webix入门:https://www.cnblogs.com/zc22/p/15912342.html。今天完成剩下两个最重要的控件,表单和表格的使用。掌握了这两个,整个Webix就入门完成了,就会进入吐槽模式。

     

    Webix 表单Form的使用

    表单的初始化布局

    本章节介绍表单的获取、设置、验证;表单控件的数据绑定。

    表单和一般控件,最大的区别,就是提供了批量操作。包括批量的设置取值、批量输入验证。先创建一个表单:

    复制代码
        webix.ui({
            id: 'webix_domasticparts',
            rows: [
                {
                    id: 'form', view: 'form', borderless: true,
                    elements: [
                        {
                            cols: [
                                { view: 'label', label: '无型号:', autowidth: true, },
                                { id: 'lb_title', name: 'lb_title', view: 'label', label: '0', width: 50, align: 'center', },
                                { id: 'sh_select', name: 'sh_select', view: 'switch', onLabel: "打开", offLabel: '关闭', width: 120, value: 0 },
                                {},
                            ],
                        }, {
                            cols: [
                                { id: 'txt_input', name: "txt_input", view: 'text', width: 200, placeholder: '商家编码', },
                                { id: 'btn_update', view: 'button', value: '设置', width: 150, },
                                {},
                            ],
                        },
                    ],
                },
            ]
        });
    复制代码

    效果演示:

    代码解释:

    • 代码创建了个基本行布局,第一行放入一个view:form,表单控件。 
    • 表单内容默认是行布局,使用elements,也可以使用rows,这里需要吐槽作者,设计API的时候任意乱来,一会element,一会cell,一会rows/columns,一会options。往后这类非常low的问题会越来越多,先预告下。
    • 表单的控件,如果需要通过方法返回集合,需要声明name属性。

     

    表单数据获取与设置

    接下来就是表单绑定事件,实现设置、更新,先看代码:

    复制代码
        $$('btn_update').attachEvent('onItemClick', function () {
            var values = $$('form').getValues();
            console.log(values);
    
            values.lb_title = values.txt_input;
            values.sh_select = 1;
            $$('form').setValues(values, true);
        });
    复制代码

    效果显示:

    代码解释:

    在输入框输入hello,点击设置,标签会变成同样内容,开关打开。

    • 获取和设置都是通过getValues, setValues控制。
    • 表单的控件通过attachEvent绑定点击事件

     

    表单输入校验

    绑定验证方法很多,我们只分享最干净的一种:

    复制代码
        webix.ui({
            id: 'webix_domasticparts',
            rows: [
                {
                    id: 'form', view: 'form', borderless: true,
                    elements: [
                        {
                            cols: [
                                { view: 'label', label: '无型号:', autowidth: true, },
                                { id: 'lb_title', name: 'lb_title', view: 'label', label: '0', width: 50, align: 'center', },
                                { id: 'sh_select', name: 'sh_select', view: 'switch', onLabel: "打开", offLabel: '关闭', width: 120, value: 0 },
                                {},
                            ],
                        }, {
                            cols: [
                                { id: 'txt_input', name: "txt_input", view: 'text', width: 200, placeholder: '商家编码', },
                                { id: 'btn_update', view: 'button', value: '设置', width: 150, },
                                {},
                            ],
                        },
                    ],
                    rules: {
                        txt_input: webix.rules.isNumber,
                    },
                },
            ]
        });
    
        $$('btn_update').attachEvent('onItemClick', function () {
            if (!$$('form').validate()) {
                webix.alert('输入错误')
                return;
            }
    
            var values = $$('form').getValues();
            console.log(values);
    
            values.lb_title = values.txt_input;
            values.sh_select = 1;
            $$('form').setValues(values, true);
        });
    复制代码

    效果演示:

    代码解释:

    • 在表单的elements节点下方,添加rules节点,里面键值对绑定控件的验证。webix默认内置了:
      • isNotEmpty
      • isNumber
      • isEmail
      • isChecked
      • 更多参考:https://docs.webix.com/desktop__data_validation.html#validationrules
    • 当然,rules节点的配置可以是自定义方法。具体不详细解释了。
    • 调用form的validate方法,通过返回值判断输入是否正确。

     

    小结

    现在我们可以制作一个比较复杂的表单了,里面包含了上传、导出等操作。先看代码:

    复制代码
        <style>
            .warn_label .webix_el_box {
                color: red;
                font-size: 18px;
                font-weight: bold;
            }
    
            .default_label .webix_el_box {
                font-weight: bold;
            }
    
            a {
                color: #333;
                text-decoration: none;
            }
        </style>
        <script type="text/javascript" charset="utf-8">
    
            const aadp_mixmode_cb = [
                { id: 1, value: '自营模式', },
                { id: 2, value: '淘宝国产代发', },
                { id: 3, value: '淘宝全代发', },
                { id: 4, value: '混采模式', },
            ];
    
            webix.ui({
                id: 'webix_domasticparts',
                rows: [
                    {
                        id: 'aadp_form', view: 'form', borderless: true,
                        elements: [
                            {
                                cols: [
                                    { view: 'label', label: '无型号:', autowidth: true, },
                                    { id: 'aadp_unknownpart', name: 'aadp_unknownpart', view: 'label', label: '0', width: 50, align: 'center', css: 'warn_label', },
                                    { view: 'label', label: '无颜色:', autowidth: true, },
                                    { id: 'aadp_unknowncolor', name: 'aadp_unknowncolor', view: 'label', label: '0', width: 50, align: 'center', css: 'warn_label', },
                                    { view: 'label', label: '无库存:', autowidth: true, },
                                    { id: 'aadp_unknownstock', name: 'aadp_unknownstock', view: 'label', label: '0', width: 50, align: 'center', css: 'warn_label', },
    
                                    { view: 'label', label: '零件总数:', autowidth: true, },
                                    { id: 'aadp_totalpart', name: 'aadp_totalpart', view: 'label', label: '0', width: 50, align: 'center', css: 'default_label', },
                                    { view: 'label', label: '总价格:', autowidth: true, },
                                    { id: 'aadp_totalprice', name: 'aadp_totalprice', view: 'label', label: '0', width: 180, align: 'center', css: 'default_label', },
                                    { view: 'label', label: '代发价格:', autowidth: true, },
                                    { id: 'aadp_totaldiscount', name: 'aadp_totaldiscount', view: 'label', label: '0', width: 180, align: 'center', css: 'default_label', },
    
                                    { id: 'aadp_unknownpart_cb', name: 'aadp_unknownpart_cb', view: 'switch', onLabel: "未知零件", offLabel: '未知零件', width: 120, value: 0 },
                                    { id: 'aadp_unknowncolor_cb', name: 'aadp_unknowncolor_cb', view: 'switch', onLabel: "未知颜色", offLabel: '未知颜色', width: 120, value: 0 },
                                    { id: 'aadp_unknownstock_cb', name: 'aadp_unknownstock_cb', view: 'switch', onLabel: "无库存", offLabel: '无库存', width: 120, value: 0 },
                                    {},
                                ],
                            },
                            {
                                cols: [
                                    { id: 'aadp_mixmode_cb', name: "aadp_mixmode_cb", view: 'richselect', label: '商家选择', width: 250, options: [], },
                                    { id: 'aadp_uploadsellercode', name: "aadp_uploadsellercode", view: 'text', width: 200, placeholder: '商家编码', },
                                    { id: 'aadp_reupload', view: 'uploader', value: '上传零件表', inputName: 'file', width: 150, css: 'webix_normal' },
                                    { id: 'aadp_download', view: 'button', value: '导出零件表', autowidth: true, },
                                    { id: 'aadp_createorder', view: 'button', value: '生成订单', autowidth: true, css: 'webix_primary' },
                                    { id: 'aadp_designcode', name: "aadp_designcode", view: 'text', width: 250, label: '零件编码', labelAlign: 'right', },
                                    { id: 'aadp_search', view: 'button', value: '搜索', autowidth: true, },
                                    {},
                                ],
                            },
                        ],
                    },
                ]
            });
    
            // 设置加载中特效
            webix.extend($$("webix_domasticparts"), webix.ProgressBar);
    
            // 代码设置下拉框
            $$('aadp_mixmode_cb').define('options', aadp_mixmode_cb);
            $$('aadp_mixmode_cb').refresh();
            $$('aadp_mixmode_cb').setValue(2);
    
    
            // 代码设置上传组件
            $$('aadp_reupload').define('formData', function () {
                var formval = $$('aadp_form').getValues();
                return {
                    mixmode: formval.aadp_mixmode_cb,
                    sellercode: formval.aadp_uploadsellercode,
                };
            });
            $$('aadp_reupload').define('upload', 'http://localhost:8001/sso/page/upload');
            $$('aadp_reupload').refresh();
            $$('aadp_reupload').attachEvent('onFileUploadError', function (file, err) {
                console.error(file, err);
                $$('webix_domasticparts').hideProgress();
                // 做一些补救措施,然后自动再上传
                $$('aadp_reupload').send();
            });
            $$('aadp_reupload').attachEvent('onAfterFileAdd', function () {
                $$('webix_domasticparts').showProgress({
                    type: 'icon',
                    delay: 1000,
                });
            });
            $$('aadp_reupload').attachEvent('onFileUpload', function (file, response) {
                console.log(response);
            });
    
            // 下载文件
            $$('aadp_download').attachEvent('onItemClick', function (e) {
                window.open(createRequestUrl('/wxss/moc/analysis/auth_exportbricklinkdomastic?orderNo=' + orderno));
            });
    
    
        </script>
    复制代码

    服务端代码:

        @RequestMapping("/upload")
        @ResponseBody
        public ApiResponseBody upload(String name, @RequestParam("file") MultipartFile file) {
            return ApiResponseBody.success(file.getOriginalFilename().toLowerCase());
        }    // 管理员国产零件导出
    复制代码
        @GetMapping("/analysis/auth_exportbricklinkdomastic")
        @ResponseBody
        public ApiResponseBody authExportBricklinkDomastic(String orderNo, HttpServletResponse response) throws Exception {
         // 这里添加下载的数据组装,filename等
    try { response.setHeader("content-type", "application/octet-stream"); response.setContentType("application/octet-stream"); // 下载文件能正常显示中文 response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")); OutputStream os = response.getOutputStream(); // 数据写入返回 System.out.println("Download successfully!"); return null; } catch (Exception e) { System.out.println("Download failed!"); return null; } finally { wb.close(); } }
    复制代码

    效果如下:

     Label关键点说明:

    • 如果要修改label的表现形式,需要增加css的属性,这是个非常常用的功能,但是这里有个巨坑,需要按照webix控件皮肤去改,改成:.warn_label .webix_el_box,原因是如果没这个css声明,会被官方的css覆盖了,导致一直改不成功。
      • 再分享一个巨坑,一旦用了自己的css属性,设置了字体的大小等,会导致label的自动调整布局resize() 全部失效,对不齐。因为官方用了默认的css去计算label的部局尺寸。
      • 从这里开始,大家应该可以理解到这个webix框架会有多烂。继续。

     Uploader关键点说明:

    • 使用上传控件,声明一个view:'uploader'的控件,他本质和button基本一样。同时要声明上传二进制的名字inputName: 'file',后台才能用file去接:@RequestParam("file")
    • 动态绑定上传地址,需要使用define('upload'这个最原始的方法,再refresh()。又是个无语的地方。
    • 同理,动态修改提交的formData,也需要使用define,然后使用方法返回运行时数据。
    • 上传组件如果需要代码再次提交,使用send()方法。比如上传的时候,服务端返回登录超时,那么前端再做一次登录,然后直接再次上传。
    • 上传组件几个关键事件:onAfterFileAdd、onFileUploadError、onFileUpload

    其他说明:

    • 如果要使用加载遮罩,需要扩展控件webix.extend,对控件增加webix.ProgressBar,然后就可以调用对应的showProgress, hideProgress。这是个透明的悬浮窗,可以遮挡用户操作行为,非常常用,但是webix竟然特么没有提供基础loading方法。
    • 动态修改下拉框的数据,同样要非常弱智的使用define('options的方式,修改控件配置,再refresh。没有提供一般性的绑定数据接口。
    • 要实现文件下载,建议使用window.open的方式。不然报错或者在iframe下,会有各种奇怪不爽问题。

     

    由于webix的坑实在多如天上繁星,接下里的datatable的坑数会翻倍。所以咱们新开一篇继续。今天的分享完毕!

     

    本文所有代码在这里可以下载:

    链接: https://pan.baidu.com/s/1jRk6Zo6YtIvNza-8I6rOtA

    提取码: eq2k

    也欢迎大家关注咱们公众号:辰同学技术 微信公众号,同样会分享各种技术10分钟从入门到吐槽:

     

  • 相关阅读:
    《canvas》之第15章 边界检测
    Java项目:员工订餐系统(java+SSM+JSP+jQuery+Mysql)
    工业自动化控制通信协议Profinet系列-2、编译p-net在虚拟机树莓派上运行示例
    使用 Sprinkles 构建您自己的类型安全版本的 Tailwind CSS
    jmeter单接口和多接口测试
    每日一题——Python实现PAT甲级1132 Cut Integer(举一反三+思想解读+逐步优化)五千字好文
    Python 网络爬取的时候使用那种框架
    【单片机】12-串口通信和RS485
    2023-10-10 mysql-{rea_create_base_table}-失败后回滚-记录
    Android 文字转语音播放实现
  • 原文地址:https://www.cnblogs.com/zc22/p/15921774.html