使用客户端框架实现单个页面应用程序: Durandal

分享于 

15分钟阅读

Web开发

  繁體 雙語

介绍

如 NAME 所建议的,它是一个应用程序所有应用程序的所有相关页面都在单个网页上。 换句话说,所有必要的资源( 如html页面。样式表。java脚本文件) 在第一次请求后加载到浏览器中,并在请求时呈现。

市场上有许多框架可以用来构建 to,但本文中我们将介绍Durandal的to框架。

Durandal: -

简而言之,它是不同标准java脚本库的组合,比如 Knockout。RequireJS。jQuery,帮助我们构建更少的时间。响应性更好的用户体验,从而更好地体验用户体验。

背景

当我是 implementaing,框架时,面对视图模型。knockout.js。require.js, css等视图配置问题。 然后找到 durandal,它提供了所有nacessary配置,这些配置需要启动一个新项目,而不需要大量工作。

实现

通常,客户端数据模型连接到服务层,用Ajax调用来发送和接收JSON数据。

在本演示中,我们不会触摸任何服务器端组件;而是完全关注客户端组件。

实现摘要:

将使用子菜单选项制作简单菜单控件;这将在每个子菜单上动态加载视图,单击。

要学习:-

  • 将Durandal框架导入Web应用程序。
  • 创建视图和视图模型。
  • 将视图绑定到相应的视图模型。
  • 使用动态数据绑定视图和视图模型。
  • 必要时动态加载视图。
  • 单个页面进行交互以查看不同的内容。

设置解决方案。

Create创建解决方案 NAME Demo.SPA. 解决方案。

添加新项目 ASP.NET Web应用程序并选择 empty- mvc模板

https://www.codeproject.com/KB/scripting/1069988/Sol1.png

解决方案将如下所示:

https://www.codeproject.com/KB/scripting/1069988/Sol2.png

向web应用程序添加 Durandal starter

https://www.codeproject.com/KB/scripting/1069988/D3.png

它将添加一些额外的文件夹,如应用程序。AppViews。AppViewModels和依赖文件 durandalconfid.cs, durandalbundle。config。DurandalController

我的解决方案将显示为

https://www.codeproject.com/KB/scripting/1069988/D4.png

https://www.codeproject.com/KB/scripting/1069988/D5.png

注意:- shell.js 下的- 将用于定义路由。

Step4。生成并运行解决方案

由于durandalController是默认控制器,因此浏览url以

http://localhost:XXXX/durandal

网页将显示为

https://www.codeproject.com/KB/scripting/1069988/D6.png

欢迎和闪烁选项卡带有默认的durandal框架

要删除这个 tabe,你需要对 shell.js. 中的below 行进行注释


{ route: '', title:'Welcome', moduleId: 'viewmodels/welcome', nav: true },



{ route: 'flickr', moduleId: 'viewmodels/flickr', nav: true }




使用代码

正向我们的示例应用程序前进。

Step5。添加视图( home.html, menu.html, productlist.html, productdetails.html, addnewproduct.html ) inside 应用程序/视图文件夹

用与html相同的NAME 添加 viewmodels,以为单位( 例如: home.js, menu.js.。) inside 应用程序/viewmodels文件夹。

由于我们不包括任何服务器端实现,我已经创建了一个名为存储库的文件夹,它负责数据部分的处理。

内部存储库文件夹创建了两个JS文件 NAME BookRepository.js 和 MenuRepository.js

脚本文件夹中有创建 globaldata.js 文件,在这里我将声明全局范围变量

并使用以下行将它的绑定到 DurandalBundle.config.cs 文件





Include("~/Scripts/globaldata.js")



因此我现在的解决方案是

https://www.codeproject.com/KB/scripting/1069988/D7.png

使用代码:

为了得到数据

在 BookRepository.js 和 MenuRepository.js 中,我定义了一些变量和方法,我们将在应用程序。

BookRepository.js





define(function (require) {



 return {



 _books: [



 { id: 0, title: 'The Low Land', writter: 'Jumpa Lahiri', price: '12', description: 'Test low land description' },



 { id: 1, title: 'The Story of time being', writter: 'Ruth Ozeki', price: '13', description: 'Test Story of time being description' },



 { id: 2, title: 'Alchemist', writter: 'Paulo', price: '14', description: 'Test Story of time being description' },



 { id: 3, title: 'The Narrow Road to the Deep North', writter: 'Richard Flanagan', price: '10', description: 'Test Narrow Road to the Deep North description' },



 { id: 4, title: 'Luminaries', writter: 'Eleanor Catton', price: '11', description: 'Test Luminaries description' },



 { id: 5, title: 'Sense of an Ending', writter: 'Julian Barnes', price: '12', description: 'Test Sense of an Ending description' } ],



 listBooks: function () { return this._books; },



 getBooksById: function (id) {



 for (var i = 0; i < this._books.length; i++) {



 if (this._books[i].id == id) {


 return this._books[i];


 break;


 }


 }


 }


 };


});



MenuRepository.js





define(function () {


 return {


 _menusItems: {


 menu: [


 { name: 'Home', link: '0', sub: null },


 {



 name: 'Products', link: '1', sub: [{ name: 'List of Products', sub: null },



 { name: 'Register New Product', sub: null },



 { name: 'Enquiry Product', sub: null }]



 },


 {


 name: 'About US', link: '2', sub: [{ name: '', sub: null },



 { name: '', sub: null }]


 },


 {



 name: 'Contact', link: '3', sub: [{ name: 'Corporate Office', sub: null },



 { name: 'Home Office', sub: null }]


 }


 ]


 },


 menuItems: function () { return this._menusItems; }


 }


})



现在我们要在菜单视图模型中工作

