EasyUI+Knockout实现经典表单的查看编辑

Posted 大饼酥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了EasyUI+Knockout实现经典表单的查看编辑相关的知识,希望对你有一定的参考价值。

此文章是基于  搭建Jquery+SpringMVC+Spring+Hibernate+MySQL平台

 

一. 准备工作

  1. 点击此下载 ims.rar,解压缩并把文件放到 ims 工程对应的文件夹下

 

二. 前端框架特色 

  1. js库为 jquery-1.8.1.min.js

  2. UI选用 jquery-easyui-1.3.2

  3. 封装了一大部分比较实用的控件和组件,如自动完成控件、弹出控件、日期控件等

  4. 选 knockoutjs 为前端mvvm框架

    采用Knockout,提供了一个数据模型与用户UI界面进行关联的高层次方式(采用行为驱动开发)

  5. css框架选用 960gssexybuttons、css3 btn

 

三. 相关文件介绍

  1. jquery.easyui.fix.js

/**
* 模块名:easyui方法修改
* 程序名: easyui.fix.js
**/
var easyuifix = {};

/** 
 * for easyloader.js
 * add after row 13 usage: easyuifix.addLoadModules(_1);
 */
easyuifix.easyloader_addLoadModules = function (modules) {
    $.extend(modules, {
        juidatepick: {
            js: rootPath+"/content/js/jquery-plugin/jquery-ui/js/jquery-ui-datepick.min.js",
            css: rootPath+"/content/js/jquery-plugin/jquery-ui/css/jquery-ui.css"
        },
        daterange: {
            js: rootPath+"/content/js/jquery-plugin/daterange/jquery.daterange.js",
            css: rootPath+"/content/js/jquery-plugin/daterange/jquery.daterange.css",
            dependencies: ["juidatepick"]
        },
        lookup: {
            js: rootPath+"/content/js/jquery-plugin/lookup/jquery.lookup.js",
            dependencies: ["combo"]
        },
        autocomplete: {
            js: rootPath+"/content/js/jquery-plugin/autocomplete/jquery.autocomplete.js",
            dependencies: ["combo"]
        }
    });
};

/** 
 *  for easyloader.js
 * add after row 181 usage: easyuifix.easyloader_setting(easyloader, src);
 */
easyuifix.easyloader_setting = function (easyloader,src) {
    easyloader.theme = "default";
    easyloader.locale = "zh_CN";
};

/**
 * for jquery.parser.js
 * add after row 89 usage: easyuifix.parser_addplugins($.parser.plugins);
 */
easyuifix.parser_addplugins = function (plugins) {
    var arr = ["daterange", "lookup", "autocomplete"];
    for (var i in arr) 
        plugins.push(arr[i]);
};

/** 
 * for jquery.tabs.js
 * add after row 415 usage: easyuifix.tabs_showtabonselect(_5d);
 */
easyuifix.tabs_showtabonselect =function(tab){
    tab.show();    //打开时其它页签先隐藏,,提升用户体验,点击时再显示
}

/**
 * for easyui-lang-zh_CN.js
 * add last row: easyuifix.lang_zh_CN();
 */
easyuifix.lang_zh_CN = function () {
    if ($.fn.lookup) {
        $.fn.lookup.defaults.missingMessage = \'该输入项为必输项\';
    }
};

/**
 * for jquery.datagrid.js
 * add after row 1137 usage: easyuifix.datagrid_beforeDestroyEditor(_10a, _10b, row);
 * for jquery.easyui.min.js
 * add after row 7622 usage: easyuifix.datagrid_beforeDestroyEditor(_530, _531, row);
 */
