转:Durandal快速入门

Durandal是一个轻量级的JavaScript框架,其目标是单页面应用(SPAs)的开发变得简单而优雅。它支持MVC、MVP和MVVM等模式,所以不论你采用哪一种类型的前端架构,Durandal都能胜任。css

Durandal以RequireJS为基础,加上一个轻量级的惯例层,带来了使人惊叹的生产效率,而且帮助你维持稳健的编码实践。配上开箱即用的富界面组件、模态对话框、事件/消息、组件、过渡效果、导航等等,使你能够轻松开发出任何你能想象的应用。html

尽管Durandal才发布大约一年时间,但其社区正以飞快的速度成长。前端

所以,咱们推出了一个Kickstarter来帮助咱们在2014年完成一些神奇的事情,但愿你能关注。但如今,我将向你展现如何开发一个简单的Durandal程序。jquery

要开始使用Durandal,能够有多种方式,这取决于你的平台。由于Durandal是一个纯JavaScript库,独立于任何服务端平台,咱们尝试用多种方式来打包,以知足各种Web开发人员。在本教程中,咱们将直接使用HTML Starter Kit。你能够在官方网站上直接下载shell

下载完HTML Starter Kit后,解压缩,你就能够直接在Firefox各版本中打开index.html页面,运行其示例程序了。或者你也能够将其部署到Web服务器中,浏览其index页面。编程

 

Starter Kit演示了一个基本的导航架构,包括导航、页面历史、数据绑定、模态对话框等等。固然,咱们不仅是看看而已,咱们要从头开始写一个小程序。首先打开app文件夹,删除里面的全部内容,而后删除index.html。这样咱们就有了一个空项目,而且预配置了全部必须的scripts和css。json

*注:IE, ChromeSafari可能没法从文件系统中直接打开这类文件。若是你仍但愿使用这些浏览器,能够将其部署到你喜欢的Web服务器中。bootstrap

Index.html
咱们开始编写index.html文件,内容以下:小程序

<!DOCTYPE html> 
<html> 
  <head> 
    <link rel="stylesheet" href="lib/bootstrap/css/bootstrap.css" /> 
    <link rel="stylesheet" href="lib/font-awesome/css/font-awesome.css" /> 
    <link rel="stylesheet" href="lib/durandal/css/durandal.css" /> 
    <link rel="stylesheet" href="css/starterkit.css" /> 
  </head> 
  <body> 
    <div id="applicationHost"></div> 
    <script src="lib/require/require.js" data-main="app/main"></script> 
  </body> 
</html>

咱们看到,文件中只有一些css样式文件,一个id为applicationHost的简单的div, ,一个script标签。咱们加上了BootstrapFontAwesome,使界面看起来美观一些,但它们并非Durandal所必须的。咱们要关注的关键代码是script标签。api

Durandal采用RequireJS做为其核心构件之一,鼓励模块化的编程方式。在Durandal应用中,全部的JS代码都写在模块中。上文index.html中的script标签就是用于加载RequireJS来完成框架的模块策略。当模块加载器完成初始化后,它经过data-main属性的值来启动应用。就像C语言中的main函数同样,data-main属性指向的是主模块,是整个应用的入口。让咱们进行下一步,建立这个模块。首先建立一个名为main.js的文件,把它放到app文件夹下。其代码以下:

main.js 
requirejs.config({ 
  paths: { 
    'text': '../lib/require/text', 
    'durandal':'../lib/durandal/js', 
    'plugins' : '../lib/durandal/js/plugins', 
    'transitions' : '../lib/durandal/js/transitions', 
    'knockout': '../lib/knockout/knockout-2.3.0', 
    'jquery': '../lib/jquery/jquery-1.9.1' 
    }  
}); 
define(function (require) { 
   var system = require('durandal/system'), 
       app = require('durandal/app'); 
   system.debug(true); 
   app.title = 'Durandal Starter Kit'; 
   app.configurePlugins({ 
     router:true, 
     dialog: true 
   }); 
   app.start().then(function() { 
     app.setRoot('shell'); 
   }); 
});

这是一个很是标准的Durandal应用的样板配置。咱们详细地看一下代码。

文件的最上面是requirejs.config代码。这部分代码用于配置模块系统,使其可以找到核心库。配置的都是一些相对路径,所以当咱们引用“jQuery”时,模块系统就知道到哪里去加载它。咱们能够看到,路径的配置包括requirejs的text插件(用于加载视图)、Durandal的核心模块、Knockout和jQuery。Durandal采用RequireJS来构建模块,Knockout用于数据绑定,而jQuery用于浏览器层的抽象。

完成RequireJS的配置后,定义应用的主模块。Durandal应用的全部代码都写在模块中,而且按照如下格式:

define(function (require) { 
  var someModule = require('some/module'); 
  ...other modules required here... 
  return someValue; 
});

咱们用define函数来建立一个模块。它的参数是另外一个函数,这个函数是模块的工厂。也就是说,这个函数的返回值将是模块的一个实例。当函数返回一个对象时,你能够建立单例对象模块。或者返回一个函数,你能够建立一个类构造器模块。另外,你也能够声明该模块依赖于其余模块,此时你须要使用require函数来引入其余模块。

在上面的主模块代码中,你能够看到咱们引入或者说require了两个Durandal模块:systemapp。而后经过system模块开启框架的调试功能,经过app模块设置应用的标题,加载两个可选的插件。最后,咱们调用start方法启动应用。该方法是一个异步的动做,当它结束时,调用一个特殊的方法:setRoot

setRoot方法被调用时,才会真正去展现页面。你能够将root视为应用的主窗口、主布局或者应用的shell。该方法的参数指向一个包含shell的行为的模块。如今惟一的问题是,嗯,它还不存在。好吧,咱们开始建立它。

Shell

Durandal的大部组件都同时包含行为(behavior)和展示(presentation)。你的应用的shell毫无疑问也遵循这个规则。咱们将经过两个文件来展现这两个不一样的概念:一个是用于行为的JavaScript文件,另外一个是用于展示的HTML文件。在app文件夹下建立:shell.jsshell.html两个文件的代码以下所示,咱们来看看它们是如何工做的。

shell.js 
define(function (require) { 
  var app = require('durandal/app'), 
      ko = require('knockout'); 
  return { 
     name: ko.observable(), 
     sayHello: function() { 
       app.showMessage('Hello ' + this.name() + '! Nice to meet you.',
 'Greetings'); 
     } 
   }; 
}); 
shell.html 
<section> 
  <h2>Hello! What is your name?</h2> 
  <form class="form-inline"> 
    <fieldset> 
       <label>Name</label> 
       <input type="text" data-bind="value: name, valueUpdate:
 'afterkeydown'"/> 
       <button type="submit" class="btn" data-bind="click: sayHello, enable: 
name">Click Me</button> 
    </fieldset> 
  </form> 
</section>

首先看看shell.js,正如咱们以前讲到的,它定义了一个模块。同时它还依赖两个别的模块:appknockout。从代码能够看出,模块返回了一个对象。这个对象有一个name属性和一个sayHello方法。属性name看起来有点特别,它是咱们使用Knockout建立的一个可被观察的(observable)属性。可被观察的(observable)属性支持数据到html的双向绑定,变动通知和一些其它特性。注意看sayHello中调用了app模块的方法来显示一个包含name属性值的消息对话框。

要彻底理解这些代码,你应该将它与HTML代码放到一块儿来看。注意观察HTML中的data-bind属性。该属性将HTML与模块中的属性和方法联系起来。例如input标签经过data-bind属性将它的值与name属性链接起来的。它同时还指定,当key down事件发生时,属性name的值将被更新(若是不指定事件,则默认光标离开时会进行更新)。一样地,按钮的click事件绑定了sayHello方法,并且仅当name属性的值为真时,按钮才是有效状态。看起来是否是很酷?如今就把应用运行起来,你能够用Firefox打开index.html,或者若是你使用其余浏览器的话,能够部署到Web服务器下而后浏览index.html。当页面打开时,会经历如下这些步骤:

  1. 加载RequireJS。
  2. RequireJS将加载main.js,而后配置框架。
  3. main.js调用setRoot展现整个应用。
  4. 加载shell.jsshell.html,绑定数据,而后注入到页面的applicationHost div中。

当页面加载完成后,在输入框中试着输入一些内容,观察按钮的有效性是如何变化的,而后点击按钮看看发生了什么。

导航

上面的例子看起来不错,但大多数应用都不仅有一页。因此,咱们开始下一步,将它扩展成具备页面导航的应用。首先,把shell.js更名为home.jsshell.html更名为home.html。而后建立两个新文件shell.jshome.js用于导航。如下是两个新文件的代码:

shell.js 
define(function (require) { 
  var router = require('plugins/router'); 
   
  return { 
     router: router, 
     activate: function () { 
       router.map([ 
         { route: '', title:'Home', moduleId: 'home', nav: true } 
       ]).buildNavigationModel(); 
       return router.activate(); 
     } 
   }; 
}); 
shell.html 
<div> 
 <div class="navbar navbar-fixed-top"> 
  <div class="navbar-inner"> 
   <ul class="nav" data-bind="foreach: router.navigationModel"> 
    <li data-bind="css: { active: isActive }"> 
     <a data-bind="attr: { href: hash }, html: title"></a> 
    </li> 
   </ul> 
   <div class="loader pull-right" data-bind="css: { active: 
