集成资源文件

5.3  集成资源文件
虽然在上一节中,我们控制了相同的脚本只在相同页面呈现一遍,但将大段相同的脚本重复呈现到不同的页面也是一种网络与服务器资源的浪费,因为这种方式完全没有利用HTTP的缓存机制,下面我们将探讨如何克服这种问题。
5.3.1  外部JS文件与部署
利用缓存最简单的办法就是把相同的代码独立到一个文件中,比如AutoFlex.js,IIS能自动处理静态文件的Http-Cache策略,它会要求客户端把请求的静态文件缓存起来,那么客户端下次请求相同文件时,就可以利用缓存而不需从服务器上把文件下载下来。
所以,您可以把上一节中实现的AutoFlex客户端组件的代码分离到专门的一个文件中,然后用ClientScriptManager类的RegisterClientScriptInclude()方法将外部脚本文件注册到页面中。
*************************************
但另一个问题又出现了,我们怎么把这个脚本文件放到用户的网站项目中去?
传统的做法是新建一个Web安装项目,将脚本文件生成到用户的网站根目录下,如C:\inetpub\wwwroot\aspnet_client,ASP.NET1.0+就是用这种方式部署验证控件所需的脚本
**************************************
但这种方式非常脆弱,只要我们需要更改网站根目录的位置,或在IIS6.0+中部署多个站点,这种方式都无能为力,所以ASP.NET2.0引入了一种新的方式,即将脚本编译成装配件中的集成资源,然后用axd后缀路径输出资源文件。
****************************************
接下来我们再次增强TextArea的功能,让它支持输入Tab键。在默认情况下,Tab键会让焦点跳到下一个可控制控件,比如按钮、链接。
不过这一次我们不从零开始编写脚本,而是借助于强大的JQuery脚本库和它最棒的插件Interface。
**************************************
5.3.2  JQuery简介
AJAX火起来后,编写JavaScript的需求迅速膨胀,于是互联网上涌现出大量优秀的JS脚本库,比如prototype.js,它的Ruby风格就曾深深地吸引了我,但不久,我就“移情别恋”了,因为我发现JQuery更让人感到亲切。一直到现在,我都把它当成最顺手的JS工具,就算使用ASP.NET AJAX框架做组件框架时,也会大量使用JQuery来实现功能。
与其他JavaScript框架(也许有些人更喜欢说成AJAX框架)相比,JQuery有如下特点:
*************************************************
(1)对DOM结构更多样的操作,JQuery允许你根据DOM元素的ID,Class,标签名等查找页面元素,更重要的是我们还可以用CSS(甚至是CSS3)和XPath语法来组合ID,Class等完成更复杂的对象选择。
比如要在异步更新页面时禁用页面中的所有输入框——$(“input[@type= text]”).attr(‘disabled’,’disabled’),
隐藏所有可见的DIV——$(“div:visible”).hide()
选中的单选按钮——$(“input[@type=radio][@checked]”),
再比如P下面的A——$(‘p/a’)
*******************************************
(2)语句链。JQuery对象的方法在执行后仍然返回JQuery对象(只有少数方法会改变JQuery对象所包含的元素),比如,
$(“#boodsTable tr”).mouseover(trMouseOverHandler).mouseout (trMouseOutHandler),
可以用链式的语句为boodsTable内的TR元素添加MouseOver事件处理函数和MouseOut事件处理函数。
(3)模拟还未在浏览器中实现的CSS3功能。
(4)优秀的AJAX支持和跨浏览器支持。
http://jquery.com
JQuery还有一大批相当优秀的插件,interface是其中最优秀的之一。
Interface不仅包含一组不错的“效果”,还有很多功能强大的组件,更多详情请访问http://interface.eyecon.ro/
********************************************
5.3.3  TabbableTextArea
很多次遭遇在想输入一个制表符时,Tab键却把焦点转到了下一个控件中的尴尬。现在好了,JQuery的Interface插件已经解决了这个问题,而且只需一行代码:$(element).EnableTabs()。
所以要完成TabbableTextArea控件并不需要写多少代码,关键在于我们怎么把jquery.js和interface.js这两个脚本文件集成进来。
******************************************
这一次,我们将采用内嵌资源的方式把脚本资源提供给户(应该是“程序”)
这种方式将控件所需脚本、图片等资源集成在控件所在的装配件中,而不需要用户(应该是“我们”)把控件依赖的文件安装到某个特定的目录,控件使用者甚至感觉不到控件依赖于某些文件,所以说它是最方便用户(应该是“我们”)的。
********************
要将资源内嵌到装配件中非常简单,将文件包含在项目中,在解决方案资源管理器窗口右键单击该文件,选择属性,将“生成操作”属性设为“嵌入的资源”即可。这样,在编译这个项目时,这些文件就会被编译成生成的装配件(原来 装配件这个词指的是dll等程序集)中的内嵌资源,需要注意的是,嵌入的文件名前会加上项目默认的命名空间,比如,MyNameSpace.MyJavascript.js,如果这些文件放置在项目的子目录下,那么子目录名也会成为文件名的一部分,比如,MyNameSpace.MyFolder.MyJavascript.js,如图5-5所示。

embadding.jpgembadding2.jpg

图5-5  嵌入资源

将资源嵌入装配件后,比较麻烦的问题是如何在控件中使用嵌入的资源。使用内嵌在装配件中的资源,需经过以下两个步骤
*******************************
用System.Web.UI.WebResourceAttribute将内嵌资源标记为Web资源,WebResourceAttribute为装配件级Attribute,在使用它时需加上assembly:前缀,比如:
[assembly:WebResource(IntegrateWithJavascriptLibrary.jquery.js","text/javascript")],WebResourceAttribute可以放在assembly.cs(在VS2005中是ClassLibrary1--〉Property--〉AssemblyInfo.cs)中,也可以放在其它cs文件的namespace语句之外,而且只要一个文件声明过一次,在整个装配件中都有效
它的第一个参数为内嵌资源文件名,后一个参数为内嵌文件的MIME类型,还可以加上第三个参数PerformSubstitution,当资源文件中使用了类似<%=WebResource (“IntegrateWithJavaScriptLibrary.tab.gif”,”image/gif”)%>这样的表达式时,则应把PerformSubstitution设为true,比如,
[assembly: WebResource("IntegrateWithJavascript Library.Tabs.css","text/css", PerformSubstitution = true)]。
使用WebResourceAttribute声明过的内嵌文件可以通过/ApplicationPath/WebResource.axd?XXX这样的路径访问。---什么意思?访问?
***********************************
②内嵌资源声明为Web资源后,使用ClientScriptManager.GetWebResourceUrl()方法获得其基于WebResource.axd的访问路径。
注:*.axd在ASP.NET 2.0网站中已被注册为使用ASP.NET解析,在根目录的Web.Config文件的httpHandlers节点中,你也可以找到
<add path="WebResource.axd" verb="GET" type="System.Web.Handlers.AssemblyResourceLoader" validate="True" />配置语句。
好了,现在我们可以完成TabbableTextArea控件了,先根据上述步骤将jquery.js和interface.js两个脚本文件包含到项目中,将设为内嵌资源,然后,将它们设为Web资源:
**************************************

[assembly:WebResource("IntegrateWithJavascriptLibrary.jquery.js"

                        ,
"text/javascript")]

[assembly:WebResource(
"IntegrateWithJavascriptLibrary.interface.js"

                        ,
"text/javascript")]

namespace IntegrateWithJavascriptLibrary

{

    
public class TabbableTextArea:TextBox

    
{

        
bool _supportJS;

        [DesignerSerializationVisibility(

                        DesignerSerializationVisibility.Hidden)]

        [Browsable(
false)]

        [EditorBrowsable(EditorBrowsableState.Advanced)]

        
public override TextBoxMode TextMode
      
{

            
get
           
{   return TextBoxMode.MultiLine;    }

            
set
             {
   
throw new NotSupportedException(
                    "Can not change the TextMode property");            }


        }


        
void DetermineJS()
       
{

            
if (!DesignMode)
           
{

                
if (Page.Request.Browser.EcmaScriptVersion.Major > 0 

                        
&& Page.Request.Browser.W3CDomVersion.Major > 0)//访问本程序的浏览器支持脚本
                
{
                    
this._supportJS = true;
                 }


            }


        }


        
protected override void OnPreRender(EventArgs e)
       
{

            
base.OnPreRender(e);

            DetermineJS();

            
if (_supportJS)
           
{

                Page.ClientScript.RegisterClientScriptResource(
this.GetType(),"IntegrateWithJavascriptLibrary.jquery.js");

                Page.ClientScript.RegisterClientScriptResource(
this.GetType(),"IntegrateWithJavascriptLibrary.interface.js");

                Page.ClientScript.RegisterStartupScript
(
this.GetType(),this.UniqueID,
       string.Format("    $('#{0}').EnableTabs();\r\n",
       this.UniqueID), true);

            }


        }


    }


}


代码非常简洁,这得益于组件化的客户端脚本。在重写的OnPreRender()方法中,使用ClientScriptManager.RegisterClientScriptResource()方法将Web资源注册到控件所在页面中,需要注意的是,ClientScriptManager类能自动保证同样的资源文件在同样页面中只注册一次。----是不是在同一个"方案(项目)"中也“只注册一次”。

posted @ 2007-12-18 14:38  shuang  阅读(313)  评论(0编辑  收藏  举报