easyuifix.datagrid_beforeDestroyEditor = function (jq, rowIndex, row) {
    var opts = $.data(jq, "datagrid").options;
    if (opts.OnBeforeDestroyEditor) {
        var editors = {}, list = $(jq).datagrid(\'getEditors\', rowIndex) || [];
        $.each(list, function () { editors[this.field] = this; });
        opts.OnBeforeDestroyEditor(editors, row, rowIndex, jq);
    }
};

/**
 * for jquery.datagrid.js 
 * add after row 1101 usage: easyuifix.datagrid_afterCreateEditor(_104, _105, row);
 * for jquery.easyui.min.js
 * add after row 7586 usage: easyuifix.datagrid_afterCreateEditor(_52a, _52b, row);
 */
easyuifix.datagrid_afterCreateEditor = function (jq, rowIndex, row) {
    var opts = $.data(jq, "datagrid").options;
    if (opts.OnAfterCreateEditor) {
        var editors = {}, list = $(jq).datagrid(\'getEditors\', rowIndex) || [];
        $.each(list, function () { editors[this.field] = this; });
        opts.OnAfterCreateEditor(editors, row, rowIndex, jq);
    }
};

/**
 * for jquery.combo.js to convert disable to readonly
 * add after row 210 usage: easyuifix.combo_disableToReadonly(_32, _33);
 */
easyuifix.combo_disableToReadonly = function (jq, b) {
    var options = $.data(jq, "combo").options;
    var combo = $.data(jq, "combo").combo;
    if (b) {
        options.disabled = true;
        $(jq).attr("readonly", true);
        combo.find(".combo-value").attr("readonly", true).addClass("readonly");
        combo.find(".combo-text").attr("readonly", true).addClass("readonly");
    } else {
        options.disabled = false;
        $(jq).removeAttr("readonly");
        combo.find(".combo-value").removeAttr("readonly").removeClass("readonly");
        combo.find(".combo-text").removeAttr("readonly").removeClass("readonly");
    }
};

/**
 * for jquery.combobox.js to showblank
 * add after row 138 usage: easyuifix.combobox_showblank(_30, _2e);
 */
easyuifix.combobox_showblank = function (combobox, b) {
    if (combobox.showblank) {
        b.unshift(combobox.blankdefault);
    }
}

/**
 * for jquery.combobox.js to showblank
 * add after row 350 usage: easyuifix.combobox_defaultblank();
 */
easyuifix.combobox_defaultblank = function () {
    $.fn.combobox.defaults = $.extend($.fn.combobox.defaults, {
        showblank: false,
        blankdefault: { value: \'\', text: \'== 请选择 ==\' }
    });    
}

/**
 * for datagrid.js
 * add after row 2065 usage: if (easyuifix) easyuifix.datagrid_editor_extend();
 * use such as: using("lookup", easyuifix.datagrid_editor_extend);
 */
easyuifix.datagrid_editor_extend = function () {
    if ($.fn.datagrid) {
        if ($.fn.numberspinner) {
            $.extend($.fn.datagrid.defaults.editors, {
                numberspinner: {
                    init: function (container, options) {
                        var input = $(\'<input type="text">\').appendTo(container);
                        return input.numberspinner(options);
                    },
                    destroy: function (target) {
                        $(target).numberspinner(\'destroy\');
                    },
                    getValue: function (target) {
                        return $(target).numberspinner(\'getValue\');
                    },
                    setValue: function (target, value) {
                        $(target).numberspinner(\'setValue\', value);
                    },
                    resize: function (target, width) {
                        $(target).numberspinner(\'resize\', width);
                    }
                }
            });
        }

        if ($.fn.autocomplete) {
            $.extend($.fn.datagrid.defaults.editors, {
                autocomplete: {
                    init: function (container, options) {
                        var input = $(\'<input type="text" class="z-text datagrid-editable-input">\').appendTo(container);
                        return input.autocomplete(options);
                    },
                    destroy: function (target) {
                        $(target).autocomplete(\'destroy\');
                    },
                    getValue: function (target) {
                        return $(target).val();
                    },
                    setValue: function (target, value) {
                        $(target).val(value);
                    },
                    resize: function (target, width) {
                        $(target).width(width);
                    }
                }
            });
        }

        if ($.fn.lookup) {
            $.extend($.fn.datagrid.defaults.editors, {
                lookup: {
                    init: function (container, options) {
                        var input = $(\'<input type="text" class="z-text datagrid-editable-input">\').appendTo(container);
                        return input.lookup(options);
                    },
                    destroy: function (target) {
                        $(target).lookup(\'destroy\');
                    },
                    getValue: function (target) {
                        return $(target).lookup(\'getValue\');
                    },
                    setValue: function (target, value) {
                        $(target).lookup(\'setValue\', value);
                    },
                    resize: function (target, width) {
                        $(target).lookup(\'resize\', width);
                    }
                }
            });
        }

        $.extend($.fn.datagrid.defaults.editors, {
            label: {
                init: function (container, options) {
                    var input = $(\'<div></div>\').appendTo(container);
                    return input;
                },
                destroy: function (target) {

                },
                getValue: function (target) {
                    return $(target).html();
                },
                setValue: function (target, value) {
                    $(target).html(value);
                },
                resize: function (target, width) {

                }
            }
        });
    }
}
View Code

    easyUI方法修改,改善方法,提升用户体验;注释中提示方法作用的位置

  

  2. knockout.bindings.js

/// <reference path="knockout-3.4.1.js" />
/**
 * 程序名: knockout自定义绑定
 **/

(function ($, ko) {
    var jqElement = function (element) {
        var jq = $(element);
        if ($(document).find(element).length == 0) {  //处理元素在父页面执行的情况
            if ($(parent.document).find(element).length > 0)
                jq = parent.$(element);
        }
        return jq;
    };

    /**
     * value binding
     * 例如:comboboxValue、lookupValue、combotreeValue
     */
    ko.creatEasyuiValueBindings = function (o) {
        o = $.extend({ type: \'\', event: \'\', getter: \'getValue\', setter: \'setValue\', fix: $.noop,formatter: function (v) { return v; }}, o);

        var customBinding = {
            init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
                var jq = jqElement(element), handler = jq[o.type](\'options\')[o.event], opt = {};

                //handle the field changing
                opt[o.event] = function () {
                    handler.apply(element, arguments);
                    var value = jq[o.type](o.getter);
                    if (valueAccessor() == null) throw "viewModel中没有页面绑定的字段";
                    valueAccessor()(value);
                };

                //handle disposal (if KO removes by the template binding)
                ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
                    jq[o.type]("destroy");
                });

                o.fix(element, valueAccessor);
                jq[o.type](opt);
            },
            update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
                value = ko.utils.unwrapObservable(valueAccessor());
                jqElement(element)[o.type](o.setter, o.formatter(value));
            }
        };
        ko.bindingHandlers[o.type + \'Value\'] = customBinding;
    };

    ko.creatEasyuiValueBindings({ type: \'combobox\', event: \'onSelect\' });
    ko.creatEasyuiValueBindings({ type: \'combotree\', event: \'onChange\' });
    ko.creatEasyuiValueBindings({ type: \'datebox\'       , event: \'onSelect\' , formatter: com.formatDate });
    ko.creatEasyuiValueBindings({ type: \'lookup\'        , event: \'onChange\' });
    ko.creatEasyuiValueBindings({ type: \'numberbox\'     , event: \'onChange\' });
    
    /*
     * enable、disable binding
     * 例如:linkbuttonEnable、linkbuttonDisable
     */
    ko.creatEasyuiEnableBindings = function (o) {
        o = $.extend({ type: \'\',method:\'Enable\', options:function(v){return \'disabled\';}, value: function (v) { return !v; } }, o);
        var customBinding = {
            update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
                var enable = ko.toJS(valueAccessor());
                $(element)[o.type](o.options(enable), o.value(enable));
            }
        };
        ko.bindingHandlers[o.type + o.method] = customBinding;
    };
    ko.creatEasyuiEnableBindings({ type: \'linkbutton\', options: function (b) { return {disabled:!b}; } });
    ko.creatEasyuiEnableBindings({ type: \'linkbutton\',method:\'Disable\', options: function (b) { return { disabled: b }; } });
    
    _readOnlyHandles = {};
    _readOnlyHandles.defaults = function (obj, b) {
        b ? obj.addClass("readonly").attr("readonly", true) : obj.removeClass("readonly").removeAttr("readonly");
    };
    _readOnlyHandles.combo = function (obj, b) {
        obj.combo(b ? "disable" : "enable");
    };
    
    /**
     * readonly binding
     * 例如:numberboxReadOnly、comboboxReadOnly,或者直接readOnly
     */
    ko.creatEasyuiReadOnlyBindings = function (o) {
        o = $.extend({ type: \'\', handler: _readOnlyHandles.defaults }, o);
        var customBinding = {
            update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
                o.handler($(element),ko.toJS(valueAccessor()));
            }
        };
        ko.bindingHandlers[o.type ?  (o.type + \'ReadOnly\'): \'readOnly\'] = customBinding;
    };

    ko.creatEasyuiReadOnlyBindings(); //default readonly
    ko.creatEasyuiReadOnlyBindings({ type: \'numberbox\' });
    ko.creatEasyuiReadOnlyBindings({ type: \'combobox\', handler: _readOnlyHandles.combo });
    ko.creatEasyuiReadOnlyBindings({ type: \'datebox\', handler: _readOnlyHandles.combo });
    ko.creatEasyuiReadOnlyBindings({ type: \'combotree\', handler: _readOnlyHandles.combo });
    ko.creatEasyuiReadOnlyBindings({ type: \'lookup\', handler: _readOnlyHandles.combo });
     
    /**
     * datasource bingding
     */
    ko.bindingHandlers.datasource = {
        init: function (element, valueAccessor) {
            var jq = jqElement(element);
            var ds = ko.toJS(valueAccessor());
            if ($.isFunction(ds)) ds = ds.call();
            if (jq.data(\'treegrid\'))
                jq.treegrid(\'loadData\', ds);
            else if (jq.data(\'datagrid\'))
                jq.datagrid(\'loadData\', ds);
            else if (jq.data(\'combotree\'))
                jq.combotree(\'loadData\', ds);
            else if (jq.data(\'combobox\')) {
                var val = jq.combobox(\'getValue\'), ds = ds.rows || ds;
                jq.combobox(\'clear\').combobox(\'loadData\',ds).combobox(\'setValue\', val);
            }
            else if (jq.data(\'tree\'))
                jq.tree(\'loadData\', ds.rows || ds);
        }
    };

    /**
     * grid binding
     * datagrid、treegrid
     */
    ko.creatEasyuiGridBindings = function (gridType) {
        var gridBinding = {
            update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
                var grid = jqElement(element), opts = ko.toJS(valueAccessor()), url = opts.url;
                var customLoader = function (queryParams) {
                    if (opts.pagination) {
                        var paging = grid.datagrid(\'getPager\').pagination(\'options\');
                        queryParams = $.extend(queryParams, { page: paging.pageNumber, rows: paging.pageSize });
                    }
                    com.ajax({
                        type: \'get\',
                        url: url,
                        data: queryParams,
                        success: function (d) {
                            if ($.isFunction(opts.afterCustomSuccess)) opts.afterCustomSuccess(d);
                            grid[gridType](\'loadData\', d);
                        }
                    });
                };

                if (opts.treeField && opts.parentField) { //only for treegrid
                    opts.loadFilter = function (data) {
                        return utils.toTreeData(data.rows || data, opts.idField||opts.treeField, opts.parentField, "children");
                    };
                }

                var handler = function () {    
                    if (grid.data(gridType)) {
                        if (opts.customLoad)
                            customLoader(opts.queryParams);
                        else
                            grid[gridType](opts);
                    } else {
                        var defaults = {
                            iconCls: \'icon icon-list\',
                            nowrap: true,           //折行
                            rownumbers: true,       //行号
                            striped: true,          //隔行变色
                            singleSelect: true,     //单选
                            remoteSort: true,       //后台排序
                            pagination: false,      //翻页
                            pageSize: 20,
                            contentType: "application/json",
                            method: "POST"
                        };
                        var winsize = function (size) {
                            var ret = {};
                            if (size && size.w) ret.width = jqElement(window).width() - size.w;
                            if (size && size.h) ret.height = jqElement(window).height() - size.h;
                            return ret;
                        };

                        opts = $.extend(defaults, opts, winsize(opts.size));
                        if (opts.customLoad) {
                            if (opts.remoteSort)
                                opts.onSortColumn = function (sort, order) { customLoader($.extend(opts.queryParams, { sort: sort, order: order })); };

                            grid[gridType](opts);
                            customLoader(opts.queryParams);

                            if (opts.pagination)
                                grid[gridType](\'getPager\').pagination({ onSelectPage: customLoader });
                        }
                        else
                            grid[gridType](opts);

                        valueAccessor()[gridType] = function () { return grid[gridType].apply(grid, arguments); }
                        valueAccessor()[\'$element\'] = function () { return grid; };
                        if (opts.size) jqElement(window).resize(function () { grid[gridType](\'resize\', winsize(opts.size)); });
                    }
                };

                grid[gridType] ? handler() : using([gridType], function () {
                    handler();
                    if (gridType==\'treegrid\') com.loadCss(\'content/images/icon/icon.css\', document, true);//解决图标被tree.css覆盖的问题
                });
            }
        };

        return gridBinding;
    };

    ko.bindingHandlers.datagrid = ko.creatEasyuiGridBindings(\'datagrid\');
    ko.bindingHandlers.treegrid = ko.creatEasyuiGridBindings(\'treegrid\');
    
    /**
     * easyui binding
     * 例如:easyuiCombotree、easyuiCombobox、easyuiLinkbutton
     */
    ko.createEasyuiInitBindings = function (o) {
        o = $.extend({ type: \'\' },o);
        var customBinding = {
            init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
                var jq = jqElement(element), opt = ko.mapping.toJS(valueAccessor());
                var handler = function () {
                    jq[o.type](opt);
                };
                jq[o.type] ? handler() : using(o.type, handler);

                //handle disposal (if KO removes by the template binding)
                ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
                    jq[o.type]("destroy");
                });
                valueAccessor()["$element"] = function () { return jq };
            },
            update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
                var jq = jqElement(element), opt = ko.mapping.toJS(valueAccessor());
                if (jq[o.type]) jq[o.type](opt);
            }
        };
        var bindName = \'easyui\' + o.type.replace(/(^|\\s+)\\w/g, function (s) {return s.toUpperCase();});
        ko.bindingHandlers[bindName] = customBinding;
    };

    ko.createEasyuiInitBindings({ type: \'tabs\' });
    ko.createEasyuiInitBindings({ type: \'tree\' });
    ko.createEasyuiInitBindings({ type: \'combotree\' });
    ko.createEasyuiInitBindings({ type: \'combobox\' });
    ko.createEasyuiInitBindings({ type: \'linkbutton\' });

    /**
     * inputwidth、autoheight、autowidth binding
     */
    ko.bindingHandlers.inputwidth = {
        update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
            var that = $(element), widthStr = ko.toJS(valueAccessor());
            var calcWidth = function (w) {
                var rate = 1
                if (typeof w == \'string\') {
                    if (w.indexOf("px") > -1 || w.indexOf("PX") > -1) w = w.replace("px", "").replace("PX", "");
                    if (w.indexOf("%") > -1) w = w.replace("%", "") / 100;
                }
                if (w > 0 && w <= 1) {
                    rate = w;
                    w = $(".val").width();
                }
                return w * rate;
            };
        
            var resizeWidth = function () {
                var width = calcWidth(widthStr);
                $.each([
                    { selector: \'input.txtBox\', handler: function (jq) { jq.width(width - 8); } },            //pading3*2 + border1*2 = 8
                    { selector: \'input[comboname],input.combo-f\', handler: function (jq) { jq.combo(\'resize\', width); } }               
                ], function () {
                    var jq = that.find(this.selector);
                    if (jq.length > 0) this.handler(jq);
                    if (that.is(this.selector)) this.handler(that);
                });
            };

            resizeWidth();
            $(window).resize(resizeWidth);
        }
    };
    
    ko.bindingHandlers.autoheight = {
        update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
            var that = $(element), obserable = valueAccessor(),
               height = $.isFunction(obserable) ? obserable() : obserable;
            that.height($(window).height() - height);
            $(window).resize(function () { that.height($(window).height() - height); });
        }
    };
    ko.bindingHandlers.autowidth = {
        update: function (element, valueAccessor, allBindingsAccessor, viewModel) {
            var that = $(element), obserable = valueAccessor(),
               width = $.isFunction(obserable) ? obserable() : obserable;
            that.width($(window).width() - width);
            $(window).resize(function () { that.width($(window).width() - width); });
        }
    };
    
    /**
     * 实现js与页面绑定
     */
    ko.bindingViewModel = function (viewModelInstance,node) {
        using(\'parser\', function () {
            $.parser.onComplete = function () {
                ko.applyBindings(viewModelInstance, node || document.body);
            };
        });
    };
 
})(jQuery, ko);
View Code

    自定义绑定,使 knockout 和 easyUI 关联,作用于页面中

  

  3. receive.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
 <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>材料收料单</title>
    <%@ include file="/common/head.jsp"%>
 </head>
 <body>
     <div class="toolbar">
        <a href="#" plain="true" class="easyui-linkbutton"  icon="icon-arrow_refresh"   title="刷新" data-bind="click:refreshClick">刷新</a>
        <a href="#" plain="true" class="easyui-linkbutton"  icon="icon-add"             title="新增" data-bind="click:addClick"    >新增</a>
        <a href="#" plain="true" class="easyui-linkbutton"  icon="icon-edit"            title="编辑" data-bind="click:editClick"   >编辑</a>
        <a href="#" plain="true" class="easyui-linkbutton"  icon="icon-cross"           title="删除" data-bind="click:deleteClick" >删除</a>    
        <a href="#" plain="true" class="easyui-linkbutton"  icon="icon-user-accept"     title="审核" data-bind="click:auditClick"  >审核</a>
        <a href="#" plain="true" class="easyui-linkbutton"  icon="icon-printer"         title="打印" data-bind="click:printClick"  >打印</a>
    </div>
    
    <div class="container_12" style="position:relative;">
        <div class="grid_1 lbl">收料单号</div>
        <div class="grid_2 val"><input type="text" data-bind="value:form.billNo" class="easyui-autocomplete txtBox" data-options="url:rootPath+\'/mms/receive!getBillNo.do\'"/></div以上是关于EasyUI+Knockout实现经典表单的查看编辑的主要内容,如果未能解决你的问题,请参考以下文章

建筑材料系统 ASP.NET MVC4.0 + WebAPI + EasyUI + Knockout 的架构设计开发

使用 Knockout.js 在表单输入上切换按钮状态

EasyUI笔记表单

EasyUI页面跳转后传值出现乱码

easyUI的form表单重复提交处理

easyui表单多重验证,动态设置easyui控件