asp.net mvc 异步数据 符合css2.0标准 栏目设计全解

来源:互联网 发布:软件开发属于政府部门 编辑:程序博客网 时间:2024/06/02 16:07
 

网站 -- 测试驱动

    首先声明:阅读该文档时,你重点要关注的不是结果,而是过程。

    这是一个关于网站“企业展示”子系统的开发过程。由于篇幅有限,我们就摘取一个栏目的异步加载来做分析。

    要看明白这个文档,你必须具备一下知识:

    1.   Asp.net Mvc  preview2  Framework 系列  

    2.   Jquery 官方论坛   和  jquery api 1.2 参考文档

    3.   Css+div 标准化

    4.   使用Linq to sql  

    5.  了解xp的测试驱动开发 -- (敏捷软件开发 第四章)

    好了,现我们就来做实践吧!

    一  我们有什么?

    首先,我们有一个xhtml标准: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> 和一个 jquery-1.2.3 .js

     二  期望的客户代码

     我们希望在一个网页上写些什么?怎么写能够出现一个清晰的分层效果,让人容易理解你的作品?当然,一个页面越简单越好:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    
<title>测试 -- 霸州供电站</title>
    
<!-- 引用jquery-1.2.3.js文件 -->
    
<script src="js/jquery-1.2.3.js" type="text/javascript"></script>
  
</head>
<body>
    
<div id="txtList" style="width:501px">
    
</div>
</body>
</html>

 

    页面内容只有一个id="txtList"的div,还引用了一个javascript框架jquery。

    接下来,我们要用jquery脚本来异步获取服务器端的一个json数据。(就是这么想的,然后写下代码)

<script type="text/javascript" language="javascript">
      $(document).ready(showMainTB);
      
function showMainTB()
      
{
          
//我们想象已经有一个javascript形式的类了(叫MainTB的内容栏目),然后创建它
          var txt1 = new MainTB($('#txtList'));
          
//使用jquery异步取得json数据然后传递给MainTB对象(还没有Handler.ashx后台处理文件)
          $.getJSON('Handler.ashx',function(jsonData){
              
//显示栏目
              txt1.display(jsonData);
          }
);
     }

    
</script>

 

     很简短的脚本,我们就希望页面脚本这么写。(或许你有更好的写法)

    三  构建代码,进行测试

    客户端页面需要一个MainTB的javascript类(包括一个display方法)和一个名为Handler.ashx的后台处理文件。

    MainTB.js

    

/*
 use jquery.js;
 js类,实现主页面的信息栏目内容区域 栏目样式
 element 为id为‘txtlist’的dom元素
 
*/

function MainTB(element) {
    
this._elem = element;
    
}

    
/*利用取得的json数据填充内容,使用字符串拼接方式写一个block*/
    MainTB.prototype.display
= function(jsonData)
    
{
        
var sb = '';
        sb 
+='<div class="tblock"><div class="w100"><b class="fleft" style="font-size:14px;"><img src="imgs/index/point1.gif" alt="通知公告"  />&nbsp;';
        sb
+=jsonData.subject;
        sb
+='</b><div class="moreimg">...................................................<a href="TextList.aspx"><img src="imgs/index/more.gif" alt="更多"/></a></div></div><hr style="height:2px; line-height:3px;width:100%;color:#0591e7;background:#0591e7;" /><div class="w100"><div class="fleft"><img alt="标题" src="imgs/index/top.gif" />&nbsp;';
        sb
+=jsonData.tit;
        sb
+='</div><div style="float:right;width:40%; text-align:center;">';
        sb
+=jsonData.date;
        sb
+='</div></div><div class="cir2" style="width:469px;background:#687896;"></div><div class="cir2" style="width:471px; "></div><div class="cir2" style="width:473px;"></div><div class="cir2in"><ul>';
        
for(var i=0; i<jsonData.context.length; i++)
        
{
            sb
+='<li><div class="fleft tbpoint"><div class="fleft"><img alt="标题" src="imgs/index/point2.gif" />&nbsp;<a href="Text.aspx">';
            sb
+=jsonData.context[i].titin;
            sb
+='</a></div><img style="float:right;" alt="新的" src="imgs/index/new.gif" /></div><div class="tbdate">';
            sb
+=jsonData.context[i].datein;
            sb
+='</div></li>';
        }

        sb
+='</ul></div><div class="cir2" style="width:473px;"></div><div class="cir2" style="width:471px;"></div><div class="cir2" style="width:469px;background:#687896;"></div></div>';
        
        
this.get_elem().append(sb);
        
    }
