﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-赢在执行-随笔分类-DOJO</title><link>http://www.blogjava.net/Jiangzy/category/26628.html</link><description>这个世界上只有两样东西愈分享愈多,那就是智慧与爱。</description><language>zh-cn</language><lastBuildDate>Sat, 26 Jan 2008 05:59:36 GMT</lastBuildDate><pubDate>Sat, 26 Jan 2008 05:59:36 GMT</pubDate><ttl>60</ttl><item><title>js压缩</title><link>http://www.blogjava.net/Jiangzy/archive/2008/01/25/177858.html</link><dc:creator>飛雪(leo)</dc:creator><author>飛雪(leo)</author><pubDate>Fri, 25 Jan 2008 15:11:00 GMT</pubDate><guid>http://www.blogjava.net/Jiangzy/archive/2008/01/25/177858.html</guid><wfw:comment>http://www.blogjava.net/Jiangzy/comments/177858.html</wfw:comment><comments>http://www.blogjava.net/Jiangzy/archive/2008/01/25/177858.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Jiangzy/comments/commentRss/177858.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Jiangzy/services/trackbacks/177858.html</trackback:ping><description><![CDATA[<p>压缩不仅仅可以提高用户的下载速度，同时还可以加密代码，下面说下一个常用的js压缩方法：</p>
<p>首先使用dojo的工具shrinksafe(http://shrinksafe.dojotoolkit.org/)压缩一下,dojo的这个工具会去掉注释，他的压缩不是简单的替换变量，而是利用了mozilla的一个工具,对js解析后才压缩，确保压缩后的代码不会出错。</p>
<p>dojo压缩后，并不会减少太多，下一步可以使用http://javascriptcompressor.com/这个站点进行更高层次的压缩,可惜只能登陆这个站点再压缩，只能将你的js代码复制的他的文本框，然后等他的压缩输出</p>
<p>经过这2步，你的js会变得既安全,文件又小 <br />
</p>
<img src ="http://www.blogjava.net/Jiangzy/aggbug/177858.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Jiangzy/" target="_blank">飛雪(leo)</a> 2008-01-25 23:11 <a href="http://www.blogjava.net/Jiangzy/archive/2008/01/25/177858.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Struts2与ajax的组合 </title><link>http://www.blogjava.net/Jiangzy/archive/2007/10/18/153730.html</link><dc:creator>飛雪(leo)</dc:creator><author>飛雪(leo)</author><pubDate>Wed, 17 Oct 2007 16:47:00 GMT</pubDate><guid>http://www.blogjava.net/Jiangzy/archive/2007/10/18/153730.html</guid><wfw:comment>http://www.blogjava.net/Jiangzy/comments/153730.html</wfw:comment><comments>http://www.blogjava.net/Jiangzy/archive/2007/10/18/153730.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Jiangzy/comments/commentRss/153730.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Jiangzy/services/trackbacks/153730.html</trackback:ping><description><![CDATA[<div style="margin-top: 1px; margin-left: 15px">
<h2><a title="永久链接：Struts2与ajax的组合" href="http://zhangljerry.javaeye.com/blog/97838">Struts2与ajax的组合</a> </h2>
</div>
<div style="margin-top: 10px; margin-left: 15px; overflow: auto">
<table width="100%">
    <tbody>
        <tr>
            <td>
            <p>Struts2与ajax的组合 <br />
            在当今——Web 2.0概念铺天盖地的Internet环境下，简易的AJAX集成对于一个成功的WEB框架来说是不可或缺的。因此，Struts 2其中的一个重要的功能（Feature）就是&#8220;First-class AJAX support - Add interactivity and flexibility with AJAX tags that look and feel just like standard Struts tags（大意：一流的AJAX支持——通过AJAX标志增加互动性和灵活性，而且使用这些AJAX标志与普通的Struts标志同样简单）&#8221;。 <br />
            实现原理 <br />
            基于不重新发明轮子的原则，Struts 2并没有开发新的AJAX框架，而是使用时下Java EE平台中比较流行的AJAX框架——Dojo和DWR。 <br />
            最近在Musachy Barroso等同志的无私奉献下，开发了Struts 2的JSON插件（Plugin），极大地方便了我们输出JSON结果（Result）。 <br />
            JSON插件（Plugin） <br />
            在Struts 2的showcase中的AJAX部分，JSON的结果输出是通过Freemaker模板实现。这种方法在简易性和灵活性上都比不上JSON插件，所以JSON插件值得向大家五星推荐。 <br />
            下面让我们看一个JSON插件的例子。 <br />
            首先到以下网址http://code.google.com/p/jsonplugin/downloads/list下载JSON插件的JAR包，并将其加入你的WebContent\WEB-INF\lib下。 <br />
            接下是本例子的Action代码： <br />
            package tutorial; <br />
            <br />
            import java.util.ArrayList; <br />
            import java.util.List; <br />
            <br />
            import com.googlecode.jsonplugin.annotations.JSON; <br />
            import com.opensymphony.xwork2.ActionSupport; <br />
            <br />
            public class JsonPluginAction extends ActionSupport { <br />
            private static final long serialVersionUID = -6784977600668791997L; <br />
            <br />
            private int bookId; <br />
            private String title; <br />
            private double price; <br />
            private List&lt;String&gt; comments; <br />
            private transient String secret1; <br />
            private String secret2; <br />
            <br />
            @JSON(name="ISBN") <br />
            public int getBookId() { <br />
            return bookId; <br />
            } <br />
            <br />
            public void setBookId(int bookId) { <br />
            this.bookId = bookId; <br />
            } <br />
            <br />
            public List&lt;String&gt; getComments() { <br />
            return comments; <br />
            } <br />
            <br />
            public void setComments(List&lt;String&gt; comments) { <br />
            this.comments = comments; <br />
            } <br />
            <br />
            public double getPrice() { <br />
            return price; <br />
            } <br />
            <br />
            public void setPrice(double price) { <br />
            this.price = price; <br />
            } <br />
            <br />
            public String getTitle() { <br />
            return title; <br />
            } <br />
            <br />
            public void setTitle(String title) { <br />
            this.title = title; <br />
            } <br />
            <br />
            @Override <br />
            public String execute() { <br />
            bookId = 15645912; <br />
            title = "Max On Java"; <br />
            price = 0.9999d; <br />
            comments = new ArrayList&lt;String&gt;(3); <br />
            comments.add("It's no bad!"); <br />
            comments.add("WOW!"); <br />
            comments.add("No comment!"); <br />
            secret1 = "You can't see me!"; <br />
            secret2 = "I am invisible!"; <br />
            return SUCCESS; <br />
            } <br />
            } <br />
            清单1 src/tutorial/JsonPluginAction.java <br />
            以上代码值得注意的是，通过@JSON的JAVA注释（Annotation），我们可以改变JSON结果的属性名称，另外带有transient修饰符与没有Getter方法的字段（field）都不会被串行化为JSON。 <br />
            然后，我们来配置一下此Action，代码如下： <br />
            &lt;?xml version="1.0" encoding="UTF-8"?&gt;</p>
            <p>&lt;!DOCTYPE struts PUBLIC <br />
            "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" <br />
            "http://struts.apache.org/dtds/struts-2.0.dtd"&gt;</p>
            <p>&lt;struts&gt; <br />
            &lt;package name="Struts2_AJAX_DEMO" extends="json-default"&gt; <br />
            &lt;action name="JsonPlugin" class="tutorial.JsonPluginAction"&gt; <br />
            &lt;result type="json" /&gt; <br />
            &lt;/action&gt; <br />
            &lt;/package&gt; <br />
            &lt;/struts&gt; <br />
            清单2 src/struts.xml <br />
            上面配置文件的&#8220;package&#8221;元素和以往不同的是，它扩展了&#8220;json-default&#8221;而不是&#8220;struts-default&#8221;。&#8220;json-default&#8221;是在jsonplugin-0.11.jar包里的struts-plugin.xml中定义的。该文件同时定义了&#8220;json&#8221;的结果类型，有兴趣的朋友可以打开此文件看看。 <br />
            发布运行应用程序，在浏览器中键入：http://localhost:8080/Struts2_Ajax/JsonPlugin.action，出现下载文件对话框，原因是JSON插件将HTTP响应（Response）的MIME类型设为&#8220;application/json&#8221;。把文件下载下来，用记事本打开，内容如下： <br />
            {"ISBN":15645912,"comments":["It's no bad!","WOW!","No comment!"],"price":0.9999,"title":"Max On Java"} <br />
            清单3 例子1输出的JSON串 <br />
            当然这还不是一个完整的AJAX的例子，下面让我们写一个HTML文件将其完成，HTML代码如下： <br />
            &lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt; <br />
            &lt;html xmlns="http://www.w3.org/1999/xhtml" &gt; <br />
            &lt;head&gt; <br />
            &lt;title&gt;JSON Plugin&lt;/title&gt; <br />
            &lt;script type="text/javascript"&gt; <br />
            var bXmlHttpSupport = (typeof XMLHttpRequest != "undefined" || window.ActiveXObject); <br />
            <br />
            if (typeof XMLHttpRequest == "undefined" &amp;&amp; window.ActiveXObject) { <br />
            function XMLHttpRequest() { <br />
            var arrSignatures = ["MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", <br />
            "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", <br />
            "Microsoft.XMLHTTP"]; <br />
            <br />
            for (var i=0; i &lt; arrSignatures.length; i++) { <br />
            try { <br />
            var oRequest = new ActiveXObject(arrSignatures[i]); <br />
            return oRequest; <br />
            } catch (oError) { /*ignore*/ } <br />
            } <br />
            <br />
            throw new Error("MSXML is not installed on your system."); <br />
            } <br />
            } <br />
            <br />
            function retrieveBook() { <br />
            if(bXmlHttpSupport) { <br />
            var sUrl = 'JsonPlugin.action'; <br />
            var oRequest = new XMLHttpRequest(); <br />
            oRequest.onreadystatechange = function() { <br />
            if(oRequest.readyState == 4) { <br />
            var oBook = eval('(' + oRequest.responseText + ')'); <br />
            var bookHolder = document.getElementById('bookHolder'); <br />
            var sBook = '&lt;p&gt;&lt;b&gt;ISBN: &lt;/b&gt;' + oBook.ISBN + '&lt;/p&gt;'; <br />
            sBook += ('&lt;p&gt;&lt;b&gt;Title: &lt;/b&gt;' + oBook.title + '&lt;/p&gt;'); <br />
            sBook += ('&lt;p&gt;&lt;b&gt;Price: &lt;/b&gt;$' + oBook.price + '&lt;/p&gt;'); <br />
            sBook += ('&lt;b&gt;&lt;i&gt;Comments: &lt;/i&gt;&lt;/b&gt;&lt;hr/&gt;'); <br />
            for(i = 0; i &lt; oBook.comments.length; i++) { <br />
            sBook += ('&lt;p&gt;&lt;b&gt;#' + (i + 1) + ' &lt;/b&gt;' + oBook.comments[i] + '&lt;/p&gt;'); <br />
            } <br />
            bookHolder.innerHTML = sBook; <br />
            } <br />
            }; <br />
            oRequest.open('POST', sUrl); <br />
            oRequest.send(null); <br />
            } <br />
            } <br />
            &lt;/script&gt; <br />
            &lt;/head&gt; <br />
            &lt;body&gt; <br />
            &lt;input type="button" value="Retrieve Book" onclick="retrieveBook()" /&gt; <br />
            &lt;div id="bookHolder"&gt;&lt;/div&gt; <br />
            &lt;/body&gt; <br />
            &lt;/html&gt; <br />
            清单4 WebContent/JsonPlugin.html <br />
            以上代码中，我没有使用任何的AJAX的Javascript包，而是参考《Professional Javascript For Web Developer》手工创建XHR（XMLHttpRequest），并在XHR完成后使用eval()方法将JSON字符串变为JSON对象。需要注意的是，要调用eval函数时，必须使用&#8220;(&#8221;和&#8220;)&#8221;将JSON字符串括起来，否则会出错的。 <br />
            打开http://localhost:8080/Struts2_Ajax/JsonPlugin.html，点击&#8220;Retrieve Book&#8221;按钮，页面如下图所示： <br />
            <br />
            图1 JsonPlugin.html页面输出 <br />
            Struts 2与Dojo <br />
            Dojo是开源Javascript工具包，它引了Widget的概念，方便了Javascript面向对象编程（OOP），改进Javascript的事件模型。在此我不打算对此进行深入的讲解，有兴趣的朋友的可以找网上找一些关于Dojo的资料学习。 <br />
            Struts 2基于Dojo编写一些AJAX标志（在Dojo中称为Widget），要使用这些标志的AJAX功能，需要将标志的&#8220;theme&#8221;属性设为&#8220;ajax&#8221;。同时，亦需要将加入在&lt;head&gt;与&lt;/head&gt;之间加入&lt;s:head theme="ajax" /&gt;。当使用这些标志的AJAX功能，有些属性可能会经常用到，所以我会对这些属性稍作解释。 <br />
            名称 描述 <br />
            href XHR（XMLHttpRequest）请求的地址 <br />
            listenTopics 监听的Dojo话题（Topic）以触发自身，如可以在可以通过发布（Publish）相应的话题，通知&lt;s:autocompleter /&gt;重新加载其备选项（Options） <br />
            notifyTopics 完成远程调用后，发出通知，触发相应的Javascript函数或Dojo Widget <br />
            formId 需要提交到服务器的表单的ID <br />
            formFilter 过滤表单字段的Javascript函数名称 <br />
            indicator 在XHR处理过程中，包含用户提示的信息的HTML元素的ID，如图片或DIV等 <br />
            表1 常用的AJAX标志属性 <br />
            这些标志包括：&lt;s:a /&gt;、&lt;s: submit /&gt;、&lt;s:autocompleter /&gt;和&lt;s:tree /&gt;等，下面我将分别讲解。 <br />
            1、&lt;s:a /&gt;和&lt;s:submit /&gt; <br />
            这两个标志方便了我们的调用XHR实现AJAX，所以上面的HTML如果使用了这两标志将会变得更简单，因为我们不用再去理会繁锁的XHR创建和设定的工作。下面是示例代码： <br />
            &lt;%@ page language="java" contentType="text/html; charset=utf-8" <br />
            pageEncoding="utf-8"%&gt; <br />
            &lt;%@ taglib prefix="s" uri="/struts-tags"%&gt;</p>
            <p>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt; <br />
            &lt;html xmlns="http://www.w3.org/1999/xhtml"&gt; <br />
            &lt;head&gt; <br />
            &lt;title&gt;JSON Plugin&lt;/title&gt; <br />
            &lt;s:head theme="ajax" /&gt; <br />
            &lt;script type="text/javascript"&gt; <br />
            dojo.addOnLoad(function() { <br />
            dojo.event.topic.subscribe('retrieveBook', this, function(data, type, e){ <br />
            if(type == 'load') { <br />
            showBook(data); <br />
            } else if(type == 'error') { <br />
            alert('Can not retrieve the book'); <br />
            } <br />
            }); <br />
            }); <br />
            <br />
            function showBook(strBook) { <br />
            var oBook = eval('(' + strBook + ')'); <br />
            var bookHolder = document.getElementById('bookHolder'); <br />
            var sBook = '&lt;p&gt;&lt;b&gt;ISBN: &lt;/b&gt;' + oBook.ISBN + '&lt;/p&gt;'; <br />
            sBook += ('&lt;p&gt;&lt;b&gt;Title: &lt;/b&gt;' + oBook.title + '&lt;/p&gt;'); <br />
            sBook += ('&lt;p&gt;&lt;b&gt;Price: &lt;/b&gt;$' + oBook.price + '&lt;/p&gt;'); <br />
            sBook += ('&lt;b&gt;&lt;i&gt;Comments: &lt;/i&gt;&lt;/b&gt;&lt;hr/&gt;'); <br />
            for(i = 0; i &lt; oBook.comments.length; i++) { <br />
            sBook += ('&lt;p&gt;&lt;b&gt;#' + (i + 1) + ' &lt;/b&gt;' + oBook.comments[i] + '&lt;/p&gt;'); <br />
            } <br />
            bookHolder.innerHTML = sBook; <br />
            } <br />
            &lt;/script&gt; <br />
            &lt;/head&gt; <br />
            &lt;body&gt; <br />
            &lt;s:url id="bookUrl" value="/JsonPlugin.action" /&gt; <br />
            &lt;s:submit href="%{bookUrl}" theme="ajax" indicator="indicator" <br />
            value="Retrieve Book" align="left" notifyTopics="retrieveBook" /&gt; <br />
            &lt;s:a theme="ajax" href="%{bookUrl}" indicator="indicator" <br />
            notifyTopics="retrieveBook"&gt;Retrieve Book&lt;/s:a&gt; <br />
            &lt;img id="indicator" <br />
            src="${pageContext.request.contextPath}/images/indicator.gif" <br />
            alt="Loading " style="display:none" /&gt; <br />
            &lt;div id="bookHolder"&gt;&lt;/div&gt; <br />
            &lt;/body&gt; <br />
            &lt;/html&gt; <br />
            清单5 WebContent/LinkButton.jsp <br />
            可能上述代码还不够简洁，因为我将HTML格式化的工作都放在Javascript中完成。但如果你的XHR返回的是HTML片段，你可以简单地将&lt;s:a /&gt;或&lt;s:submit /&gt;的&#8220;targets&#8221;属性设为&#8220;bookHolder&#8221;即可，详情大家可以参考Struts 2 Showcase。至于返回HTML片段，可以通过Action + Freemaker完成。 <br />
            2、&lt;s:autocompleter /&gt; <br />
            Autocomplete是比较经典的AJAX应用，虽然谷歌已经停止使用这一功能，但就Autocompleter自身而言的确是很酷的。下面是一个&lt;s:autocompleter /&gt;的例子。 <br />
            首先，我要伪造一些字符串数据，代码如下： <br />
            package tutorial; <br />
            <br />
            import java.util.ArrayList; <br />
            import java.util.List; <br />
            <br />
            public final class Datas { <br />
            public static final List&lt;String&gt; NAMES; <br />
            static { <br />
            NAMES = new ArrayList&lt;String&gt;(); <br />
            NAMES.add("Alabama"); <br />
            NAMES.add("Alaska"); <br />
            NAMES.add("American Samoa"); <br />
            NAMES.add("Arizona"); <br />
            NAMES.add("Arkansas"); <br />
            NAMES.add("Armed Forces Europe"); <br />
            NAMES.add("Armed Forces Pacific"); <br />
            NAMES.add("Armed Forces the Americas"); <br />
            NAMES.add("California"); <br />
            NAMES.add("Colorado"); <br />
            NAMES.add("Connecticut"); <br />
            NAMES.add("Delaware"); <br />
            NAMES.add("District of Columbia"); <br />
            NAMES.add("Federated States of Micronesia"); <br />
            NAMES.add("Florida"); <br />
            NAMES.add("Georgia"); <br />
            NAMES.add("Guam"); <br />
            NAMES.add("Hawaii"); <br />
            NAMES.add("Idaho"); <br />
            NAMES.add("Illinois"); <br />
            NAMES.add("Indiana"); <br />
            NAMES.add("Iowa"); <br />
            NAMES.add("Kansas"); <br />
            NAMES.add("Kentucky"); <br />
            NAMES.add("Louisiana"); <br />
            NAMES.add("Maine"); <br />
            NAMES.add("Marshall Islands"); <br />
            NAMES.add("Maryland"); <br />
            NAMES.add("Massachusetts"); <br />
            NAMES.add("Michigan"); <br />
            NAMES.add("Minnesota"); <br />
            NAMES.add("Mississippi"); <br />
            NAMES.add("Missouri"); <br />
            NAMES.add("Montana"); <br />
            NAMES.add("Nebraska"); <br />
            NAMES.add("Nevada"); <br />
            NAMES.add("New Hampshire"); <br />
            NAMES.add("New Jersey"); <br />
            NAMES.add("New Mexico"); <br />
            NAMES.add("New York"); <br />
            NAMES.add("North Carolina"); <br />
            NAMES.add("North Dakota"); <br />
            NAMES.add("Northern Mariana Islands"); <br />
            NAMES.add("Ohio"); <br />
            NAMES.add("Oklahoma"); <br />
            NAMES.add("Oregon"); <br />
            NAMES.add("Pennsylvania"); <br />
            NAMES.add("Puerto Rico"); <br />
            NAMES.add("Rhode Island"); <br />
            NAMES.add("South Carolina"); <br />
            NAMES.add("South Dakota"); <br />
            NAMES.add("Tennessee"); <br />
            NAMES.add("Texas"); <br />
            NAMES.add("Utah"); <br />
            NAMES.add("Vermont"); <br />
            NAMES.add("Virgin Islands, U.S."); <br />
            NAMES.add("Virginia"); <br />
            NAMES.add("Washington"); <br />
            NAMES.add("West Virginia"); <br />
            NAMES.add("Wisconsin"); <br />
            NAMES.add("Wyoming"); <br />
            } <br />
            } <br />
            清单6 src/tutorial/Datas.java <br />
            然后是用于获取和过滤数据的Action，代码如下： <br />
            package tutorial; <br />
            <br />
            import java.util.ArrayList; <br />
            import java.util.List; <br />
            <br />
            import com.opensymphony.xwork2.ActionSupport; <br />
            <br />
            public class AutocompleterAction extends ActionSupport { <br />
            private static final long serialVersionUID = -8201401726773589361L; <br />
            <br />
            private List&lt;String[]&gt; names; <br />
            private String start; <br />
            <br />
            public void setStart(String start) { <br />
            this.start = start; <br />
            } <br />
            <br />
            public List&lt;String[]&gt; getNames() { <br />
            return names; <br />
            } <br />
            <br />
            @Override <br />
            public String execute() { <br />
            names = new ArrayList&lt;String[]&gt;(); <br />
            if(start == null || "".equals(start.trim())) { <br />
            start = "a"; <br />
            } <br />
            for(String s : Datas.NAMES) { <br />
            if(s.toLowerCase().startsWith(start.toLowerCase())) { <br />
            names.add(new String[]{ s, s }); <br />
            } <br />
            } <br />
            return SUCCESS; <br />
            } <br />
            } <br />
            清单7 src/tutorial/AutocmpleterAction.java <br />
            上述Action会以JSON的形式返回以start开头的Datas.NAMES的中字符串，以下是此Action的配置： <br />
            &lt;action name="Autocompleter" class="tutorial.AutocompleterAction"&gt; <br />
            &lt;result type="json"&gt; <br />
            &lt;param name="root"&gt;names&lt;/param&gt; <br />
            &lt;/result&gt; <br />
            &lt;/action&gt; <br />
            清单8 Autocompleter Action的配置代码片段 <br />
            在JSON类型结果的参数中加入&#8220;root&#8221;参数可以设定输出JSON结果的根，以上述情况为例，如果没有&#8220;root&#8221;参数，输出将为&#8220;{ "names": [ ["xxx", "xxx"]...] }&#8221;，加了之后变就会成&#8220;[ ["xxx", "xxx"]...] &#8221;。接下来，让我们看看页面的代码： <br />
            &lt;%@ page language="java" contentType="text/html; charset=utf-8" <br />
            pageEncoding="utf-8"%&gt; <br />
            &lt;%@ taglib prefix="s" uri="/struts-tags"%&gt;</p>
            <p>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt; <br />
            &lt;html xmlns="http://www.w3.org/1999/xhtml"&gt; <br />
            &lt;head&gt; <br />
            &lt;title&gt;Struts 2 AJAX - Autocompleter&lt;/title&gt; <br />
            &lt;s:head theme="ajax" /&gt; <br />
            &lt;/head&gt; <br />
            &lt;body&gt; <br />
            &lt;h2&gt; <br />
            Autocompleter <br />
            &lt;/h2&gt; <br />
            &lt;s:form action="autocompleterForm"&gt; <br />
            &lt;s:textfield label="abc" name="abc" /&gt; <br />
            &lt;tr&gt; <br />
            &lt;td class="tdLabel"&gt; <br />
            &lt;label class="label"&gt; <br />
            No AJAX Autocompleter: <br />
            &lt;/label&gt; <br />
            &lt;/td&gt; <br />
            &lt;td&gt; <br />
            &lt;s:autocompleter theme="simple" name="user" <br />
            list="@tutorial.Datas@NAMES" /&gt; <br />
            &lt;/td&gt; <br />
            &lt;/tr&gt; <br />
            &lt;tr&gt; <br />
            &lt;td class="tdLabel"&gt; <br />
            &lt;label class="label"&gt; <br />
            AJAX Autocompleter: <br />
            &lt;/label&gt; <br />
            &lt;/td&gt; <br />
            &lt;td&gt; <br />
            &lt;s:url id="dataUrl" value="/Autocompleter.action" /&gt; <br />
            &lt;s:autocompleter theme="ajax" name="start" href="%{dataUrl}" <br />
            loadOnTextChange="true" loadMinimumCount="1" indicator="indicator" <br />
            autoComplete="false" showDownArrow="false" /&gt; <br />
            &lt;img id="indicator" <br />
            src="${pageContext.request.contextPath}/images/indicator.gif" <br />
            alt="Loading " style="display:none" /&gt; <br />
            &lt;/td&gt; <br />
            &lt;/tr&gt; <br />
            &lt;/s:form&gt; <br />
            &lt;/body&gt; <br />
            &lt;/html&gt; <br />
            清单9 WebContent/Autocompleter.jsp <br />
            上述页面包含两个&lt;s:autocompleter /&gt;标志，前者使用&#8220;simple&#8221;模板，所以不具有AJAX功能，它的数据将以HTML方式输出到最终页面里；而后者则使用了&#8220;ajax&#8221;模板，每当输入框的值发生改变时，它都向URL&#8220;/Autocompleter.action&#8221;发送请求，Action根据请求中的start参数的值，返回相当的JSON，在请求完成后页面通过回调函数改变输入框的下拉提示，效果如下图所示： <br />
            <br />
            图2 Autocompleter.jsp页面输出 <br />
            3、&lt;s:tree /&gt; <br />
            树是是比较常用的数据结构，因为它可以很好地体现真实世界中对象之间的关系。&lt;s:tree /&gt;的使用也相对简单，但需要说明的是——Struts 2.0.6 GA版本的&lt;s:tree /&gt;是有BUG的，大家可以点击这个链接https://issues.apache.org/struts/browse/WW-1813了解详细的情况。这个BUG主要是在&lt;s:tree /&gt;的通过&#8220;treeCollapsedTopic&#8221;、&#8220;treeExpandedTopic&#8221;和&#8220;treeSelectedTopic&#8221;设定的话题（Topic）都没有起作用，上述链接相应给出了解决方法，但我认为该方法太麻烦（需要自己重新编译和打包Struts 2），所以下面的例子，我将另辟徯径，请参考以下代码。 <br />
            &lt;%@ page language="java" contentType="text/html; charset=utf-8" <br />
            pageEncoding="utf-8"%&gt; <br />
            &lt;%@ taglib prefix="s" uri="/struts-tags"%&gt;</p>
            <p>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt; <br />
            &lt;html xmlns="http://www.w3.org/1999/xhtml"&gt; <br />
            &lt;head&gt; <br />
            &lt;title&gt;Struts 2 AJAX - Tree&lt;/title&gt; <br />
            &lt;s:head theme="ajax" debug="true" /&gt; <br />
            &lt;script type="text/javascript"&gt; <br />
            function treeNodeSelected(arg) { <br />
            alert(arg.source.title + ' selected'); <br />
            } <br />
            dojo.addOnLoad(function() { <br />
            var s = dojo.widget.byId('parentId').selector; <br />
            dojo.event.connect(s, 'select', 'treeNodeSelected'); <br />
            }); <br />
            &lt;/script&gt; <br />
            &lt;/head&gt; <br />
            &lt;body&gt; <br />
            &lt;h2&gt; <br />
            Tree <br />
            &lt;/h2&gt; <br />
            &lt;div style="float:left; margin-right: 50px;"&gt; <br />
            &lt;s:tree label="parent" id="parentId" theme="ajax" <br />
            templateCssPath="/struts/tree.css" showRootGrid="true" <br />
            showGrid="true"&gt; <br />
            &lt;s:treenode theme="ajax" label="child1" id="child1Id"&gt; <br />
            &lt;s:treenode theme="ajax" label="grandchild1" id="grandchild1Id" /&gt; <br />
            &lt;s:treenode theme="ajax" label="grandchild2" id="grandchild2Id" /&gt; <br />
            &lt;s:treenode theme="ajax" label="grandchild3" id="grandchild3Id" /&gt; <br />
            &lt;/s:treenode&gt; <br />
            &lt;s:treenode theme="ajax" label="child2" id="child2Id" /&gt; <br />
            &lt;s:treenode theme="ajax" label="child3" id="child3Id" /&gt; <br />
            &lt;s:treenode theme="ajax" label="child4" id="child4Id" /&gt; <br />
            &lt;s:treenode theme="ajax" label="child5" id="child5Id"&gt; <br />
            &lt;s:treenode theme="ajax" label="gChild1" id="gChild1Id" /&gt; <br />
            &lt;s:treenode theme="ajax" label="gChild2" id="gChild2Id" /&gt; <br />
            &lt;/s:treenode&gt; <br />
            &lt;/s:tree&gt; <br />
            &lt;/div&gt; <br />
            &lt;/body&gt; <br />
            &lt;/html&gt; <br />
            清单10 WebContent/Tree.jsp <br />
            因为Dojo的树控件，即使在没有设定&#8220;selector&#8221;情况下，也会自动生成一个默认的Selector，所以只要将其事件绑定到特定的事件处理函数即可。 <br />
            打开http://localhost:8080/Struts2_Ajax/Tree.jsp，点击任一树节点，页面如下图所示： <br />
            <br />
            图3 Tree.jsp页面输出 <br />
            更多&lt;s:tree /&gt; <br />
            在Struts 2的showcase中有两个&lt;s:tree /&gt;的例子，分别是静态树与动态树。所谓的静态树即是在编写JSP代码时通过&lt;s:treenode /&gt;生成树节点。我的上一篇文章的例子就是一个典型的静态树。而动态树则是在程序运行期间，Struts 2 运行时（Runtime）根据程序中的数据动态创建树节点。虽然在两个例子中&lt;s:tree /&gt;的theme属性都为&#8220;ajax&#8221;，但是从严格意义上来说，这两种树都不属于AJAX树，因为它们都是在输出页面时将全部节点加载到其中，而不是在父节点展开时通过XHR（XMLHttpRequest）获取节点数据。 <br />
            动态树 <br />
            下面我们先看一下动态树的例子，接着再一步步地将其改造为名副其实的AJAX 树。下例将会把WEB应用程序的目录树展现在JSP页面中。因此，我需要先包装一下java.io.File 类，代码如下： <br />
            package tutorial; <br />
            <br />
            import java.io.File; <br />
            <br />
            public class FileWrapper { <br />
            private File file; <br />
            <br />
            public FileWrapper(String path) { <br />
            file = new File(path); <br />
            } <br />
            <br />
            public FileWrapper(File file) { <br />
            this.file = file; <br />
            } <br />
            <br />
            public String getId() { <br />
            return "file_" + file.hashCode(); <br />
            } <br />
            <br />
            public String getName() { <br />
            return file.getName(); <br />
            } <br />
            <br />
            public String getAbsolutePath() { <br />
            return file.getAbsolutePath(); <br />
            } <br />
            <br />
            public FileWrapper[] getChildren() { <br />
            File[] files = file.listFiles(); <br />
            if(files != null &amp;&amp; files.length &gt; 0) { <br />
            int length = files.length; <br />
            FileWrapper[] wrappers = new FileWrapper[length]; <br />
            for(int i = 0; i &lt; length; ++i) { <br />
            wrappers[i] = new FileWrapper(files[i]); <br />
            } <br />
            return wrappers; <br />
            } <br />
            return new FileWrapper[0]; <br />
            } <br />
            } <br />
            清单1 src/tutorial/FileWrapper.java <br />
            之所以需要对File类进行如此包装，是因为&lt;s:tree /&gt;用于动态树时，rootNode、nodeIdProperty、nodeTitleProperty 和 childCollectionProperty等属性都必填的。 <br />
            然后是Action类的代码如下： <br />
            package tutorial; <br />
            <br />
            import javax.servlet.http.HttpServletRequest; <br />
            <br />
            import org.apache.struts2.interceptor.ServletRequestAware; <br />
            <br />
            import com.opensymphony.xwork2.ActionSupport; <br />
            <br />
            public class DynamicTreeAction extends ActionSupport implements ServletRequestAware { <br />
            private static final long serialVersionUID = 1128593047269036737L; <br />
            <br />
            private HttpServletRequest request; <br />
            private FileWrapper root; <br />
            <br />
            public void setServletRequest(HttpServletRequest request) { <br />
            this.request = request; <br />
            } <br />
            <br />
            public FileWrapper getRoot() { <br />
            return root; <br />
            } <br />
            <br />
            @Override <br />
            public String execute() { <br />
            root = new FileWrapper(request.getSession().getServletContext().getRealPath("/")); <br />
            return SUCCESS; <br />
            } <br />
            } <br />
            清单2 src/tutorial/DynamicTreeAction.java <br />
            上述代码取得WEB应用程序的根目录的绝对路径后，初始化FileWrapper对象root。该对象将为JSP页面的&lt;s:tree /&gt;的根节点。如下代码所示： <br />
            &lt;%@ page language="java" contentType="text/html; charset=utf-8" <br />
            pageEncoding="utf-8"%&gt; <br />
            &lt;%@ taglib prefix="s" uri="/struts-tags"%&gt;</p>
            <p>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt; <br />
            &lt;html xmlns="http://www.w3.org/1999/xhtml"&gt; <br />
            &lt;head&gt; <br />
            &lt;title&gt;Struts 2 AJAX - More Tree&lt;/title&gt; <br />
            &lt;s:head theme="ajax" debug="true" /&gt; <br />
            &lt;script type="text/javascript"&gt; <br />
            /* &lt;![CDATA[ */ <br />
            function treeNodeSelected(arg) { <br />
            alert(arg.source.title + ' selected'); <br />
            } <br />
            <br />
            function treeNodeExpanded(arg) { <br />
            alert(arg.source.title + ' expanded'); <br />
            } <br />
            <br />
            function treeNodeCollapsed(arg) { <br />
            alert(arg.source.title + ' collapsed'); <br />
            } <br />
            <br />
            dojo.addOnLoad(function() { <br />
            var t = dojo.widget.byId('appFiles'); <br />
            dojo.event.topic.subscribe(t.eventNames.expand, treeNodeExpanded); <br />
            dojo.event.topic.subscribe(t.eventNames.collapse, treeNodeCollapsed); <br />
            <br />
            var s = t.selector; <br />
            dojo.event.connect(s, 'select', 'treeNodeSelected'); <br />
            }); <br />
            /* ]]&gt; */ <br />
            &lt;/script&gt; <br />
            &lt;/head&gt; <br />
            &lt;body&gt; <br />
            &lt;h2&gt; <br />
            Dynamic Tree Example <br />
            &lt;/h2&gt; <br />
            &lt;div style="float:left; margin-right: 50px;"&gt; <br />
            &lt;s:tree id="appFiles" theme="ajax" rootNode="root" <br />
            nodeTitleProperty="name" nodeIdProperty="id" <br />
            childCollectionProperty="children" /&gt; <br />
            &lt;/div&gt; <br />
            &lt;/body&gt; <br />
            &lt;/html&gt; <br />
            清单3 WebContent/Tree.jsp <br />
            因为&lt;s:tree /&gt;的treeCollapsedTopic和treeExpandedTopic属性都没有起作用，所以如果我们想要监听这两个事件，就必须使用上述代码的方法。 <br />
            最后是struts.xml配置文件： <br />
            &lt;?xml version="1.0" encoding="UTF-8"?&gt;</p>
            <p>&lt;!DOCTYPE struts PUBLIC <br />
            "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" <br />
            "http://struts.apache.org/dtds/struts-2.0.dtd"&gt;</p>
            <p>&lt;struts&gt; <br />
            &lt;package name="Struts2_AJAX_DEMO" extends="struts-default"&gt; <br />
            &lt;action name="DynamicTree" class="tutorial.DynamicTreeAction"&gt; <br />
            &lt;result&gt;Tree.jsp&lt;/result&gt; <br />
            &lt;/action&gt; <br />
            &lt;/package&gt; <br />
            &lt;/struts&gt; <br />
            清单4 src/struts.xml <br />
            发布运行应用程序，在浏览器地址栏中键入http://localhost:8080/Struts2_Ajax2/DynamicTree.action，有如下图所示页面： <br />
            <br />
            图1 动态树示例 <br />
            AJAX 树 <br />
            正如我在文章开头所说，Struts 2所提供的静态树和动态树都不是严格意义上的AJAX树。下面就让我们来实现一个如假包换的AJAX树。首先要说明的是，Struts 2的&lt;s:tree /&gt;默认是不支持这种按需加载数据的AJAX树。不过因为它是基于Dojo的树控件（Widget）所以要扩展也很方便。 <br />
            Dojo 通过名为&#8220;TreeRPCController&#8221;的控件实现 AJAX 树，它会监听被控制树的事件。当发生展开节点的事件时，TreeRPCController就会向URL发送XHR请求，该URL由TreeRPCController的RPCUrl 属性定义。XHR请求格式类似如下格式： <br />
            http://localhost:8080/Struts2_Ajax2/AjaxTree.action?action=getChildren&amp;data={"node":{"widgetId":"file_226092423","objectId":"C:\\Program Files\\Tomcat 5.5\\webapps\\Struts2_Ajax2","index":0,"isFolder":true},"tree":{"widgetId":"appFiles","objectId":""}}&amp;dojo.preventCache=1182913465392 <br />
            清单5 XHR样本 <br />
            显而易见，请求中包含三个参数，分别是action为&#8220;getChildren&#8221;（固定值），data一个包含当前节点与树信息的JSON串和dojo.preventCache随机串，用于缓存不同节点的请求响应（父节点只会在第一次被展开时到服务器端加载数据，之后都是从浏览器的缓存中读取数据，可以提高应用程序性能）。 <br />
            首先我要先写一个加载树节点数据的Action类，代码如下： <br />
            package tutorial; <br />
            <br />
            import java.util.Map; <br />
            <br />
            import com.googlecode.jsonplugin.JSONExeption; <br />
            import com.googlecode.jsonplugin.JSONUtil; <br />
            <br />
            public class AjaxTreeAction extends DynamicTreeAction { <br />
            private static final long serialVersionUID = 3970019751740942311L; <br />
            <br />
            private String action; <br />
            private String data; <br />
            private FileWrapper[] wrappers; <br />
            <br />
            public void setAction(String action) { <br />
            this.action = action; <br />
            } <br />
            <br />
            public void setData(String data) { <br />
            this.data = data; <br />
            } <br />
            <br />
            public FileWrapper[] getWrappers() { <br />
            return wrappers; <br />
            } <br />
            <br />
            @Override <br />
            public String execute() { <br />
            if("getChildren".equals(action)) { <br />
            try { <br />
            Object o = JSONUtil.deserialize(data); <br />
            String path = ((Map) ((Map) o).get("node")).get("objectId").toString(); <br />
            wrappers = new FileWrapper(path).getChildren(); <br />
            } catch (JSONExeption e) { <br />
            e.printStackTrace(); <br />
            } <br />
            return "ajax"; <br />
            } <br />
            return super.execute(); <br />
            } <br />
            } <br />
            清单6 src/tutorial/AjaxTreeAction.java <br />
            上述代码可能需要解释一下： <br />
            1. action属性对应于XHR中的action，如果它为&#8220;getChildren&#8221;时，则需要进行加载子节点操作。否则，会读取树的根节点，并返回JSP页面； <br />
            2. 通过上面XHR的分析，大家可以知道data是代表树和当前节点的JSON串，故应将其反串行化为Map对象，并将其 objectId属性取出。通常情况下，Dojo树的objectId属性代表服务器端的对象的标识，在本例中为文件夹的绝对路径； <br />
            3. wrappers属性表示当前文件夹下的文件数组，它被传送到Freemarker页面，翻译为Dojo树节点数组的JSON串。 <br />
            下面是Freemarker页面的代码： <br />
            [ <br />
            &lt;#list wrappers as r&gt; <br />
            { "title": "${r.name}", "isFolder": &lt;#if r.children?size gt 0&gt;true&lt;#else&gt;false&lt;/#if&gt;, "id": "${r.id}", "objectId": "${r.absolutePath?js_string}" }&lt;#if r_has_next&gt;,&lt;/#if&gt; <br />
            &lt;/#list&gt; <br />
            ] <br />
            清单7 WebContent/AjaxTree.ftl <br />
            以上代码中&lt;#list&gt;&lt;/#lsit&gt;的写法是Freemarker中遍历集合的写法；而&lt;#if r.children?size gt 0&gt;判断&#8220;r&#8221;对象的children属性是否为空；r.absolutePath?js_string 就是将&#8220;r&#8221;的absolutePath属性的值输出为Javascript 的字串符形式；&lt;#if r_has_next&gt;&lt;/#if&gt;判断集合是否有下一项数据。如果希望更详细地了解Freemarker的使用，请参考该手册。 <br />
            接下来，让我们看看Action的配置代码片段： <br />
            &lt;action name="AjaxTree" class="tutorial.AjaxTreeAction"&gt; <br />
            &lt;result&gt;AjaxTree.jsp&lt;/result&gt; <br />
            &lt;result name="ajax" type="freemarker"&gt;AjaxTree.ftl&lt;/result&gt; <br />
            &lt;/action&gt; <br />
            清单8 src/struts.xml配置片段 <br />
            最后是JSP页面代码： <br />
            &lt;%@ page language="java" contentType="text/html; charset=utf-8" <br />
            pageEncoding="utf-8"%&gt; <br />
            &lt;%@ taglib prefix="s" uri="/struts-tags"%&gt;</p>
            <p>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt; <br />
            &lt;html xmlns="http://www.w3.org/1999/xhtml"&gt; <br />
            &lt;head&gt; <br />
            &lt;title&gt;Struts 2 AJAX - More Tree&lt;/title&gt; <br />
            &lt;s:head theme="ajax" debug="true" /&gt; <br />
            &lt;script type="text/javascript"&gt; <br />
            /* &lt;![CDATA[ */ <br />
            function treeNodeSelected(arg) { <br />
            alert(arg.source.title + ' selected'); <br />
            } <br />
            <br />
            dojo.addOnLoad(function() { <br />
            var t = dojo.widget.byId('appFiles'); <br />
            var s = t.selector; <br />
            dojo.event.connect(s, 'select', 'treeNodeSelected'); <br />
            }); <br />
            /* ]]&gt; */ <br />
            &lt;/script&gt; <br />
            &lt;/head&gt; <br />
            &lt;body&gt; <br />
            &lt;h2&gt; <br />
            AJAX Tree Example <br />
            &lt;/h2&gt; <br />
            &lt;div style="float:left; margin-right: 50px;"&gt; <br />
            &lt;script type="text/javascript"&gt; <br />
            /* &lt;![CDATA[ */ <br />
            dojo.require("dojo.lang.*"); <br />
            dojo.require("dojo.widget.*"); <br />
            dojo.require("dojo.widget.Tree"); <br />
            dojo.require("dojo.widget.TreeRPCController"); <br />
            /* ]]&gt; */ <br />
            &lt;/script&gt; <br />
            &lt;div dojoType="TreeRPCController" widgetId="treeController" <br />
            DNDcontroller="create" RPCUrl="&lt;s:url /&gt;"&gt;&lt;/div&gt; <br />
            &lt;div dojoType="Tree" widgetId="appFiles" toggle="fade" controller="treeController"&gt; <br />
            &lt;div dojoType="TreeNode" title='&lt;s:property value="root.name" /&gt;' <br />
            widgetId='&lt;s:property value="root.id" /&gt;' <br />
            isFolder='&lt;s:property value="root.children.length &gt; 0" /&gt;' <br />
            objectId='&lt;s:property value="root.absolutePath" /&gt;'&gt; <br />
            &lt;/div&gt; <br />
            &lt;/div&gt; <br />
            &lt;/div&gt; <br />
            &lt;/body&gt; <br />
            &lt;/html&gt; <br />
            清单9 WebContent/AjaxTree.jsp <br />
            由于上面所提及的原因，我在上述的代码中并没有使用&lt;s:tree /&gt;标志，而是使用了Dojo的写法——创建 widgetId 为&#8220;treeController&#8221;的 TreeRPCController 并将设为树的控制器。 <br />
            发布运行应用程序，在浏览器地址栏中键入http://localhost:8080/Struts2_Ajax2/AjaxTree.action，点开某个节点，在节点加载的过程中，加号图标变成时钟状图标，如下图所示页面： <br />
            <br />
            图2 AJAX树示例 <br />
            自定义&lt;s:tree /&gt;的AJAX的主题（theme） <br />
            Struts 2的标志过人之外在于它允许开发人员自定义标志的页面输出。要做到这一点，你所需要做的只是创建一个自定义的theme并将其应用到相应标志。下面就让我自定义一个真正的AJAX的&lt;s:tree/&gt;的theme。 <br />
            首先，你的源文件的根目录下新建包&#8220;template.realajax&#8221;。 <br />
            然后，在上一步所建的包中新建&#8220;tree.ftl&#8221;文件，内容如下： <br />
            &lt;script type="text/javascript"&gt; <br />
            /* &lt;![CDATA[ */ <br />
            dojo.require("dojo.lang.*"); <br />
            dojo.require("dojo.widget.*"); <br />
            dojo.require("dojo.widget.Tree"); <br />
            dojo.require("dojo.widget.TreeRPCController"); &lt;#-- Added by Max --&gt; <br />
            /* ]]&gt; */ <br />
            &lt;/script&gt; <br />
            &lt;#-- Added by Max --&gt; <br />
            &lt;div dojoType="TreeRPCController" <br />
            widgetId="${parameters.id?html}_controller" <br />
            DNDcontroller="create" <br />
            RPCUrl="&lt;@s.url /&gt;"&gt; <br />
            &lt;/div&gt; <br />
            &lt;#-- End --&gt; <br />
            &lt;div dojoType="Tree" <br />
            &lt;#if parameters.blankIconSrc?exists&gt; <br />
            gridIconSrcT="&lt;@s.url value='${parameters.blankIconSrc}' encode="false" includeParams='none'/&gt;" <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.gridIconSrcL?exists&gt; <br />
            gridIconSrcL="&lt;@s.url value='${parameters.gridIconSrcL}' encode="false" includeParams='none'/&gt;" <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.gridIconSrcV?exists&gt; <br />
            gridIconSrcV="&lt;@s.url value='${parameters.gridIconSrcV}' encode="false" includeParams='none'/&gt;" <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.gridIconSrcP?exists&gt; <br />
            gridIconSrcP="&lt;@s.url value='${parameters.gridIconSrcP}' encode="false" includeParams='none'/&gt;" <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.gridIconSrcC?exists&gt; <br />
            gridIconSrcC="&lt;@s.url value='${parameters.gridIconSrcC}' encode="false" includeParams='none'/&gt;" <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.gridIconSrcX?exists&gt; <br />
            gridIconSrcX="&lt;@s.url value='${parameters.gridIconSrcX}' encode="false" includeParams='none'/&gt;" <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.gridIconSrcY?exists&gt; <br />
            gridIconSrcY="&lt;@s.url value='${parameters.gridIconSrcY}' encode="false" includeParams='none'/&gt;" <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.gridIconSrcZ?exists&gt; <br />
            gridIconSrcZ="&lt;@s.url value='${parameters.gridIconSrcZ}' encode="false" includeParams='none'/&gt;" <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.expandIconSrcPlus?exists&gt; <br />
            expandIconSrcPlus="&lt;@s.url value='${parameters.expandIconSrcPlus}' includeParams='none'/&gt;" <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.expandIconSrcMinus?exists&gt; <br />
            expandIconSrcMinus="&lt;@s.url value='${parameters.expandIconSrcMinus?html}' includeParams='none'/&gt;" <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.iconWidth?exists&gt; <br />
            iconWidth="&lt;@s.url value='${parameters.iconWidth?html}' encode="false" includeParams='none'/&gt;" <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.iconHeight?exists&gt; <br />
            iconHeight="&lt;@s.url value='${parameters.iconHeight?html}' encode="false" includeParams='none'/&gt;" <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.toggleDuration?exists&gt; <br />
            toggleDuration=${parameters.toggleDuration?c} <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.templateCssPath?exists&gt; <br />
            templateCssPath="&lt;@s.url value='${parameters.templateCssPath}' encode="false" includeParams='none'/&gt;" <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.showGrid?exists&gt; <br />
            showGrid="${parameters.showGrid?default(true)?string}" <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.showRootGrid?exists&gt; <br />
            showRootGrid="${parameters.showRootGrid?default(true)?string}" <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.id?exists&gt; <br />
            id="${parameters.id?html}" <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.treeSelectedTopic?exists&gt; <br />
            publishSelectionTopic="${parameters.treeSelectedTopic?html}" <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.treeExpandedTopic?exists&gt; <br />
            publishExpandedTopic="${parameters.treeExpandedTopic?html}" <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.treeCollapsedTopic?exists&gt; <br />
            publishCollapsedTopic="${parameters.treeCollapsedTopic?html}" <br />
            &lt;/#if&gt; <br />
            &lt;#if parameters.toggle?exists&gt; <br />
            toggle="${parameters.toggle?html}" <br />
            &lt;/#if&gt; <br />
            controller="${parameters.id?html}_controller" &lt;#-- Added by Max --&gt; <br />
            &gt; <br />
            &lt;#if parameters.label?exists&gt; <br />
            &lt;div dojoType="TreeNode" title="${parameters.label?html}" <br />
            &lt;#if parameters.nodeIdProperty?exists&gt; <br />
            id="${stack.findValue(parameters.nodeIdProperty)}" <br />
            &lt;#else&gt; <br />
            id="${parameters.id}_root" <br />
            &lt;/#if&gt; <br />
            &gt; <br />
            &lt;#elseif parameters.rootNode?exists&gt; <br />
            ${stack.push(parameters.rootNode)} <br />
            &lt;#-- Edited by Max --&gt; <br />
            &lt;div dojoType="TreeNode" <br />
            title="${stack.findValue(parameters.nodeTitleProperty)}" <br />
            widgetId="${stack.findValue(parameters.nodeIdProperty)}" <br />
            isFolder="&lt;#if stack.findValue(parameters.childCollectionProperty)?size gt 0&gt;true&lt;#else&gt;false&lt;/#if&gt;" <br />
            objectId="${stack.findValue(parameters.nameValue)}"&gt; <br />
            &lt;/div&gt; <br />
            &lt;#-- End --&gt; <br />
            &lt;#assign oldNode = stack.pop()/&gt; &lt;#-- pop the node off of the stack, but don't show it --&gt; <br />
            &lt;/#if&gt; <br />
            清单10 src/template/realajax/tree.ftl <br />
            对上述稍作解释，上述代码主要在原版的src/template/ajax/tree.ftl的基础上添加了TreeRPCController的控件，并只输出根节点。由于&lt;s:tree /&gt;没有类似nodeObjectIdProperty的属性，所以我用了value属性表示objectId对应的属性名称。 <br />
            接着新建tree-close.ftl文件，内容和原版的一样，如下所示： <br />
            &lt;#if parameters.label?exists&gt;&lt;/div&gt;&lt;/#if&gt;&lt;/div&gt; <br />
            清单11 src/template/realajax/tree-close.ftl <br />
            再下来就应该是将theme应用到&lt;s:tree /&gt;，如下代码所示： <br />
            &lt;%@ page language="java" contentType="text/html; charset=utf-8" <br />
            pageEncoding="utf-8"%&gt; <br />
            &lt;%@ taglib prefix="s" uri="/struts-tags"%&gt;</p>
            <p>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt; <br />
            &lt;html xmlns="http://www.w3.org/1999/xhtml"&gt; <br />
            &lt;head&gt; <br />
            &lt;title&gt;Struts 2 AJAX - More Tree&lt;/title&gt; <br />
            &lt;s:head theme="ajax" debug="true" /&gt; <br />
            &lt;script type="text/javascript"&gt; <br />
            /* &lt;![CDATA[ */ <br />
            function treeNodeSelected(arg) { <br />
            alert(arg.source.title + ' selected'); <br />
            } <br />
            <br />
            dojo.addOnLoad(function() { <br />
            var t = dojo.widget.byId('appFiles'); <br />
            var s = t.selector; <br />
            dojo.event.connect(s, 'select', 'treeNodeSelected'); <br />
            }); <br />
            /* ]]&gt; */ <br />
            &lt;/script&gt; <br />
            &lt;/head&gt; <br />
            &lt;body&gt; <br />
            &lt;h2&gt; <br />
            AJAX Tree Example <br />
            &lt;/h2&gt; <br />
            &lt;div style="float:left; margin-right: 50px;"&gt; <br />
            &lt;s:tree id="appFiles" theme="realajax" rootNode="root" <br />
            nodeTitleProperty="name" nodeIdProperty="id" <br />
            childCollectionProperty="children" value="absolutePath" /&gt; <br />
            &lt;/div&gt; <br />
            &lt;/body&gt; <br />
            &lt;/html&gt; <br />
            清单12 WebContent/AjaxTreeTheme.jsp <br />
            上述代码中&lt;s:tree /&gt;的用法，除了theme改为&#8220;realajax&#8221;和多了value="absolutePath"外，几乎和静态树中的一样。 <br />
            为了不影响前一个例子，我们为该JSP文件配置类型相同的Action，如下代码所示： <br />
            &lt;action name="AjaxTreeTheme" class="tutorial.AjaxTreeAction"&gt; <br />
            &lt;result&gt;AjaxTreeTheme.jsp&lt;/result&gt; <br />
            &lt;result name="ajax" type="freemarker"&gt;AjaxTree.ftl&lt;/result&gt; <br />
            &lt;/action&gt; <br />
            清单13 src/struts.xml配置片段 <br />
            发布运行应用程序，在浏览器地址栏中键入http://localhost:8080/Struts2_Ajax2/AjaxTreeTheme.action，结果如图2所示。 <br />
            总结 <br />
            通过上述例子，大家知道Struts 2 的AJAX 标志是基于Dojo控件开发的，所以如果大家希望熟练地使用这些标志，最好去了解一下Dojo。 <br />
            本来还打算介绍一下Struts 2与DWR，不过看看文章的篇幅似乎足够自成一篇了，因此DWR相关的内容要留待下文继续了。</p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<img src ="http://www.blogjava.net/Jiangzy/aggbug/153730.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Jiangzy/" target="_blank">飛雪(leo)</a> 2007-10-18 00:47 <a href="http://www.blogjava.net/Jiangzy/archive/2007/10/18/153730.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DOJO试用手记4--dojo基础  </title><link>http://www.blogjava.net/Jiangzy/archive/2007/10/18/153729.html</link><dc:creator>飛雪(leo)</dc:creator><author>飛雪(leo)</author><pubDate>Wed, 17 Oct 2007 16:32:00 GMT</pubDate><guid>http://www.blogjava.net/Jiangzy/archive/2007/10/18/153729.html</guid><wfw:comment>http://www.blogjava.net/Jiangzy/comments/153729.html</wfw:comment><comments>http://www.blogjava.net/Jiangzy/archive/2007/10/18/153729.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Jiangzy/comments/commentRss/153729.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Jiangzy/services/trackbacks/153729.html</trackback:ping><description><![CDATA[<table cellspacing="0" cellpadding="0" width="100%" border="0">
    <tbody>
        <tr>
            <td style="font-size: 12pt; padding-top: 10px" align="center" width="99%" height="40"><strong>DOJO试用手记4--dojo基础 </strong></td>
        </tr>
        <tr>
            <td style="border-bottom: #cccccc 1px solid" align="center" height="30">来源：原创 作者：zxub 发布时间：2006-04-06 17:05:00 &nbsp; </td>
        </tr>
        <tr>
            <td valign="top" height="300">
            <table style="margin-top: 8px" cellspacing="0" cellpadding="0" width="100%" border="0">
                <tbody>
                    <tr>
                        <td width="6" height="52"></td>
                        <td>
                        <table width="100%">
                            <tbody>
                                <tr>
                                    <td align="right"></td>
                                </tr>
                            </tbody>
                        </table>
                        <div class="postbody">
                        <p>　　前面说了dojo在ajax方面的一些个东西，感觉要理解透彻还有些dojo内部的东西需要理解，所以想好好看一下dojo的东西，恶补一阵:-)<br />
                        　　看了会官方一些个文档，有了些许体会。<br />
                        　　<span class="pre"><font face="Courier New">dojo.js被包含进来后，一些对象和函数就可以用了，在用JSEclipse编辑的时候，可以看到一些，不过是包含在dojo.js中的，官网说还包括boostrap文件里的，我查了下，有bootstrap1.js和bootstrap2.js，不过那些对象直接显示不出来，估计有什么地方要设置，弄清楚后再补上来。<br />
                        　　可用的东东有：<br />
                        </font></span>　　１．<span class="pre"><font face="Courier New">dojo.render对象：该对象存放了dojo运行环境的一些信息。<br />
                        　　dojo.render.name：根据dojo.render.name = navigator.appName，可以知道这是浏览器的名称，但是直接显示出来是空的，估计还没有被赋值，运行</p>
                        <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #008080">1</span>&nbsp;<span style="color: #000000">dojo.render.name&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;navigator.appName;<br />
                        </span><span style="color: #008080">2</span>&nbsp;<span style="color: #000000">alert(dojo.render.name);</span></div>
                        <p><br />
                        我的出来的是：Microsoft Internet Explorer。<br />
                        　　<span class="pre">dojo.render.os:看名字就知道与操作系统有关，事实确实如此。这个属性直接打印出来是［object Object］，可以知道是一个对象。查了下源代码，发现这个对象有3个属性：dojo.render.os.osx，当操作系统为"MacOS"取值为true;dojo.render.os.linux，当操作系统为"Linux"的时候为true;dojo.render.os.win，Windows系统取值为true。3个属性的默认值都为false,一进dojo，则某一个属性被赋值为true，我的Windows系统当然是dojo.render.os.win为true了。根据源码，若不是这3种系统，dojo.render.os.linux将赋值为true。<br />
                        　　<span class="pre">dojo.render.ver，官网上说与<span class="pre">dojo.version一样，但我一打印发现不对，查了下代码，发现如下一段：dojo.render.ver = parseFloat(navigator.appVersion, 10)，是与浏览器版本号有关，我这里dojo.render.ver的值为4。再找dojo.version，发现这么一段：</p>
                        <div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #000000">dojo.version&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;{<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;major:&nbsp;</span><span style="color: #000000">0</span><span style="color: #000000">,&nbsp;minor:&nbsp;</span><span style="color: #000000">2</span><span style="color: #000000">,&nbsp;patch:&nbsp;</span><span style="color: #000000">2</span><span style="color: #000000">,&nbsp;flag:&nbsp;</span><span style="color: #000000">""</span><span style="color: #000000">,<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;revision:&nbsp;Number(</span><span style="color: #000000">"</span><span style="color: #000000">$Rev:&nbsp;2836&nbsp;$</span><span style="color: #000000">"</span><span style="color: #000000">.match(</span><span style="color: #000000">/</span><span style="color: #000000">[</span><span style="color: #000000">0</span><span style="color: #000000">-</span><span style="color: #000000">9</span><span style="color: #000000">]</span><span style="color: #000000">+/</span><span style="color: #000000">)[</span><span style="color: #000000">0</span><span style="color: #000000">]),<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;toString:&nbsp;</span><span style="color: #0000ff">function</span><span style="color: #000000">()&nbsp;{<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">with</span><span style="color: #000000">&nbsp;(dojo.version)&nbsp;{<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;major&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">.</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;minor&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">.</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;patch&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;flag&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;(</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;revision&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">)</span><span style="color: #000000">"</span><span style="color: #000000">;<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
                        &nbsp;&nbsp;&nbsp;&nbsp;}<br />
                        };</span></div>
                        <p><br />
                        将dojo.version打印一下，是0.2.2(2836)，上面一段的结果。<br />
                        　　<span class="pre">dojo.render.html，这也是一个对象，它有好几个属性。<span class="pre">dojo.render.html.</span><span class="pre">capable，宿主环境是否支持html，一般来说，都是true。其它几个是与浏览器类型有关的，都是布尔类型。<span class="pre">dojo.render.html.</span><span class="pre">moz，当浏览器为Mozilla或者Mozilla核心的浏览器（例如 Firefox）时为true； </span></span></span><span class="pre"><span class="pre">dojo.render.html.</span>safari，使用苹果的Safari浏览器的时候为true，<span class="pre"><span class="pre">dojo.render.html.</span></span><span class="pre">ie，平常的机器这个属性都是true，因为我们基本是用Microsoft Internet Explorer，即ie浏览器；<span class="pre"><span class="pre"><span class="pre">dojo.render.html.</span></span>opera，使用Opera浏览器的时候为true；<span class="pre"><span class="pre"><span class="pre">dojo.render.html.</span></span></span><span class="pre">khtml，使用KHTML浏览器(例如Konqueror，但是我还就真没听过这种KHTML浏览器，其它的都知道，看来还是知识不够，唉～)的时候为true。<span class="pre">dojo.render.html对象主要是用来判断浏览器类型的。我的机器上dojo.render.html.ie为true。<br />
                        　　其它还有<span class="pre">dojo.render.svg，<span class="pre">dojo.render.vml</span></span>，<span class="pre">dojo.render.swf，<span class="pre">dojo.render.swt，由上面的资料，可以知道是对SVG、VML、SWF、SWT的支持，它们都有个<span class="pre">capable属性，表示是否支持该技术，ie5.0以上版本支持VML，所以我的<span class="pre">dojo.render.vml.<span class="pre">capable为true，SVG需要装插件，所以不支持该项，<span class="pre">dojo.render.svg.<span class="pre">capable为false，<span class="pre">dojo.render.swf.<span class="pre">capable也为false,这里的swf不是指flash的swf，而是Simple Web Framework，Simple Web Framework (SWF)是一个基于事件的web框架.它很适合于那些想要开发胖客户端Web应用程序但又不想转向JSF的Struts开发人员。SWF跟Struts一样也是构建在Jakarta commons基础之上,但使用一个不同的request processor。SWF事件模型支持基于XmlHttpRequest的事件提交。至于<span class="pre">dojo.render.swt，不清楚了，难道与java中的SWT有关系？这四个对象的其它属性，在源码中居然没看到相应代码？？以后弄明白再回来补过。<br />
                        　　２．<span class="pre">dojo.version对象。在上面已经讲过这个对象，是dojo库文件的版本，没啥好研究的了。<br />
                        　　３．dojo.hostenv对象，个人认为里面的东西很有看头，不过要慢慢讲来也太费时间了，具体可以去看源码中那几个hostenv_XXX.js文件，dojo.hostenv.getText函数和dojo.hostenv.println函数还有点意思，以后随时补充吧。<br />
                        　　下面讲一讲dojo中的一些基本函数。<br />
                        　　</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p>
                        </span></span></span></font></span></div>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/Jiangzy/aggbug/153729.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Jiangzy/" target="_blank">飛雪(leo)</a> 2007-10-18 00:32 <a href="http://www.blogjava.net/Jiangzy/archive/2007/10/18/153729.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Dojo学习笔记</title><link>http://www.blogjava.net/Jiangzy/archive/2007/10/18/153726.html</link><dc:creator>飛雪(leo)</dc:creator><author>飛雪(leo)</author><pubDate>Wed, 17 Oct 2007 16:31:00 GMT</pubDate><guid>http://www.blogjava.net/Jiangzy/archive/2007/10/18/153726.html</guid><wfw:comment>http://www.blogjava.net/Jiangzy/comments/153726.html</wfw:comment><comments>http://www.blogjava.net/Jiangzy/archive/2007/10/18/153726.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Jiangzy/comments/commentRss/153726.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Jiangzy/services/trackbacks/153726.html</trackback:ping><description><![CDATA[<p>Dojo学习笔记2007年06月05日 星期二 17:18(1. 模块与包)</p>
