由来

一直以来做开发,尤其是web开发,少不了和JavaScript打交道,自认为js脚本还可以吧!
有一天,我发现 select控件、下拉框、ajax请求、文件上传控件等等 大多地方都要使用的到,
有些虽然用的也是别人的写好的控件,可是根据项目的要求,自己想在封装一下,来满足
自己的需求!

可是写了很久,以失败而告终!常用的,说实话,大家都会,可是要深入研究久逊色点了。
所以,不能放弃治疗,哪里有病就要治疗哪里,绝不能怠慢!

示例: 封装select_tree.js

  1. 效果图:
  2. iOS开发 封装threejs_selectTree

  3. 封装代码缩略图:
  4. iOS开发 封装threejs_selectTree_02

  5. html调用
引入样式: <link href="/js/component/selectTree/selecttree.css" rel="stylesheet" />
引入脚本:   <script src="/js/component/selectTree/selectTree.js"></script>
控件:<input id="equ_category_small"  name="equ_category_small" type="text" class="form-control"  />
  1. js调用
$("#equ_category_small").selectTree({
                url: "/equipment/GetCategoryList",
                isRadio: true,
                title: "请选择设备",
                requestCallBack: function (data) {
                    var treedata = [];
                    if (data.code == 0) {
                        $(data.data.CategoryBig).each(function (i, o) {
                            var node = {};
                            var id = o.categoryId;
                            var pid = o.pCategoryId;
                            node.id = id;
                            node.pId = pid;
                            node.name = o.categoryName;
                            node.isParent = true;
                            node.open = true;
                            treedata.push(node);
                        });
                        $(data.data.CategorySmall).each(function (i, o) {
                            var node = {};
                            var id = o.categoryId;
                            var pid = o.pCategoryId;
                            node.id = id;
                            node.pId = pid;
                            node.name = o.categoryName;
                            treedata.push(node);
                        });
                    }
                    return treedata;
                },
                selected: function (node) {
                    $("#equ_category_small").val(node[0].id);
                    //$("#equ_category_small").valid();
                }
            });
  1. 后台数据
@RequestMapping("GetCategoryList")
@ResponseBody
public String GetCategoryList()
{
    List<BasEquType> ListSmall =basEquTypeService.categoryListSmall(0);
    List<BasEquType> ListBig = basEquTypeService.categoryListBig(0);

    Dictionary<String,List<BasEquType>> map=new Hashtable<>();
    map.put("CategoryBig",ListBig);
    map.put("CategorySmall",ListSmall);
    Result result=new Result();
    result.setCode("0");
    result.setData(map);
    return JSON.toJSONString(result) ;
}

如何封装自己js库

上面只是提供了一个完整示例,并没有介绍如何封装js组件,好了,接下重点讲接一下。

  1. 创建匿名函数
Q: 什么是匿名函数?
A: 顾名思义就是没有名称的函数
Q: 匿名函数作用是什么?
A: 匿名函数的作用主要是实现自己定义内部中的函数,从而扩大函数的使用功能
Q: 为什么要使用匿名函数?
A: 因为页面的脚本会越来越多,全局变量和和方法会越来越多,主要是为了避免重名,还有就是模块化。

匿名函数:

匿名函数
(function ($) {
       //....封装组件逻辑
})(jQuery);
--------------------------------------------------------------------
拆分来看
var fn = function($){
    //.....组件封装逻辑
};
fn(jQuery);
立即执行的函数
  1. 创建模块内容
    模块就是实现特定功能的一组方法。
    a. 一般写法 :只要把不同的函数(以及记录状态的变量)简单地放在一起,就算是一个模块。
例如: 

function  fun1(){
    //...
  }
function fun2(){
    //...
  }

上面的函数fun1()和fun2(),组成一个模块。使用的时候,直接调用就行了。

b. 为了解决上面的缺点,可以把模块写成一个对象,所有的模块成员都放到这个对象里面

var module1 = new Object({

    _count : 0,

fun1: function (){
      //...
  },

fun2: function (){
      //...
    }

 });

上面的函数fun1()和fun2(),都封装在module1对象里。使用的时候,就是调用这个对象的属性。
module1.fun1();

但是,这样的写法会暴露所有模块成员,内部状态可以被外部改写。比如,外部代码可以直接改变内部计数器的值。 module1._count = 100;

c. 为了解决这个问题,我们使用”立即执行函数”(Immediately-Invoked Function Expression,IIFE)也就是匿名函数,可以达到不暴露私有成员的目的。

