自我救赎之路—(js自己封装组件)

由来

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

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

示例: 封装select_tree.js

  1. 效果图:
    自我救赎之路—(js自己封装组件)_第1张图片

  2. 封装代码缩略图:
    自我救赎之路—(js自己封装组件)_第2张图片

  3. html调用

    引入样式: 
    引入脚本:   
    控件:
    
  4. 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();
                    }
                });
  5. 后台数据

    @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);
    立即执行的函数
    
  2. 创建模块内容

    模块就是实现特定功能的一组方法。

    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" }
    
  2. prototype 属性的用法和含义:

    prototype 属性使您有能力向对象添加属性和方法
    
    例如:
    SelectTree.prototype.initDom = function ()
    SelectTree.prototype.setCheckNode = function ()
    .......................................
    
  3. $.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 = "
"
; 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; }

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

共同学习,共同进步,技术交流群:

自我救赎之路—(js自己封装组件)_第3张图片

华北IT技术交流群

你可能感兴趣的:(JavaScript)