代码改变世界

ASP.Net AJAX+userControl+js实现仿igoogle效果网站

2009-03-15 19:37  乱世文章  阅读(209)  评论(0编辑  收藏  举报

不知道大家有没有用过igoogle这个google的个人门户网站,我弄的这个东西就是模仿igoogle,主要的难点是新闻模块的动态生成和模块的拖放功能和位置保存。基本原理是用userControl去实现新闻的容器--新闻模块,模块的内容由RSS提供,ASP.Net AJAX实现模块的拖放和服务器的数据存储,js负责提供页面的动态信息交给服务器处理。

 

一、userControl编写

userControl负责存放新闻,我们为了可以重复使用给他填上了属性。这样根据不同的属性就可以让

userControl提供不同的新闻。
模块的信息来源是RSS然后通过程序分析XML中的信息放在userControl中。

后台代码如下:

 


 1 using System;
 2 using System.Data;
 3 using System.Configuration;
 4 using System.Collections;
 5 using System.Web;
 6 using System.Web.Security;
 7 using System.Web.UI;
 8 using System.Web.UI.WebControls;
 9 using System.Web.UI.WebControls.WebParts;
10 using System.Web.UI.HtmlControls;
11 using UI_Servers;
12 using DB_Servers;
13 using Castle.ActiveRecord;
14 using Castle.ActiveRecord.Framework;
15 
16 
17     //public delegate void ClickEventHandler(object sender, EventArgs e);
18     public partial class WebUserControl : System.Web.UI.UserControl
19     {
20         private string Cid;//用户控件ID
21         private string Rssid;//获得数据库中Rss链接的编号
22         private RSSChannel channel;//Rss新闻信息
23         private int count;
24         public string CID
25         {
26             get { return Cid; }
27             set { Cid = value; }
28         }
29         public string RSSID
30         {
31             get { return Rssid; }
32             set { Rssid = value; }
33         }
34 
35         public int Count
36         {
37             get { return count; }
38             set { count = value; }
39         }
40         protected void Page_Load(object sender, EventArgs e)
41         {
42             string url;
43             Rss RSS = Rss.Find(Convert.ToInt32(Rssid));//通过Rssid获得Rss实体类(使用了Castle AR技术,数据库层这里不多做介绍了)
44             channel = new RSSChannel(RSS.RssURL);//通过RSS的URL建立新闻列表实体。
45             channel.ReadChannel();//为新闻实体添加数据(从RSS的XML分析而来)
46         }
47         /// <summary>
48         /// 填充页面RSS新闻
49         /// </summary>
50         /// <returns></returns>
51         public string GetContent()
52         {
53             string ret = string.Empty;
54             RSSItem[] items = new RSSItem[channel.Items.Count];
55             int i = 0;
56             for (; i < count && i < channel.Items.Count; i++)
57             {
58                 items[i] = channel.Items[i];
59                 ret += "<li><a href=/"" + items[i].Link + "/" alt=/"" + items[i].Description + "/">" +
60                     items[i].Title +
61                     "</a></li>";
62             }
63             return ret;
64 
65         }
66         /// <summary>
67         /// RSS新闻模块标题填充
68         /// </summary>
69         /// <returns></returns>
70         public string Title()
71         {
72             return "<href=/"" + channel.Link + "/" name=/"check/">" + channel.Title + "</a>";
73         }
74         /// <summary>
75         /// 生成拖动控件ID
76         /// 为以后ASP.Net AJAX的拖放注册准备
77         /// </summary>
78         /// <returns></returns>
79         public string DragID()
80         {
81             return Cid + "Drag";
82         }
83 
84 
85 

前台代码如下:

 


 1 <%@ Control Language="C#" AutoEventWireup="true" CodeFile="WebUserControl.cs" Inherits="WebUserControl" %>
 2 <div id="<%=CID %>" class="items">
 3         <div id="List_top" class="itemTop">
 4             <div id="<%=DragID() %>" class="itemTitle">
 5                 <%=Title() %>
 6             </div>
 7             <%--<asp:Button runat="server" ID="close_but"  Text="X" CssClass="closing" OnClientClick="elemClose(this);"/>--%>
 8             <input id="close_but" value="X" class="closing" onclick="elemClose(this);"  type="button"/>
 9         </div>
10                     <!-- 内容区域 OnClick="AButton_Click"-->
11         <div class="itemContent">
12             <ul>
13                 <%=GetContent() %>
14             </ul>
15         </div>
16         <div style="height:10px;"></div>
17 </div>
18

 

二、ASP.Net AJAX拖放编写

这里用到的是ASP.Net AJAX的拖放实现是依靠 ASP.Net AJAX CTP实现的,普通的ASP.Net AJAX 1.0是没有这个功能的。

在aspx页面上面加以下代码加载拖放的功能。

 


1     <asp:ScriptManager ID="sm" runat="server" EnablePageMethods="true">
2         <Scripts>
3             <asp:ScriptReference Assembly="Microsoft.Web.Preview" Name="PreviewScript.js" />
4             <asp:ScriptReference Assembly="Microsoft.Web.Preview" Name="PreviewDragDrop.js" />
5         </Scripts>
6     </asp:ScriptManager

现在拖放功能加载了,但是要告诉程序那个控件是可以拖放的,那个地方可以是投放控件的容器。ASP.Net AJAX CTP实现拖放需要用XML来注册控件的信息。下面是容器和容器注册的代码:

 1 <div id="cccc" style="display: block;">
 2         <!-- 左 (容器)-->
 3         <div id="leftArea" class="list1" runat="server">
 4         </div>
 5         <!-- 中 (容器)-->(容器)
 6         <div id="middleArea" class="list2" runat="server">
 7         </div>
 8         <!-- 右 (容器)-->(容器)
 9         <div id="rightArea" class="list3" runat="server">
10         </div>
11         <!-- template elements -->
12         <div style="display: none;">
13             <!-- 内有元素时候显示 -->
14             <div id="dropCueTpl" class="dropCue">
15             </div>
16             <!-- 内没有元素时候显示 -->
17             <div id="emptyTpl" class="emptyList">
18                 Drop content here.
19             </div>
20         </div>
21     </div> 
22 <!--下面是注册代码(XML)-->
23    <script type="text/xml-script">
24   <page>
25     <components>
26 
27       <!-- 左 -->
28       <control id="leftArea">(id为容器控件ID)
29         <behaviors>
30           <dragDropList id="leftDragDropBehavior"  dragDataType="HTML" 
31             acceptedDataTypes="'HTML'" dragMode="Move" direction="Vertical">
32             <dropCueTemplate>(内有元素时候显示)
33               <template layoutElement="dropCueTpl" />
34             </dropCueTemplate>
35             <emptyTemplate>(内没有元素时候显示)
36               <template layoutElement="emptyTpl" />
37             </emptyTemplate>
38           </dragDropList>
39         </behaviors>
40       </control>
41       <!-- 中 -->
42       <control id="middleArea">
43         <behaviors>
44           <dragDropList id="middleDragDropBehavior"  dragDataType="HTML" 
45             acceptedDataTypes="'HTML'" dragMode="Move" direction="Vertical">
46             <dropCueTemplate>
47               <template layoutElement="dropCueTpl" />
48             </dropCueTemplate>
49             <emptyTemplate>
50               <template layoutElement="emptyTpl" />
51             </emptyTemplate>
52           </dragDropList>
53         </behaviors>
54       </control>
55 
56       <!-- 右 -->
57       <control id="rightArea">
58         <behaviors>
59           <dragDropList id="rightDragDropBehavior" dragDataType="HTML" 
60             acceptedDataTypes="'HTML'" dragMode="Move" direction="Vertical">
61             <dropCueTemplate>
62               <template layoutElement="dropCueTpl" />
63             </dropCueTemplate>
64             <emptyTemplate>
65               <template layoutElement="emptyTpl" />
66             </emptyTemplate>
67           </dragDropList>
68         </behaviors>
69       </control>
70 
71       <!-- 可拖放控件的注册代码下面会提到 -->
72     <%=getreg() %>
73 
74     </components>
75   </page>
76     </script>
可拖放控件的注册代码<control id=可拖放的控件的ID><behaviors><draggableListItme handle=可拖放控件的触发控件(即点击此控件拖动就可以拖动可拖动控件)的ID/></behaviors></control>

 下面介绍一下拖放时候的可以用到的两个触发事件:

  1. Sys.Preview.UI.DragDropManager.add_dragStart(function(){})在拖拽开始的时候触发
  2. Sys.Preview.UI.DragDropManager.add_dragStop(function(){})在拖拽结束的时候触发

括号里面是执行的函数。

三、新闻模块的动态生成

新闻模块既然已经被做成userControl,那么只要把userControl当做一个类实例化它,再通过页面初始化时候加载它就可以实现了。但是这个涉及到的问题就是如何在程序中将userControl当做类实例化,如何使其具有拖拽功能,又放在那里。

首先我们来解决userControl的实例化问题,有些朋友可能发现直接写出userControl的名字程序不认识,就算是放在一个解决方案中using这个方案也不行,其实这个是要在.aspx页面下面注册的,注册或就可以在.cs下面访问了,这个和加载其他第三方控件是一样的。需要在aspx的文件开头就注册好程序中才能使用,当然在Web.config文件中也可以注册。一下是两种注册方法:

Title
  1. <% Register Src=userControl文件路径 TagName=元素的标记名称(在程序中的类名) TagPrefit=命名控件别名%>(aspx中注册)
  2. <add Src=  TagName=  TagPrefit= />(在web.config中注册)

这样解决了这个问题就可以动态实例化一个userControl了


1 WebUserControl b = (WebUserControl)LoadControl("WebUserControl.ascx");
2                             b.CID = item.Trim();
3                             b.RSSID = item_data[1].Trim(); ;
4                             b.Count = Convert.ToInt32(item_data[2

设置了这些属性以后在程序调用实例化userControl,其初始化时候新闻信息就会添加在这个userControl中了。

下面是如何实现拖放功能,想让其有拖放功能在前面已经做好了其拖放容器好容器的注册,现在只需要将其加入注册就可以了,因为控件是动态生成的没有办法直接写在aspx代码里面我们用<%=函数名%>实现向aspx中添加注册代码的方式实现注册。把userControl的CID和DragID以上面的可拖放控件的注册方式生成一段注册字符串,再提供给函数就可以了,由于比较简单这里就不增加代码了。

四、JS对userControl的定位和位置存储。

这个是我编这个网站时候遇到的最大的问题,我在这里想了一个方法实现这个问题是一段字符串来记录的,因为每次用户的拖拽时间都要去改变本用户的页面设置,也就是说每次数据库都要有改动,都要和服务器有信息交换,为了不花销过多的服务器资源把大部分的计算工作留给了预览器即JS处理,然后将页面状况描述为一个二维数组,再由有服务器将数组变成字符串存储在个人的设置中。

字符串格式

JS会在每次拖放结束的时候执行,搜索所有的新闻模块,然后根据其位置经过计算处理整理出字符串。

JS处理代码如下:

  1     // JScript 文件
  2     function pageLoad(sender, args) {
  3         //加载拖放结束时间的触发函数
  4         Sys.Preview.UI.DragDropManager.add_dragStop(DragStopped);
  5         //Sys.Preview.UI.DragDropManager.add_dragStart(function(){window.alert("Asdf");});
  6     }
  7     //拖放结束时间的触发函数
  8     function DragStopped(sender, args) {
  9         //模块位置排序
 10         var elems=elemSort();
 11         //userid为当前用户ID因为AJAX在程序中无法访问Session的值所以放在一个input中用AJAX回传
 12         var userid=$get("userIdHidden");
 13         //调用服务器事件保存模块位置
 14         PageMethods.elemOffset(elems,userid.value);
 15     }
 16     //function DragStart(sender, args)
 17     //{
 18     //    window.alert("DragStart Goes");
 19     //}
 20     //模块类
 21     function elem(ID,X,Y)
 22     {
 23         this.ID=ID;
 24         this.X=X;//模块位子X
 25         this.Y=Y;//模块位子Y
 26     }
 27     //获得模块
 28     //findElemsName为可拖放模块的Name熟悉,这里的拖放模块Name值都是一致的。
 29     function elemGet(findElemsName)
 30     {
 31         
 32         //获得可拖放模块集合
 33         var ele=document.getElementsByName(findElemsName);
 34         var elems=new Array;
 35         if(ele.length)
 36         {
 37             var temp_ele;
 38             for(elecount=0;elecount<ele.length;elecount++)
 39             {
 40                 var tempOffset=getoffset(ele[elecount]);
 41                 temp_ele=elemFilter(ele[elecount].parentNode.parentNode.parentNode.id);
 42                 var temp=new elem(temp_ele,tempOffset.x,tempOffset.y);
 43                 elems.push(temp);
 44             }
 45         }
 46         return elems;
 47     }
 48     //获得拖放模块ID
 49     function elemFilter(elemid)
 50     {
 51         //window.alert("elemFilter load");
 52         var temp=new Array();
 53         temp=elemid.split("X");
 54         i=0;
 55         var ret="";
 56         //window.alert(elemid);
 57         while(temp.length&&i<3)
 58         {
 59            if(temp[i])
 60            {
 61                 if(i!=0)
 62                     ret+="X";
 63                 ret+=temp[i];
 64                 i++;
 65            }
 66         }
 67         return ret;
 68     }
 69     //元素位子
 70     function elemOffset(x,y)
 71     {
 72         this.x=x;
 73         this.y=y;
 74         
 75     }
 76     //获得元素位子
 77     function getoffset(e) 
 78     {  
 79         var x=e.offsetLeft;  
 80         var y=e.offsetTop;  
 81         while(e=e.offsetParent) 
 82         {  
 83           x+=e.offsetLeft;  
 84           y+=e.offsetTop;  
 85         }  
 86         var rec = new elemOffset(x,y);
 87         return rec
 88     }  
 89     //
 90     function elemSort()
 91     {
 92         var elems=new Array();
 93         elems=elemGet("check");
 94         elems=sortY(elems);
 95         elems=sortX(elems);
 96         //三个数组分辨对应相应列
 97         var elemSorted=new Array(new Array(),new Array(),new Array());
 98         //获得列的位置
 99         var leftArea=getoffset(document.getElementById("leftArea"));
100         var middleArea=getoffset(document.getElementById("middleArea"));
101         var rightArea=getoffset(document.getElementById("rightArea"));
102        //和列位置比较看当前循环模块属于那个列,并降模块ID压入相应数组
103         for(elemscount=0;elemscount<elems.length;elemscount++)
104         {
105 
106            
107             if(elems[elemscount].X>=leftArea.x&&elems[elemscount].X<middleArea.x)
108             {
109                 elemSorted[0].push(elems[elemscount].ID);
110                 
111                 
112             }
113             else if(elems[elemscount].X>=middleArea.x&&elems[elemscount].X<rightArea.x)
114             {
115                 elemSorted[1].push(elems[elemscount].ID);
116             }
117             else
118             {
119                 elemSorted[2].push(elems[elemscount].ID);
120             }
121         }
122         return elemSorted;
123     }
124 
125     //拖放模块当前列排序
126     function sortY(elems)
127     {
128         var temp=new elem();
129         if(elems.length)
130         {
131             for(sorti=0;i<elems.length-1;sorti++)
132             {
133                 for(sortj=elems.length-1;sortj>sorti+1;sortj--)
134                 {
135                     if(elems[sortj].Y<elems[sortj-1].Y)
136                     {
137                         temp=elems[sortj];
138                         elems[sortj]=elems[sortj-1];
139                         elems[sortj-1]=temp;
140                     }
141                 }
142             }
143         }
144         return elems;
145     }
146 
147     //拖放模块当前行排序
148     function sortX(elems)
149     {
150         var temp=new elem();
151         if(elems.length)
152         {
153             for(Sorti=0;Sorti<elems.length-1;Sorti++)
154             {
155                 for(Sortj=elems.length-1;Sortj>Sorti+1;Sortj--)
156                 {
157                     if(elems[Sortj].X<elems[Sortj-1].X)
158                     {
159                         temp=elems[Sortj];
160                         elems[Sortj]=elems[Sortj-1];
161                         elems[Sortj-1]=temp;
162                     }
163                 }
164             }
165         }
166         return elems;
167     }
168 /*以下是控件关闭按钮客户端事件*/
169 function elemClose(sender)
170 {
171     var closeElemId=sender.parentNode.parentNode.id;
172     
173     var closeElem=document.getElementById(closeElemId);
174     //删除节点
175     closeElem.parentNode.removeChild(closeElem);
176     //模块排序
177     var elemCloseSort=elemSort();
178     var userid=$get("userIdHidden");
179     //保存位置
180     PageMethods.elemOffset(elemCloseSort,userid.value);
181 }

最后是首页的源码可以更好的理解程序但是代码不能运行哦首页代码