集成 Knockout、JSRender 和 Twitter Bootstrap 与 MVC4





4.00/5 (2投票s)
如何在 MVC4 中将 JSRender 模板与 knockout.js 一起使用
引言
MVC 框架 毫无疑问地 改变了我们现在编写 Web 应用程序的方式,实现了表示层、数据和逻辑的清晰分离。
通过 HTML5/CSS3 和 jQuery,我们可以看到客户端实现的显著转变。
JSRender 和 Knockout 等新库为客户端代码带来了更多的关注点分离。
在这篇简短的文章中,我想展示一个关于我如何实现 MVC4、JSRender 和 Knockout 集成的示例。
背景
此代码主要用于展示客户端技术,以解耦您的数据与视图。我只会使用控制器来模拟从存储库检索数据。
准备您的解决方案
- 创建一个新的 MVC 4 应用程序
- 使用 NuGet 添加以下程序包- jQuery
- Knockout
- Autofac
- Twitter Bootstrap
 
- 从 https://github.com/BorisMoore/jsrender/ 下载 Jsrender
添加对新依赖项的引用
在 Web 项目的 App_Start 目录下,使用 BundleConfig.cs 注册 bootstrap 文件
bundles.Add(new StyleBundle("~/Content/bootstrap/css"));
bundles.Add(new ScriptBundle("~/bundles/bootstrap/js").Include("~/Scripts/bootstrap.js"));
bundles.Add(new ScriptBundle("~/bundles/custom").Include("~/Scripts/knockout-2.1.0.js",	"~/Scripts/jsRender.js"));
bundles.Add(new ScriptBundle("~/bundles/demo").Include("~/Scripts/demo.js"));  
在 _Layout.cshtml 中注册这些捆绑包
@Styles.Render("~/Content/themes/base/css",
"~/Content/css", "~/Content/bootstrap/css") @Scripts.Render("~/bundles/modernizr")
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/custom")
….
@Scripts.Render("~/bundles/bootstrap/js")
JsRender
JsRender 是 jQuery 模板的新替代品。
Boris Moore 的更多示例:此处。
JSRender 的优势在于它比 jQuery 模板快得多,并提供了清晰的关注点分离。
在此示例中,我使用外部文件模板以实现更好的分离。JSRender 模板可以位于同一页面中,位于 <script id='myTemplate' type='text/x-jsrender'></script> 标签内。
在文件中使用模板的优势在于,模板可以更轻松地在不同页面上重复使用。
问题是 JSRender 如何找到要渲染的模板。
在我的示例中,我有一个 demo.js 文件,其中包含两个函数:.getPath 和 .renderTemplate: 它们会查找 Templates/HTML/ 文件夹。
getPath 函数使用命名约定来解析文件名,renderTemplate 函数加载文件 "_“ + name +”.tmpl.html”。
jQuery 的 .get() 函数将读取文件并将上下文加载到内存中,然后渲染模板并使用 Knockout.js 绑定数据。
Knockout.js 用于提供 MVVM 模式,触发绑定并刷新模板。
创建 JSRender 模板
首先,我将添加一个没有任何数据绑定的模板。
在 Web 项目中添加新文件夹 Templates/HTML
添加新的 HTML 文件
- _home.tmpl.html
- _head.tmpl.html
- _contacts.tmpl.html
删除新文件中的所有内容。
_header.tmpl.html 内容
<p>
To learn
more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">
Bla … bla… bla 
</p>
_home.tmpl.html 内容
<h3>We suggest the following:</h3>
<ol class="round">
    <li class="one">
        <h5>Getting Started</h5>
        Bla … bla… bla
</ol>
将 JSRender 模板绑定到视图
现在,我们将外部文件中的简单 jsrender 模板绑定到 Index.cshtml 视图中加载。
为了在 Index.cshtml 视图页面上显示模板,我们需要添加自定义脚本以与 knockout 库绑定。
我们将使用两个不同的 DIV 进行数据绑定:一个用于标题,一个用于正文。
Index.cshtml 应如下所示
@{
    ViewBag.Title = "Home Page";
}
@section featured {
    <section class="featured">
        <div class="content-wrapper">
            <hgroup class="title">
                <h1>@ViewBag.Title.</h1>
                <h2>@ViewBag.Message</h2>
            </hgroup>            
        </div>
    </section>
}
@Scripts.Render("~/bundles/demo")
<div data-bind="html: demo.head.headHtml" id="headHtml"></div>
<div data-bind="html: demo.body.bodyHtml"></div>
请注意本例中使用的命名空间 – demo。
创建自定义脚本
我将使用我们之前创建的自定义脚本文件来指定我们要加载的模板。这是一个通用函数,在异步读取模板文件完成后将使用异步进程渲染模板。
我们添加以下代码:
var demo = demo || {};
 