;
    
    
/* 属性存取器 */
    MainTB.prototype.get_elem
= function()
    
{
        
return this._elem;
    }
;
    MainTB.prototype.set_elem
= function(value)
    
{
        
this._elem = value;
    }
;
    
    
/* 属性存取器 */

 

    (1). 测试MainTB。首先,我们做了一个类,必须得测试它是否是符合我们的要求。

    不妨先把客户代码改一下:

    

<script type="text/javascript" language="javascript">
      $(document).ready(showMainTB);
      
function showMainTB()
      
{
           
//创建一个主内容栏目
          var txt1 = new MainTB($('#txtList'));
          
//手动构建一个son数据
          Var jsonData = {
               
'subject':'通知公告',
                
'tit':'标题区域',
                
'date':'上传时间',
                
'context':[
                    
{'titin':'文章标题''datein':'2008年4月11日 17:15'},
                    
{'titin':'霸州供电局公告''datein':'2008年4月11日 17:15'},
                    
{'titin':'霸州供电局公告''datein':'2008年4月11日 17:15'},
                    
{'titin':'霸州供电局公告''datein':'2008年4月11日 17:15'},
                    
{'titin':'文章标题''datein':'2008年4月11日 17:15'},
                    
{'titin':'霸州供电局公告''datein':'2008年4月11日 17:15'},
                    
{'titin':'霸州供电局公告''datein':'2008年4月11日 17:15'},
                    
{'titin':'霸州供电局公告''datein':'2008年4月11日 17:15'}
                    ]
                }

          txt1.display(jsonData);
     }

    
</script>

 

     运行网页还需要引入两个样式表文件com.css和context.css。之后我们就能看到下边的效果sl-1:

预览实例

图(sl-1)

    是不是你期望的样子呢?

    (2) 测试异步传输。在我们的原始客户端代码中有一段代码 $.getJSON( 'Handler.ashx' , function (jsonData) )。其中第一个参数指定了处理该异步请求的是一个叫Handler.ashx的后台文件;第二个参数是一个函数,表示完成异步请求后要做的操作,该函数会得到一个后台传过来的json数据。所以,总的一句话“handler.ashx文件要把一个json数据写到response里,好让我们从客户端得到”。

    Handler.ashx文件

     

public class Handler : IHttpHandler {
    
public void ProcessRequest (HttpContext context) {
        context.Response.ContentType 
= "text/plain";
        var sb 
= new System.Text.StringBuilder();
        sb.Append( 
"{");
         sb.Append(
"'subject':'通知公告',");
          sb.Append(
"'tit':'标题区域',");
         sb.Append(
" 'date':'上传时间',");
          sb.Append(
"'context':[");
              sb.Append(
"{'titin':'文章标题', 'datein':'2008年4月11日 17:15'},");
              sb.Append(
"{'titin':'霸州供电局公告', 'datein':'2008年4月11日 17:15'},");
              sb.Append(
"{'titin':'霸州供电局公告', 'datein':'2008年4月11日 17:15'},");
              sb.Append(
"{'titin':'霸州供电局公告', 'datein':'2008年4月11日 17:15'},");
              sb.Append(
"{'titin':'文章标题', 'datein':'2008年4月11日 17:15'},");
              sb.Append(
"{'titin':'霸州供电局公告', 'datein':'2008年4月11日 17:15'},");
              sb.Append(
"{'titin':'霸州供电局公告', 'datein':'2008年4月11日 17:15'},");
              sb.Append(
"{'titin':'霸州供电局公告', 'datein':'2008年4月11日 17:15'}");
              sb.Append(
"]");
          sb.Append(
"}");
        context.Response.Write(sb.ToString());
        context.Response.End();
        
    }

 
    
public bool IsReusable {
        
get {
            
return false;
        }

    }


}

 

     再次测试仍然可以看到图( sl-1)的效果。

    (3) 到这一步,我们的工作要做一个质的改变了——应用asp.net mvc框架

    Asp.net mvc 框架的第一步就是要我们在Models文件夹中建立数据实体TB.dbml。注意两个表之间的引用,即主键和外键的关系。系统自动生成的类里边主键表里要有一个EntitySet<外键表>类型的属性。

    然后在Cotrollers文件夹中建立一个HomeController继承BaseController——这里我们还封装了一个基类BaseController,该个类继承自Controller,并提供了一个json序列化对象的操作(有重载),和一个写Response的方法。(操作步骤可以参看资料提供的blog),具体代码如下:

    BaseController.cs

     