router.isNavigating }"> 
     <i class="icon-spinner icon-2x icon-spin"></i> 
   </div> 
  </div> 
 </div> 
 <div class="container-fluid page-host" data-bind="router: { 
transition:'entrance' }"></div> 
</div>

能够看到,shell.js仍然是模块的标准定义方式。首先require了一个router插件,利用它建立对象。咱们配置了一个route指向home模块。router配置中指定了每一个route匹配的模式、显示的标题、对应加载的moduleId,以及route匹配时,是否应该将此route显示到导航栏中(nav:true)。配置完成后,调用buildNavigationModel。该方法利用route信息,构建一个特殊的集合,这个集合经过数据绑定,能够用来显示页面顶部的导航栏。最后,咱们激活这个router。全部这些都发生在activate方法中。每次Durandal向屏幕展示一个组件时,它都会查找可选的activate回调方法。若是找到,就会在数据绑定前调用此方法。所以这种方式容许你执行自定义的激活代码,例如上面的例子在activate方法中配置应用程序的router。

若是把模块和视图的代码放到一块儿,此次你应该很容易理解它们是如何工做的了。首先绑定navigationModel属性,生成一个导航栏navbar。每个可导航的route被转换成一个li标签,其中包含一个连接。连接的标题对应title,地址对应hash。同时,在navbar中还包含了一个spinner动画图标,并将其与router.isNavigating属性进行绑定。当应用从一个页面导航到另外一页面时,咱们就能看到一个spinner动画图标。

在html文件的最下方有一个特殊的router绑定,也就是链接模块中的router。它扮演占位符的角色,用于显示当前页面。属性transition表示当页面发生变化时,Durandal要使用“entrance”过渡动画。

如今将它运行起来。它看起来跟以前差很少,除了在顶端多了个导航栏。由于如今仍然只有一个页面,所以没有什么使人印象深入的东西。咱们开始建立第二个页面,以便可以在页面间前进或后退。

第二页:雷尼尔峰

咱们建立的第二个页面将调用Flickr,获取一组雷尼尔峰的照片并进行展现。首先修改shell的router配置,增长另外一个route,这样它就有了两个route:

{ route:'', title:'Home', moduleId:'home', nav:true }, 
{ route:'rainier', title:'Mount Rainier', moduleId:'rainier', nav:true }

第一个是咱们以前的home route,第二个是新的route用于即将建立的新页面。这时候,但愿你已经知道应该怎么作了。咱们为新页面建立一个模块(module)和一个视图(view)。

rainier.js 
define(function (require) { 
  var http = require('plugins/http'), 
      ko = require('knockout'); 
  var url = 'http://api.flickr.com/services/feeds/photos_public.gne'; 
  var qs = {  
    tags: 'mount ranier',  
    tagmode: 'any',  
    format: 'json'  
  }; 
  return { 
     images: ko.observableArray([]), 
     activate: function () { 
       var that = this; 
       if (this.images().length > 0) { 
           return; 
       } 
      
       return http.jsonp(url, qs, 'jsoncallback').then(function(response) { 
          that.images(response.items); 
       }); 
     } 
   }; 
}); 
rainier.html 
<section> 
  <h2>Mount Rainier</h2> 
  <div class="row-fluid"> 
    <ul class="thumbnails" data-bind="foreach: images"> 
      <li> 
         <img style="width: 260px; height: 180px;" data-bind="attr:
 { src: media.m }"/> 
      </li> 
    </ul> 
  </div> 
</section>

我想你已经可以看出来它是怎么工做的了。新模块在activate回调方法中使用http插件调用Flickr的api去获取图片。而后将数据保存到images属性中。Images是一个可被观察的(observable)数组,页面绑定这个数组并展现图片。

将应用运行起来,能够看到在导航栏中出现了两项,你能在二者间进行前进和后退操做。你也可使用浏览器的返回按钮。Durandal能作的事情远不止这些。也许你该下载Starter Kit并仔细研究,就会发现一些更有趣的东西。又或者你应该将官方的示例程序下载下来,看看各类功能是如何工做的,例如发布/订阅消息、自定义模态对话框、组件、高级的视图组合等等。若是你想看一些更酷的东西,能够看看Kickstarter资助的系列培训中咱们将构建的应用。

Durandal经过模块化的方法,使得构建富客户端,动态的JavaScript应用更加简单。所以理所固然地,咱们的社区发展得很是快。咱们的计划才刚刚开始,但愿你也能加入咱们的奇妙旅程。请浏览一下咱们的Kickstarter。2014年咱们已经有了一些很酷的目标,同时,也有一些很是棒的奖励给你。Web正在发生改变,光明的将来指日可待,但愿咱们在那里相逢。

相关文章
相关标签/搜索