【jquery模仿net控件】简单的dropdownlist与datalist

各位大哥晚上好,好久不见。小弟实习了三个月了,由.net转成了java,工作期间正在努力学习。

但是有一点非常痛苦,我不止一次听到一个声音,”.net真的很简单,我原来也学过。直接拖就是了......“

啊!!!感觉好没有技术含量啊!莫法,小弟技术不行,无力辩驳什么。

并且就技术层次本身来说,不论我确实还有很多路要走,就不多说了。

起因


 

我们最近在做一个项目,其中核心模块需要用到类似于igoogle中那种小工具的功能,当时经过众人商议,

最后决定用jquery写控件。

控件!!!好机会啊!我发现项目需要的功能和.net中的datalist真的非常像,于是很想插进去.......

但是,我那浅薄的水平,以及我那悲剧的实习生头衔,在其他同事面前确实不大说得上话。

最后眼睁睁看着别人写了1more js代码,然后让我去读。

呵呵,不是那个前辈代码写的不好,相反我在他的代码中学了很多东西,当然是带着极其抵触的情绪在努力的看!

总觉得这也不好,那也不好,甚至有时候在抠人家命名规范的问题,总是想推翻一点加上自己的思路......

说到这里,我深刻的感觉团队合作,团队交流,团队协作真的很重要!

 你有一个想法,你要如何表达自己的思路,如何写出代码,如何让别人接受你的想法,接受你的代码,

甚至让别人帮助你充实你的想法,真的是一门大学问!

你若是做了一个东西,确实不错,但是你不表现的谦虚,其他同事必定不会买账,根本不会认同你的想法。

而且,一个你觉得很好的点子,在人家的分析后,肯定会发现很多问题,那就要看你如何获得人家的认同与帮助了!

 

项目过程


 

就那前辈的代码,我其实发现了一些问题,项目过程中他的代码也确实遇到了一点问题,主要原因就是代码除他之外,没人想去动。

然后站在设计模式的高度来看,他的代码可维护性,可扩展性有点问题,当然我设计模式看了一次也忘得车不多了。

最后在学习前辈的代码,再加上.net控件思路的高度,我自己花了点时间写了两个控件模拟.net中的dropdownlist与datalist。

再次交出代码,抛砖引玉,请各位大哥弄点更好的东西出来吧!!!

因为我也是才学js,代码写的不好,请各位大哥提点下吧!

Dropdownlist


 

一、效果图()

因为这个控件是练手的,我需要的是datalist,所以就算起一个探索作用,没有写太多。

其功能就算想模拟.net中的控件,根据不同数据源,生成不同的代码。

最主要是想把事件控制权交出来,让使用这个控件的人不用去关注控件本身,(这也是前辈的主要问题)

二、简单代码

 核心代码:

 

var item = function (value, text) {
    this.attribute = {
        id: '',
        value: value ? value : '',
        text: text ? text : '',
        title: '',
        selected: ''
    };
    this.htmlElement = null;
    this.callBack = {
        onClick: null
    };
}

item.prototype.bindEvent = function () {
    var sender = this;
    //    alert(sender.dataSource);
    var element = sender.htmlElement;
    if (sender.callBack.onClick) {
        element.unbind("click");
        element.bind("click", function () {
            sender.callBack.onClick.call(sender);
        });
    }
}

var dropDownList = function (id) {
    this.attribute = {
        id: id
    };
    this.style = {
        width: '',
        height: ''
    };
    this.callBack = {
        onSelectedChanged: null,
        onClick:null
    };
    this.htmlElement = null;
    this.items = [];
    this.selectedValue = '';
    this.selectedItem = {};
    this.dataSourceType = '';
    this.dataSource = {}; //应该支持不同数据源
    this.dataTextField = '';
    this.dataValueField = '';
    this.dataTitleField = '';
}

