常听人说不喜欢javascript。然而我一个一直用C#做后端的人,最喜欢的编程语言就是javascript了,我接收它的优点,也接收它的缺点!

前段时间接触过easyui,用过里面的DataGrid和Combobox等控件,感觉DataGrid的确减少了一些重复的工作,但是easyui改变原有的Element,比如textbox,不能用$("#id").val()获取值了,只能用$(“#id”).textbox('getValue')来获取,不喜欢这样。国庆放假,票到3号了,今天有时间就根据使用easyui的感觉写了两个数据控件DataGrid和Select。

先看看最后结果和前段代码:

HTML:

文章类型:
<div class="input-control select">
    <select id="type" data-url="/home/TypeList"></select>
</div>

<div class="input-control text" style="width:300px;">
    <input type="text" placeholder="请输入关键字" id="keyword" />
    <button class="button" onclick="search()"><span class="mif-search"></span></button>
</div>

<table id="tblist" class="table border bordered" data-url="/home/PageData">
    <thead>
        <tr>
            <th data-field="$index"></th>
            <th data-field="ID">编号</th>
            <th data-field="Title">标题</th>
            <th data-field="Type" data-url="/home/TypeList">类型</th>
            <th data-field="Author">作者</th>
            <th data-field="AddTime">添加时间</th>
            <th data-field="_operator" data-formatter="operateFormatter">操作</th>
        </tr>
    </thead>
</table>

JavaScript:

    <script src="~/Scripts/jquery.min.js"></script>
    <script src="~/js/data-widget.js"></script>
    <script>
        var dg = new dw.DataGrid($('#tblist'));
        var type = new dw.Select($("#type"));
        function search() {
            dg.search({ keyword: $("#keyword").val(), type: $("#type").val() });
        }
        function operateFormatter(value, item) {
            return '<a href="##" onclick="alert(' + item.ID + ')">修改</a>';
        }
    </script>

 


Select数据控件:

id为type的select元素上有个data-url的属性,这个表示加载数据的地址,这个地址必须返回一个拥有ID和Name属性的对象数组的json格式,如下:

[{ID: 1, Name: "类型1"}, {ID: 2, Name: "类型2"}, {ID: 3, Name: "类型3"}, {ID: 4, Name: "类型4"},…]

在实例化dw.Select对象的时候,第一个参数是select元素的jquery对象,上面用$('type')得到,第二个是可选参数,说明如下:

{
    value: undefined,      // 加载过数据选中的值
    onInit: undefined,     // 初始化完成后执行的函数,用加载的数据作为参数
    hasDefault: true,      // 是否有默认选项
    defaultName: '请选择',  // 默认选项显示名
    defaultID: ''          // 默认选项值
}

DataGrid数据控件:

id为tblist的table元素可有三个自定义属性:

  • data-url : 要加载数据的后台地址;
  • data-page-size : 每页显示多少条数据,默认是10,会作为查询参数的pageSize;
  • data-page-index : 加载时显示第几页,默认是1,会作为查询参数的pageIndex(可能永远也用不到,感觉默认值1很合理......);

data-url后台地址返回的格式应该如下:

{
    PageCount :  100  //总页数 --int,
    PageIndex :  1    //当前页 --int,
    List : [
         {ID:1,  Title : '标题1'  ,AddTime : "/Date(1332919782070)/" },
         ......
    ]                // 分页数据列表---Array
}

在实例化dw.DataGrid对象的时候,第一个参数是table元素的jquery对象,上面用$('tblist')得到,第二个是查询参数,可选。

在thead里定义表头,每个th表示一列,th可有四个自定义属性:

  • data-field:返回数据列表的对象属性名,必须;
  • data-formatter : 该列的格式化器,用于修改这列数据的显示形式,比如性别是bool,可以显示成“男”或“女”,比如上面例子中_operator列,虽然不对应任何字段,但是可以显示自定义的内容
  • data-format : 目前用于日期格式(“/Date(1332919782070)/”)的字符串(注意是字符串类型,但是是日期格式),默认值是:“yyyy-MM-dd hh:mm”
  • data-url : 用于从ID映射成对应的Name,比如文章列表的文章类型Type返回的是类型ID,可以提供这个url返回数据,控件自动映射成类型名称,从html大号字的两个地方可以看出,地址和Select的data-url是一样的。

DataGrid对象有个search方法,参数是查询参数,用法如上。

注:加红的“查询参数”是指同一个东西,这个参数会加上pageIndex和pageSize一起post到table的data-url地址来查询数据。我用asp.net mvc做的例子中的后台Action方法签名如下:

, )