因为我们从 MenuRepository.js, 获取菜单数据以便在菜单视图中获取菜单数据,首先需要加载 MenuRepository,我们将在定义框中声明,如 such。


define(['Repository/MenuRepository'], function (mRepository)



这样我们就可以将 MenuRepository.js的变量和函数访问到这个页面。

我们将存储在 obserbable array 中的菜单数据并将它的绑定到视图。

因此,相应的数据将出现在网络上。

Menu.js


define(['Repository/MenuRepository'], function (mRepository) {


 var menuConstructor = function () {


 var self = this;


 g_menuItemObservable = ko.observable("");


 self.menuItems = ko.observableArray([]);


 self._menus = [];


 self.getMenu = function () {


 self._menus = mRepository.menuItems();


 }


 self.attached = function (view) {


 self.getMenu();


 self.menuItems(self._menus.menu);


 } 


 }


 return new menuConstructor();


})



Menu.html


<div class="menu-style" style=" height:80%; width:70%; margin-left:10%; margin-top:2%;">


 <nav class="navbar navbar-inverse">


 <div class="container-fluid">


 <div>


 <ul class="nav navbar-nav" data-bind="foreach:menuItems">


 <li class="dropdown">


 <a class="dropdown-toggle" data-toggle="dropdown" data-bind="text:name"></a>


 <ul class="dropdown-menu" data-bind="foreach: sub">


 <li data-bind="text:name"></li>


 </ul></li>


 </ul>


 </div></div>


 </nav>


</div>



查看模型遵循某些生命周期。 在这里我使用合成生命周期( 根据我的要求 activateattach )

对于生命周期,请检查 durandal docs.link (http://durandaljs.com/documentation/Hooking-Lifecycle-Callbacks.html)

我们将创建productlsit视图和视图模型的方法

Productlist.js


define(['Repository/BookRepository'], function (repository) {


 var productConstructorViewModel;


 var productConstructor = function () {


 var self = this;


 productDetailObservable = ko.observable("");


 self.products = ko.observableArray([]);


 self._products = []


 self.getProducts = function () {


 self._products = repository.listBooks();


 self.products(self._products);


 };


 self.activate = function (data) {


 self.getProducts();


 }


 self.removeProfile = function (list) {


 if (confirm("Are you sure you want to delete this profile?")) {


 self.products.remove(list);


 }


 }


 self.editProfile = function (list) {


 // Implement your logic


 }


 self.getList = function (data, event) {


 g_productID = data.id;


 $('#divProductdetails').css("display", "block");


 }


 }


 return new productConstructor();


})



Productlist.html


<div><div> 


 <table class="table table-striped table-bordered table-condensed" >


 <tr><th>Title</th><th>Author</th></tr>


 <tbody data-bind="foreach:products">


 <tr><td><a data-bind="text:title"></a></td>


 <td data-bind="text:writter"></td>


 <td><button class="btn btn-mini btn-danger" data-bind="click: function(data, event) {$root.getList(data, event); return true;}">Details</button></td>


 <td><button class="btn btn-mini btn-danger" data-bind="click: $parent.removeProfile">Remove</button></td>


 <td><button class="btn btn-mini btn-danger" data-bind="click: $parent.editProfile">Edit</button></td></tr>


 </tbody>


 </table>


 </div>



现在我要将菜单与家和productlist结合菜单

这里我们使用了一个重要的knockout绑定概念 compose。

Home.js


define([], function () {


 var homeconstructorViewModel;


 homeconstructorViewModel = function () {


 self = this;


 self.menuItemObservable = ko.observable("");


 self.categories = ["Product List"];


 self.productListObservable = ko.observable("");


 self.loadProductList = function (data, event) {


 self.productListObservable({ view: 'views/productlist.html', model: 'viewmodels/productlist' });


 $('#divProducts').css("display", "block")


 }


 $(document).on("click", ".dropdown-menu li", function (e) {


 var ctrl = $(this).text();


 if (ctrl == "List of Products") {


 self.menuItemObservable({ view: 'views/productlist.html', model: 'viewmodels/productlist' })


 }


 if (ctrl == "Register New Product") {


 self.menuItemObservable({ view: 'views/addnewproduct.html', model: 'viewmodels/addnewproduct' })


 }


 })


 }


 return homeconstructorViewModel;


});



Home.html


<div>


 <div style="height:80%; width:70%"><div>


 <div data-bind="compose:{ model:'viewmodels/menu', view:'views/menu.html'}">


 </div> </div> </div>


 <div>


 <div id="divMenuItemBody" style="margin-left:10%; margin-top:2%; width:70%; height:40%">


 <div data-bind="compose: menuItemObservable" style="height:100%;"></div>


 </div> </div>


</div>



这是第二种情况,在第二种情况下,它可以动态地加载视图模型和视图模型,但是在第二种情况下,可以看到任何可见的变量值改变了( 签入 home.js )。

它的余的页面都是通过使用同样的逻辑来设计的,你可以通过下载示例进行检查。

Step8。现在进入路由部分

我想浏览页面加载的主页,以便在 shell.js 文件中将路由定义为 below。


{ route: 'home', title: 'Demo', moduleId: 'viewmodels/home', nav: true }



Points of Interest

在本文中,我们讨论了如何在web应用程序中使用 durandal。

这篇文章是我在头脑中保持初学者的。

希望本文对你有帮助。

源代码

我上传这个示例项目的一些功能 使用本文。 你可以下载这个示例代码,让你对这些概念和实现的理解更加深入。

使用以下url运行 applcation

http://localhost:XXXX/durandal

是运行应用程序的本地系统的端口号。


  IMP  framework  Implementation  SID  SIN  
相关文章