dropDownList.prototype.bindEvent = function () {
    var sender = this;
    //    alert(sender.dataSource);
    var element = sender.htmlElement;
    if (sender.callBack.onSelectedChanged) {
        element.unbind("change");
        element.bind("change", function () {
            sender.callBack.onSelectedChanged.call(sender);
        });
    }
    if (sender.callBack.onClick) {
        element.unbind("click");
        element.bind("click", function () {
            sender.callBack.onClick.call(sender);
        });
    }
}
dropDownList.prototype.dataBind = function (element) {
    var sender = this;
    sender.htmlElement = $('<select id="' + sender["attribute"]["id"] + '"></select>');

    $.each(sender.dataSource, function (itemKey, itemValue) {
        //        alert(itemKey + ":" + itemValue);
        var _item = new item();
        _item["attribute"]['value'] = itemValue[sender['dataValueField']];
        _item["attribute"]['text'] = itemValue[sender['dataTextField']];
        _item["attribute"]['title'] = itemValue[sender['dataTitleField']];
        sender.items.push(_item);
        sender.insertItem(_item);
    });
    //呈现前,样式加载
    sender.styleLoad();
    element.append(sender.htmlElement);
}

dropDownList.prototype.styleLoad = function () {
    var sender = this;
    var element = sender.htmlElement;
    $.each(sender["style"], function (styleKey, styleValue) {
        //        alert(styleKey + ":" + styleValue);
        if (styleValue) {
            element.css(styleKey, styleValue);
        }
    });
}

dropDownList.prototype.insertItem = function (optionItem) {
    var sender = this;
    var element = sender.htmlElement;
    var itemSender = optionItem;
    //    alert(element["id"]);
    var option = $('<option></option>');
    var optrinAtrribute = optionItem["attribute"];
    var id = optrinAtrribute["id"];
    var value = optrinAtrribute["value"];
    var text = optrinAtrribute["text"];
    var title = optrinAtrribute["title"];
    var selected = optrinAtrribute["selected"];
    if (id && id.length > 0) {
        option.attr("id", id);
    }
    if (value && value.length > 0) {
        option.attr("value", value);
    }
    if (title && title.length > 0) {
        option.attr("title", title);
    }
    if (selected && selected.length > 0) {
        option.attr("selected", selected);
    }
    if (text && text.length > 0) {
        option.text(text);
    }
    itemSender.htmlElement = option;
    element.append(option);
}

  

前端调用:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script src="scripts/jquery-1.4.1.js" type="text/javascript"></script>
    <script src="js/dropDownList.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            var data = [];
            for (var i = 0; i < 3; i++) {
                data[i] = {};
                data[i]["v"] = "value_" + i.toString();
                data[i]["t"] = "text_" + i.toString();
            }

            var $div = $("#divwl");
            var drop1 = new dropDownList("drop1");

            drop1.dataSource = data;
            drop1.dataValueField = "v";
            drop1.dataTextField = "t";
            drop1.dataTitleField = "v";
            drop1.dataBind($div);

            for (var i = 0; i < 3; i++) {
                var v = "inertValue_" + i;
                var t = "insertText_" + i;
                var _item = new item(v, t);
                drop1.insertItem(_item);
            }
            drop1.style.width = '300px';
            drop1.style.height = '50px';
            drop1.style.background = 'green';
            drop1.styleLoad();
            var funClick = function () {
                var dropSender = this.htmlElement;
                var selectedValue = dropSender.val()
                var $div = $("#text");
                $div.html(selectedValue);
            };
            var funChange = function () {
                var dropSender = this.htmlElement;
                var selectedValue = dropSender.val()
                alert(selectedValue);
            };

            drop1.items[1].callBack.onClick = funClick;
            drop1.items[1].bindEvent();

            drop1.callBack.onSelectedChanged = funChange;
            drop1.bindEvent();

        });
      
    </script>
</head>
<body>
    <div id="divwl">
    </div>
    <div id="text"> </div>
    
</body>
</html>

  

 

Datalist


 

 好了,开始进入本文重点,这也是项目真正需要的,这个版本没有完全完成,在得到大家意见后再改吧!

 一、效果图:

 所用数据源:

二、思路

 原来也读过.net 控件开发一书,对控件开发知识有个大概了解,所以做起来时候还是比较顺手。

① datalist首先提供了一个公共的模板,就是itemtemplate中可以写任何代码包括数据绑定代码,

然后依次循环调用,所以我觉得这个控件需要一个模板保存类似于.net中的html代码,以及数据绑定代码。

当然,我们不可能写在js代码中,于是出现了一下模板文件:

itemTemplate.spt:

<table>
  <tr>
    <td>
      新闻ID
    </td>
    <td>
      {%newsId%}
    </td>
  </tr>
  <tr  >
    <td >
      新闻标题
    </td>
    <td>
      {%newsName%}
    </td>
  </tr>
  <tr  >
    <td>
      新闻摘要
    </td>
    <td>
      <input  id="contentMore" value="详情" type="button"/>
    </td>
  </tr>
  <tr  >
    <td colspan="2" style=" display:none;" class="content">
      {%newsContent%}
    </td>
  </tr>