<p><br />
Intro:</p>
<p>Dojo是一个非常强大的面向对象的JavaScript的工具箱, 建议读者能够去补充一下JavaScript下如何使用OO进行编程的, 这对于你以后阅读Dojo Source有很大的用处</p>
<p>请大家下载dojo 0.3.1, 以下的说明均针对此版本</p>
<p>翻译自http://manual.dojotoolkit.org/WikiHome/DojoDotBook/BookUsingDojo</p>
<p><br />
Getting Started</p>
<p>1: 把Dojo加入到我们的Web程序中</p>
<p>1. 标志</p>
<p>&lt;script type="text/javascript"&gt;<br />
djConfig = { isDebug: false };<br />
&lt;/script&gt;<br />
djConfig是Dojo里的一个全局对象, 其作用就是为Dojo提供各种选项, isDebug是最常用的属性之一, 设置为True以便能够在页面上直接看到调试输出, 当然其中还有些属性与调试有关, 这里就不罗索了</p>
<p>2. 引用 dojo 的启动代码</p>
<p>&lt;script type="text/javascript" src="/yourpath/dojo.js" /&gt;<br />
这样你就引用了dojo的代码, 并可以直接使用其中部分常用的对象, 下载下来的dojo.js是压缩(remove comments and space)后的代码, 要阅读的话,建议阅读dojo.js.uncompressed.js, dojo.js大概有127K, 而未压缩前有211K, ok, 为什么会这么大呢, 原来其已经把部分常用的模块整合进dojo.js里, 因此显得大了一点, build.txt里就说明了默认的dojo.js包含了哪些模块</p>
<p>3. 声明你所要用到的包</p>
<p>&lt;script type="text/javascript"&gt;<br />
dojo.require("dojo.math");<br />
dojo.require("dojo.io.*");<br />
dojo.require("dojo.widget.*");<br />
&lt;/script&gt;<br />
你就把这些代码当成是java的import语句或C#中的using语句一样, 如果你不require的话, 而模块本身又没有整合在dojo.js中, 是会出现脚本错误的喔</p>
<p>2. 针对不同需求提供的预整合包</p>
<p>Dojo本身是由许多模块所组合而成的, 但是由于用户需求的多样性, dojo针对不同的需求而提供了不同的版本, 用户在下载dojo的时候就看见可以选择很多的版本, 比如Ajax版和Widget版, 每个版本最重要的区别就在于dojo.js文件, 但是除此之外, 每一个版本都是全功能的, dojo.js根据版本的不同而整合进了不同的模块</p>
<p>3. 直接获取Dojo的最新源代码</p>
<p>首先你必须安装 Subversion, 当Subversion在你的电脑上能够正常工作后,你就可以通过如下命令下载dojo的源代码:</p>
<p>svn co http://svn.dojotoolkit.org/dojo/trunk/<br />
这会在你的当前目录下创建一个 trunk 的目录; 如果你希望直接Get到当前目录, 用这个命令:</p>
<p>svn co http://svn.dojotoolkit.org/dojo/trunk/ .<br />
或者你希望Get到当前目录下的 MyDir 目录, 用这个命令:</p>
<p>svn co http://svn.dojotoolkit.org/dojo/trunk/ MyDir</p>
<p>模块与包</p>
<p>模块</p>
<p>Dojo的代码被划分为逻辑单元称之为模块, 这有点类似于Java中的package,除了dojo的模块能够包含类 (类似于java中的classes)和简单函数</p>
<p>比如: 模块"dojo.html"包含了一系列的函数, 比如dojo.html.getContentBox(), 模块"dojo.dnd"包含了一系列的HtmlDragObject的类</p>
<p>注意名称约定, 函数的首字母为小写字母,类的首字母为大写</p>
<p>模块也可以称之为"命名空间"</p>
<p>包</p>
<p>在多数情况下, dojo的模块只需要定义在一个文件就可以了, 但有时, 一个模块可能划分到多个文件, 比如: 模块dojo.html, 本来是定义在一个文件中, 可是由于功能的增强, 文件逐渐变大, 我们不得不将其拆分为多个文件, 这主要是为性能考虑, 以便浏览器可以只下载其需要用到的代码, 不幸的是其实现细节对于dojo的用户看起来不那么透明, 你必须知道你想要用到的功能到底是包含在哪个文件, 然后才能require并使用它</p>
<p>这样的每一个文件都称之为一个包</p>
<p>dojo.require("dojo.html.extras")<br />
将引用文件 src/html/extras.js, 这将定义模块 dojo.html 的若干(并非所有)函数</p>
<p>据我所知, 尽管单个文件可以定义包里的多个类, 单个脚本文件不能定义多个模块 (在Java可以等效于在一个文件中定义2个类), 并且, 包的名称和模块的名称可以不同, 比如: 包dojo.widget.Button定义了dojo.widget.html.Button</p>
<p>基本上你应该这样认为, 包和模块尽管密切相关, 但是是两个完全不同的实体</p>
<p>为什么会有模块和包这样的概念?</p>
<p>为什么会有模块和包这样的概念? 为了满足你的应用程序只需要加载其所用到的东西的需求, 充分利用模块化设计的优点, dojo维护了最小的足印以便仍能提供你所需要的功能, 为什么要你的用户浪费时间去下载用不到的JavaScript, 当一个包就是一个js文件时, 一个模块本质上就是一个命名空间, 比如: dojo.style 或 dojo.html.extras<br />
多数简单情况下, 一个包包含了一个模块, 但更常见的是, 一个模块可能被拆分为几个包文件</p>
<p>利用包和模块, 将能确保你能够交付最相关的功能代码, 最小程度的减少代码的膨胀和消除由此带来的不好的用户体验,这就是模块设计的主要目标, 通过模块化, 你能够引入自定义模块(你自己拥有的 JavaScript 工具), 并且维护模块对于核心代码库基本不会产生什么影响</p>
<p>另外, Dojo的模块系统也提供了内建的机制来使用代码提供命名空间, 比如, 通过模块dojo.event定义的Dojo的事件系统</p>
<p>怎样引用</p>
<p>设置引用语句</p>
<p>你怎样才能知道该引用哪个包到dojo.require()?</p>
<p>1. 模块</p>
<p>首先, 确定你要使用什么模块, 这个例子我们假定你要使用 dojo.lfx.html</p>
<p>2. 包</p>
<p>搜索代码后你发现dojo.lfx.html定义在2个文件:</p>
<p>src/lfx/html.js <br />
src/lfx/extras.js <br />
根据你要用到的功能, 你可以 </p>
<p>dojo.require("dojo.lfx.html");<br />
或 </p>
<p>dojo.require("dojo.lfx.html");<br />
dojo.require("dojo.lfx.extras");</p>
<p>通配符</p>
<p>新用户可能会对dojo.lfx.*这样就可以替代上面2句而感到诧异, 实际上, __package__.js 中已经定义了通配符可以代替的语句, 并且这样可以让dojo根据当时的环境而决定加载具体的模块</p>
<p>Dojo学习笔记(2. djConfig解说)</p>
<p><br />
djConfig是dojo内置的一个全局设置对象，其作用是可以通过其控制dojo的行为</p>
<p>首先我们需要在引用dojo.js前声明djConfig对象，以便在加载dojo.js的时候才能够取得所设置的值，虽然在0.3版本以后dojo支持在加载后设置，但是强烈建议你把声明djConfig的代码作为第一段script</p>
<p>一个完整的djConfig对象定义如下（值均为dojo的默认值）</p>
<p>&lt;script type="text/javascript"&gt;<br />
var djConfig = {<br />
isDebug: false,<br />
debugContainerId: "",<br />
bindEncoding: "",<br />
allowQueryConfig: false,<br />
baseScriptUri: "",<br />
parseWidgets: true<br />
searchIds: [],<br />
baseRelativePath: "",<br />
libraryScriptUri: "",<br />
iePreventClobber: false,<br />
ieClobberMinimal: true,<br />
preventBackButtonFix: true,<br />
};<br />
&lt;/script&gt;<br />
isDebug是一个很有用的属性，顾名思义，如果设置为真，则所有dojo.Debug的输出有效，开发时应该设置为true，发布时应该设置为false</p>
<p>debugContainerId同样也是与调试有关的，如果不指定的话，调试信息将会直接利用 document.write输出，这样可能会破坏页面的整体布局，所以你可以指定任何一个可以作为容器的html元素的id作为调试信息输出容器</p>
<p>allowQueryConfig，这个属性指明 dojo是否允许从页面url的参数中读取djConfig中的相关属性，当值为true时，dojo会优先从url参数中读取djConfig的其他属性，比如: http://server/dojoDemo.htm?djConfig.debugContainerId=divDebug</p>
<p>baseScriptUri，一般不需要设置，dojo会自动根据你引用dojo.js的路径设置这个值，比如，&lt;script type="text/javascript" src="../dojo/dojo.js"&gt;&lt;/script&gt;，自动获取的值便是 ../dojo/<br />
ps: 如果你有多个工程需要同时引用dojo.js的话，建议也把dojo当作一个独立的工程，引用的时候采用绝对路径就可以了</p>
<p>parseWidgets，这个是可以控制dojo是否自动解析具有dojoType的html元素为对应的widget，如果你没有使用任何Widget，建议设置为false以加快dojo的加载速度</p>
<p>searchIds，这是一个字符串数组，定义了所有需要解析为widget的html元素的ID，如果ID不在其中的html元素是不会被解析的，当数组为空数组时，则所有具有dojoType的元素都会被解析</p>
<p>还有一个bindEncoding，是用来设置默认的bind请求的编码方式</p>
<p>至于其它的属性，不是用处不大，就是不知道有什么作用</p>
<p>在实际开发中，可以把djConfig的定义放在一个js文件里，并将其作为第一个引用的js文件，这样应该是最方便的。</p>
<p>Dojo学习笔记(3. Dojo的基础对象和方法)</p>
<p>这里所说的基础对象和方法是指的不Require任何包就能够调用的对象和方法</p>
<p>匿名函数</p>
<p>在开始前，我想介绍一下js里的匿名函数，这个在阅读dojo的源代码的时候，会发现到处都有匿名函数</p>
<p>;(function(){<br />
alert(123);<br />
})();<br />
//前面的分号是一个空语句，是可以不要的<br />
匿名函数。一个匿名函数就是一个没有名字的函数。</p>
<p>你可以认为他们是一次性函数。当你只需要用一次某个函数时，他们就特别有用。通过使用匿名函数，没有必要把函数一直放在内存中，所以使用匿名函数更加有效率。</p>
<p>当然你也可以根本不定义函数，但是使用匿名函数可以把你的代码分段，就像C#中的#region一样</p>
<p>dojo.byId</p>
<p>非常有用的一个方法，与prototype.js的著名的$一样</p>
<p>似乎以前的版本还有dojo.byIdArray, 不过最新的版本已经找不到这个函数了(除了src\compat\0.2.2.js)</p>
<p>如果有多个元素具有指定的id，则返回的是一个集合</p>
<p>Usage Example:</p>
<p>dojo.byId("divTest");<br />
dojo.byId("divTest", document);<br />
dojo.byId(document.getElementById("divTest"));</p>
<p><br />
dojo.version</p>
<p>dojo的版本，可以取得major, minor, patch, flag和revision</p>
<p>这个对象没什么太大用处，除非你要根据dojo的版本选择执行你的代码</p>
<p>dojo.raise</p>
<p>抛出一个异常</p>
<p>dojo.errorToString</p>
<p>将异常转换为字符串</p>
<p>Usage Example:</p>
<p>try<br />
{<br />
dojo.raise("打印失败", new Error("文件不存在"));<br />
}<br />
catch(e)<br />
{<br />
alert(dojo.errorToString(e));<br />
}</p>
<p><br />
dojo.render</p>
<p>系统环境对象</p>
<p>dojo.render.name 返回 browser ，说明是工作在浏览器下<br />
dojo.render.ver 返回 4 ，似乎没什么用<br />
dojo.os.win 返回true说明操作系统是Windows<br />
dojo.os.linux 返回true说明操作系统是Linux<br />
dojo.os.osx 返回true说明操作系统是MacOS<br />
dojo.html.ie 返回true说明浏览器是Internet Explorer<br />
dojo.html.opera 返回true说明浏览器是Opera<br />
dojo.html.khtml 返回true说明浏览器是Konqueror<br />
dojo.html.safari 返回true说明浏览器是Safari<br />
dojo.html.moz 返回true说明浏览器是Mozilla FireFox<br />
dojo.svg.capable 返回true说明浏览器支持svg<br />
dojo.vml.capable 返回true说明浏览器支持vml<br />
dojo.swf.capable 返回true说明浏览器支持swf<br />
dojo.swt.capable 返回true说明浏览器支持swt (IBM开发的Standard Widget Toolkit)<br />
如果dojo.html.ie为true的话</p>
<p>dojo.html.ie50 返回true说明浏览器是IE 5.0<br />
dojo.html.ie55 返回true说明浏览器是IE 5.5<br />
dojo.html.ie60 返回true说明浏览器是IE 6.0<br />
dojo.html.ie70 返回true说明浏览器是IE 7.0</p>
<p><br />
dojo.addOnLoad</p>
<p>可以加载指定函数到window.load时执行，好处就是可以很方便的在window.load时执行多个函数</p>
<p>Usage Example:</p>
<p>dojo.addOnLoad(init); //init是一个函数<br />
dojo.addOnLoad(myObject, init); //init是myObject对象的一个方法</p>
<p><br />
dojo.require</p>
<p>如果你想调用一个模块的对象的时候，你应该首先用dojo.require来请求这个模块，dojo会根据你的请求自动取得相应的js文件，并加载到内存中，这样你才能调用或创建其中的对象</p>
<p>dojo会自动维护已加载的模块列表，所以是不会重复加载模块的</p>
<p>Usage Example:</p>
<p>dojo.require("dojo.event");<br />
dojo.requireIf=dojo.requireAfterIf</p>
<p>可以根据指定的条件来决定是否加载指定的模块</p>
<p>Usage Example:</p>
<p>dojo.requireIf(dojo.html.ie, "dojo.html"); //如果dojo.html.ie为true，才会加载dojo.html模块</p>
<p><br />
dojo.provide</p>
<p>除非你要开发自己的模块，不然是用不到这个方法的，你可以这句看成是向系统注册这个模块名称</p>
<p>Usage Example:</p>
<p>dojo.provide("dojo.custom");<br />
dojo.exists</p>
<p>判断指定对象是否具有指定名称的方法</p>
<p>Usage Example:</p>
<p>dojo.exists(dojo, "exists"); //will return true</p>
<p><br />
dojo.hostenv.getText</p>
<p>返回指定url的内容</p>
<p>PS: 由于浏览器的安全限制，因此只能用于取得同域名的url的内容，否则会报告权限不够</p>
<p>Usage Example:</p>
<p>aSync = false; //同步，确保返回内容不为null<br />
silent = true; //不抛出错误<br />
s = dojo.hostenv.getText("http://www.google.com/", aSync, silent); //返回Google的首页的HTML<br />
alert(s);<br />
dojo.debug</p>
<p>输出调试信息，如果在djConfig中指定了debugContainerId，则输出到指定的console容器中，否则直接document.write</p>
<p>所有的调试信息均以 DEBUG: 开头</p>
<p>Usage Example:</p>
<p>dojo.debug("这是调试信息");</p>
<p><br />
dojo.hostenv.println</p>
<p>与dojo.debug类似，不同的是，输出内容没有 DEBUG:</p>
<p>Usage Example:</p>
<p>dojo.hostenv.println("这是一般的输出信息");</p>
<p><br />
dojo.debugShallow</p>
<p>输出指定对象的全部信息(Shallow说明并不会遍历到下一级别的对象属性)以供调试</p>
<p>Usage Example:</p>
<p>dojo.debugShallow(dojo.render.html);<br />
Dojo学习笔记(4. dojo.string &amp; dojo.lang) </p>
<p>模块：dojo.string.common / dojo.stringdojo.string.common 和 dojo.string 是一样的，只要require其中一个就可以使用以下方法dojo.string.trim去掉字符串的空白Usage Example:s = " abc ";dojo.string.trim(s); //will return "abc"dojo.string.trim(s, 0); //will return "abc"dojo.string.trim(s, 1); //will return "abc "dojo.string.trim(s, -1);//will return " abc"<br />
dojo.string.trimStart去掉字符串开头的空白Usage Example:s = " abc ";dojo.string.trimStart(s); //will return "abc "dojo.string.trimEnd去掉字符串结尾的空白Usage Example:s = " abc ";dojo.string.trimEnd(s); //will return " abc"dojo.string.repeat生成由同一字符(串)重复组成的字符串Usage Example:dojo.string.repeat("a", 4); //will return "aaaa"dojo.string.repeat("1234", 3, "-"); //will return "1234-1234-1234"dojo.string.pad使用字符补齐字符串Usage Example:dojo.string.pad("100", 6); //will return "000100"dojo.string.pad("100", 6, "0", 1); //will return "000100"dojo.string.pad("100", 6, "0", -1); //will return "100000"dojo.string.padLeft使用字符补齐字符串开头Usage Example:dojo.string.padLeft("100", 6); //will return "000100"dojo.string.padRight使用字符补齐字符串结尾Usage Example:dojo.string.padRight("100", 6); //will return "100000"<br />
模块：dojo.lang.common / dojo.langdojo.lang.common 和 dojo.lang 是一样的，只要require其中一个就可以使用以下方法<br />
dojo.lang.mixin将一个对象的方法和属性增加到另一个对象上Usage Example:var s1 = {name: "TestObj", test1: function(){alert("this is test1!");}}var s2 = {value: 1000, test2: function(){alert("this is test2!");}}var d = {};dojo.lang.mixin(d, s1, s2); //执行后d就具备了s1和s2的所有属性和方法d.test1();dojo.lang.extend为指定类的原型扩展方法与属性Usage Example:TestClass = function() {};dojo.lang.extend(TestClass, {name: "demo", test: function(){alert("Test!");}});var o = new TestClass(); //TestClass本来是没有test方法的，但是extend以后就有test方法了o.test();dojo.lang.find=dojo.lang.indexOf查找指定对象在指定数组中的位置Usage Example:var arr = [1,2,3,3,2,1];dojo.lang.find(arr, 2); //will return 1dojo.lang.find(arr, 2, true); //will return 1dojo.lang.find(arr, "2", true); //will return -1dojo.lang.find(arr, "2", false); //will return 1dojo.lang.find(arr, 2, true, true); //will return 4dojo.lang.findLast=dojo.lang.lastIndexOf查找指定对象在指定数组中的位置，从后往前查Usage Example:var arr = [1,2,3,3,2,1];dojo.lang.findLast(arr, 2); //will return 4dojo.lang.findLast(arr, 2, true); //will return 4dojo.lang.findLast(arr, "2", true); //will return -1dojo.lang.findLast(arr, "2", false); //will return 4dojo.lang.inArray查找指定对象是否在指定数组中Usage Example:var arr = [1,2,3];dojo.lang.inArray(arr, 1); //will return truedojo.lang.inArray(arr, 4); //will return falsedojo.lang.isObject判断输入的类型是否为对象Usage Example:dojo.lang.isObject(new String()); //will return truedojo.lang.isObject("123")); //will return falsedojo.lang.isArray判断输入的类型是否为数组Usage Example:dojo.lang.isArray({a:1,b:2}); //will return falsedojo.lang.isArray([1,2,3]); //will return truedojo.lang.isFunction判断输入的类型是否为函数Usage Example:dojo.lang.isFunction(function() {}); //will return truedojo.lang.isString判断输入的类型是否为字符串Usage Example:dojo.lang.isString(""); //will return truedojo.lang.isString(0); //will return falsedojo.lang.isAlien判断输入的类型是否为系统函数Usage Example:dojo.lang.isAlien(isNaN); //will return truedojo.lang.isBoolean判断输入的类型是否为布尔类型Usage Example:dojo.lang.isBoolean(2&gt;1); //will return truedojo.lang.isNumber判断输入的类型是否为数值，根据注释所说，此函数使用不太可靠，但是可替换使用的系统函数isNaN也不太可靠dojo.lang.isUndefined判断输入是否为未定义，根据注释所说，此函数有可能会导致抛出异常，推荐使用 typeof foo == "undefined" 来判断<br />
模块：dojo.lang.extrasdojo.lang.setTimeout延迟指定时间后执行指定方法Usage Example:function onTime(msg){dojo.debug(msg)}dojo.lang.setTimeout(onTime, 1000, "test"); //1秒后会输出调试信息"test"dojo.lang.setTimeout(dojo, "debug", 1000, "test"); //1秒后会输出调试信息"test"dojo.lang.getNameInObj获得指定项目在指定对象中的名称Usage Example:dojo.lang.getNameInObj(dojo, dojo.debug); //will return "debug"dojo.lang.shallowCopy返回指定对象的浅表复制副本Usage Example:dojo.lang.shallowCopy({}); //will return a 空对象dojo.lang.firstValued返回第一个存在定义的参数Usage Example:var a;dojo.lang.firstValued(a,2,3); //will return 2以上全部是自己阅读源代码写的总结，如有错误，还请指明。 </p>
<img src ="http://www.blogjava.net/Jiangzy/aggbug/153726.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Jiangzy/" target="_blank">飛雪(leo)</a> 2007-10-18 00:31 <a href="http://www.blogjava.net/Jiangzy/archive/2007/10/18/153726.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>DOJO试用手记2--Event System  </title><link>http://www.blogjava.net/Jiangzy/archive/2007/10/18/153723.html</link><dc:creator>飛雪(leo)</dc:creator><author>飛雪(leo)</author><pubDate>Wed, 17 Oct 2007 16:28:00 GMT</pubDate><guid>http://www.blogjava.net/Jiangzy/archive/2007/10/18/153723.html</guid><wfw:comment>http://www.blogjava.net/Jiangzy/comments/153723.html</wfw:comment><comments>http://www.blogjava.net/Jiangzy/archive/2007/10/18/153723.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Jiangzy/comments/commentRss/153723.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Jiangzy/services/trackbacks/153723.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: DOJO试用手记2--Event System                             来源：原创 作者：zxub 发布时间：2006-04-02 11:13:00 &nbsp;                                                                                   ...&nbsp;&nbsp;<a href='http://www.blogjava.net/Jiangzy/archive/2007/10/18/153723.html'>阅读全文</a><img src ="http://www.blogjava.net/Jiangzy/aggbug/153723.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Jiangzy/" target="_blank">飛雪(leo)</a> 2007-10-18 00:28 <a href="http://www.blogjava.net/Jiangzy/archive/2007/10/18/153723.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>