注:Select的data-url和Type列的data-url相同,在内部是有缓存的,所以加载这部分数据的时候用的是同步ajax,从加载效果可以看出只加载了一次,缓存生效了:

data-widget.js依赖jQuery;

data-widget.js源码如下:

;/*
file:        data-widget.js
author:      loogn
date :       2016-10-1
descript:    DataGrid、Select、Pager
*/

var dw = (function () {
    var dw = {};

    //根据url缓存 ,没有的话要同步获取
    dw.cache = {};
    dw.getCache = function (url) {
        var key = url.toLowerCase();
        var data = dw.cache[key];
        if (data) return data;
        $.ajax({
            url: url,
            type: 'POST',
            async: false,
            success: function (result) {
                dw.cache[key] = result;
                data = result;
            }
        });
        return data;
    }

    var styleArr = [];
    //pager.css
    styleArr.push('table .page a{ text-decoration:none; font-weight:normal;}');
    styleArr.push('table .page span{ text-decoration:none; font-weight:normal;}');
    styleArr.push('table .page a:hover{ text-decoration:none;}');
    styleArr.push('table .page{padding: 15px 20px;text-align: left;color: #ccc;}');
    styleArr.push('table .page a{display: inline-block;color: #428bca;display: inline-block;height: 25px;    line-height: 25px;    padding: 0 10px;border: 1px solid #ddd;    margin: 0 2px;border-radius: 4px;vertical-align: middle;}');
    styleArr.push('table .page span.current{display: inline-block;height: 25px;line-height: 25px;padding: 0 10px;margin: 0 2px;color: #fff;background-color: #428bca;    border: 1px solid #428bca;border-radius: 4px;vertical-align: middle;}');
    styleArr.push('table .page a:hover{text-decoration: none;border: 1px solid #428bca;}');
    styleArr.push('table .page span.disabled{    display: inline-block;height: 25px;line-height: 25px;padding: 0 10px;margin: 0 2px;    color: #bfbfbf;background: #f2f2f2;border: 1px solid #bfbfbf;border-radius: 4px;vertical-align: middle;}');

    var style = $('<style>').text(styleArr.join(''));
    $('head').append(style);

    //dateFormat(new Date(),'yyyy-MM-dd hh:mm:ss')
    dw.dateFormat = function (date, format) {
        var o = {
            "M+": date.getMonth() + 1, //month
            "d+": date.getDate(), //day
            "h+": date.getHours(), //hour
            "m+": date.getMinutes(), //minute
            "s+": date.getSeconds(), //second
            "q+": Math.floor((date.getMonth() + 3) / 3), //quarter
            "S": date.getMilliseconds() //millisecond
        }
        if (/(y+)/.test(format)) {
            format = format.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
        }
        for (var k in o) {
            if (new RegExp("(" + k + ")").test(format)) {
                format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
            }
        }
        return format;
    }

    //得到指定url参数
    dw.getQueryString = function (name) {
        var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", 'i');
        var r = window.location.search.substr(1).match(reg);
        if (r !== null)
            return unescape(decodeURIComponent(r[2]));
        return null;
    };

    //得到所有url参数对象
    dw.getQueryObject = function () {
        var args = {};
        var query = location.search.substring(1);
        var pairs = query.split("&");
        for (var i = 0; i < pairs.length; i++) {
            var pos = pairs[i].indexOf('=');
            if (pos == -1) continue;
            var name = pairs[i].substring(0, pos);
            var value = pairs[i].substring(pos + 1);
            value = decodeURIComponent(value);
            args[name.toLowerCase()] = value;
        }
        return args;
    };

    return dw;
}());

