the game is on简谱:Dojo Tips and Tricks - InsideRIA

来源:百度文库 编辑:偶看新闻 时间:2024/04/19 11:03:47

This article provides 10 tips and best practices (in no particularorder) for maximizing the benefits that Dojo can bring to your nextproject. For a more thorough introduction to Dojo, see the article Dojo:The JavaScript Toolkit with Industrial Strength Mojo or pick up acopy of Dojo: TheDefinitive Guide.

1 - Use AOL's Content Delivery Network to get up and running quickly(利用AOL或者google的js相关服务)

Although you'll likely want to downloadthe entire toolkit at some point, using AOL's CDN is perhaps thesimplest ways to get started. In addition to fostering rapid prototypingby giving you access to the entire toolkit at the cost of inserting aSCRIPT tag, it can also streamline some of the configuration managementfor a project. For example, if you don't want to check a specificversion of Dojo into your own project's repository or don't want torequire other members on your team to have to go through the extra stepsof downloading, configuring, and maintaining a development environmentjust yet, it's the way to go. It works well for dabbling and productionalike.

Here's an example template that loads the latest 1.2 release from theCDN, which comes across the wire gzipped at just under 30KB:



Dojo ala CDN from AOL






Dojo

In short, the dojo.xd.js file is a special XDomain build ofBase, the kernel of the toolkit, and defines the global identifer dojo.On that note, it's a good habit to confine your use of the toolkitwithin the dojo.addOnLoad callback that fires when thetoolkit has loaded in order to prevent race conditions that may arisewhen using an XDomain build.

2 - Use dojo.query for find-it-and-do-something-with-it operations(使用dojo.query查某样东西/做某项操作)

The dojo.queryfunction allows you to provide a CSS selector to findnodes in the DOM and then do something with them. For example, to findall of the hyperlinks on a page, you'd simply do a call to dojo.query("a").The result of a dojo.query operation is a NodeListof DOM elements, and a NodeList is essentially an Arraywith some handy extensions that provide the syntactic sugar of chainingtogether results. For example, consider the following block of code thatfinds all of the hyperlinks in a page with rel attributeof "special", adds a foo class to them and sets up a clickhandler:

dojo.query("a[rel=special]")
.addClass("foo")
.onclick(function(evt) {
console.log("Just added the foo class to the following anchor tag", evt.target);
});

It is also noteworthy that most of the methods provided by NodeList suchas addClass,removeClass,style,and so forth are just simple wrappers around handy utility functionsalready provided by Base. Hopefully, it's not very hard to imagine allof the code you can save yourself from writing and maintaining with afriend like dojo.query in your corner.

3 - Use Deferreds to simplify I/O handling

Any Web 2.0 is undoubtedly going to be performing a lot of servercommunication, so the better the abstraction for handling I/O requests,the better. Dojo provides a godsend called Deferred(originating from MochiKit, which inturn borrowed the concept from Twisted)that provides a uniform interface for handling synchronous andasynchronous requests alike while also eliminating the need to keeptrack of whether or not a request is in flight or already completed.Deferreds provide the basis for Dojo's entire I/O subsystem, so commonlyused functions like dojo.xhrGetreturn Deferreds, although you may not have even realized it. As anexample, consider the following boilerplate for an asynchronous XHRrequest(最初起源于MochiKit,借用的是Twisted的概念。):

var dfd = dojo.xhrGet({
url : "/example",
handleAs : "json", // interpret the response as JSON vs text
load : function(response, ioArgs) {
/* Do something with the response object */
return response;
},
error : function(response, ioArgs) {
/* Handle any errors that occur */
return response;
}
});

/* Regardless of the state of the request, the Deferred is available
right now for chaining more callbacks or errbacks. Regardless of
whether the Deferred has already returned, failed, or still in flight,
the dfd still provides the same uniform interface */

dfd.addCallback(function(response) {
/* If the request is successful, this callback fires
after the first one (defined in "load") finishes. Always return the
response so it can propagate into the next callback */
return response;
});
dfd.addErrback(function(response) {
/* Likewise, this would be the second errback to fire
(right after the one defined in "error") if something goes awry. */
return response;
});

With Deferreds, life becomes considerably more simple when doing lots ofI/O because you have to do very little thinking. Just make a request,and then add callbacks and errbacks whenever you need to. The status ofthe request has no bearing on the way you treat the Deferred that'sreturned to you.

4 - Use dojo.data to work with "local" data(操作本地数据)