</table>
<hr/>

  {%newsName%} 是模拟Eval("")的写法,后期作为数据绑定使用

② 然后每次循环生成具体的模板js代码如下:itemTemplate.js

/// <reference path="../scripts/jquery-1.4.1.js" />

var itemTemplate = function () {
    //源模板文本,现在为itemTemplate.spt
    //可能是文本,可能是js文件,可能是字符串
    //最终形成字符串传给htmlTemplateText
    this.htmlTemplateText = "";
    //最终会形成一独立html字符串,dom结构的标签
    this.htmlElement = null;
    this.idPrefix = "id_"; //id前缀
    this.parentId = "";
    this.id = "";
    this.event = {
        onClick: null,
        onMousemove: null
    };
    //将要执行
    //    this.evetElementSource = {};
    this.elementEvent = null;
};
itemTemplate.prototype.getItemElement = function (elementKey) {
    var sender = this;
    var id = "#" + sender.id + " " + elementKey;
    var element = $(id);
    return element;
}
//elementKey #id、 .className、 htmlElement
itemTemplate.prototype.bindElementEvent = function (elementKey, eventType, funcName) {
    var sender = this;
    var id = "#" + sender.id + " " + elementKey;
    var element = $(id);

    if (funcName) {
        element.unbind(eventType);
        element.bind(eventType, function () {
            funcName.call(sender);
        });
    }
}

//elementKey #id、 .className、 htmlElement
itemTemplate.prototype.bindAllElementEvent = function () {
    var sender = this;
    var itemElementEvents = sender.elementEvent;
    //    alert(element+"=="+id);
    //数据项元素事件绑定
    $.each(itemElementEvents, function (eventObjKey, eventObj) {
        var elementKey = eventObj.elementKey;
        var eventType = eventObj.eventType;
        var funcName = eventObj.funcName;
        sender.bindElementEvent(elementKey, eventType, funcName);
    });
}

itemTemplate.prototype.bindEvent = function () {
    var sender = this;
    var element = sender.htmlElement;
    var events = sender.event;
    $.each(events, function (eventKey, funcName) {
        //        alert(funcKey + "---" + funcValue);
        if (funcName) {
            var _event = eventKey;
            _event = _event.substring(2, _event.length);
            _event = _event.toLowerCase();
            element.unbind(_event);
            element.bind(_event, function () {
                funcName.call(sender);
            });
        }
    });
};

itemTemplate.prototype.load = function (itemIndex, itemDataSource) {
    var sender = this;
    var id = sender.parentId + "_" + sender.idPrefix + itemIndex;
    sender.id = id;
    var element = $("<div id='" + id + "'></div>");
    var html = "";
    var _templateText = sender.htmlTemplateText;
    tempHtm = _templateText;
    $.each(itemDataSource, function (i, item) {
        var id = item;
        var regStr = "/\\{%" + i + "%\\}/g";
        var reg = eval(regStr);
        tempHtm = tempHtm.replace(reg, item);
    });
    html = tempHtm;
    element.append($(html))
    sender.htmlElement = element;
    sender.bindEvent();

};

  

 技术细节便不说了,其主要采用正则表达式方式替换相应内容,所以完全根据我们提供的数据源而定:

③ 外层datalist代码:dataList.js

/// <reference path="../scripts/jquery-1.4.1.js" />

/*
思考:
1 如何给数据项某个html标签添加事件
因为我们并不知道生成的dom树是什么,所以模板里面的html标签无法绑定事件,暂时只能后期绑定

*/
/* 控件生成流程

*/

var dataList = function (id, templateUrl) {
    this.attribute = {
        id: id
    };
    this.style = {
        width: "",
        height: ""
    };
    this.itemEvent = {
        onClick: null,
        onDblclick: null,
        onKeydown: null,
        onKeypress: null,
        onKeyup: null,
        onMousedown: null,
        onMousemove: null,
        onMouseout: null,
        onMouseover: null,
        onMouseup: null
    };
    this.itemElementEvent = {};
    //    this.itemElementEvent = {
    //        one: {
    //            elementKey: "",
    //            eventType: "",
    //            funcName: null
    //        }
    //    };

    this.htmlElement = null;
    this.templateUrl = templateUrl ? templateUrl : ""; //提供项目模板地址
    this.htmlTemplateText = "";
    this.items = [];
    this.dataSource = {}; //应该支持不同数据源
};