public class BaseController : Controller
    
{
        [NonAction]
        
public void RenderJson(object obj)
        
{
            var json 
= new JavaScriptSerializer();
            var str 
= new StringBuilder();
            json.Serialize(obj, str);
            ResponseJson(str.ToString());
        }

        [NonAction]
        
public void RenderJson(string str)
        
{
            ResponseJson(str);
        }

        [NonAction]
        
protected void ResponseJson(string json)
        
{
            Response.Clear();
            Response.ContentEncoding 
= Encoding.UTF8;
            Response.ContentType 
= "application/json";
            Response.Write(json);
            Response.Flush();
            Response.End();
        }

    }

 

    HomeController.cs

     

public class HomeController : BaseController
    
{
        
public void Default()
        
{
            RenderView(
"Index");
        }

        
        
public void SetAjaxTB()
        
{
            TBDataContext tb 
= new TBDataContext();
            
//test1
            
//只能获取sql
            var data = from col in tb.GetTable<Colum>()
                       
where col.ID == 1
                       select 
new
                       
{
                           Title 
= col.Title,
                           Articles 
= from art in col.Articles
                                      select 
new
                                      
{
                                          ID 
= art.ID,
                                          Title 
= art.Title,
                                          UpTime 
= art.UpTime
                                      }

                       }
;
           
            
//组织一个json数据
            var tb1 = new StringBuilder();
            
foreach (var jsonData in data)
            
{
                tb1.Append(
"{");
                tb1.Append(
"'subject':'" + jsonData.Title + "',");
                tb1.Append(
"'tit':'标题区域', 'date':'上传时间','context':[");
                
foreach (var con in jsonData.Articles)
                
{
                    tb1.Append(
"{'titin':'" + con.Title + "', 'datein':'" + con.UpTime + "'},");
                }

                tb1.Remove(tb1.Length 
- 11);
                tb1.Append(
"]}");
            }

            RenderJson(tb1.ToString());
        }

    }

 

    关于SetAjaxTB () 函数的实现,我本想用模式来分离操作。这个函数有三步实现,一个是组成一个查询query;另一个是拼接一个json字符串(这里我们也可以用BaseController里的json对象序列化来实现);第三个已经分出去了,用RendJson(string)把拼接好的json字符串直接写到Response里。

    如果吧第一步和第二步分出去,那么他们之间的关联就需要传递一个IQueryable<>泛型参数。如果这样做了,那么在第二个步骤里边 jsonData.Title 就不知道是什么了,这是一个不好的实现,不过解决的办法还是有的(比如,我们第一步不用匿名方法)。

    再根据职责分配原则,类HomeController应该负责第一步和第二步吗?初看这两个都不应该是它来负责的操作,如果有个MakeQuery类提供建立查询query,一个MakeTB负责建立json字符串,就能够满足“单一职责原则”,提高了可扩展性和可维护性。

    还要做一步改动,客户端js代码中的后台处理文件路径“Handler.ashx”改成“/Home/SetAjaxTB”(Home指代Controller前缀,SetAjaxTB是HomeController的一个[Action]方法)这样就符合asp.net mvc的风格了。

    运行,是否符合你的期望呢?

