【jquery仿dataList】应用之——模仿igoogle【定制化、拖动排序,最大化、分屏】
接上一次日志哈,这一次用原来写的datalist实现了简单应用,模拟igoogle。
做的过程中发现代码很多问题,主要是流程上的问题。
主要是自己层次不够,明明已经感到这样那样的问题,都能说出来就是不知道怎么改。主要问题:
1 初始化时候参照其他jquery框架,应该达到配置最小化,却怎么都做不好
2 现在控件必须提供数据源datalist与模板template,数据源还好说,但是模板的写法真的太坑爹,现在是放在数据库里面了
以后怎么做还说不清哦
3 与.net中datalist一致,不论datalist还是item都会生成多余的标签,这里是生成的div,看上去很是别扭
4 最大问题还是,混乱!!!就像这篇文章一样,js控制力不同于服务器语言,所有整个做起来,不论事件绑定
还是其他什么定义都感觉有点混乱,流程不清,这是我主要应该改进的地方。
主要流程:
1 加载小工具模板:现在先一次性加载,以后用到一个保存一个作为全局参数
2 加载该用户的所有小工具:现在先一次性加载,以后先加载第一页,
根据页索引判断加载
3 根据用户小工具数据,初始化所有小工具外框
由于数据以及模板已经取出,此时加载速度应该非常快,左中右一次加载
**此处注意,虽说小工具外框一样,但是新增的小工具可能会在外框加载结束后再修饰外框
比如,weibo、top.....,此数据存于小工具定制列(CustomData)
4 此时进行数据异步加载,
***数据可以统一加载,但是此处先加载所有小工具每列前两名数据
在根据后台用户干预加载那些大数据小工具,加载结束后,当用户滑动鼠标便进行以下
控件加载,每次控件加载数量可配置化
5 所有控件加载结束,已加载结束控件,可能会根据后台配置要求动态刷新数据
此处需要做轮询
6 控件加载结束后,开始做控件事件绑定
***注意粒度尽量小,不要和其他模块相互影响
首页效果图:
此处点击都会触发事件,一个是异步加载选项卡数据,一个是展开摘要:
也可以延后加载,比如:开始只加载前三个模块,鼠标滑动后,再加载后面的模块:
一下是,初始化后鼠标滑动前与鼠标滑动后的效果:
分屏、分页效果
点击上面1,2,3肯定会指向不同也了,其实现在用户是我,若是用户换了也会有所不同
下面是第二页和第三页
拖动排序也实现了,之前想自己写一个拖动插件,拖动时实现了却发现插件非常困难,
局限于自己的层次,就直接用的jquery ui的拖动
下面是拖动排序的展示,保存到数据库的,最后一张是刷新后重新排序的图:
点击最大化,并实现鼠标滚动到最下边重新加载数据(滚动分页嘛):
数据库简要设计,因为我没有安装数据库,所有优点不好弄:
设计缘由:由于今后可能不止五页,做到页数动态化
NO. |
字段名称 |
说明 |
1 |
uuid |
页面唯一标识 |
2 |
pageSort |
页面排序 |
3 |
pageName |
页面标题,默认1,2,3,4,5 |
4 |
pageDes |
页面描述,鼠标划上显示 |
5 |
|
|
小工具模板表 templates(基本字段)
NO. |
字段名称 |
说明 |
1 |
uuid |
页面唯一标识 |
2 |
templateKey |
标识 |
3 |
templateValue |
模板内容 |
4 |
des |
描述 |
5 |
|
|
小工具表 modules(基本字段)
小工具参数化,可变参数,具有验证性
NO. |
字段名称 |
说明 |
1 |
uuid |
小模块唯一标识 |
|
author |
小工具作者 |
2 |
alias |
模块前台标识名,对应category |
3 |
title |
小模块名称 |
4 |
dataSourceUrl |
数据源链接地址 |
5 |
pageId |
当前小工具属于第几屏,对应pages 的 uuid |
6 |
colId |
当前小工具属于第几列(暂分为1,2,3列) |
7 |
sort |
当前小工具顺序 |
8 |
templateId |
当前小工具对应模板,对应templates表 |
9 |
type |
当前小工具类型,frame或者json |
|
|
|
|
|
|
参数化后
NO. |
字段名称 |
说明 |
1 |
uuid |
小模块唯一标识 |
2 |
alias |
模块前台标识名,对应category |
3 |
title |
小模块名称 |
5 |
pageId |
当前小工具属于第几屏,对应pages 的 uuid |
6 |
colId |
当前小工具属于第几列(暂分为1,2,3列) |
7 |
sort |
当前小工具顺序 |
8 |
moduleParameter |
当前小工具具有的参数对象,现在采用json对象 采用键值对,加一个描述字段 {dataSourceUrl:XXXXX ,templateId:XXXX , type:XXX } 以上是基本属性,应该是字段吧….. |
灰色部分可以不用,直接默认在第一页第一排,默认最大 其默认值在用户小工具表中体现出来
|
小工具参数moduleParameter
NO. |
字段名称 |
说明 |
1 |
uuid |
小模块唯一标识 |
2 |
moduleKey |
|
3 |
moduleValue |
|
4 |
des |
|
5 |
isTransfer |
是否形成json传向前台 |
|
|
|
|
用户小工具设置表(用户参数设置)
userModules
NO. |
字段名称 |
说明 |
1 |
uuid |
小模块唯一标识 |
2 |
userId |
用户id |
3 |
moduleId |
小工具Id |
|
userPrefers |
用户偏好设置 |
|
|
|
|
用户小工具参数偏好userModulePre
NO. |
字段名称 |
说明 |
1 |
uuid |
小模块唯一标识 |
2 |
preKey |
|
3 |
preValue |
|
4 |
des |
|
5 |
isTransfer |
是否形成json传向前台 |
|
|
|
|
最终表设计
核心实现代码如下:原来的datalist的代码我就不发了:
/// <reference path="../scripts/jquery-1.4.1.js" /> /// <reference path="dataList.js" /> /// <reference path="itemTemplate.js" /> //全局变量设置 var templateWarehouse = {}; var userModuleData = {}; var leftColModule, centerColModule, rightColModule; //首页模块加载参数 var moduleLoadPara = {}; moduleLoadPara.index = 1; //初始化加载索引 moduleLoadPara.num = 1; //每次索引加载个数 moduleLoadPara.isLoad = false; //当前是否在加载 //--------------------------------------------------------------------------- //第一步,加载模板 function loadTemplate() { $.ajax({ type: "post", url: "../Ajax.aspx?sql=select * from templates ", type: "json", async: false, success: function (data) { $.each(data, function (i, item) { templateWarehouse[item.templateKey] = item.templateValue; }); } }); } //加载所有模板数据 function loadModuleData(isAsync) { var _isAsync = false; if (isAsync) _isAsync = isAsync; var userId = "wl"; $.ajax({ type: "post", url: "../Ajax.aspx?sql=select * from modules m ,userModules um where 1=1 and m.uuid=um.moduleId and um.userId='" + userId + "'", type: "json", async: _isAsync, success: function (data) { userModuleData["1"] = []; userModuleData["2"] = []; userModuleData["3"] = []; userModuleData["4"] = []; userModuleData["5"] = []; $.each(data, function (i, item) { var userPrefs = item.userPrefers; if (typeof (userPrefs) == "string") { userPrefs = eval("(" + userPrefs + ")"); ; } item.userPrefers = userPrefs; userModuleData[userPrefs.pageId].push(item); }); } }); } //--------------------------------------------------------------------------- //根据用户id,按要求加载其模板 function initModuleFrame(_pageId) { var pageId = 1; if (_pageId) pageId = _pageId; var $div = $("#main"); $div.html(""); loadColModule(pageId, "left_conter"); loadColModule(pageId, "cell_conter"); loadColModule(pageId, "right_conter"); } function loadColModule(pageId, colId) { var $div = $("#main"); var colData = getColData(pageId, colId); var colModule = new dataList(colId, "commonFrame"); colModule.itemElementEvent = { _sortItems: { elementKey: ".content", eventType: "ready", funcName: itemSort }, _itemMaxClick: { elementKey: ".btn_close", eventType: "click", funcName: itemMaxClick }, _itemMenuClick: { elementKey: ".btn_more", eventType: "click", funcName: itemMenuClick } }; colModule.className = "column"; colModule.dataSource = colData; colModule.dataBind($div); if (colId == "left_conter") { leftColModule = colModule; } else if (colId == "cell_conter") { centerColModule = colModule; } else if (colId == "right_conter") { rightColModule = colModule; } } function getColData(pageId, colId) { var tempData = []; var data = userModuleData[pageId]; $.each(data, function (i, item) { var userPrefs = item.userPrefers; if (userPrefs.pageId == pageId && userPrefs.colId == colId) { tempData.push(item); } }); tempData = tempData.sort(function (a, b) { if (a.userPrefers.sort < b.userPrefers.sort) { return -1; } if (a.userPrefers.sort > b.userPrefers.sort) { return 1; } return 0; }); return tempData; } //--------------------------------------------------------------------------- function loadItemMax(sender, param, e, isClick) { var dataSourceUrl = param.dataSourceUrl; var templateId = param.templateId + "-max"; var title = param.title; var type = param.type; var id = sender.id; var $max = $("#list-max"); var $main = $("#main"); var $content = $("#list-max #list-max-content"); if (isClick) $content.html(""); var $title = $("#list-max #list-max-title"); var $itemList = $("#list-max .list"); var $listMore = $("#list-max #list-max-more"); var isLoad = $listMore.val(); $listMore.val("-1"); var len = $itemList.length; var _index = len + 1; var itemStr = '<fieldset class="list"><legend><span class="index">page' + _index.toString() + '</span></legend><div id="itemContent' + _index.toString() + '" style=" margin:10px 10px 10px 10px;">数据加载中......</div></fieldset>'; $main.hide(); $max.show(); $title.html(title); if (type && type == "s-html") { var html = '<iframe scrolling="no" style="width:100%;height:200px" frameborder="0" src="' + dataSourceUrl + '"></iframe>'; $content.html(html); } else { $content.append(itemStr); $.ajax({ type: "post", url: dataSourceUrl, type: "json", async: true, success: function (data) { var $itemContent = $("#list-max #itemContent" + _index.toString() + ""); $itemContent.html(""); var dataNews = data; if (typeof (dataNews) == "string") { dataNews = eval("(" + data + ")"); } var listMax = new dataList(id + "_max", templateId); listMax.dataSource = dataNews; listMax.dataBind($itemContent); $listMore.val("1"); } }); } } //小工具事件定义,小工具事件处理函数 function itemMaxClick() { var sender = this; var param = arguments[0]; var e = arguments[1]; loadItemMax(sender, param, e, true); $(document).unbind("scroll"); $(document).bind("scroll", function (e) { var windowHeight = $(window).height(); var windowScrollTop = $(window).scrollTop(); var documentHeight = $(document).height(); var $listMore = $("#list-max #list-max-more"); var isLoad = $listMore.val(); if ((windowHeight + windowScrollTop + 100) > documentHeight && isLoad == "1") { loadItemMax(sender, param, e); } }); } //小工具事件定义,点击出现菜单栏 function itemMenuClick() { var sender = this; var param = arguments[0]; var e = arguments[1]; // alert("弹出菜单" + "--" + param.uuid1 + "--" + sender.id) var uuid = param.uuid1; var popupMenu = $("#popupMenu"); } //定义小工具会用到的工具类 var moduleInitTool = {}; //适用于不同模板,若是有新模板,只需根据规范添加函数即可,工厂方法 moduleInitTool.jsonModule = function (sender, param, e) { var templateId = param.templateId; var id = param.uuid; var dataSourceUrl = param.dataSourceUrl; var $itemContent = sender.getItemElement(".content"); if (dataSourceUrl) { moduleLoadPara.isLoad = false; $.ajax({ type: "post", url: dataSourceUrl, type: "json", async: true, success: function (data) { $itemContent.html(""); var dataNews = data; if (typeof (dataNews) == "string") { dataNews = eval("(" + data + ")"); ; } var listItemNews = new dataList(id + "_news", templateId); listItemNews.itemElementEvent = { clickTitle: { elementKey: ".span2", eventType: "click", funcName: titleClick } } listItemNews.dataSource = dataNews; listItemNews.dataBind($itemContent); // if (sender.id == "right_conter_id_1") // setInterval(function () { // alert("重新加载" + sender.id); // }, 5000); moduleLoadPara.isLoad = true; } }); } } moduleInitTool.htmlModule = function (sender, param, e) { var id = param.uuid; var dataSourceUrl = param.dataSourceUrl; var $itemContent = sender.getItemElement(".content"); if (dataSourceUrl) { var html = '<iframe scrolling="no" style="width:100%;height:200px" frameborder="0" src="' + dataSourceUrl + '"></iframe>'; $itemContent.html(html); } } moduleInitTool.weiboModule = function (sender, param, e) { } moduleInitTool.labelModule = function (sender, param, e) { var templateId = param.templateId; var id = param.uuid; var dataSourceUrl = param.dataSourceUrl; var customData = param.customData; var modulePara = param.moduleParameter; if (typeof (modulePara) == "string") { modulePara = eval("(" + modulePara + ")"); ; } templateWarehouse["labelHeadTemplate"] = modulePara.labelHeadTemplate; var $itemContent = sender.getItemElement(".content"); $itemContent.html(customData); var lableHead = sender.getItemElement("#labelHead"); moduleLoadPara.isLoad = false; $.getJSON("../Ajax.aspx?sql=select * from bigType", function (data) { var labelHeadList = new dataList(id + "_head", "labelHeadTemplate"); labelHeadList.dataSource = data; labelHeadList.className = "labelHead"; labelHeadList.itemEvent = { _labelHeadClick: { eventType: "click", funcName: function () { var _sender = this; var _param = arguments[0]; var _e = arguments[1]; var labelBody = sender.getItemElement("#labelBody"); var bigTypeId = _param.id; var url = "../Ajax.aspx?sql=select * from smallType where bigTypeId=" + bigTypeId + ""; $.getJSON(url, function (_data) { labelBody.html(""); var labelBodyList = new dataList(bigTypeId + "_head", templateId); labelBodyList.dataSource = _data; labelBodyList.dataBind(labelBody); }); } } }; labelHeadList.dataBind(lableHead); moduleLoadPara.isLoad = true; }); } function elementDatabind(s) { var sender = this; var param = arguments[0]; var e = arguments[1]; var type = param.type; if (type && type.length > 2) { var _funcName = type.substring(2) + "Module"; // eval(_funcName);//此方法不能异步调用 var funcName = moduleInitTool[_funcName]; if (funcName && typeof (funcName) == "function") { funcName(sender, param, e); } } } function titleClick() { var sender = this; var param = arguments[0]; var e = arguments[1]; var summary = sender.getItemElement(".summary"); var isShow = summary.css("display"); if (isShow == "none") { summary.show(); } else { summary.hide(); } } //用于小工具排序 function itemSort() { var sender = this; var html = sender.htmlElement; // alert(html.offset().top); $(".column").sortable({ connectWith: ".column", cursor: 'move', opacity: 0.7, handle: " .title", stop: sortItemsAjax }); } //向后台发送数据 function sortItemsAjax() { submitSortData("left_conter"); submitSortData("cell_conter"); submitSortData("right_conter"); } function submitSortData(colId) { var parent = $("#" + colId); var $children = parent.children(); $children.each(function (i, item) { var id = item.id; var itemId = "#" + id + " #itemId"; var $uuid = $(itemId); var uuid = $uuid.html(); var userPrefers = item.userPrefers; $.ajax({ type: "post", url: "../Ajax.aspx?sort=" + i + "&colId=" + colId + "&id=" + uuid + "&no=no", type: "json", async: true, success: function (data) { } }); }); } //--------------------------------------------------------------------------- //总体外部流程,外部方法 function mainProcess() { var $max = $("#list-max"); var $main = $("#main"); var $btn_Narrow = $("#list-max .btn_Narrow"); $btn_Narrow.unbind("click"); $btn_Narrow.bind("click", function () { if ($max.css("display") == "none") { $main.hide(); $max.show(); } else { $(document).unbind("scroll"); var $listMore = $("#list-max #list-max-more"); $listMore.val("-1"); $main.show(); $max.hide(); } }); } function LaterEvent() { var commomEvent = { _loadItems: { elementKey: ".content", eventType: "ready", funcName: elementDatabind } }; var num = (moduleLoadPara.index) * (moduleLoadPara.num); for (var i = 0; i < num; i++) { if (leftColModule.items[i]) leftColModule.items[i].eventAdd(commomEvent); if (centerColModule.items[i]) centerColModule.items[i].eventAdd(commomEvent); if (rightColModule.items[i]) rightColModule.items[i].eventAdd(commomEvent); } moduleLoadPara.index++; // leftColModule.eventAdd(commomEvent); // centerColModule.eventAdd(commomEvent); // rightColModule.eventAdd(commomEvent); } function delayLoad() { var commomEvent = { _loadItems: { elementKey: ".content", eventType: "ready", funcName: elementDatabind } }; $(document).unbind("scroll"); $(document).bind("scroll", function (e) { if (moduleLoadPara.isLoad) { var num = (moduleLoadPara.index) * (moduleLoadPara.num); var oldNum = (moduleLoadPara.index-1) * (moduleLoadPara.num); for (var i = oldNum; i < num; i++) { if (leftColModule.items[i]) leftColModule.items[i].eventAdd(commomEvent); if (centerColModule.items[i]) centerColModule.items[i].eventAdd(commomEvent); if (rightColModule.items[i]) rightColModule.items[i].eventAdd(commomEvent); } moduleLoadPara.index++; } }); } function pageClick() { for (var i = 1; i <= 5; i++) { var page = $("#pageIndex" + i.toString()); page.unbind("click"); page.bind("click", function (e) { var _p = $(this); initModuleFrame(_p.text()); LaterEvent(); var $max = $("#list-max"); var $main = $("#main"); $main.show(); $max.hide(); $(document).unbind("scroll"); var $listMore = $("#list-max #list-max-more"); $listMore.val("-1"); //置顶 $('html,body').animate({ scrollTop: '0px' }, 800); // A:return false --->In event handler ,prevents default behavior and event bubbing 。 //return false 在事件的处理中,可以阻止默认事件和冒泡事件。 //B:event.preventDefault()---> In event handler ,prevent default event (allows bubbling) 。 //event.preventDefault()在事件的处理中,可以阻止默认事件但是允许冒泡事件的发生。 //C:event.stopPropagation()---> In event handler ,prevent bubbling (allows default behavior). //event.stopPropagation()在事件的处理中,可以阻止冒泡但是允许默认事件的发生。 e.stopPropagation(); return false; }); } } function pageLoad() { mainProcess(); loadTemplate(); loadModuleData(); initModuleFrame(); LaterEvent(); pageClick(); //置顶 $('html,body').animate({ scrollTop: '0px' }, 800); delayLoad(); //5分钟更新一次模块数据 var updateModuleData = setInterval("loadModuleData(true)", 50000); } //---------------------------------------------------------------------------
代码太多不做说明了,以后肯定会封装,
就现在看来整个应用感觉问题不少,实际用处不大吧。
后面点代码整理后再一并发出吧,如果有需要的话。