dataList.prototype.init = function () {
    var sender = this;
    var templateUrl = sender.templateUrl;
    if (!templateUrl || templateUrl.length == 0)
        templateUrl = "itemTemplate/itemTemplate.spt";
    this.htmlTemplateText = getAjaxStr(templateUrl);
    var htmlElement = $("<div id='" + sender.attribute.id + "'></div>");
    sender.htmlElement = htmlElement;
};

dataList.prototype.dataBind = function (element) {
    this.init();
    var sender = this;
    var templateText = sender.htmlTemplateText;
    var itemEvent = sender.itemEvent;
    var itemElementEvents = sender.itemElementEvent;
    //需要替换itemTemplate
    var itemIndex = 0;
    $.each(sender.dataSource, function (dataKey, dataValue) {
        var _item = new itemTemplate();
        _item.parentId = sender.attribute.id;
        _item.htmlTemplateText = templateText;
        _item.event = itemEvent;
        _item.elementEvent = itemElementEvents;
        //传递父ID ,当前模板编号,源模板,当前项数据项源,事件绑定源
        _item.load(itemIndex, dataValue);
        var _itemElement = _item.htmlElement;
        sender.items.push(_item);
        sender.insertDomItem(_itemElement);
        itemIndex++;
    });
    //呈现前,样式加载
    sender.styleLoad();
    element.append(sender.htmlElement);
    //模板中的html标签的事件绑定
    var items = sender.items;
    $.each(items, function (i, item) {
        item.bindAllElementEvent();
    });
};

dataList.prototype.styleLoad = function () {
    var sender = this;
    var element = sender.htmlElement;
    $.each(sender.style, function (styleKey, styleValue) {
        //                alert(styleKey + ":" + styleValue);
        if (styleValue) {
            //            alert(element);
            element.css(styleKey, styleValue);
        }
    });
}

dataList.prototype.insertDomItem = function (domItem) {
    var sender = this;
    var element = sender.htmlElement;
    element.append(domItem);
};
//dataList.prototype.bindItemEvent = function (domItem) {
//    var sender = this;
//    var element = sender.htmlElement;
//    element.append(domItem);
//};
//dataList.prototype.bindEvent = function () {
//    var sender = this;
//    var element = sender.htmlElement;
//    var events = sender["event"];
//    $.each(events, function (eventKey, funcName) {
//        //        alert(funcKey + "---" + funcValue);
//        if (funcName) {
//            var _event = eventKey;
//            _event = _event.substring(2, _event.length);
//            _event = _event.toLowerCase();
//            element.unbind(_event);
//            element.bind(_event, function () {
//                funcName.call(sender);
//            });
//        }
//    });
//};

//异步获取文件
function getAjaxStr(url) {
    var templateStr = "";
    $.ajax({
        url: url,
        async: false,
        dataType: "html",
        success: function (result) {
            templateStr = result;
            if (templateStr)
                return templateStr;
        },
        error: function (e) {
            alert("模板加载错误:" + e.toString());
        }
    });
    return templateStr;
}

  

③ 前台调用界面代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script src="scripts/jquery-1.4.1.js" type="text/javascript"></script>
    <script src="js/itemTemplate.js" type="text/javascript"></script>
    <script src="js/dataList.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            var dataSource = {};
            $.ajax({
                type: "post",
                url: "Ajax.aspx",
                type: "json",
                async: false,
                success: function (data) {
                    dataSource = data;
                }
            });
            var $divHtml = $("#html");


            var $div = $("#wl");
            var $div1 = $("#wl1");
            var itemElementEvents = {
                contentClick: {
                    elementKey: "#contentMore",
                    eventType: "click",
                    funcName: contentMoreClick
                }
            };

            var list = new dataList("divwl");
            list.itemEvent.onMousemove = itemmousemove;
            list.itemEvent.onMouseout = itemmouseout;

            list.itemElementEvent = itemElementEvents;
            list.style.width = "700px";
            list.dataSource = dataSource;
            list.dataBind($div);



            function contentMoreClick() {
                var sender = this;
                var newsContent = sender.getItemElement(".content");
                var contentMore = sender.getItemElement("#contentMore");
                if (newsContent.css("display") == "none") {
                    contentMore.attr("value", "隐藏");
                    newsContent.css("display", "");
                } else {
                    contentMore.attr("value", "详情");
                    newsContent.css("display", "none");
                }
            }
            function itemmousemove() {
                var sender = this;
                var $ee = sender.htmlElement;
                $ee.css("background", "Gray");
            }
            function itemmouseout() {
                var sender = this;
                var $ee = sender.htmlElement;
                $ee.css("background", "white");
            }

        });
    </script>
