使用C#编写JavaScript
前端开发中JavaScript代码的维护总是让人头疼,特别是在富客户端应用中,必须要编写非常庞大的JavaScript代码,虽然JavaScript声称是面向对象的语言,但对于现代语言中常见的继承、强类型等的支持十分有限。如果我们能够将C#语言中的特性运用于JavaScript上,那么肯定将极大地提高JavaScript代码的维护性,提升开发效率。Saltarelle编译器就是这样的一个工具,他能将C#代码编译为JavaScript代码。
本文将展示如何使用Saltarelle编写JavaScript代码,我们将结合Saltarelle.jQuery和Saltarelle.Knockout库说明如何使用Saltarelle。本文使用Visual Studio 2012作为开发工具,通过NuGet获取相关扩展包。
1、首先新建一个空ASP.NET应用项目,此项目作为前端演示网站,项目名称为Web
2、添加一个类库项目,作为JavaScript脚本项目,该项目使用Saltarelle编译器自动生成脚本代码,项目名称为Scripts
3、选择Scripts项目,单击右键,选择“管理NuGet程序包”,在程序包管理界面,在上方搜索窗口中输入Saltarelle,搜索有关Saltarelle的包:
依次安装Saltarelle C# to JavaScript Compiler、Runtime library for the Saltarelle C# to JavaScript… 、Metadata required to use jQuery with Saltarelle …、Metadata required to use Knockout with Saltarelle …
4、Saltarelle包会更新Scripts项目,添加必要程序集引用,并修改项目使用Saltarelle编译器,由于Visual Studio 本身Bug,我们需要手动卸载并重新载入Scripts项目。此操作通过项目右键菜单完成。
5、修改Scripts项目类型:单击Scripts项目,右键选择属性,在输出类型中选择“控制台应用程序”,做此项修改的原因是让Saltarelle编译器自动调用Scripts的入口方法(即,Program的Main方法)
6、打开Properties文件夹下的AssemblyInfo.cs代码文件,注释掉一下ComVisible和Guid特性:
// 将 ComVisible 设置为 false 使此程序集中的类型 // 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, // 则将该类型上的 ComVisible 特性设置为 true。 //[assembly: ComVisible(false)] // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID //[assembly: Guid("ecc66b86-53da-44b6-b83a-87b52da11e91")]
7、将Scripts项目中自动添加的Class1.cs代码文件修改为Program,并添加Main方法:
namespace Scripts { class Program { static void Main() { } } }
8、生成Scripts项目,完成后,我们可以在生成输出目录看到所生成的Scripts.js文件
接下来,我们演示如何使用jQuery:
jQuery中可以使用ready注册在页面载入完成后所要执行的程序,在Saltarelle.jQuery中,我们可通过OnDocumentReady方法来完成相同的功能,下面示例实现在页面载入完成后弹出提示框的功能:
1、在Program.cs中添加System.Html和jQueryApi命名空间
2、修改Main方法,代码如下:
using System.Html; using jQueryApi; namespace Scripts { class Program { static void Main() { jQuery.OnDocumentReady(() => { Window.Alert("Page is loaded"); }); } } }
copy $(TargetDir)$(TargetName).js $(SolutionDir)Web\Scripts\$(TargetName).js
5、为了保证在生成Web项目时能自动更新Scripts.js脚本,可在Web项目中添加对Scripts项目的引用
6、下面在Web项目中添加一个名称为Index.html的HTML页面。在head标签内添加必要js文件的引用:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> <script type="text/javascript" src="Scripts/mscorlib.min.js"></script> <script type="text/javascript" src="Scripts/jquery-1.9.1.js"></script> <script type="text/javascript" src="Scripts/Scripts.js"></script> </head> <body> </body> </html>
using System; using KnockoutApi; namespace Scripts { public class IndexViewModel { // 页面标题, 使用Observable表示该字段支持更改通知,当值改变时,它所关联的UI将自动更新 public Observable<string> PageTitle = Knockout.Observable<string>(); // 表示支持更改通知的数组 public ObservableArray<LogItem> Logs = Knockout.ObservableArray<LogItem>(); } public class LogItem { public string Level = String.Empty; public DateTime Time; public String Message = String.Empty; } }
注意:有关如何使用Knockout实现MVVM模式,请参考Knockout官方网站
2、在Main方法中绑定ViewModel:
using System.Html; using jQueryApi; using KnockoutApi; namespace Scripts { class Program { static void Main() { jQuery.OnDocumentReady(() => { Window.Alert("Page is loaded"); IndexViewModel vm = new IndexViewModel(); vm.PageTitle.Value = "未命名"; Knockout.ApplyBindings(vm); }); } } }
3、将包中Knockout库文件拷贝到Web项目的Scripts目录中
4、在Index.html文件中添加对Knockout库js文件的引用
<script type="text/javascript" src="Scripts/mscorlib.min.js"></script> <script type="text/javascript" src="Scripts/jquery-1.9.1.js"></script> <script type="text/javascript" src="Scripts/knockout-2.2.0.min.js"></script> <script type="text/javascript" src="Scripts/Scripts.js"></script>
5、在Index.html使用ViewModel,实现数据绑定
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> <script type="text/javascript" src="Scripts/mscorlib.min.js"></script> <script type="text/javascript" src="Scripts/jquery-1.9.1.js"></script> <script type="text/javascript" src="Scripts/knockout-2.2.0.min.js"></script> <script type="text/javascript" src="Scripts/Scripts.js"></script> </head> <body> <h1 data-bind="text:pageTitle"></h1> <button id="btnEdit">修改标题</button> <p> <strong>日志:</strong> </p> <ul data-bind="foreach:logs"> <li>[<span data-bind="text:time"></span>]<span data-bind="text:level"></span><br /><span data-bind="text:message"></span></li> </ul> </body> </html>
需要注意的是,Salarelle编译器在生成js文件时,会自动对C#中的名称转换为js规范,故我们看到在html中,数据绑定时所使用的字段名称都是以小写字母开始。
6、在Html中有个“修改标题”的按钮,我们需要为此按钮增加事件处理函数,这里我们采用jQuery的click事件绑定方式,只需在Main方法、OnDocumentReady中增加以下代码:
jQuery.Select("#btnEdit").Click((s) => { vm.PageTitle.Value = "标题" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); vm.Logs.Value = vm.Logs.Value.Concat(new LogItem() { Level = "信息", Time= DateTime.Now, Message = "修改了标题" }); });
代码很简单,直接修改PageTitle,并向日志列表中添加一项日志。
7、启动调试,单击页面中按钮,执行效果