(function (dwName, dw) {
    function Pager($wrap, pageCount, current, onPageChange) {

        this.$wrap = $wrap;
        this.pageCount = pageCount;
        this.current = current || 1;
        this.onPageChange = onPageChange || function () { };
        this.bindEvent();
        this.render(pageCount, current);

    }

    Pager.prototype.render = function (pageCount, current) {

        this.pageCount = pageCount;
        this.current = current;
        if (pageCount <= 1) {
            this.$wrap.empty();
            return;
        }

        //上一页
        var htmlArr = [];
        if (current > 1) {
            htmlArr.push('<a href="javascript:;" class="prevPage">上一页</a>');
        } else {

            htmlArr.push('<span class="disabled">上一页</span>');
        }
        //中间页码
        if (current != 1 && current >= 4 && pageCount != 4) {
            htmlArr.push('<a href="javascript:;" class="tcdNumber">' + 1 + '</a>');
        }
        if (current - 2 > 2 && current <= pageCount && pageCount > 5) {
            htmlArr.push('<span>...</span>');
        }
        var start = current - 2, end = current + 2;
        if ((start > 1 && current < 4) || current == 1) {
            end++;
        }
        if (current > pageCount - 4 && current >= pageCount) {
            start--;
        }
        for (; start <= end; start++) {
            if (start <= pageCount && start >= 1) {
                if (start != current) {
                    htmlArr.push('<a href="javascript:;" class="tcdNumber">' + start + '</a>');
                } else {
                    htmlArr.push('<span class="current">' + start + '</span>');
                }
            }
        }
        if (current + 2 < pageCount - 1 && current >= 1 && pageCount > 5) {
            htmlArr.push('<span>...</span>');
        }
        if (current != pageCount && current < pageCount - 2 && pageCount != 4) {
            htmlArr.push('<a href="javascript:;" class="tcdNumber">' + pageCount + '</a>');
        }
        //下一页
        if (current < pageCount) {
            htmlArr.push('<a href="javascript:;" class="nextPage">下一页</a>');
        } else {
            this.$wrap.remove('.nextPage');
            htmlArr.push('<span class="disabled">下一页</span>');
        }
        //修改表现
        this.$wrap.html(htmlArr.join(''));
    }

    Pager.prototype.bindEvent = function () {
        var pager = this;
        this.$wrap.on("click", "a.tcdNumber", function () {
            var current = parseInt($(this).text());
            pager.render(pager.pageCount, current);
            if (typeof (pager.onPageChange) == "function") {
                pager.onPageChange(current);
            }
        });
        //上一页
        this.$wrap.on("click", "a.prevPage", function () {
            var current = parseInt(pager.$wrap.children("span.current").text());
            pager.render(pager.pageCount, current - 1);
            if (typeof (pager.onPageChange) == "function") {
                pager.onPageChange(current);
            }
        });
        //下一页
        this.$wrap.on("click", "a.nextPage", function () {
            var current = parseInt(pager.$wrap.children("span.current").text());
            pager.render(pager.pageCount, current + 1);
            if (typeof (pager.onPageChange) == "function") {
                pager.onPageChange(current);
            }
        });
    }

    dw.Pager = Pager;
}('Pager', dw));

