[ASP.NET 2.0]创建母版页引来的麻烦

一、问题提出

    由于总体排版和设计的需要,我们往往创建母版页来实现整个网站的统一性,最近我由于统一性的需要,把原来整个项目单独的页面全部套用了母版页。但是出现了一个错误……在我的Blog中记录一下,方便大家参考。

二、 抽象模型

    由于整个页面内容过多,所以我把这个页面中最为本质的问题抽象出来。
    原来单一页面,就是利用按钮触发JS事件,在文本域中插入“(_)”功能,其实现代码如下: 

<% @ Page Language = " C# "  AutoEventWireup = " true "   CodeFile = " Default.aspx.cs "  Inherits = " _Default "   %>
<! 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 runat = " server " >
    
< title > 单一页面抽象模型-YJingLee </ title >
< script language = " javascript "  type = " text/javascript " >
//  <!CDATA[
function insert() {
           document.getElementById(
" txt " ).value = document.getElementById( " txt " ).value + " (__) " ;
        
return ;
}
//  ]]>
</ script >
</ head >
< body >
    
< form id = " form1 "  runat = " server " >
    
< div >
        
< textarea id = " txt "  runat = " server "  name = " txt "  rows = " 10 "  cols = " 50 " ></ textarea >
        
< asp:Button ID = " btnInsert "  runat = " server "  Text = " 服务器端插入(_) "   OnClientClick = " insert(); " />
        
< input id = " btnInsert2 "  name = " insert "  onclick = " insert(); "  type = " button "  value = " 客户端插入(_) "  runat = " server " /></ div >
    
</ form >
</ body >
</ html >

上述页面可以正常使用。后来使用模板页后,其代码如下:

<% @ Page Language = " C# "  MasterPageFile = " ~/MasterPage.master "  AutoEventWireup = " true "  CodeFile = " Default2.aspx.cs "  Inherits = " Default2 "  Title = " 使用母版页面抽象模型-YJingLee "   %>
< asp:Content ID = " Content1 "  ContentPlaceHolderID = " ContentPlaceHolder1 "  Runat = " Server " >
< script language = " javascript "  type = " text/javascript " >
//  <!CDATA[
function insert() {
           document.getElementById(
" txt " ).value = document.getElementById( " txt " ).value + " (__) " ;
        
return ;
}
//  ]]>
</ script >
    
< div >
        
< textarea id = " txt "  runat = " server "  name = " txt "  rows = " 10 "  cols = " 50 " ></ textarea >
        
< asp:Button ID = " btnInsert "  runat = " server "  Text = " 服务器端插入(_) "   OnClientClick = " insert(); " />
        
< input id = " btnInsert2 "  name = " insert "  onclick = " insert(); "  type = " button "  value = " 客户端插入(_) "  runat = " server " /></ div >
</ asp:Content >

    当打开后按下按钮出现了“Microsoft JScript 运行时错误: 'document.getElementById(...)' 为空或不是对象”。这是什么原因呢?原来好好的,怎么套用个母版页就出现这个奇怪的问题呢?困扰了好久,和朋友讨论了一下,终于找到了答案……

三、分析本质

原来我们仔细看看其生成的HTML代码:
    单一页面:

<! 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 >     单一页面抽象模型-YJingLee </ title >
< script language = " javascript "  type = " text/javascript " >
//  <!CDATA[
function insert() {
     document.getElementById(
" txt " ).value = document.getElementById( " txt " ).value + " (__) " ;
    
return ;
}
//  ]]>
</ script >
</ head >
< body >
    
< form name = " form1 "  method = " post "  action = " Default.aspx "  id = " form1 " >
< div >
< input type = " hidden "  name = " __VIEWSTATE "  id = " __VIEWSTATE "  value = " /wEPDwUKMTEzMjE5NDA0NWRkKlEH1jSXJkIbnUaP2d9Dra8LQEk= "   />
</ div >
    
< div >
        
< textarea name = " txt "  id = " txt "  rows = " 10 "  cols = " 50 " ></ textarea >
        
< input type = " submit "  name = " btnInsert "  value = " 服务器端插入(_) "  onclick = " insert(); "  id = " btnInsert "   />
        
< input name = " btnInsert2 "  type = " button "  id = " btnInsert2 "  onclick = " insert(); "  value = " 客户端插入(_) "   /></ div >
< div >
    
< input type = " hidden "  name = " __EVENTVALIDATION "  id = " __EVENTVALIDATION "  value = " /wEWBALVid/5DQKShrDCCQL5w9POBQL5w4vOBZPGqxUU/yvoKTqG8k+uG8YroGTv "   />
</ div ></ form >
</ body >
</ html >

再看看套用母版页之后,生成的HTML代码: 

<! 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 > 使用母版页面抽象模型-YJingLee </ title ></ head >
< body >
    