While functions like dojo.xhrGet make it easy tocommunicate with the server on a per-request basis, the dojo.datamodule takes streamlining interaction with server-side data sets to awhole new level by providing you with the abstraction of a data storethat implements a robust API for reading, writing, and handling eventsas they occur on data items. While the dojox.datamodule includes many full blown implementations of useful stores forinteracting with Google web services, OPMLdata, Wikipedia, and lots more, a basic demonstration of the ItemFileWriteStore,which implements all four of the dojo.dataAPIs (Read, Identity, Write, and Notification) should give you agood idea of how this works.

/* Assuming you wanted to plug this example into the template
for using AOL's CDN, recall the importance of confining
the use of the toolkit to the dojo.addOnLoad block */
dojo.require("dojo.data.ItemFileWriteStore");

dojo.addOnLoad(function() {

/* Create a store with inline JavaScript data. We could have
fetched the exact same data just as easily from a server
by passing in a url to the ItemFileWriteStore constructor */
var store = new dojo.data.ItemFileWriteStore({
data : {
identifier : "id",
items : [
{"id" : 1, "label" : "apple"},
{"id" : 2, "label" : "banana"},
{"id" : 3, "label" : "orange"}
]
}
});

store.onNew(function(item) {
/* Callback for doing something whenever an item is added */
});

store.onDelete(function(item) {
/* Callback for doing something whenever an item is deleted */
});

/* Add an item to the store - a synchronous operation */
store.newItem({"id" : 4, "label" : "pear"});

/* Fetch the pear - an asynchronous operation */
store.fetch({
query : {label : "pear"}, //The Identity API also allows for querying by identifier
onItem : function(item) {

/* Do something with the item, like delete it - a synchronous operation */
store.deleteItem(item);

/* Save the results */
store.save();

/* A call to store.revert(); can revert a store to its last saved state */
}
});

});

While just a glimpse of what dojo.data can do, youhopefully get a idea of how convenient it can be to write applicationlogic that leverages about a local data store (or at least theappearance of one) that conforms to a set a well-defined APIs versusstore you had to hack together yourself or no store at all.

Encapsulate reusable UI components into widgets

Dojo provides extensive machinery for building widgets. In short,anything that descends from dijit._Widgetis a "dijit" (a Dojo widget) where dijit._Widget itself builds upon thebasis provided by dojo.declarefor simulating class-based inheritance. To oversimplify things a bit, dijit._Widgetprovides an infrastructure and lifecycle hooks for achieving specificfunctionality during the creation and destruction; dijit._Templatedfurther builds on what is provided by dijit._Widget totrivialize the effort required to give a widget a visible DOMmanifestation. All of Dijit, Dojo's trove of accessible turn-key widgets,builds upon this fabric, so you're in good company if you use it tobuild your own widgets.

For a very minimal widget example that exposes just a bit of thisfabric, consider the following example widget that would be encapsulatedinto a file called Dog.js enclosed in a folder named example ,which maps the namespace and name of the widget:

/* Enable consumers of the widget to dojo.require it */
dojo.provide("example.Dog");

/* Pull in infrastructure */
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");

/* "Inherit from" _Widget and _Templated to provide a widget */
dojo.declare("example.Dog", [dijit._Widget, dijit._Templated], {

templateString : '<div dojoAttachPoint="messageNode"></div>',

message : '',

postCreate : function() {

/* The dojoAttachPoint attribute in markup makes "messageNode"
available as a property of "this" widget */
this.messageNode = message;
}
});

Dynamically creating the widget and inserting it into the page may bedone by simply passing in any applicable construction properties and theID of a node on the page:

var _widget = new example.Dog({message : "Ruff, ruff."}, "someExistingNodeID");

Alternatively, you could omit the node ID and use the resulting _widgetobject's domNode property to insert it into the page:

var _widget = new example.Dog({message : "Ruff, ruff."});
dojo.body().appendChild(_widget.domNode);

In order to include the widget in an HTML page and have it automaticallyparsed and rendered on page load, you would need to pass in some flagsto djConfigto specify that the page should be scanned for widgets specified by dojoTypetags and automatically parsed as well as provide a base URL and paththat maps the example namespace to a physical disk path(relative to the containing HTML document.)



Parsing Custom Widgets on Page Load (with XDomain)









Use dijit.Declaration for markup-driven development

Although the norm is to create widgets in JavaScript code, dijit.Declarationprovides the ability to accomplish the very same things in markup.While this approach can be great for prototyping even if you are aJavaScripter, designers may prefer a markup-driven approach all of thetime simply because it may seem more natural and less cumbersome. Thegeneral idea behind dijit.Declaration and markup-drivendevelopment with Dojo is pretty intuitive: you create a DOM structurefor the widget and then use dojo/method and dojo/connectSCRIPT tags to define, connect to, or override methods. Here's a verysimple example adapted from Dojo:The Definitive Guide that illustrates the concept.

 

