不知道大家有没有用过igoogle这个google的个人门户网站,我弄的这个东西就是模仿igoogle,主要的难点是新闻模块的动态生成和模块的拖放功能和位置保存。基本原理是用userControl去实现新闻的容器--新闻模块,模块的内容由RSS提供,ASP.Net AJAX实现模块的拖放和服务器的数据存储,js负责提供页面的动态信息交给服务器处理。
一、userControl编写
userControl负责存放新闻,我们为了可以重复使用给他填上了属性。这样根据不同的属性就可以让 userControl提供不同的新闻。 模块的信息来源是RSS然后通过程序分析XML中的信息放在userControl中。
后台代码如下:
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 " < a 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
前台代码如下:
userControl前台代码
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>
下面介绍一下拖放时候的可以用到的两个触发事件:
Sys.Preview.UI.DragDropManager.add_dragStart(function(){})在拖拽开始的时候触发
Sys.Preview.UI.DragDropManager.add_dragStop(function(){})在拖拽结束的时候触发
括号里面是执行的函数。
三、新闻模块的动态生成
新闻模块既然已经被做成userControl,那么只要把userControl当做一个类实例化它,再通过页面初始化时候加载它就可以实现了。但是这个涉及到的问题就是如何在程序中将userControl当做类实例化,如何使其具有拖拽功能,又放在那里。
首先我们来解决userControl的实例化问题,有些朋友可能发现直接写出userControl的名字程序不认识,就算是放在一个解决方案中using这个方案也不行,其实这个是要在.aspx页面下面注册的,注册或就可以在.cs下面访问了,这个和加载其他第三方控件是一样的。需要在aspx的文件开头就注册好程序中才能使用,当然在Web.config文件中也可以注册。一下是两种注册方法:
Title
<% Register Src=userControl文件路径 TagName=元素的标记名称(在程序中的类名) TagPrefit=命名控件别名%>(aspx中注册)
<add Src= TagName= TagPrefit= />(在web.config中注册)
这样解决了这个问题就可以动态实例化一个userControl了
Code
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
}
最后是首页的源码可以更好的理解程序但是代码不能运行哦首页代码