< form name = " aspnetForm "  method = " post "  action = " Default2.aspx "  id = " aspnetForm " >
      < div >
        < input type = " hidden "  name = " __VIEWSTATE "  id = " __VIEWSTATE "  value = " /wEPDwUKLTEwMTY2NjE0OWRkADUETiohcorj2qXOE9M1qhFVw20= "   />
     </ div >
   
< div >         
< script language = " javascript "  type = " text/javascript " >
//  <!CDATA[
function insert() {
           document.getElementById(
" txt " ).value = document.getElementById( " txt " ).value + " (__) " ;
        
return ;
}
//  ]]>
</ script >
    
< div >
        
< textarea name = " ctl00$ContentPlaceHolder1$txt "  id = " ctl00_ContentPlaceHolder1_txt "  rows = " 10 "  cols = " 50 " ></ textarea >
        
< input type = " submit "  name = " ctl00$ContentPlaceHolder1$btnInsert "  value = " 服务器端插入(_) "  onclick = " insert(); "  id = " ctl00_ContentPlaceHolder1_btnInsert "   />
        
< input name = " ctl00$ContentPlaceHolder1$btnInsert2 "  type = " button "  id = " ctl00_ContentPlaceHolder1_btnInsert2 "  onclick = " insert(); "  value = " 客户端插入(_) "   /></ div >
    
</ div >     
< div >
    
< input type = " hidden "  name = " __EVENTVALIDATION "  id = " __EVENTVALIDATION "  value = " /wEWBAKyga4JAtO59ZELApOT2tEDApOTwvAC83bfMO00kt0PYcRte7XQOsXBcFE= "   />
</ div ></ form >
</ body >
</ html >

    是不是看到问题了,源文件控件元素的ID和生成HTML文件的ID不一致。表单from的name属性和id属性变成了aspnetForm,控件的id属性被无缘无故了加上了ctl00_ContentPlaceHolder1_前缀,其name属性也加上了ctl00$ContentPlaceHolder1$前缀。
这下知道了,难怪提示“'document.getElementById(...)' 为空或不是对象”的错误了,原来生成页面后其ID都变了。
那么我们如何解决它呢?既然他id变了,我们就把JS代码id改为生成后的id。代码如下: 

function insert() {
document.getElementById(
" ctl00$ContentPlaceHolder1$txt " ).value = document.getElementById( " ctl00$ContentPlaceHolder1$txt " ).value + " (__) " ;
        
return ;
}
// 或者
function insert() {
document.getElementById(
" ctl00_ContentPlaceHolder1_txt " ).value = document.getElementById( " ctl00_ContentPlaceHolder1_txt " ).value + " (__) " ;
        
return ;
}

    好了,问题解决了,不过想想有什么更好的办法呢?到底为什么呢?
    其实分析一下,它是后来生成的客户端id,我们可以用C#语句Control的ClientID属性,像这样写:txt.ClientID; txt还是原来控件的id,后面的ClientID就是新生成的id。txt.ClientID是从程序里取到的后来生成新的id,这样不是更好吗。修改代码如下:

function insert() {
document.getElementById(
" <%=txt.ClientID %> " ).value = document.getElementById( " <%=txt.ClientID %> " ).value + " (__) " ;
        
return ;
}

   还有在后台Request.Form["txt"]键值需要改变,必须变为Request.Form["<%=txt.ClientID %>"]才能接收到页面的值。想想如果想要得到ID的control是一个用户控件的话,当生成页面后尽管能得到其ClientID,但是却得不到这个对象,所以也就不能设置或获得其属性了。比如,我要做的这个用户控件,由三个DropDownList组成,可是我却想得到一个完整的日期值(指在客户端),一种思路是先获得三个DropDownList的ClientID,然后再由ID1.value+ID2.value+ID3.value取得,可是如果你一个页面上需要放多个这样的用户控件的话,你需要取得多少个ClientID?显然这样做的话,工作量会很大,而且要操作众多的对象,很容易出错。

四、总结

    这一类问题我像在我们编写程序时往往经常会遇到,总结一下:这应该属于“使用了MasterPage,或者GridView中的模版列后所有元素ID不一致问题”。由于种种原因(比如使用了MasterPage,或者GridView中的模版列),一个控件在设计时的ID往往不同于生成页面后的ID,为了获得控件客户端ID,我们可以从生成的页面入手,取控件id有以下三种修改方法:(当然我还是推荐第三种)

document.getElementById( " ctl00$编辑区ID$控件ID " );
document.getElementById(
" ctl00_编辑区ID_控件ID " );
document.getElementById(
" <%=控件名ID.ClientID %> " );

    至于为什么,是自己还没有深刻理解其中的根源还是.NET机制问题呢?
    在我们设计时往往就会出现一些莫名其妙的问题,我想我们遇到问题时,冷静思考,把握主次,从底层框架入手,纠其原因,相信最终会找到答案。

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值