[OpenSource] ScriptLoader V4:与组件系统共舞,让分享更清晰
前言
虽然ScriptLoader这个组件产生于一个基于组件部署的系统,但是其实它并没有完全实现预先的目标,和平台系统更好的协调工作.这次因为要将这个组件用在我的另一个正在开发的平台系统中,所以对整个组件进行了一次升级和完善,解决了原来一些遗留的问题,新增了某些功能.新的版本将能在平台和组件间更好的协调工作.
主要更新
- 将使用的.Net Framework从3.5降为2.0.
本来用3.5只是为了偷懒,用了LINQ的一些功能,比如LINQ To XML, LINQ To Object. 这样子也导致了部分人必须自己重新整理整个组件才能应用在其基于2.0的项目中.这次升级就直接把那些LINQ的代码重写了一遍,放弃使用LINQ语法. - 实现了原来支持多语言资源(js,js变量资源)载入的功能.
- 实现了添加自定义namespace的功能,主要用于组件间的类库区分,便于各组件之间的协调,减少冲突的可能.
- 增加自定义请求后缀名,解决某些IIS站点下,asp.net没办法捕获到.js/.css的httphanlder的bug.
- 修改了原来的某些bug,比如监视文件的变动.
功能演示
- 1.区分多语言自动载入相关js和js变量资源
先看下整个文件的组织
这里面有几个逻辑判断点.
1. 当WebForm1.aspx被请求的时候,会自动判断当前 WebForm1.aspx.currentculture.js(WebForm1.aspx.zh-CN.js)是否存在,如果存在则载入.
如果不存在,则判断WebForm1.aspx.js是否存在,如果存在则载入.
2. 我把后缀名为.jsresx的称为js变量资源,它的载入机制和js的载入是一样的.先判断WebForm1.aspx.zh-CN.jsresx是否存在,再判断WebForm1.aspx.zh-CN.jsresx是否存在.
jsresx是一个xml文件,格式如下
<?xml version="1.0" encoding="utf-8" ?>
<Variables>
<lang>中文</lang>
<name>浪子</name>
</Variables>
载入页面之后,就会在页面生成两个变量
var lang='中文';
var name='浪子';
至于如何配置让页面自动关联js,请查看以前的相关文章 [OpenSource]ScriptLoaderV2:彻底改变你的编程习惯 或者 code.google.com上的相关wiki页面
- 2.为某些js配置一个指定的namespace
1.一个平台系统可能本身会带有一些js类库,比如统一使用jquery/prototype等,这样子在组件系统中就没必要重复载入.
2.另外一种情况是,本身作为一个组件,你可能还会和其他系统公用到一部分相同的js类库,但是不是平台提供的.这样子,当两个组件被最终用户组合到一个页面的时候,会导致js的重复载入.
而ScriptLoader原来配置js只有两个文件lib.config和user.config, 显然每个组件都需要这些配置文件,发布的时候,变成需要把内容整合到平台底下的这两个文件中,同时js也需要整合到根目录底下的Scripts里面.显然这样子对于组件的部署是很不方便的.
在V4中,修改了这个机制,把原来的固定的配置文件(lib.config和user.config)取消,取而代之的是以.jsconfig为后缀名的xml文件,配置的格式基本上不变了,只增加了一个小的属性.
举个例子说明,会更好理解些
lib.jsconfig
<?xml version="1.0" encoding="utf-8" ?>
<Scripts>
<Script Name="jquery" Inherit="jquery.min.js">
</Script>
</Scripts>
scripts.jsconfig
<?xml version="1.0" encoding="utf-8" ?>
<Scripts>
<Script Name="MyScript" Inherit="myscript1.js">
<References>
<Reference Name="demo2"></Reference>
</References>
</Script>
<Script Name="demo2" Inherit="demo2.js">
<References>
<Reference Name="jquery" Namespace="lib"></Reference>
</References>
</Script>
</Scripts>
在scripts.jsconfig中,demo2引用了jquery这个js,但是jquery被定义在另外一个jsconfig中,而且那个jsconfig被放在一个名为lib的文件夹底下. 所以必须增加一个namespace="lib".如果没有加这个namespace则表示引用的是当前jsconfig里的一个名为jquery的js.
这段描述有点拗口.不过我们可以看得出来, namespace是和jsconfig所在的文件夹相对应的. 当一个jsconfig文件放在某个文件夹底下的时候,在这个jsconfig中配置的js都会被加上这个文件夹的名称作为一个前缀namespace,比如jquery这个js被定义在lib文件夹下的lib.jsconfig里面,所以在别的jsconfig引用它的时候,就必须标明是Namespace="lib", 而在lib.jsconfig中要引用jquery,则不需要多加这个属性,同一个jsconfig中的js默认为同一namespace底下.
不过有两种情况是不会自动添加文件夹名称作为namespace的:
1.程序根目录
2.Scrtipts文件夹内,这个是为了和以前的版本兼容
css的载入也是同样的,文件夹会作为一个namespace加到name里面,除了根目录和Styles文件夹除外.比如
则载入的代码就变为
protected void Page_Load(object sender, EventArgs e)
{
LangZi.Scripts.ScriptLoader loader = LangZi.Scripts.ScriptLoader.RegisterInstance(this);
loader.LoadStylesheet("Stylesheet1");
loader.LoadStylesheet("Custom.Stylesheet2");
}
有了这个namespace,我们就可以容易的区分各个组件,每个组件使用自己的对应名称的文件夹,以后部署就不会存在冲突,而lib是一样的,即使部署上去了冲突了,也会被忽略掉一个.或者可以根据文件夹的深度来决定哪个要被抛弃,这个还没做实现代码:)
其实这里还有一个重要的功能没有实现,就是类似JSI 的冲突隔离,因为两个框架的关注点不一样,所以ScriptLoader暂时没有考虑这个功能,不过如果实现这个功能,将对组件的部署提供更稳健的保障,或许等待下一个版本:)
- 3.自定义请求后缀名
上次在一个项目中,ScriptLoader的boot.js一直载入不成功,最终发现原来asp.net没有handle到js和css的请求,一直没发现IIS哪里有问题, 将请求后缀改为.aspx则可以成功捕获到.巨晕,所以就加了这个功能,如果你想使用自定义的请求后缀名的话,只需要在web.config中进行修改.
原来的配置是
<httpHandlers>
<add verb="GET" path="*.js" type="LangZi.Scripts.ScriptLoaderHandler,LangZi.ScriptLoader"/>
<add verb="GET" path="*.css" type="LangZi.Scripts.ScriptLoaderHandler,LangZi.ScriptLoader"/>
</httpHandlers>
需要改为如下配置
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="LoaderSuffix" value=".aspx"/>
</appSettings>
<system.web>
<httpHandlers>
<add verb="GET" path="*.js.aspx" type="LangZi.Scripts.ScriptLoaderHandler,LangZi.ScriptLoader"/>
<add verb="GET" path="*.css.aspx" type="LangZi.Scripts.ScriptLoaderHandler,LangZi.ScriptLoader"/>
</httpHandlers>
</system.web>
</configuration>
另外注意点的地方是,如果你使用页面手工注册boot.js的引入的,则需要更改script中的后缀,如
<script src="LangZi.Scripts.boot.js" charset="UTF-8" type="text/javascript"></script>要修改为
<script src="LangZi.Scripts.boot.js.aspx" charset="UTF-8" type="text/javascript"></script>
如果使用的是服务端的注册方式,则不需要更改代码.
protected void Page_Load(object sender, EventArgs e)
{
LangZi.Scripts.ScriptLoader loader = LangZi.Scripts.ScriptLoader.RegisterInstance(this);
}
- 相关资源
1.部分文档已经增加到code.google.com的wiki页上面,其他文档会陆续进行完善,欢迎使用中的朋友帮忙一起完善^_^
2.相关代码可以从 http://code.google.com/p/langzi/downloads/list 获取到