Markup-driven Development with dijit.Declaration

rel="stylesheet"
type="text/css"
href="http://o.aolcdn.com/dojo/1.2/dojo/resources/dojo.css">











dojoType="dijit.Declaration"
widgetClass="dtdg.HelloWorld"
defaults="{greeting:'Hello World'}">

${greeting}








The example does nothing more than present a "Hello World" messageenclosed in a node that responds to mouse events to providehighlighting, but hopefully, it gives you the general idea of how you'dgo about implementing a design. Note that inside of dojo/methodtags, you can reference the enclosing widget through the keyword thisjust like you would in methods that are defined in JavaScript.

At first thought, this approach seems to do little to encourage codereuse since you don't end up with a collection of reusable JavaScriptfiles, but it's totally conceivable that you could create a robustsystem that consolidates markup-driven widgets into physical templatesor isolated PHP files. The technique of designing widgets with dijit.Declarationis perhaps one of the most overlooked aspects of the toolkit, which isunfortunate given how much it can lower the barrier for designers andprogrammers.

Skin your widgets with themes(给所用的部件使用皮肤)

Dijit comes packed with three great looking themes out of the box: Tundra,Soria,and Nihilo.(The previous links take you to Dijit's theme tester where you canexplore the skins for yourself.) In case you're wondering, Tundra'sinspiration is the tundra landscape and exhibits light blue and greyhues, Soria is predominantly a glossy looking blue on blue theme(rumored to have been inspired from a view of the sky taken aroundSoria, Spain), and Nihilo (playing off of the  ex nihiloconcept) is an extremely minimalistic theme with thin grey outlines and atouch of blue and yellow.

Putting a baked in theme to work is as simple as including theappropriate CSS files and declaring a class on the BODY tag. Forexample, the following example applies Soria to the page. Using Tundraor Nihilo would simply entail doing a global replacement of the word"soria" to "tundra" or "nihilo".


Buttons styled with Dojo's Built-in Themes




Putting Built-in Dijit Themes To Work


rel="stylesheet"
type="text/css"
href="http://o.aolcdn.com/dojo/1.2/dojo/resources/dojo.css">



rel="stylesheet"
type="text/css"
href="http://o.aolcdn.com/dojo/1.2/dijit/themes/soria/soria.css">









A Soria Button


Use gfx for two-dimensional cross-browser drawing(跨浏览器的2维绘图部件)

The dojox.gfxis a really nice piece of engineering and popular subproject of DojoX, arich ecosystem of specialized and experimental subprojects. gfx(pronounced "graphics" or "g-f-x") module exposes a common 2D drawingAPI that is loosely based on  SVGand comes stock with several back end implementations that cover all ofthe common bases. For Firefox or Safari, an SVG back end is used fordrawing; in Internet Explorer  VML is the default,but Silverlight may be used if it is available; a  canvasimplementation is also provided. Other back end renderers such as Flashcould be implemented as well if someone wanted to take a bit of time tohack out the Flash-JavaScript bridge and implement the API. Regardless,the great thing about gfx is that since you're programmingagainst a uniform API, code you write is portable and will "just work"on any modern browser that it runs on.(dojox.gfx是dojox的一个子项目,目前更多的是试验性。基于SVG,后端根据各个浏览器而不同,比如firefox safari,使用的是svg;ie默认使用vml,需要silverlight;html5之后,会变得相同,都使用canvas标签。……)

The following example introduces some of the API with self-descriptivedrawing operations. Although this example doesn't illustrate arbitrary3x3 matrix operations, the gfx API does provide the abilityto manipulate arbitrary 3x3 matrices, so you have full spectrum controlover the rotation, translation, and scaling of objects that you draw.



2D Drawing with dojox.gfx








A very small sampling of some basic shapes drawn with dojox.gfx

The next time you're faced with the task of visualizing some data,consider giving gfx a shot before resorting to Flash. Or atleast know that you have the option if you want it.

Use the DataGrid to display large data sets without pagination(无分页,逐步载入大数据)

Although paginating large data sets has become somewhat of anestablished pattern in the unwritten web development handbook, it's notreally the most appealing interface from the standpoint of a user. Onthe desktop, you just scroll through large data sets most of the time,so why should your web experience have to be any different? Fortunately,the Ajax revolution has provided options for killing pagination dead,and Dojo's terrific DataGridwidget gives it to you as a built-in luxury that you'll soon be takingfor granted.(桌面上,比如doc文件,只需要滚动,而没有分页。当然,坏处就是无法快速定位到所需的页面了)

Employing the DataGrid is drastically simpler than it wasback in the 1.1, so if it's been a while since you've taken a look atthe grid, you're in for a real treat. For most scenarios, you simplypoint the grid to one of the many stores that implement the dojo.dataAPIs, specify a minimal configuration and you're done. Most of this canbe accomplished in markup, so there's very little learning curve to get abasic grid up and running. The following example illustrates:



Employing the DataGrid Dojo Widget

















A few rows loaded into Dojo's DataGrid

In short, you give the grid a store along with a layout that provides amapping of fields in the store to column names, and that's it. Onceconstructed, the DataGrid provides fairly fine-grainedcontrol over managing the selection, firing event handlers when cellsare clicked, and even editing data in the grid. After all, the grid isreally nothing more than an extremely fancy view on top of some data.

Use the build system to improve performance(使用构建系统来提升性能)

For development, it's great to be able to throw in a dojo.requirestatement and slurp in resources when you need them. Unfortunately,however, each of those dojo.require statements incur around trip to the server, and the latency really adds up -- especiallyfor non-trivial applications with lots of JavaScript goodness inside.Dojo's build system provides the ability to create what's known as a"build profile" that allows you to specify layers for your applicationand create a consolidated JavaScript file that is a conglomerate of allof the various module dependencies on the page.

For example, if you had an application with two primary views that eachhad their own dependencies on various Dojo resources, you could use thebuild system to generate a single JavaScript file that roll up those allof those dependencies. The end result is that you may end up with asfew as two I/O request for JavaScript files for each "layer" in yourapp: one for dojo.js and one for your layer file. While it'stechnically possible to roll up Base (all of the stuff in dojo.js )into a layer file, it's usually not advantageous to take this approachsince dojo.js is a dependency for any layer file you'd createand can almost always be cached after the first time it is downloaded.

But that's not all. The build system can also minify your JavaScriptcode by running it through ShrinkSafe.Basically, "minifying" JavaScript code means reducing overall file sizeby doing things like replacing symbol names with shorter symbol namesand eliminating whitespace in the code. While the concept may sounddeceptively simple, the end result can make quite a difference on theuser experience. While the build system offers a vast number of otheruseful options that can be rather overwhelming, the most common usage isto simply define a build profile that ensures that the JavaScript codeis run through ShrinkSafe, the CSS files are consolidated, and templatestrings are interned.

Consider the following simple build profile bundled with the toolkit andlocated at util/buildscripts/profiles/fx.profile.js , whichspecifies a layer that bundles up some handy animation utilities thattake advantage of dojo.fx.

dependencies = {
layers: [
{
name: "../dojox/fx.js",
dependencies: [
"dojo.NodeList-fx",
"dojox.fx.ext-dojo.NodeList",
"dojox.fx",
"dojo.fx.easing"
]
}
],

prefixes: [
[ "dijit", "../dijit" ],
[ "dojox", "../dojox" ]
]
};

To deconstruct that a bit, the profile specifies that a layer named fx.jsshould be produced (which will be created in the top level dojoxfolder), which rolls up everything in the the dojo.NodeList-fx,dojox.fx.ext-dojo.NodeList,dojox.fx,and dojo.fx.easingmodules.

Before you can actually put that profile to work, however, you shouldactually know that in order to get the build tools, you'll need to checkout the code from Subversion because the build tools aren't included ina typical download. Therepository can be found at http://svn.dojotoolkit.org/src/,and if you wanted to check out the entire toolkit, you'd want toexecute the following command, which uses svn externalsto simplify matters a bit:

http://svn.dojotoolkit.org/src/view/anon/all/trunk/.

After downloading the build tools, you might invoke the build.shor build.bat scripts as follows:

bash build.sh optimize=shrinksafe action=release profile=fx releaseName=fx cssOptimize=comments copyTests=false

Invoking build.sh or build.bat script withoutany arguments provides a complete list of options, but in short, theexample given produces build of the toolkit that includes a minifiedversion of everything in dojo.* and dojox.*along with a layer file called fx.js that "rolls" up thedependencies outlined in the build profile.

Beyond

There's only so much ground to be had in a short article, so be sure topick up a copy of Dojo:The Definitive Guide for more complete coverage of the toolkit. Inthe meanwhile, why not downloadDojo and put some of this newly found knowledge to work.