jquery插件Asgrid开发小记

      最近做的一个项目中用到EasyUI,在开发起来还是非常方便的,而且文档齐全,看了两天文档,对照官方的例子,基本上都能找到相应的解决方法。但是easyUI的datagrid控件在加载数据过多的时候就会非常慢,特别是在IE上的时候,同事测试的时候500条记录从返回数据给前端到前端显示出来需要10秒左右,对于用的人来说这个等待时间太长了。是不可以接受的。有人会说为什么一定要加载这么多数据呢,可以分页嘛。其实分页每页的显示是可以选择,可以设置每页显示50或500等等。那为什么要显示500条呢,不为什么,因为需要需要显示这么多。

     好关于jquery插件开发可以看上一篇我转载过来的文章,已经非常详细了     :jQuery插件开发指南

     作为这个控件主要是为了替换easyui的datagrid控件太慢的问题。所以主要功能为一下几点:

插件定位

主要是为了解决加载慢的问题

1.尽量保持easyui中datagrid控件api保持一致

2.只做数据显示,去掉编辑功能保持轻量级

 

基本格式

 (function($){

})(jquery);

如果有向我一样js是半吊子的话,可以看看

Javascript中的自执行匿名函数

所谓知其然而知其所以然

插件结构

(function ($) {

    //默认的参数  
    var defaults = {
    //key value的参数  
     }

     $.fn.AsGrid = function (options, param) {
        if (typeof options == 'string') {
            return methods[options](this, param);
        }
        var def = $.extend(defaults, options);
        return this.each(function () {

        });
    }
   //实现的方法 
    var methods = {
     }
}

首先我们定义了默认的参数 defaults ,它将在function (options, param)主入口函数的如下代码中体现出来,将传入的参数和默认参数合并,$.extend()参考  http://www.ostools.net/apidocs/apidoc?api=jquery 

 var def = $.extend(defaults, options);

主函数中的

if (typeof options == 'string') {
            return methods[options](this, param);
        }


表示传入的第一个参数如果是字符串,也就是要实现的方法名,那么就执行methods里面的方法

最后是一个返回

return this.each(function () {

        });

这样形成了一个闭包  ,不太明白的可以看javascript的闭包的形成

为什么这里是this .each 而不是直接返回呢,这个去看看jquery对象是怎么回事。

好这样就形成了基本的插件结构  。 

默认参数

   //默认的参数  
    var defaults = { columns: {},
        method: "post",
        idField: "id",
        singleSelect: false,
        pageNumber: 0,
        pageSize: 10,
        rowStyler: function (index, row) { },
        data: {},
        pagination: true,
        paginationHeight: 30,
        paginationControl: null,
        headHeight: 30,
        width: -1,
        height: -1,
        pageNumber: 1,
        pageSize: 10,
        pageList: [10, 20, 30],
        queryParams: {},
        onLoading: function () { } //在数据加载完成后执行  
    };


      以上是默认参数设置,基本上是参考easyUI的一部分内容 。

创建插件的Dom

  return this.each(function () {
            // 初始化  构建表格对象  
            var tb = $(this);
            var iscreate = tb.closest(".AsGridcs");
            if (iscreate.length == 0) {
                // if (def.IsCreate) {
                //创建是判断是否存在url 
                if (options.url == undefined) {
                    def.url = undefined;
                }
                //创建表头   
                var hd = $("<div class='AsGrid_head' style='height:" + def.headHight + "px'></div>");
                var th = $("<div class='AsGrid_head_move'></div>");

                var tr = "<table><tr>";
                for (var i in def.columns) {
                    var col = def.columns[i];
                    if (col.checkbox) {
                        tr += "<td class='AsGrid_head_col ' style='width:" + col.width + "px'><input id='col_All_" + i + "' type='checkbox' /></td>";
                    }
                    else {
                        if (col.title == undefined)
                            col.title = '';
                        tr += "<td class='AsGrid_head_col' style='width:" + col.width + "px'>" + col.title + "</td>";
                    }
                }
                tr += "</tr></table>";
                th.append(tr);

                hd.append(th);
                //创建主容器 
                var parentdiv = $("<div class='AsGridcs' ></div>");
                var contrentdiv = $("<div class='AsGrid_Content'></div>");

                tb.before(parentdiv).appendTo(parentdiv).before(hd);
                var grid_loading = $("<div class='AsGrid_loading'><div>正在加载,请稍后……</div></div>");
                parentdiv.append(grid_loading);
                var pagination = $("<div  class='AsGrid_pagination'></div>");
                var pa_control = $("<div class='AsGrid_pagination_control'></div>");
                 

                if (!def.singleSelect) {
                    CheckboxClick(tb);
                }
                //设置容器的区域大小

                var w = 20;
                for (var x in def.columns) {
                    var colen = def.columns[x];
                    w += colen.width;
                }

                if (def.width != undefined) {
                    parentdiv.css("width", def.width);
                    contrentdiv.css("width", def.width);
                }
                if (def.height != undefined) {
                    parentdiv.css("height", def.height);
                    contrentdiv.css("height", def.height - def.headHeight - def.paginationHeight - 10);
                }
                contrentdiv.css({ overflow: "auto" });
                hd.css({ "overflow": "hidden", width: def.width, "position": "relative" });
                tb.addClass("AsGrid_Table");
                tb.css("width", w);
                th.css({ "width": 10000, "position": "relative" });
                pagination.css("width", def.paginatinoHeight);
                //设置容器滚动条偏移 
                contrentdiv.scroll(function () {
                    th.css("left", -$(this).scrollLeft());
                    // th.offset({ left: -$(this).scrollLeft() });

                    // th.offset({ left: this.scrollLeft });
                });
                 
                //判断是否存储url 如果存在  直接加载  

            }
            if (def.url != undefined) {
                var v = $.extend({ rows: def.pageSize, page: def.pageNumber }, def.queryParams);
                $(".AsGrid_loading").css({ "display": "block" });
                $.post(def.url, v, function (data) {
                    if (data.rows == undefined) {
                        tb.AsGrid("loadData", data);
                    }
                    else {
                        def.paginationControl.pagination({ total: data.total, pageNumber: def.pageNumber });
                        tb.AsGrid("loadData", data.rows);
                    }
                }, "json");
            }
            tb.data("def", def);
        });

    首先我们获取当前对象,并查看是否有.AsGridcs的div,如果有就根据传入的值没有就开始创建dom,并设置了一些css样式

  var tb = $(this);
  var iscreate = tb.closest(".AsGridcs");
  if (iscreate.length == 0) 
  {//创建dom
  }

 

当传入存在url的时候需要加载数据,这里使用了等一下要说道的 loadData来绑定数据

if (def.url != undefined) {
                var v = $.extend({ rows: def.pageSize, page: def.pageNumber }, def.queryParams);
                $(".AsGrid_loading").css({ "display": "block" });
                $.post(def.url, v, function (data) {
                    if (data.rows == undefined) {
                        tb.AsGrid("loadData", data);
                    }
                    else {
                        def.paginationControl.pagination({ total: data.total, pageNumber: def.pageNumber });
                        tb.AsGrid("loadData", data.rows);
                    }
                }, "json");
            }
            tb.data("def", def);

最主要的一句是最后一句 tb.data(“def”,def);

将所有的数据保存了起来,方便后面调用

实现方法

这里我实现了一个loadData的方法 ,其实就是将数据转换为dom然后插入 。这里将data保存在了def.data中  

 var methods = {
        loadData: function (obj, data) {

            //删除所有节点 并重新加载  
            var def = obj.data("def");
            def.data = data;
            obj.children().empty();
            var a = new Array();
            var j = 0;
            var k = 0;
           //创建数据
            for (var d in data) {
                if (k++ % 2 == 1) {
                    a[j++] = "<tr class='rowColorOdd AsGridRow'>";
                }
                else
                { a[j++] = "<tr class='rowColorEve AsGridRow'>"; }

                for (var i in def.columns) {
                    var col = def.columns[i];
                    if (col.checkbox) {
                        a[j++] = "<td class='AsGrid_content_ckbox' width='" + col.width + "px'><input class='col_All_" + i + "' type='checkbox' /></td>"
                    }
                    else {
                        // if (data[d][col.formatter] == undefined) {
                        var s = "";
                        if (!(data[d][col.field] == null || data[d][col.field] == undefined)) {
                            s = data[d][col.field];
                        }
                        if (col.formatter == undefined) {
                            a[j++] = "<td width='" + col.width + "px'>" + s + "</td>";
                        }
                        else {
                            a[j++] = "<td width='" + col.width + "px'>" + col.formatter(s, data[d], d) + "</td>";
                        }
                    }
                }
                a[j++] = "</tr>";
            }
            $(".AsGrid_loading").css({ "display": "none" });
            obj.append(a.join(''));
            a = null;

            //数据加载完后发生
            def.onLoading();
             //鼠标移动事件
            mouseMove(obj)
            //初始化事件 
            obj.find("tr").click(function () {

                var ev = $(this);
                var classname = ev.attr("class");
                var classlist = classname.split(" ");
                var flag = false;
                for (var o in classlist) {
                    if (classlist[o] == "selectColor") {
                        flag = true;
                        break;
                    }
                }
                if (flag) {
                    unselectRow(ev);
                }
                else {
                    //执行全部取消 
                    if (def.singleSelect) {
                        methods.unselectAll(obj);
                       }
                    selectRow(ev);
                } 

            });

            return obj;
        }
}


最后我们将obj返回,这是为了支持jquery的链式操作 ,其他方法实现起来的方法都大致相同,基本就是获取数据,执行操作 ,返回值。如果方法不需要返回值可以返回自己来支持链式操作,如下根据编号选中行 

 selectRow: function (obj, index) {
            var def = obj.data("def");//获取数据
            selectRow(obj.children('tr').eq(index));//执行操作 
            return obj;//返回值 
        },

 

 

小结

       由于项目前期写了很多代码,要是替换成别的表格控件,很多代码都不可用了,在不需要编辑只有浏览的页面实现一个尽量简洁的控件,找到定位很重要,最开始还想着要让表格支持翻页,最后使用了easyUI里的翻页控件集成了进去。然后加控制联动参数 。

      作为一个js还是个半吊子,前期做个简单的demo来验证想法很重要 ,原理弄清楚后,后面就简单了。现在应该比半吊子进步一点点了。

posted @ 2013-03-22 16:17  张巍的博客  阅读(318)  评论(0编辑  收藏  举报