(function (dwName, dw) {

    function DataGrid($table, params) {
        this.name = dwName;
        this.$table = $table;         //表格对象
        this.url = $table.data('url');       //加载数据的url
        this.pageSize = $table.data('page-size') || 10;  // 每页大小
        this.pageIndex = $table.data('page-index') || 1; //当前页码
        this.columns = []; //列数据
        this.params = {}; //查询参数
        this.pager = null;//分页控件
        this.isSearch = false;
        var $this = this;

        $table.find('thead>tr>th').each(function () {
            var $th = $(this);
            var field = $th.data('field');
            if (field == "$index") {
                if (!$th.attr("style") || $th.attr("style").indexOf("width") < 0) {
                    $th.css("width", "20px");
                }
            }
            $this.columns.push({ field: field, formatter: $th.data('formatter'), format: $th.data('format'), url: $th.data('url') });
        });
        //分页
        $table.append('<tfoot><tr><td colspan="' + this.columns.length + '" class="page"></td></tr></tfoot>');
        this.load(params);
    }

    //加载数据
    DataGrid.prototype.load = function (params) {
        params = params || {};
        this.params = params;
        params.pageIndex = this.pageIndex;
        params.pageSize = this.pageSize;
        var $this = this;
        $.post(this.url, params, function (data) {
            $this.render(data);
        });
    };
    DataGrid.prototype.search = function (params) {
        this.pageIndex = 1;
        this.isSearch = true;
        this.load(params);
    }

    DataGrid.prototype.render = function (data) {
        var $datagrid = this;

        var html_arr = [];
        html_arr.push('<tbody>');

        for (var i = 0; i < data.List.length; i++) {
            var item = data.List[i];
            html_arr.push('<tr>');

            for (var j = 0; j < $datagrid.columns.length; j++) {
                var column = this.columns[j];
                html_arr.push('<td>');
                if (column.field == "$index") {
                    html_arr.push(this.pageSize * (this.pageIndex - 1) + i + 1);
                } else {
                    var renderValue = getRenderValue(item, column);
                    html_arr.push(renderValue);
                }
                html_arr.push('</td>');
            }
            html_arr.push('</tr>');
        }
        html_arr.push('</tbody>');
        var tbody = $datagrid.$table.find('tbody');
        if (tbody.length > 0) {
            tbody.replaceWith(html_arr.join(''));
            if (this.isSearch) {
                $datagrid.pager.render(data.PageCount, data.PageIndex);
                this.isSearch = false;
            }
        } else {
            $datagrid.$table.append(html_arr.join(''));
            //分页

            this.pager = new dw.Pager($datagrid.$table.find('.page'), data.PageCount, data.PageIndex, function (num) {
                $datagrid.pageIndex = num;
                $datagrid.load($datagrid.params);
            })
        }
    };

    function urlMapping(id, list) {
        for (var i = 0; i < list.length; i++) {
            var item = list[i];
            if (id == item.ID) {
                return item.Name;
            }
        }
        return '';
    }

    function getRenderValue(item, column) {
        var val = item[column.field];
        if (column.formatter) {
            return eval(column.formatter + '(val,item)');
        }
        else if (column.url) {
            var list = dw.getCache(column.url);
            return urlMapping(val, list);
        }
        else {
            if (typeof (val) === "string") {
                if (/Date\([\d+]+\)/.test(val)) {
                    var date = eval(val.replace(/\/Date\((\d+)\)\//gi, "new Date($1)"));
                    val = dw.dateFormat(date, column.format || 'yyyy-MM-dd hh:mm');
                    return val;
                }
            }
            return val;
        }
    }

    dw.DataGrid = DataGrid;

}('DataGrid', dw));

(function (dwName, dw) {
    function Select($select, params) {
        this.name = dwName;
        var args = $.extend({
            value: undefined,
            onInit: undefined,
            hasDefault: true,
            defaultName: '请选择',
            defaultID: ''
        }, params);

        this.$select = $select;
        var url = $select.data('url');

        var list = dw.getCache(url);
        fillSelect(list);

        //[{ID:id,Name:name}]
        function fillSelect(list) {
            var htmlArr = [];
            if (args.hasDefault) {
                htmlArr.push('<option value="' + args.defaultID + '">' + args.defaultName + '</option>');
            }
            for (var i = 0; i < list.length; i++) {
                var item = list[i];
                htmlArr.push('<option value="' + item.ID + '">' + item.Name + '</option>');
            }
            $select.html(htmlArr.join(''));
            if (args.value !== undefined) {
                $select.val(args.value);
            }
            if (args.onInit && typeof (args.onInit) === "function") {
                args.onInit(list);
            }
        }
    }

    dw.Select = Select;
}('Select', dw));

data-widget.js

用于后台管理的列表数据控件:DataGrid和Select的更多相关文章

  1. VS2010/MFC编程入门之二十九(常用控件:列表视图控件List Control 下)

    上一节是关于列表视图控件List Control的上半部分,简单介绍了列表视图控件,其通知消息的处理和有关结构体的定义.本节继续讲解下半部分,包括列表视图控件的创建.CListCtrl类的主要成员函数 ...

  2. MFC常用控件之列表视图控件(List Control)

    近期学习了鸡啄米大神的博客,对其中的一些知识点做了一些自己的总结.不过,博客内容大部分来自鸡啄米.因此,这个博客算是转载博客,只是加了一些我自己的理解而已.若想学习鸡啄米大神的博客总结,请点击连接:h ...

  3. VS2010-MFC(常用控件:列表视图控件List Control 下)

    转自:http://www.jizhuomi.com/software/197.html 上一节是关于列表视图控件List Control的上半部分,简单介绍了列表视图控件,其通知消息的处理和有关结构 ...

  4. ASP.NET Web数据控件

    ASP.NET Web数据控件 1.数据控件简介 这包括数据源控件和格式设置控件,前者使您可以使用 Web 控件访问数据库中的数据,后者使您可以显示和操作ASP.NET 网页上的数据.  2.数据控件 ...

  5. 用于列出选项的Windows窗体控件

    可以提供选项列表的控件有ListBox.ComboBox.CheckedListBox,如何正确的使用和选择这些控件,下面对此进行讨论.首先对这三种控件的功能分别进行说明: ListBox ListB ...

  6. ASP.NET数据控件

    数据服务器控件就是能够显示数据的控件,与那些简单格式的列表控件不同,这些控件不但提供显示数据的丰富界面(可以显示多行多列数据并根据用户定义来显示),还提供了修改.删除和插入数据的接口. ASP.NET ...

  7. 浅析五大ASP.NET数据控件

    转自:http://kb.cnblogs.com/page/69207/ 摘要:ASP.NET中有不少的控件,在这当中有一部分是用来处理数据的控件.在这里我们正要讨论的就是ASP.NET数据控件,希望 ...

  8. VS2010/MFC编程入门之二十八(常用控件:列表视图控件List Control 上)

    前面一节中,鸡啄米讲了图片控件Picture Control,本节为大家详解列表视图控件List Control的使用.      列表视图控件简介 列表视图控件List Control同样比较常见, ...

  9. Jquery如何序列化form表单数据为JSON对象 C# ADO.NET中设置Like模糊查询的参数 从客户端出现小于等于公式符号引发检测到有潜在危险的Request.Form 值 jquery调用iframe里面的方法 Js根据Ip地址自动判断是哪个城市 【我们一起写框架】MVVM的WPF框架(三)—数据控件 设计模式之简单工厂模式(C#语言描述)

    jquery提供的serialize方法能够实现. $("#searchForm").serialize();但是,观察输出的信息,发现serialize()方法做的是将表单中的数 ...

随机推荐

  1. MySQL操作使用

    这只是一些简单的数据库命令,作为新手记录一下,以供后面查询使用. 查询服务器版本号和当前日期: select version(), current_date; 一个命令通常用一个SQL语句组成,后面跟 ...

  2. 剑指Offer面试题:5.重建二叉树

    一.题目:重建二叉树 题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序 ...

  3. 跟我一起数据挖掘(22)——spark入门

    Spark简介 Spark是UC Berkeley AMP lab所开源的类Hadoop MapReduce的通用的并行,Spark,拥有Hadoop MapReduce所具有的优点:但不同于MapR ...

  4. 《Entity Framework 6 Recipes》中文翻译系列 (46) ------ 第八章 POCO之领域对象测试和仓储测试

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 8-8  测试领域对象 问题 你想为领域对象创建单元测试. 这主要用于,测试特定的数 ...

  5. 体验了微信小程序,发现安卓用户终于把果粉“碾压”了一次

    今天早上,张小龙在微信公开课上分享了小程序的理念,并且公布了小程序将于1月9日上线. 为了体现张小龙对未来程序形态的理解,小程序有四个特定:无需安装.触手可及.用完即走.无需卸载.今天,36氪刚好有机 ...

  6. 学习RBAC 用户·角色·权限·表

  7. 如何用注解简化SSH框架

    一.简化代码第一步,删除映射文件,给实体类加上注解 @Entity //声明当前类为hibernate映射到数据库中的实体类 @Table(name="news") //声明tab ...

  8. 我的SQL总结---未完待续

    我的SQL总结---未完待续 版权声明:本文为博主原创文章,未经博主允许不得转载. 总结: 主要的SQL 语句: 数据操作(select, insert, delete, update) 访问控制(g ...

  9. slave IO流程之二:注册slave请求和dump请求

    slave IO流程已经在http://www.cnblogs.com/onlyac/p/5815566.html中有介绍 这次我们要探索注册slave请求和dump请求的报文格式和主要流程. 一.注 ...

  10. 小谈Java里的线程

    今天,我们来谈一谈Java里的线程. 一.进程与线程的基本概念 大家可能没听过线程这个概念,但是相信,用计算机的朋友都听过进程这个概念.打开电脑的任务管理器,我们就可以看到许多进程.它们主要分为三类, ...