65.9K
CodeProject 正在变化。 阅读更多。
Home

集成 Knockout、JSRender 和 Twitter Bootstrap 与 MVC4

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (2投票s)

2012年7月9日

CPOL

3分钟阅读

viewsIcon

63183

downloadIcon

1212

如何在 MVC4 中将 JSRender 模板与 knockout.js 一起使用

引言

MVC 框架 毫无疑问地 改变了我们现在编写 Web 应用程序的方式,实现了表示层、数据和逻辑的清晰分离。

通过 HTML5/CSS3 和 jQuery,我们可以看到客户端实现的显著转变。

JSRender 和 Knockout 等新库为客户端代码带来了更多的关注点分离。

在这篇简短的文章中,我想展示一个关于我如何实现 MVC4、JSRender 和 Knockout 集成的示例。

背景

此代码主要用于展示客户端技术,以解耦您的数据与视图。我只会使用控制器来模拟从存储库检索数据。

准备您的解决方案

  1. 创建一个新的 MVC 4 应用程序
  2. 使用 NuGet 添加以下程序包
    1. jQuery
    2. Knockout
    3. Autofac
    4. Twitter Bootstrap
  3. 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 调用数据后加载模板。 

指向最新版源代码项目的链接此处

© . All rights reserved.