$(function() {
    demo.utils = function () {
        var getPath = function (name) {
            return "../Templates/HTML/_" + name + ".tmpl.html";
        };
 
        var renderTemplate = function (item) {
            var file = getPath(item.name);
            $.when($.get(file))               
		.done(function (tmplData) {
                    $.templates({ tmpl: tmplData });                   
		    item.selector($.render.tmpl(item.data));                    
                });
        };
        return {
            getPath: getPath,           
	    renderTemplate: renderTemplate
        };
    }();
});
我正在使用递归模式,其中函数会调用自身(注意函数末尾的 ())。
现在,为首页声明我们的 UI 视图模型,这可以放在单独的文件中,但为了简单起见,我将重用我们的 demo.js 文件。
现在我们可以将我们的模型添加到 demo.js 文件中。
 $(function() {
    demo.head = function() {
        var headHtml = ko.observable(),
            loadTemplate = demo.utils.renderTemplate({
                name: "head",
                data: "",
                selector: headHtml
            });
        return {
            loadTemplate: loadTemplate,
            headHtml: headHtml
        };
    }();
    demo.body = function() {
        var bodyHtml = ko.observable(),
            loadTemplate = demo.utils.renderTemplate({
                name: "home",
                data: "",
                selector: bodyHtml
            });
        return {
            bodyHtml: bodyHtml,
            loadTemplate: loadTemplate
        };
    }();
demo.contacts = function() {
        var 
            contactHtml = ko.observable(),
            loadContacts = function() {
                $.ajax({
                    url: '/Home/LoadContacts',
                    type: "POST",
                    /*contentType: "application/json; charset=utf-8",*/
                    dataType: 'json',
                    success: function(d) {                        
                        demo.utils.renderTemplate({
                            path: "../",
                            name: 'contacts',
                            data: d,
                            selector: contactHtml
                        });
                    }
                });
            };
        return {           
            contactHtml: contactHtml,
            loadContacts: loadContacts
        };
    }();    
    
ko.applyBindings(demo.head);
ko.applyBindings(demo.body);
demo.contacts.loadContacts(); // Get data before binding template
ko.applyBindings(demo.contacts);
    
});
此时,如果我们运行应用程序,应该看不到原始 MVC 主页与我们自定义的主页之间的任何区别。
现在,我们想添加一个 JSRender 视图,它将绑定真实数据,而这些数据将来自服务器端。我们将通过 AJAX 调用检索数据。
打开 Contacts.cshtml 并修改它。它应该如下所示
@{
    ViewBag.Title = "Contacts";
}
<hgroup class="title">
    <h1>@ViewBag.Title.</h1>
    <h2>@ViewBag.Message</h2>
</hgroup>
@Scripts.Render("~/bundles/demo")
<div data-bind="html: demo.contacts.contactHtml" id="headHtml"></div>
为了从控制器加载数据,我们将添加一个新的 AJAX 调用。
打开 HomeController.cs 并添加以下代码
[HttpGet]
public JsonResult LoadContacts()
{
	var contacts = new List<Contact>
					   {
						  new Contact {fn = "Ben", ln = "Doe", title = "Developer", 
						               email = "myemail@code.com", phone = "888-555-6565"},
						  new Contact {fn = "John", ln = "Smith", title = "Boss", 
						               email = "boss@code.com", phone = "888-555-7777"}
					   };
	return Json(contacts);
}
您还需要创建一个简单的 Contact 类
public class Contact
{
	public string FirstName { get; set; }
	public string LastName { get; set; }
	public string Title { get; set; }
	public string Phone { get; set; }
	public string Email { get; set; }
}
在我们的 demo.js 文件中,我们需要修改模板绑定,并在收到 AJAX 调用数据后加载模板。
指向最新版源代码项目的链接:此处。