var module1 = (function(){
   var _count = 0;

   var fun1= function(){
      //...
    };

    var fun2= function(){
      //...
    };

    return {
            fun1: fun1,
            fun2: fun2
    };

  })();

使用上面的写法,外部代码无法读取内部的_count变量。
console.info(module1._count); //undefined

d.一个模块很大,必须分成几个部分,或者一个模块需要继承另一个模块,这时就有必要采用”放大模式”(augmentation)。

var module1 = (function (mod){

   mod.fun3= function () {
      //...
   };

   return mod;

})(module1);

上面的代码为module1模块添加了一个新方法fun3(),然后返回新的module1模块。

e.在浏览器环境中,模块的各个部分通常都是从网上获取的,有时无法知道哪个部分会先加载。如果采用上一节的写法,第一个执行的部分有可能加载一个不存在空对象,这时就要采用”宽放大模式”。(Loose augmentation)。

var module1 = ( function (mod){

    //...

    return mod;

 })(window.module1 || {});

模块的写法就介绍到这里了,在我们创建的匿名函数里面写我们需要的函数和属性,如上图封装代码缩略图所示

重点知识

  1. JQuery 的扩展方法$.extend()的用法和含义:
extend()方法作用就是合并另个对象,有相同的则覆盖,没有相同的则添加
例子1:
var settings = { url: '#', title: 'xxx', param: "ok" };
var options = { title: 'abc', param: "no" };
$.extend(settings, options);

结果1:
settings == { url: '#', title: 'abc', param: "no" }

例子2:
var empty = {};
var defaults =  { url: '#', title: 'xxx', param: "ok" };
var options = { title: 'abc', param: "no" };
var settings = $.extend(empty, defaults, options);

结果:
settings ==  { url: '#', title: 'abc', param: "no" }
empty == { url: '#', title: 'abc', param: "no" }
  1. prototype 属性的用法和含义:
prototype 属性使您有能力向对象添加属性和方法