附上css文件和图片(ff和ie7下兼容):

    com.cs

    

body,form,p,ul{margin:0;padding:0;}
        div
{ margin:0px auto; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
        div ul>li
{ margin-left:20px; line-height:20px;clear:both;}
        ul
{list-style:none;}
        img
{border:0px;}
        input
{ height:14px;}
        a:link,a:visited
{text-decoration:none;}
        a:hover
{text-decoration:underline;}
        a:link
{color:#000;}
        a:visited
{color:Red;}
        a:hover
{color:Orange;}
        
        a.whair:link
{color:#fff;}
        a.whair:visited
{color:Red;}
        a.whair:hover
{color:Orange;}

.fleft
{float:left;}      
.w100  
/*宽度100%*/{width:100%;}
.margin5
{margin-top:5px;}
.mtxt
{margin:10px 20px 10px 20px;letter-spacing:2px;word-spacing:3px;text-indent:28px;text-align:left; white-space:normal; line-height:24px;background:#f9f9f9;}
    context.css
    body
{font:12px 宋体,simsun,sans-serif; text-align:center; vertical-align:middle;}
            
.fw14  
/*加粗14px的字体*/{font-size:14px;font-weight:bold;}

.all
{width:980px;}
.hair
{margin-left:5px;background:#008f99;height:20px;line-height:20px}
#noplaymsg
{height:123px; line-height:123px; text-decoration:blink;}
.nav
{background:url(../imgs/index/nav_bg.gif);height:29px; line-height:29px;}
.nav_b
{width:86px;height:29px;}
.nav_b2
{width:2px;height:29px;line-height:29px;background:url(../imgs/index/nav_bg_r.gif);}

.cir
{ height:1px; border:#e0e0e0 solid; border-width:0px 1px;}  
.cirin
{width:249px;border:#e0e0e0 solid; border-width:0px 1px;}
.cir2
{ height:1px; border:#687896 solid; border-width:0px 1px;}  
.cir2in
{width:474px;border:#687896 solid; text-align:left; border-width:0px 1px;}
 
.left
{width:251px;margin-top:5px;}
.lb1
{margin-top:5px;margin-bottom:5px;width:230px;border:solid 2px #999999;text-align:left;}
.lbtit
{font-size:14px;border-top:solid 1px #7a7a7a;border-bottom:solid 1px #7a7a7a;background:url(../imgs/index/l_tit_bg.gif);height:29px;line-height:29px;vertical-align:middle;width:100%;}
.lbtxt
{border-bottom:solid 1px #fff; border-top:solid 1px #fff; background:url(../imgs/index/l_txt_bg.gif);height:22px;line-height:22px;width:100%;}
.lbtxtimg
{float:left;margin-left:30px;width:14px; height:14px; background:url(../imgs/index/go_ahead.gif)}

.txt
{width:729px;float:left;}
.map
{height:28px;line-height:28px;font-size:14px;margin-top:5px; margin-left:5px;}
.photo
{width:100%;height:120px;line-height:120px;vertical-align:middle;text-decoration:blink;margin-top:2px;background-color:Orange;}
.tblock
{width:95%;margin:10px auto;}
.moreimg
{width:80%;color:Red; text-align:right; float:right;}
.tbpoint
{margin-left:5px;width:60%;}
.tbdate
{float:right;width:35%;text-align:left;}

.rblock
{width:90%;border:solid 1px #cee0f1;margin-top:5px;margin-bottom:5px;}
.rbtit
{text-align:left;font-size:14px;width:100%;height:31px;line-height:31px;vertical-align:middle;background:url(../imgs/index/r_tit_bg.gif);}
.rbbg
{background:#c8e7f8; text-align:left;}

.foottxt
{margin:10px 50px 10px 50px;line-height:24px;}

/*********** 页面的TList.ascx *************/

.rtxt
{width:95%;}
原创粉丝点击