</head>
<body>
    <div id="html" style="display: block">
    </div>
    <div id="wl">
    </div>
    <div id="wl1">
    </div>
</body>
</html>

  大概代码如上,看一下调用界面基本知道如何使用的。

在此我有个没有解决的问题,请各位大哥帮下忙:

除模板之中的html dom 结构没有前期事件绑定外,其他生成的dom都是在展现前便绑定事件:

 

 //呈现前,样式加载
    sender.styleLoad();
    element.append(sender.htmlElement);
    //模板中的html标签的事件绑定
    var items = sender.items;
    $.each(items, function (i, item) {
        item.bindAllElementEvent();
    });

  其实这个代码最先是写在itemTemplate.js文件中的,在没有将dom append到页面中,但是因为dom结构没有生成,我无法通过除以上的方法找到

对应html标签,所有无法做事件绑定,这里把我弄模糊了。各位大哥有兴趣看了代码便和我说说吧,代码会跟进。

 

今天又更新了一点代码,有点变化,现在先弄上datalist嵌套的用法,具体的代码后面点看有没有需要弄出来

效果:其实就是新闻类型嵌套一个新闻列表

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script src="scripts/jquery-1.4.1.js" type="text/javascript"></script>
    <script src="js/itemTemplate.js" type="text/javascript"></script>
    <script src="js/dataList.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            var dataItems = {};
            $.ajax({
                type: "post",
                url: "Ajax.aspx?sql=select top 5 * from Item where ItemKind=1 ",
                type: "json",
                async: false,
                success: function (data) {
                    dataItems = data;
                }
            });
            var $div = $("#wl");
            var listItem = new dataList("newsItem", "itemTemplate/items.spt");
            var itemElementEvents = {
                loadItemNews: {
                    elementKey: "#itemNews",
                    eventType: "ready",
                    funcName: elementDatabind
                }
            };
            listItem.itemElementEvent = itemElementEvents;

            listItem.dataSource = dataItems;
            listItem.dataBind($div);

            function elementDatabind() {
                var sender = this;
                var $itemId = sender.getItemElement("#itemId");
                var $itemNews = sender.getItemElement("#itemNews");
                var listItemNews = new dataList("news", "itemTemplate/itemTemplate.spt");
                var _itemElementEvents = {
                    contentClick: {
                        elementKey: "#contentMore",
                        eventType: "click",
                        funcName: contentMoreClick
                    }
                };
                var id = $itemId.html();
                var s = $itemNews.html();
                var dataNews = {};
                $.ajax({
                    type: "post",
                    url: "Ajax.aspx?sql=select top 3  newsId,newsName, newsContent from news where itemId='" + id + "' ",
                    type: "json",
                    async: false,
                    success: function (data) {
                        dataNews = data;
                    }
                });
                listItemNews.itemEvent.onMousemove = itemmousemove;
                listItemNews.itemEvent.onMouseout = itemmouseout;
                listItemNews.itemElementEvent = _itemElementEvents;

                listItemNews.dataSource = dataNews;
                listItemNews.dataBind($itemNews);
            }

            function contentMoreClick() {
                var sender = this;
                var newsContent = sender.getItemElement(".content");
                var contentMore = sender.getItemElement("#contentMore");
                if (newsContent.css("display") == "none") {
                    contentMore.attr("value", "隐藏");
                    newsContent.css("display", "");
                } else {
                    contentMore.attr("value", "详情");
                    newsContent.css("display", "none");
                }
            }
            function itemmousemove() {
                var sender = this;
                var $ee = sender.htmlElement;
                $ee.css("background", "Gray");
            }
            function itemmouseout() {
                var sender = this;
                var $ee = sender.htmlElement;
                $ee.css("background", "white");
            }

        });
    </script>
</head>
<body>
    <div id="wl">
    </div>
</body>
</html>

  

等以后代码完善了,我在整理发出吧。

 

 

 

 

posted on 2012-01-22 02:24  叶小钗  阅读(4272)  评论(7编辑  收藏  举报