例如:
SelectTree.prototype.initDom = function ()
SelectTree.prototype.setCheckNode = function ()
.......................................
  1. $.fn.selectTree = function (options) {//…}
这个就表示向jquery对象添加自定义方法

$.fn.selectTree = function (options, param) {
   //...
};
调用:
 $("#equ_category_small").selectTree({
  //...
 });

js脚本和样式


脚本 selecttree.js

(function ($) {
    "use strict";
    var CON_TYPE_NULL = "请选择";
    var BASEHtml = "<div class=\"dropdown\"><button class=\"btn dropdown-toggle form-control\" type=\"button\" data-toggle=\"dropdown\" data-ztree=\"check\" id=\"btnType\"> <span >请选择类别</span> <span class=\"caret\"></span></button> <div class=\"panel dropdown-menu selecttree\"> <div class=\"panel-body\"> <ul class=\"ztree\" ></ul></div><div class=\"panel-footer\"> <div class=\"btn-group btn-group-justified\"><a class=\"btn\" id=\"btnCancel\">取消</a><a class=\"btn btn-success\" id=\"btnOK\">确定</a></div></div></div></div>";
    var TreeIndex = 1;
    /**
     * selectTree插件基于jquery,bootstrap,ztree,使用时要引用相应的js
     *   param: {
     *      NullText:默认提示信息
     *      objTitle: "btnTitle", 选择后需要显示的控件I
     *      isRadio: false,        是否是单选
     *      url: "/Machine/KBS/GetContentTypes"   数据请求的URL 暂时基于post方式请求
     *      requestCallBack:数据获取后的回调方法
     *      succes:点击确定按钮的处理事件
     *      cancel:点击取消按钮的处理事件
     *      selected:单选选定回调
     *      isParentSelect:父级可选
     *  },
     * 使用:$("#type").selectTree();
     */

    function SelectTree(obj, params) {
        this.tiggerObj = obj;

        this.param = this.param || {};
        if (!this.param.NullText || this.param.NullText == "") {
            this.param.NullText = CON_TYPE_NULL;
        }
        this.param = $.extend(this.param, params);
        this.initDom();
        this.objTitle = $(this.tiggerObj).prev().children("button").children("span").eq(0);
        this.ishide = true;
        this.isCancel = true;
        if (this.param.title) {
            this.objTitle.text(this.param.title);
        }
        this.getContent();
        this.initValue();
        this.initEvent();
    }
    SelectTree.prototype.reload = function (params) {
        this.param = $.extend(this.param, params);
        //this.objTitle = $(this.tiggerObj).prev().children("button").children("span").eq(0);
        this.ishide = true;
        this.isCancel = true;
        if (this.param.title) {
            this.objTitle.text(this.param.title);
        }
        this.getContent();
        this.initValue();
        this.initEvent();
    };
    //初始化组件DOM元素
    SelectTree.prototype.initDom = function () {
        this.tiggerObj.css({ "height": "0.5px", "width": "0px", "padding": "0px", "margin": "0px" });
        this.tiggerObj.before(BASEHtml);

        if (this.param.isRadio) {
            $(".selecttree .panel-footer .btn").hide();
        }
    };
    //初始化事件定义
    SelectTree.prototype.initEvent = function () {
        var self = this;
        var isthis = false;
        //点击组件内部触发动作
        $(".dropdown .panel-body").click(function () {
            self.ishide = false;
            if (self.param.isRadio) {
                self.isCancel = false;
            }
        });
        if (!self.param.isRadio) {
            var btnCancel = $(this.tiggerObj).parent().find("#btnCancel");
            $(btnCancel).click(function () {
                //console.log("btnCancel");
                self.ishide = true;
                if (self.param.cancel) {
                    self.param.cancel();
                }
            });
            var btnOk = $(this.tiggerObj).parent().find("#btnOK");
            $(btnOk).click(function () {
                // console.log("btnOk");
                self.ishide = true;
                self.isCancel = false;
                if (self.param.succes) {
                    self.param.succes();
                }
            });
        }
        //组件消失时触发
        $(this.tiggerObj).parent().on("hide.bs.dropdown", function (e) {
            var node = self.TreeObj.getSelectedNodes()[0];
            if (self.param.isRadio && self.param.isParentSelect) {
                var selectedNodes = self.TreeObj.getSelectedNodes();
                if (self.param.selected) {
                    self.param.selected(selectedNodes);
                }
                var names = [];
                var id = [];
                var tid = [];
                var pname = "";
                var pid = "";
                $(selectedNodes).each(function (i, o) {
                    names.push(o.name);
                    id.push(o.id);
                    tid.push(o.tId);
                    var pnode = o.getParentNode();
                    if (pnode && pnode != null) {
                        pname += pnode.name;
                        if (pnode.value) {
                            pid += pnode.value;
                        } else {
                            pid += pnode.id;
                        }
                    }
                });
                var name = names.join(",");
                if (name == "")
                    name = self.param.NullText;
                $(self.objTitle).text(name);
                if (self.param.name) {
                    $("#" + self.param.name).val(name);
                }
                if (self.param.parentName) {
                    $("#" + self.param.parentName).val(pname);
                }
                if (self.param.parentValue) {
                    $("#" + self.param.parentValue).val(pid);
                }
                $(self.tiggerObj).val(id.join(","));
                $(self.tiggerObj).data("tids", tid.join(","));
                return;
            }
            if ((!self.ishide && !self.param.isRadio) || (self.param.isRadio && !self.ishide && node && node.isParent)) {
                self.ishide = true;
                if (self.param.isRadio) {
                    self.isCancel = true;
                }
                e.preventDefault();
            } else {
                if (!self.isCancel) {
                    var treeObj = self.TreeObj;
                    var selectedNodes;
                    if (self.param.isRadio) {
                        selectedNodes = treeObj.getSelectedNodes();
                    } else {
                        selectedNodes = treeObj.getCheckedNodes(true);
                    }
                    if (self.param.selected) {
                        self.param.selected(selectedNodes);
                    }
                    var names = [];
                    var id = [];
                    var tid = [];
                    var pname = "";
                    var pid = "";
                    $(selectedNodes).each(function (i, o) {
                        if (!o.isParent) {
                            names.push(o.name);
                            id.push(o.id);
                            tid.push(o.tId);
                            var pnode = o.getParentNode();
                            if (pnode && pnode != null) {
                                pname += pnode.name;
                                if (pnode.value) {
                                    pid += pnode.value;
                                } else {
                                    pid += pnode.id;
                                }
                            }
                        }
                    });
                    var name = names.join(",");
                    if (name == "")
                        name = self.param.NullText;
                    $(self.objTitle).text(name);
                    if (self.param.name) {
                        $("#" + self.param.name).val(name);
                    }
                    if (self.param.parentName) {
                        $("#" + self.param.parentName).val(pname);
                    }
                    if (self.param.parentValue) {
                        $("#" + self.param.parentValue).val(pid);
                    }
                    $(self.tiggerObj).val(id.join(","));
                    $(self.tiggerObj).data("tids", tid.join(","));
                }
            }

        });
        //组件显示时触发
        $(this.tiggerObj).parent().on("show.bs.dropdown", function (e) {
            // console.log($(self.tiggerObj).data("tids"));
            self.setCheckNode();
            self.isCancel = true;
        });
    };
    //设置选择node
    SelectTree.prototype.setCheckNode = function () {
        var self = this;
        if (self.param.isRadio) {
            var selectnode = self.TreeObj.getSelectedNodes();
            if (selectnode.length > 0) {
                self.TreeObj.cancelSelectedNode(selectnode[0]);
            }
        } else {
            self.TreeObj.checkAllNodes(false);
        }
        var check = $(self.tiggerObj).data("tids");
        if (check) {
            var tids = check.split(",");
            $(tids).each(function (i, o) {
                var node = self.TreeObj.getNodeByTId(o);
                if (self.param.isRadio) {
                    self.TreeObj.selectNode(node);
                } else {
                    self.TreeObj.checkNode(node, true, true);
                }
            });
        }
    };
    //获取树内容
    SelectTree.prototype.getContent = function () {
        var url = this.param.url;
        var self = this;
        $.ajax({
            "type": "Get",
            //"contentType": "application/json",
            "url": url,
            "async": false,
            //"dataType": "json",
            "success": function (resp) {
                var zNodes = [];
                var setting = treeSetting(self.param.isRadio);
                if (self.param.requestCallBack) {
                    zNodes = self.param.requestCallBack($.parseJSON(resp));
                } else {
                    zNodes = $.parseJSON(resp).data;
                }
                var treeContent = $(self.tiggerObj).prev().children().children(".panel-body").children(".ztree").eq(0);
                $(treeContent)[0].id = "tree" + TreeIndex;

                self.TreeObj = $.fn.zTree.init(treeContent, setting, zNodes);
                TreeIndex++;
                //  self.initValue();
            }
        });
    };
    //初始化组件值
    SelectTree.prototype.initValue = function () {
        var value = $(this.tiggerObj).val();
        var self = this;
        if (value && value != "") {
            var ids = value.split(',');
            //var nodes = [];
            var tids = [];
            var name = [];
            $(ids).each(function (i, o) {
                var node = self.TreeObj.getNodesByParam("id", o, null)[0];
                if (node && node != null) {
                    //nodes.push(node);
                    name.push(node.name);
                    tids.push(node.tId);
                }

            });

            if (tids.length > 0) {
                this.objTitle.text(name.join(','));
                $(this.tiggerObj).data("tids", tids.join(','))
            }
        } else {
            this.objTitle.text(this.param.NullText);
        }
    };
    //获取ztree设置
    function treeSetting(isradio) {
        if (isradio) {
            return {
                data: {
                    simpleData: {
                        enable: true
                    }
                }
            };
        } else {
            return {
                check: {
                    enable: true,
                    nocheckInherit: false
                },
                data: {
                    simpleData: {
                        enable: true
                    }

                }
            };
        }
    }

    $.fn.selectTree = function (options) {
        var select = new SelectTree(this, options);
        return select;
    };
})(jQuery);

样式 selecttree.css

.input-group .dropdown {
    display: table-cell;
}
.selecttree {
    padding-left: 0;
    padding-right: 0;
    border: solid 1px #ccc;
}
.ztree * {
    font-size:1em;
}
.dropdown {
    display: inline-block;
}
.atct .dropdown {
    max-width: 530px;
}
.atct .dropdown button:first-child {
    overflow: hidden;
    text-overflow: ellipsis;
    -o-text-overflow: ellipsis;
    white-space: nowrap;
    width: 490px;
    display: block;
}
.dropdown-menu {
    padding: 0;
}
.panel-footer {
    width: 100%;
    padding: 0;
}
.selecttree ul.ztree {
    max-height: 200px;
    overflow-y: auto;
    overflow-x: auto;
}

.btn {
    border: 1px solid #e6e6e6;
}

我们,平凡的如一粒沙,普通的像一颗草。迎着太阳,倔强生长;跟随大风,独自飘零。尽管生活差强人意,尽管人生一路风雨,我们也要一心一意做好自己。即使不完美,也是最美。美好一天从“做好自己”开始!