欧美日韩中文在线,免费精品视频,国产日韩视频一区二区三区http://www.aygfsteel.com/Jiangzy/category/26628.html這個世界上只有兩樣東西愈分享愈多,那就是智慧與愛。zh-cnSat, 26 Jan 2008 05:59:36 GMTSat, 26 Jan 2008 05:59:36 GMT60js壓縮http://www.aygfsteel.com/Jiangzy/archive/2008/01/25/177858.html飛雪(leo)飛雪(leo)Fri, 25 Jan 2008 15:11:00 GMThttp://www.aygfsteel.com/Jiangzy/archive/2008/01/25/177858.htmlhttp://www.aygfsteel.com/Jiangzy/comments/177858.htmlhttp://www.aygfsteel.com/Jiangzy/archive/2008/01/25/177858.html#Feedback0http://www.aygfsteel.com/Jiangzy/comments/commentRss/177858.htmlhttp://www.aygfsteel.com/Jiangzy/services/trackbacks/177858.html壓縮不僅僅可以提高用戶的下載速度,同時還可以加密代碼,下面說下一個常用的js壓縮方法:

首先使用dojo的工具shrinksafe(http://shrinksafe.dojotoolkit.org/)壓縮一下,dojo的這個工具會去掉注釋,他的壓縮不是簡單的替換變量,而是利用了mozilla的一個工具,對js解析后才壓縮,確保壓縮后的代碼不會出錯。

dojo壓縮后,并不會減少太多,下一步可以使用http://javascriptcompressor.com/這個站點進行更高層次的壓縮,可惜只能登陸這個站點再壓縮,只能將你的js代碼復制的他的文本框,然后等他的壓縮輸出

經過這2步,你的js會變得既安全,文件又小



飛雪(leo) 2008-01-25 23:11 發表評論
]]>
Struts2與ajax的組合 http://www.aygfsteel.com/Jiangzy/archive/2007/10/18/153730.html飛雪(leo)飛雪(leo)Wed, 17 Oct 2007 16:47:00 GMThttp://www.aygfsteel.com/Jiangzy/archive/2007/10/18/153730.htmlhttp://www.aygfsteel.com/Jiangzy/comments/153730.htmlhttp://www.aygfsteel.com/Jiangzy/archive/2007/10/18/153730.html#Feedback0http://www.aygfsteel.com/Jiangzy/comments/commentRss/153730.htmlhttp://www.aygfsteel.com/Jiangzy/services/trackbacks/153730.html

Struts2與ajax的組合

Struts2與ajax的組合
在當今——Web 2.0概念鋪天蓋地的Internet環境下,簡易的AJAX集成對于一個成功的WEB框架來說是不可或缺的。因此,Struts 2其中的一個重要的功能(Feature)就是“First-class AJAX support - Add interactivity and flexibility with AJAX tags that look and feel just like standard Struts tags(大意:一流的AJAX支持——通過AJAX標志增加互動性和靈活性,而且使用這些AJAX標志與普通的Struts標志同樣簡單)”。
實現原理
基于不重新發明輪子的原則,Struts 2并沒有開發新的AJAX框架,而是使用時下Java EE平臺中比較流行的AJAX框架——Dojo和DWR。
最近在Musachy Barroso等同志的無私奉獻下,開發了Struts 2的JSON插件(Plugin),極大地方便了我們輸出JSON結果(Result)。
JSON插件(Plugin)
在Struts 2的showcase中的AJAX部分,JSON的結果輸出是通過Freemaker模板實現。這種方法在簡易性和靈活性上都比不上JSON插件,所以JSON插件值得向大家五星推薦。
下面讓我們看一個JSON插件的例子。
首先到以下網址http://code.google.com/p/jsonplugin/downloads/list下載JSON插件的JAR包,并將其加入你的WebContent\WEB-INF\lib下。
接下是本例子的Action代碼:
package tutorial;

import java.util.ArrayList;
import java.util.List;

import com.googlecode.jsonplugin.annotations.JSON;
import com.opensymphony.xwork2.ActionSupport;

public class JsonPluginAction extends ActionSupport {
private static final long serialVersionUID = -6784977600668791997L;

private int bookId;
private String title;
private double price;
private List<String> comments;
private transient String secret1;
private String secret2;

@JSON(name="ISBN")
public int getBookId() {
return bookId;
}

public void setBookId(int bookId) {
this.bookId = bookId;
}

public List<String> getComments() {
return comments;
}

public void setComments(List<String> comments) {
this.comments = comments;
}

public double getPrice() {
return price;
}

public void setPrice(double price) {
this.price = price;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

@Override
public String execute() {
bookId = 15645912;
title = "Max On Java";
price = 0.9999d;
comments = new ArrayList<String>(3);
comments.add("It's no bad!");
comments.add("WOW!");
comments.add("No comment!");
secret1 = "You can't see me!";
secret2 = "I am invisible!";
return SUCCESS;
}
}
清單1 src/tutorial/JsonPluginAction.java
以上代碼值得注意的是,通過@JSON的JAVA注釋(Annotation),我們可以改變JSON結果的屬性名稱,另外帶有transient修飾符與沒有Getter方法的字段(field)都不會被串行化為JSON。
然后,我們來配置一下此Action,代碼如下:
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
<package name="Struts2_AJAX_DEMO" extends="json-default">
<action name="JsonPlugin" class="tutorial.JsonPluginAction">
<result type="json" />
</action>
</package>
</struts>
清單2 src/struts.xml
上面配置文件的“package”元素和以往不同的是,它擴展了“json-default”而不是“struts-default”。“json-default”是在jsonplugin-0.11.jar包里的struts-plugin.xml中定義的。該文件同時定義了“json”的結果類型,有興趣的朋友可以打開此文件看看。
發布運行應用程序,在瀏覽器中鍵入:http://localhost:8080/Struts2_Ajax/JsonPlugin.action,出現下載文件對話框,原因是JSON插件將HTTP響應(Response)的MIME類型設為“application/json”。把文件下載下來,用記事本打開,內容如下:
{"ISBN":15645912,"comments":["It's no bad!","WOW!","No comment!"],"price":0.9999,"title":"Max On Java"}
清單3 例子1輸出的JSON串
當然這還不是一個完整的AJAX的例子,下面讓我們寫一個HTML文件將其完成,HTML代碼如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>JSON Plugin</title>
<script type="text/javascript">
var bXmlHttpSupport = (typeof XMLHttpRequest != "undefined" || window.ActiveXObject);

if (typeof XMLHttpRequest == "undefined" && window.ActiveXObject) {
function XMLHttpRequest() {
var arrSignatures = ["MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0",
"MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP",
"Microsoft.XMLHTTP"];

for (var i=0; i < arrSignatures.length; i++) {
try {
var oRequest = new ActiveXObject(arrSignatures[i]);
return oRequest;
} catch (oError) { /*ignore*/ }
}

throw new Error("MSXML is not installed on your system.");
}
}

function retrieveBook() {
if(bXmlHttpSupport) {
var sUrl = 'JsonPlugin.action';
var oRequest = new XMLHttpRequest();
oRequest.onreadystatechange = function() {
if(oRequest.readyState == 4) {
var oBook = eval('(' + oRequest.responseText + ')');
var bookHolder = document.getElementById('bookHolder');
var sBook = '<p><b>ISBN: </b>' + oBook.ISBN + '</p>';
sBook += ('<p><b>Title: </b>' + oBook.title + '</p>');
sBook += ('<p><b>Price: </b>$' + oBook.price + '</p>');
sBook += ('<b><i>Comments: </i></b><hr/>');
for(i = 0; i < oBook.comments.length; i++) {
sBook += ('<p><b>#' + (i + 1) + ' </b>' + oBook.comments[i] + '</p>');
}
bookHolder.innerHTML = sBook;
}
};
oRequest.open('POST', sUrl);
oRequest.send(null);
}
}
</script>
</head>
<body>
<input type="button" value="Retrieve Book" onclick="retrieveBook()" />
<div id="bookHolder"></div>
</body>
</html>
清單4 WebContent/JsonPlugin.html
以上代碼中,我沒有使用任何的AJAX的Javascript包,而是參考《Professional Javascript For Web Developer》手工創建XHR(XMLHttpRequest),并在XHR完成后使用eval()方法將JSON字符串變為JSON對象。需要注意的是,要調用eval函數時,必須使用“(”和“)”將JSON字符串括起來,否則會出錯的。
打開http://localhost:8080/Struts2_Ajax/JsonPlugin.html,點擊“Retrieve Book”按鈕,頁面如下圖所示:

圖1 JsonPlugin.html頁面輸出
Struts 2與Dojo
Dojo是開源Javascript工具包,它引了Widget的概念,方便了Javascript面向對象編程(OOP),改進Javascript的事件模型。在此我不打算對此進行深入的講解,有興趣的朋友的可以找網上找一些關于Dojo的資料學習。
Struts 2基于Dojo編寫一些AJAX標志(在Dojo中稱為Widget),要使用這些標志的AJAX功能,需要將標志的“theme”屬性設為“ajax”。同時,亦需要將加入在<head>與</head>之間加入<s:head theme="ajax" />。當使用這些標志的AJAX功能,有些屬性可能會經常用到,所以我會對這些屬性稍作解釋。
名稱 描述
href XHR(XMLHttpRequest)請求的地址
listenTopics 監聽的Dojo話題(Topic)以觸發自身,如可以在可以通過發布(Publish)相應的話題,通知<s:autocompleter />重新加載其備選項(Options)
notifyTopics 完成遠程調用后,發出通知,觸發相應的Javascript函數或Dojo Widget
formId 需要提交到服務器的表單的ID
formFilter 過濾表單字段的Javascript函數名稱
indicator 在XHR處理過程中,包含用戶提示的信息的HTML元素的ID,如圖片或DIV等
表1 常用的AJAX標志屬性
這些標志包括:<s:a />、<s: submit />、<s:autocompleter />和<s:tree />等,下面我將分別講解。
1、<s:a />和<s:submit />
這兩個標志方便了我們的調用XHR實現AJAX,所以上面的HTML如果使用了這兩標志將會變得更簡單,因為我們不用再去理會繁鎖的XHR創建和設定的工作。下面是示例代碼:
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>JSON Plugin</title>
<s:head theme="ajax" />
<script type="text/javascript">
dojo.addOnLoad(function() {
dojo.event.topic.subscribe('retrieveBook', this, function(data, type, e){
if(type == 'load') {
showBook(data);
} else if(type == 'error') {
alert('Can not retrieve the book');
}
});
});

function showBook(strBook) {
var oBook = eval('(' + strBook + ')');
var bookHolder = document.getElementById('bookHolder');
var sBook = '<p><b>ISBN: </b>' + oBook.ISBN + '</p>';
sBook += ('<p><b>Title: </b>' + oBook.title + '</p>');
sBook += ('<p><b>Price: </b>$' + oBook.price + '</p>');
sBook += ('<b><i>Comments: </i></b><hr/>');
for(i = 0; i < oBook.comments.length; i++) {
sBook += ('<p><b>#' + (i + 1) + ' </b>' + oBook.comments[i] + '</p>');
}
bookHolder.innerHTML = sBook;
}
</script>
</head>
<body>
<s:url id="bookUrl" value="/JsonPlugin.action" />
<s:submit href="%{bookUrl}" theme="ajax" indicator="indicator"
value="Retrieve Book" align="left" notifyTopics="retrieveBook" />
<s:a theme="ajax" href="%{bookUrl}" indicator="indicator"
notifyTopics="retrieveBook">Retrieve Book</s:a>
<img id="indicator"
src="${pageContext.request.contextPath}/images/indicator.gif"
alt="Loading " style="display:none" />
<div id="bookHolder"></div>
</body>
</html>
清單5 WebContent/LinkButton.jsp
可能上述代碼還不夠簡潔,因為我將HTML格式化的工作都放在Javascript中完成。但如果你的XHR返回的是HTML片段,你可以簡單地將<s:a />或<s:submit />的“targets”屬性設為“bookHolder”即可,詳情大家可以參考Struts 2 Showcase。至于返回HTML片段,可以通過Action + Freemaker完成。
2、<s:autocompleter />
Autocomplete是比較經典的AJAX應用,雖然谷歌已經停止使用這一功能,但就Autocompleter自身而言的確是很酷的。下面是一個<s:autocompleter />的例子。
首先,我要偽造一些字符串數據,代碼如下:
package tutorial;

import java.util.ArrayList;
import java.util.List;

public final class Datas {
public static final List<String> NAMES;
static {
NAMES = new ArrayList<String>();
NAMES.add("Alabama");
NAMES.add("Alaska");
NAMES.add("American Samoa");
NAMES.add("Arizona");
NAMES.add("Arkansas");
NAMES.add("Armed Forces Europe");
NAMES.add("Armed Forces Pacific");
NAMES.add("Armed Forces the Americas");
NAMES.add("California");
NAMES.add("Colorado");
NAMES.add("Connecticut");
NAMES.add("Delaware");
NAMES.add("District of Columbia");
NAMES.add("Federated States of Micronesia");
NAMES.add("Florida");
NAMES.add("Georgia");
NAMES.add("Guam");
NAMES.add("Hawaii");
NAMES.add("Idaho");
NAMES.add("Illinois");
NAMES.add("Indiana");
NAMES.add("Iowa");
NAMES.add("Kansas");
NAMES.add("Kentucky");
NAMES.add("Louisiana");
NAMES.add("Maine");
NAMES.add("Marshall Islands");
NAMES.add("Maryland");
NAMES.add("Massachusetts");
NAMES.add("Michigan");
NAMES.add("Minnesota");
NAMES.add("Mississippi");
NAMES.add("Missouri");
NAMES.add("Montana");
NAMES.add("Nebraska");
NAMES.add("Nevada");
NAMES.add("New Hampshire");
NAMES.add("New Jersey");
NAMES.add("New Mexico");
NAMES.add("New York");
NAMES.add("North Carolina");
NAMES.add("North Dakota");
NAMES.add("Northern Mariana Islands");
NAMES.add("Ohio");
NAMES.add("Oklahoma");
NAMES.add("Oregon");
NAMES.add("Pennsylvania");
NAMES.add("Puerto Rico");
NAMES.add("Rhode Island");
NAMES.add("South Carolina");
NAMES.add("South Dakota");
NAMES.add("Tennessee");
NAMES.add("Texas");
NAMES.add("Utah");
NAMES.add("Vermont");
NAMES.add("Virgin Islands, U.S.");
NAMES.add("Virginia");
NAMES.add("Washington");
NAMES.add("West Virginia");
NAMES.add("Wisconsin");
NAMES.add("Wyoming");
}
}
清單6 src/tutorial/Datas.java
然后是用于獲取和過濾數據的Action,代碼如下:
package tutorial;

import java.util.ArrayList;
import java.util.List;

import com.opensymphony.xwork2.ActionSupport;

public class AutocompleterAction extends ActionSupport {
private static final long serialVersionUID = -8201401726773589361L;

private List<String[]> names;
private String start;

public void setStart(String start) {
this.start = start;
}

public List<String[]> getNames() {
return names;
}

@Override
public String execute() {
names = new ArrayList<String[]>();
if(start == null || "".equals(start.trim())) {
start = "a";
}
for(String s : Datas.NAMES) {
if(s.toLowerCase().startsWith(start.toLowerCase())) {
names.add(new String[]{ s, s });
}
}
return SUCCESS;
}
}
清單7 src/tutorial/AutocmpleterAction.java
上述Action會以JSON的形式返回以start開頭的Datas.NAMES的中字符串,以下是此Action的配置:
<action name="Autocompleter" class="tutorial.AutocompleterAction">
<result type="json">
<param name="root">names</param>
</result>
</action>
清單8 Autocompleter Action的配置代碼片段
在JSON類型結果的參數中加入“root”參數可以設定輸出JSON結果的根,以上述情況為例,如果沒有“root”參數,輸出將為“{ "names": [ ["xxx", "xxx"]...] }”,加了之后變就會成“[ ["xxx", "xxx"]...] ”。接下來,讓我們看看頁面的代碼:
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Struts 2 AJAX - Autocompleter</title>
<s:head theme="ajax" />
</head>
<body>
<h2>
Autocompleter
</h2>
<s:form action="autocompleterForm">
<s:textfield label="abc" name="abc" />
<tr>
<td class="tdLabel">
<label class="label">
No AJAX Autocompleter:
</label>
</td>
<td>
<s:autocompleter theme="simple" name="user"
list="@tutorial.Datas@NAMES" />
</td>
</tr>
<tr>
<td class="tdLabel">
<label class="label">
AJAX Autocompleter:
</label>
</td>
<td>
<s:url id="dataUrl" value="/Autocompleter.action" />
<s:autocompleter theme="ajax" name="start" href="%{dataUrl}"
loadOnTextChange="true" loadMinimumCount="1" indicator="indicator"
autoComplete="false" showDownArrow="false" />
<img id="indicator"
src="${pageContext.request.contextPath}/images/indicator.gif"
alt="Loading " style="display:none" />
</td>
</tr>
</s:form>
</body>
</html>
清單9 WebContent/Autocompleter.jsp
上述頁面包含兩個<s:autocompleter />標志,前者使用“simple”模板,所以不具有AJAX功能,它的數據將以HTML方式輸出到最終頁面里;而后者則使用了“ajax”模板,每當輸入框的值發生改變時,它都向URL“/Autocompleter.action”發送請求,Action根據請求中的start參數的值,返回相當的JSON,在請求完成后頁面通過回調函數改變輸入框的下拉提示,效果如下圖所示:

圖2 Autocompleter.jsp頁面輸出
3、<s:tree />
樹是是比較常用的數據結構,因為它可以很好地體現真實世界中對象之間的關系。<s:tree />的使用也相對簡單,但需要說明的是——Struts 2.0.6 GA版本的<s:tree />是有BUG的,大家可以點擊這個鏈接https://issues.apache.org/struts/browse/WW-1813了解詳細的情況。這個BUG主要是在<s:tree />的通過“treeCollapsedTopic”、“treeExpandedTopic”和“treeSelectedTopic”設定的話題(Topic)都沒有起作用,上述鏈接相應給出了解決方法,但我認為該方法太麻煩(需要自己重新編譯和打包Struts 2),所以下面的例子,我將另辟徯徑,請參考以下代碼。
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Struts 2 AJAX - Tree</title>
<s:head theme="ajax" debug="true" />
<script type="text/javascript">
function treeNodeSelected(arg) {
alert(arg.source.title + ' selected');
}
dojo.addOnLoad(function() {
var s = dojo.widget.byId('parentId').selector;
dojo.event.connect(s, 'select', 'treeNodeSelected');
});
</script>
</head>
<body>
<h2>
Tree
</h2>
<div style="float:left; margin-right: 50px;">
<s:tree label="parent" id="parentId" theme="ajax"
templateCssPath="/struts/tree.css" showRootGrid="true"
showGrid="true">
<s:treenode theme="ajax" label="child1" id="child1Id">
<s:treenode theme="ajax" label="grandchild1" id="grandchild1Id" />
<s:treenode theme="ajax" label="grandchild2" id="grandchild2Id" />
<s:treenode theme="ajax" label="grandchild3" id="grandchild3Id" />
</s:treenode>
<s:treenode theme="ajax" label="child2" id="child2Id" />
<s:treenode theme="ajax" label="child3" id="child3Id" />
<s:treenode theme="ajax" label="child4" id="child4Id" />
<s:treenode theme="ajax" label="child5" id="child5Id">
<s:treenode theme="ajax" label="gChild1" id="gChild1Id" />
<s:treenode theme="ajax" label="gChild2" id="gChild2Id" />
</s:treenode>
</s:tree>
</div>
</body>
</html>
清單10 WebContent/Tree.jsp
因為Dojo的樹控件,即使在沒有設定“selector”情況下,也會自動生成一個默認的Selector,所以只要將其事件綁定到特定的事件處理函數即可。
打開http://localhost:8080/Struts2_Ajax/Tree.jsp,點擊任一樹節點,頁面如下圖所示:

圖3 Tree.jsp頁面輸出
更多<s:tree />
在Struts 2的showcase中有兩個<s:tree />的例子,分別是靜態樹與動態樹。所謂的靜態樹即是在編寫JSP代碼時通過<s:treenode />生成樹節點。我的上一篇文章的例子就是一個典型的靜態樹。而動態樹則是在程序運行期間,Struts 2 運行時(Runtime)根據程序中的數據動態創建樹節點。雖然在兩個例子中<s:tree />的theme屬性都為“ajax”,但是從嚴格意義上來說,這兩種樹都不屬于AJAX樹,因為它們都是在輸出頁面時將全部節點加載到其中,而不是在父節點展開時通過XHR(XMLHttpRequest)獲取節點數據。
動態樹
下面我們先看一下動態樹的例子,接著再一步步地將其改造為名副其實的AJAX 樹。下例將會把WEB應用程序的目錄樹展現在JSP頁面中。因此,我需要先包裝一下java.io.File 類,代碼如下:
package tutorial;

import java.io.File;

public class FileWrapper {
private File file;

public FileWrapper(String path) {
file = new File(path);
}

public FileWrapper(File file) {
this.file = file;
}

public String getId() {
return "file_" + file.hashCode();
}

public String getName() {
return file.getName();
}

public String getAbsolutePath() {
return file.getAbsolutePath();
}

public FileWrapper[] getChildren() {
File[] files = file.listFiles();
if(files != null && files.length > 0) {
int length = files.length;
FileWrapper[] wrappers = new FileWrapper[length];
for(int i = 0; i < length; ++i) {
wrappers[i] = new FileWrapper(files[i]);
}
return wrappers;
}
return new FileWrapper[0];
}
}
清單1 src/tutorial/FileWrapper.java
之所以需要對File類進行如此包裝,是因為<s:tree />用于動態樹時,rootNode、nodeIdProperty、nodeTitleProperty 和 childCollectionProperty等屬性都必填的。
然后是Action類的代碼如下:
package tutorial;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.interceptor.ServletRequestAware;

import com.opensymphony.xwork2.ActionSupport;

public class DynamicTreeAction extends ActionSupport implements ServletRequestAware {
private static final long serialVersionUID = 1128593047269036737L;

private HttpServletRequest request;
private FileWrapper root;

public void setServletRequest(HttpServletRequest request) {
this.request = request;
}

public FileWrapper getRoot() {
return root;
}

@Override
public String execute() {
root = new FileWrapper(request.getSession().getServletContext().getRealPath("/"));
return SUCCESS;
}
}
清單2 src/tutorial/DynamicTreeAction.java
上述代碼取得WEB應用程序的根目錄的絕對路徑后,初始化FileWrapper對象root。該對象將為JSP頁面的<s:tree />的根節點。如下代碼所示:
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Struts 2 AJAX - More Tree</title>
<s:head theme="ajax" debug="true" />
<script type="text/javascript">
/* <![CDATA[ */
function treeNodeSelected(arg) {
alert(arg.source.title + ' selected');
}

function treeNodeExpanded(arg) {
alert(arg.source.title + ' expanded');
}

function treeNodeCollapsed(arg) {
alert(arg.source.title + ' collapsed');
}

dojo.addOnLoad(function() {
var t = dojo.widget.byId('appFiles');
dojo.event.topic.subscribe(t.eventNames.expand, treeNodeExpanded);
dojo.event.topic.subscribe(t.eventNames.collapse, treeNodeCollapsed);

var s = t.selector;
dojo.event.connect(s, 'select', 'treeNodeSelected');
});
/* ]]> */
</script>
</head>
<body>
<h2>
Dynamic Tree Example
</h2>
<div style="float:left; margin-right: 50px;">
<s:tree id="appFiles" theme="ajax" rootNode="root"
nodeTitleProperty="name" nodeIdProperty="id"
childCollectionProperty="children" />
</div>
</body>
</html>
清單3 WebContent/Tree.jsp
因為<s:tree />的treeCollapsedTopic和treeExpandedTopic屬性都沒有起作用,所以如果我們想要監聽這兩個事件,就必須使用上述代碼的方法。
最后是struts.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
<package name="Struts2_AJAX_DEMO" extends="struts-default">
<action name="DynamicTree" class="tutorial.DynamicTreeAction">
<result>Tree.jsp</result>
</action>
</package>
</struts>
清單4 src/struts.xml
發布運行應用程序,在瀏覽器地址欄中鍵入http://localhost:8080/Struts2_Ajax2/DynamicTree.action,有如下圖所示頁面:

圖1 動態樹示例
AJAX 樹
正如我在文章開頭所說,Struts 2所提供的靜態樹和動態樹都不是嚴格意義上的AJAX樹。下面就讓我們來實現一個如假包換的AJAX樹。首先要說明的是,Struts 2的<s:tree />默認是不支持這種按需加載數據的AJAX樹。不過因為它是基于Dojo的樹控件(Widget)所以要擴展也很方便。
Dojo 通過名為“TreeRPCController”的控件實現 AJAX 樹,它會監聽被控制樹的事件。當發生展開節點的事件時,TreeRPCController就會向URL發送XHR請求,該URL由TreeRPCController的RPCUrl 屬性定義。XHR請求格式類似如下格式:
http://localhost:8080/Struts2_Ajax2/AjaxTree.action?action=getChildren&data={"node":{"widgetId":"file_226092423","objectId":"C:\\Program Files\\Tomcat 5.5\\webapps\\Struts2_Ajax2","index":0,"isFolder":true},"tree":{"widgetId":"appFiles","objectId":""}}&dojo.preventCache=1182913465392
清單5 XHR樣本
顯而易見,請求中包含三個參數,分別是action為“getChildren”(固定值),data一個包含當前節點與樹信息的JSON串和dojo.preventCache隨機串,用于緩存不同節點的請求響應(父節點只會在第一次被展開時到服務器端加載數據,之后都是從瀏覽器的緩存中讀取數據,可以提高應用程序性能)。
首先我要先寫一個加載樹節點數據的Action類,代碼如下:
package tutorial;

import java.util.Map;

import com.googlecode.jsonplugin.JSONExeption;
import com.googlecode.jsonplugin.JSONUtil;

public class AjaxTreeAction extends DynamicTreeAction {
private static final long serialVersionUID = 3970019751740942311L;

private String action;
private String data;
private FileWrapper[] wrappers;

public void setAction(String action) {
this.action = action;
}

public void setData(String data) {
this.data = data;
}

public FileWrapper[] getWrappers() {
return wrappers;
}

@Override
public String execute() {
if("getChildren".equals(action)) {
try {
Object o = JSONUtil.deserialize(data);
String path = ((Map) ((Map) o).get("node")).get("objectId").toString();
wrappers = new FileWrapper(path).getChildren();
} catch (JSONExeption e) {
e.printStackTrace();
}
return "ajax";
}
return super.execute();
}
}
清單6 src/tutorial/AjaxTreeAction.java
上述代碼可能需要解釋一下:
1. action屬性對應于XHR中的action,如果它為“getChildren”時,則需要進行加載子節點操作。否則,會讀取樹的根節點,并返回JSP頁面;
2. 通過上面XHR的分析,大家可以知道data是代表樹和當前節點的JSON串,故應將其反串行化為Map對象,并將其 objectId屬性取出。通常情況下,Dojo樹的objectId屬性代表服務器端的對象的標識,在本例中為文件夾的絕對路徑;
3. wrappers屬性表示當前文件夾下的文件數組,它被傳送到Freemarker頁面,翻譯為Dojo樹節點數組的JSON串。
下面是Freemarker頁面的代碼:
[
<#list wrappers as r>
{ "title": "${r.name}", "isFolder": <#if r.children?size gt 0>true<#else>false</#if>, "id": "${r.id}", "objectId": "${r.absolutePath?js_string}" }<#if r_has_next>,</#if>
</#list>
]
清單7 WebContent/AjaxTree.ftl
以上代碼中<#list></#lsit>的寫法是Freemarker中遍歷集合的寫法;而<#if r.children?size gt 0>判斷“r”對象的children屬性是否為空;r.absolutePath?js_string 就是將“r”的absolutePath屬性的值輸出為Javascript 的字串符形式;<#if r_has_next></#if>判斷集合是否有下一項數據。如果希望更詳細地了解Freemarker的使用,請參考該手冊。
接下來,讓我們看看Action的配置代碼片段:
<action name="AjaxTree" class="tutorial.AjaxTreeAction">
<result>AjaxTree.jsp</result>
<result name="ajax" type="freemarker">AjaxTree.ftl</result>
</action>
清單8 src/struts.xml配置片段
最后是JSP頁面代碼:
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Struts 2 AJAX - More Tree</title>
<s:head theme="ajax" debug="true" />
<script type="text/javascript">
/* <![CDATA[ */
function treeNodeSelected(arg) {
alert(arg.source.title + ' selected');
}

dojo.addOnLoad(function() {
var t = dojo.widget.byId('appFiles');
var s = t.selector;
dojo.event.connect(s, 'select', 'treeNodeSelected');
});
/* ]]> */
</script>
</head>
<body>
<h2>
AJAX Tree Example
</h2>
<div style="float:left; margin-right: 50px;">
<script type="text/javascript">
/* <![CDATA[ */
dojo.require("dojo.lang.*");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.Tree");
dojo.require("dojo.widget.TreeRPCController");
/* ]]> */
</script>
<div dojoType="TreeRPCController" widgetId="treeController"
DNDcontroller="create" RPCUrl="<s:url />"></div>
<div dojoType="Tree" widgetId="appFiles" toggle="fade" controller="treeController">
<div dojoType="TreeNode" title='<s:property value="root.name" />'
widgetId='<s:property value="root.id" />'
isFolder='<s:property value="root.children.length > 0" />'
objectId='<s:property value="root.absolutePath" />'>
</div>
</div>
</div>
</body>
</html>
清單9 WebContent/AjaxTree.jsp
由于上面所提及的原因,我在上述的代碼中并沒有使用<s:tree />標志,而是使用了Dojo的寫法——創建 widgetId 為“treeController”的 TreeRPCController 并將設為樹的控制器。
發布運行應用程序,在瀏覽器地址欄中鍵入http://localhost:8080/Struts2_Ajax2/AjaxTree.action,點開某個節點,在節點加載的過程中,加號圖標變成時鐘狀圖標,如下圖所示頁面:

圖2 AJAX樹示例
自定義<s:tree />的AJAX的主題(theme)
Struts 2的標志過人之外在于它允許開發人員自定義標志的頁面輸出。要做到這一點,你所需要做的只是創建一個自定義的theme并將其應用到相應標志。下面就讓我自定義一個真正的AJAX的<s:tree/>的theme。
首先,你的源文件的根目錄下新建包“template.realajax”。
然后,在上一步所建的包中新建“tree.ftl”文件,內容如下:
<script type="text/javascript">
/* <![CDATA[ */
dojo.require("dojo.lang.*");
dojo.require("dojo.widget.*");
dojo.require("dojo.widget.Tree");
dojo.require("dojo.widget.TreeRPCController"); <#-- Added by Max -->
/* ]]> */
</script>
<#-- Added by Max -->
<div dojoType="TreeRPCController"
widgetId="${parameters.id?html}_controller"
DNDcontroller="create"
RPCUrl="<@s.url />">
</div>
<#-- End -->
<div dojoType="Tree"
<#if parameters.blankIconSrc?exists>
gridIconSrcT="<@s.url value='${parameters.blankIconSrc}' encode="false" includeParams='none'/>"
</#if>
<#if parameters.gridIconSrcL?exists>
gridIconSrcL="<@s.url value='${parameters.gridIconSrcL}' encode="false" includeParams='none'/>"
</#if>
<#if parameters.gridIconSrcV?exists>
gridIconSrcV="<@s.url value='${parameters.gridIconSrcV}' encode="false" includeParams='none'/>"
</#if>
<#if parameters.gridIconSrcP?exists>
gridIconSrcP="<@s.url value='${parameters.gridIconSrcP}' encode="false" includeParams='none'/>"
</#if>
<#if parameters.gridIconSrcC?exists>
gridIconSrcC="<@s.url value='${parameters.gridIconSrcC}' encode="false" includeParams='none'/>"
</#if>
<#if parameters.gridIconSrcX?exists>
gridIconSrcX="<@s.url value='${parameters.gridIconSrcX}' encode="false" includeParams='none'/>"
</#if>
<#if parameters.gridIconSrcY?exists>
gridIconSrcY="<@s.url value='${parameters.gridIconSrcY}' encode="false" includeParams='none'/>"
</#if>
<#if parameters.gridIconSrcZ?exists>
gridIconSrcZ="<@s.url value='${parameters.gridIconSrcZ}' encode="false" includeParams='none'/>"
</#if>
<#if parameters.expandIconSrcPlus?exists>
expandIconSrcPlus="<@s.url value='${parameters.expandIconSrcPlus}' includeParams='none'/>"
</#if>
<#if parameters.expandIconSrcMinus?exists>
expandIconSrcMinus="<@s.url value='${parameters.expandIconSrcMinus?html}' includeParams='none'/>"
</#if>
<#if parameters.iconWidth?exists>
iconWidth="<@s.url value='${parameters.iconWidth?html}' encode="false" includeParams='none'/>"
</#if>
<#if parameters.iconHeight?exists>
iconHeight="<@s.url value='${parameters.iconHeight?html}' encode="false" includeParams='none'/>"
</#if>
<#if parameters.toggleDuration?exists>
toggleDuration=${parameters.toggleDuration?c}
</#if>
<#if parameters.templateCssPath?exists>
templateCssPath="<@s.url value='${parameters.templateCssPath}' encode="false" includeParams='none'/>"
</#if>
<#if parameters.showGrid?exists>
showGrid="${parameters.showGrid?default(true)?string}"
</#if>
<#if parameters.showRootGrid?exists>
showRootGrid="${parameters.showRootGrid?default(true)?string}"
</#if>
<#if parameters.id?exists>
id="${parameters.id?html}"
</#if>
<#if parameters.treeSelectedTopic?exists>
publishSelectionTopic="${parameters.treeSelectedTopic?html}"
</#if>
<#if parameters.treeExpandedTopic?exists>
publishExpandedTopic="${parameters.treeExpandedTopic?html}"
</#if>
<#if parameters.treeCollapsedTopic?exists>
publishCollapsedTopic="${parameters.treeCollapsedTopic?html}"
</#if>
<#if parameters.toggle?exists>
toggle="${parameters.toggle?html}"
</#if>
controller="${parameters.id?html}_controller" <#-- Added by Max -->
>
<#if parameters.label?exists>
<div dojoType="TreeNode" title="${parameters.label?html}"
<#if parameters.nodeIdProperty?exists>
id="${stack.findValue(parameters.nodeIdProperty)}"
<#else>
id="${parameters.id}_root"
</#if>
>
<#elseif parameters.rootNode?exists>
${stack.push(parameters.rootNode)}
<#-- Edited by Max -->
<div dojoType="TreeNode"
title="${stack.findValue(parameters.nodeTitleProperty)}"
widgetId="${stack.findValue(parameters.nodeIdProperty)}"
isFolder="<#if stack.findValue(parameters.childCollectionProperty)?size gt 0>true<#else>false</#if>"
objectId="${stack.findValue(parameters.nameValue)}">
</div>
<#-- End -->
<#assign oldNode = stack.pop()/> <#-- pop the node off of the stack, but don't show it -->
</#if>
清單10 src/template/realajax/tree.ftl
對上述稍作解釋,上述代碼主要在原版的src/template/ajax/tree.ftl的基礎上添加了TreeRPCController的控件,并只輸出根節點。由于<s:tree />沒有類似nodeObjectIdProperty的屬性,所以我用了value屬性表示objectId對應的屬性名稱。
接著新建tree-close.ftl文件,內容和原版的一樣,如下所示:
<#if parameters.label?exists></div></#if></div>
清單11 src/template/realajax/tree-close.ftl
再下來就應該是將theme應用到<s:tree />,如下代碼所示:
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Struts 2 AJAX - More Tree</title>
<s:head theme="ajax" debug="true" />
<script type="text/javascript">
/* <![CDATA[ */
function treeNodeSelected(arg) {
alert(arg.source.title + ' selected');
}

dojo.addOnLoad(function() {
var t = dojo.widget.byId('appFiles');
var s = t.selector;
dojo.event.connect(s, 'select', 'treeNodeSelected');
});
/* ]]> */
</script>
</head>
<body>
<h2>
AJAX Tree Example
</h2>
<div style="float:left; margin-right: 50px;">
<s:tree id="appFiles" theme="realajax" rootNode="root"
nodeTitleProperty="name" nodeIdProperty="id"
childCollectionProperty="children" value="absolutePath" />
</div>
</body>
</html>
清單12 WebContent/AjaxTreeTheme.jsp
上述代碼中<s:tree />的用法,除了theme改為“realajax”和多了value="absolutePath"外,幾乎和靜態樹中的一樣。
為了不影響前一個例子,我們為該JSP文件配置類型相同的Action,如下代碼所示:
<action name="AjaxTreeTheme" class="tutorial.AjaxTreeAction">
<result>AjaxTreeTheme.jsp</result>
<result name="ajax" type="freemarker">AjaxTree.ftl</result>
</action>
清單13 src/struts.xml配置片段
發布運行應用程序,在瀏覽器地址欄中鍵入http://localhost:8080/Struts2_Ajax2/AjaxTreeTheme.action,結果如圖2所示。
總結
通過上述例子,大家知道Struts 2 的AJAX 標志是基于Dojo控件開發的,所以如果大家希望熟練地使用這些標志,最好去了解一下Dojo。
本來還打算介紹一下Struts 2與DWR,不過看看文章的篇幅似乎足夠自成一篇了,因此DWR相關的內容要留待下文繼續了。



飛雪(leo) 2007-10-18 00:47 發表評論
]]>
DOJO試用手記4--dojo基礎 http://www.aygfsteel.com/Jiangzy/archive/2007/10/18/153729.html飛雪(leo)飛雪(leo)Wed, 17 Oct 2007 16:32:00 GMThttp://www.aygfsteel.com/Jiangzy/archive/2007/10/18/153729.htmlhttp://www.aygfsteel.com/Jiangzy/comments/153729.htmlhttp://www.aygfsteel.com/Jiangzy/archive/2007/10/18/153729.html#Feedback0http://www.aygfsteel.com/Jiangzy/comments/commentRss/153729.htmlhttp://www.aygfsteel.com/Jiangzy/services/trackbacks/153729.html DOJO試用手記4--dojo基礎 來源:原創 作者:zxub 發布時間:2006-04-06 17:05:00  

  前面說了dojo在ajax方面的一些個東西,感覺要理解透徹還有些dojo內部的東西需要理解,所以想好好看一下dojo的東西,惡補一陣:-)
  看了會官方一些個文檔,有了些許體會。
  dojo.js被包含進來后,一些對象和函數就可以用了,在用JSEclipse編輯的時候,可以看到一些,不過是包含在dojo.js中的,官網說還包括boostrap文件里的,我查了下,有bootstrap1.js和bootstrap2.js,不過那些對象直接顯示不出來,估計有什么地方要設置,弄清楚后再補上來。
  可用的東東有:
  1.dojo.render對象:該對象存放了dojo運行環境的一些信息。
  dojo.render.name:根據dojo.render.name = navigator.appName,可以知道這是瀏覽器的名稱,但是直接顯示出來是空的,估計還沒有被賦值,運行

1 dojo.render.name = navigator.appName;
2 alert(dojo.render.name);


我的出來的是:Microsoft Internet Explorer。
  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。
  dojo.render.ver,官網上說與dojo.version一樣,但我一打印發現不對,查了下代碼,發現如下一段:dojo.render.ver = parseFloat(navigator.appVersion, 10),是與瀏覽器版本號有關,我這里dojo.render.ver的值為4。再找dojo.version,發現這么一段:

dojo.version = {
    major: 
0, minor: 2, patch: 2, flag: "",
    revision: Number(
"$Rev: 2836 $".match(/[0-9]+/)[0]),
    toString: 
function() {
        
with (dojo.version) {
            
return major + "." + minor + "." + patch + flag + " (" + revision + ")";
        }
    }
};


將dojo.version打印一下,是0.2.2(2836),上面一段的結果。
  dojo.render.html,這也是一個對象,它有好幾個屬性。dojo.render.html.capable,宿主環境是否支持html,一般來說,都是true。其它幾個是與瀏覽器類型有關的,都是布爾類型。dojo.render.html.moz,當瀏覽器為Mozilla或者Mozilla核心的瀏覽器(例如 Firefox)時為true; dojo.render.html.safari,使用蘋果的Safari瀏覽器的時候為true,dojo.render.html.ie,平常的機器這個屬性都是true,因為我們基本是用Microsoft Internet Explorer,即ie瀏覽器;dojo.render.html.opera,使用Opera瀏覽器的時候為true;dojo.render.html.khtml,使用KHTML瀏覽器(例如Konqueror,但是我還就真沒聽過這種KHTML瀏覽器,其它的都知道,看來還是知識不夠,唉~)的時候為true。dojo.render.html對象主要是用來判斷瀏覽器類型的。我的機器上dojo.render.html.ie為true。
  其它還有dojo.render.svg,dojo.render.vmldojo.render.swf,dojo.render.swt,由上面的資料,可以知道是對SVG、VML、SWF、SWT的支持,它們都有個capable屬性,表示是否支持該技術,ie5.0以上版本支持VML,所以我的dojo.render.vml.capable為true,SVG需要裝插件,所以不支持該項,dojo.render.svg.capable為false,dojo.render.swf.capable也為false,這里的swf不是指flash的swf,而是Simple Web Framework,Simple Web Framework (SWF)是一個基于事件的web框架.它很適合于那些想要開發胖客戶端Web應用程序但又不想轉向JSF的Struts開發人員。SWF跟Struts一樣也是構建在Jakarta commons基礎之上,但使用一個不同的request processor。SWF事件模型支持基于XmlHttpRequest的事件提交。至于dojo.render.swt,不清楚了,難道與java中的SWT有關系?這四個對象的其它屬性,在源碼中居然沒看到相應代碼??以后弄明白再回來補過。
  2.dojo.version對象。在上面已經講過這個對象,是dojo庫文件的版本,沒啥好研究的了。
  3.dojo.hostenv對象,個人認為里面的東西很有看頭,不過要慢慢講來也太費時間了,具體可以去看源碼中那幾個hostenv_XXX.js文件,dojo.hostenv.getText函數和dojo.hostenv.println函數還有點意思,以后隨時補充吧。
  下面講一講dojo中的一些基本函數。
  



飛雪(leo) 2007-10-18 00:32 發表評論
]]>
Dojo學習筆記http://www.aygfsteel.com/Jiangzy/archive/2007/10/18/153726.html飛雪(leo)飛雪(leo)Wed, 17 Oct 2007 16:31:00 GMThttp://www.aygfsteel.com/Jiangzy/archive/2007/10/18/153726.htmlhttp://www.aygfsteel.com/Jiangzy/comments/153726.htmlhttp://www.aygfsteel.com/Jiangzy/archive/2007/10/18/153726.html#Feedback0http://www.aygfsteel.com/Jiangzy/comments/commentRss/153726.htmlhttp://www.aygfsteel.com/Jiangzy/services/trackbacks/153726.htmlDojo學習筆記2007年06月05日 星期二 17:18(1. 模塊與包)


Intro:

Dojo是一個非常強大的面向對象的JavaScript的工具箱, 建議讀者能夠去補充一下JavaScript下如何使用OO進行編程的, 這對于你以后閱讀Dojo Source有很大的用處

請大家下載dojo 0.3.1, 以下的說明均針對此版本

翻譯自http://manual.dojotoolkit.org/WikiHome/DojoDotBook/BookUsingDojo


Getting Started

1: 把Dojo加入到我們的Web程序中

1. 標志

<script type="text/javascript">
djConfig = { isDebug: false };
</script>
djConfig是Dojo里的一個全局對象, 其作用就是為Dojo提供各種選項, isDebug是最常用的屬性之一, 設置為True以便能夠在頁面上直接看到調試輸出, 當然其中還有些屬性與調試有關, 這里就不羅索了

2. 引用 dojo 的啟動代碼

<script type="text/javascript" src="/yourpath/dojo.js" />
這樣你就引用了dojo的代碼, 并可以直接使用其中部分常用的對象, 下載下來的dojo.js是壓縮(remove comments and space)后的代碼, 要閱讀的話,建議閱讀dojo.js.uncompressed.js, dojo.js大概有127K, 而未壓縮前有211K, ok, 為什么會這么大呢, 原來其已經把部分常用的模塊整合進dojo.js里, 因此顯得大了一點, build.txt里就說明了默認的dojo.js包含了哪些模塊

3. 聲明你所要用到的包

<script type="text/javascript">
dojo.require("dojo.math");
dojo.require("dojo.io.*");
dojo.require("dojo.widget.*");
</script>
你就把這些代碼當成是java的import語句或C#中的using語句一樣, 如果你不require的話, 而模塊本身又沒有整合在dojo.js中, 是會出現腳本錯誤的喔

2. 針對不同需求提供的預整合包

Dojo本身是由許多模塊所組合而成的, 但是由于用戶需求的多樣性, dojo針對不同的需求而提供了不同的版本, 用戶在下載dojo的時候就看見可以選擇很多的版本, 比如Ajax版和Widget版, 每個版本最重要的區別就在于dojo.js文件, 但是除此之外, 每一個版本都是全功能的, dojo.js根據版本的不同而整合進了不同的模塊

3. 直接獲取Dojo的最新源代碼

首先你必須安裝 Subversion, 當Subversion在你的電腦上能夠正常工作后,你就可以通過如下命令下載dojo的源代碼:

svn co http://svn.dojotoolkit.org/dojo/trunk/
這會在你的當前目錄下創建一個 trunk 的目錄; 如果你希望直接Get到當前目錄, 用這個命令:

svn co http://svn.dojotoolkit.org/dojo/trunk/ .
或者你希望Get到當前目錄下的 MyDir 目錄, 用這個命令:

svn co http://svn.dojotoolkit.org/dojo/trunk/ MyDir

模塊與包

模塊

Dojo的代碼被劃分為邏輯單元稱之為模塊, 這有點類似于Java中的package,除了dojo的模塊能夠包含類 (類似于java中的classes)和簡單函數

比如: 模塊"dojo.html"包含了一系列的函數, 比如dojo.html.getContentBox(), 模塊"dojo.dnd"包含了一系列的HtmlDragObject的類

注意名稱約定, 函數的首字母為小寫字母,類的首字母為大寫

模塊也可以稱之為"命名空間"

在多數情況下, dojo的模塊只需要定義在一個文件就可以了, 但有時, 一個模塊可能劃分到多個文件, 比如: 模塊dojo.html, 本來是定義在一個文件中, 可是由于功能的增強, 文件逐漸變大, 我們不得不將其拆分為多個文件, 這主要是為性能考慮, 以便瀏覽器可以只下載其需要用到的代碼, 不幸的是其實現細節對于dojo的用戶看起來不那么透明, 你必須知道你想要用到的功能到底是包含在哪個文件, 然后才能require并使用它

這樣的每一個文件都稱之為一個包

dojo.require("dojo.html.extras")
將引用文件 src/html/extras.js, 這將定義模塊 dojo.html 的若干(并非所有)函數

據我所知, 盡管單個文件可以定義包里的多個類, 單個腳本文件不能定義多個模塊 (在Java可以等效于在一個文件中定義2個類), 并且, 包的名稱和模塊的名稱可以不同, 比如: 包dojo.widget.Button定義了dojo.widget.html.Button

基本上你應該這樣認為, 包和模塊盡管密切相關, 但是是兩個完全不同的實體

為什么會有模塊和包這樣的概念?

為什么會有模塊和包這樣的概念? 為了滿足你的應用程序只需要加載其所用到的東西的需求, 充分利用模塊化設計的優點, dojo維護了最小的足印以便仍能提供你所需要的功能, 為什么要你的用戶浪費時間去下載用不到的JavaScript, 當一個包就是一個js文件時, 一個模塊本質上就是一個命名空間, 比如: dojo.style 或 dojo.html.extras
多數簡單情況下, 一個包包含了一個模塊, 但更常見的是, 一個模塊可能被拆分為幾個包文件

利用包和模塊, 將能確保你能夠交付最相關的功能代碼, 最小程度的減少代碼的膨脹和消除由此帶來的不好的用戶體驗,這就是模塊設計的主要目標, 通過模塊化, 你能夠引入自定義模塊(你自己擁有的 JavaScript 工具), 并且維護模塊對于核心代碼庫基本不會產生什么影響

另外, Dojo的模塊系統也提供了內建的機制來使用代碼提供命名空間, 比如, 通過模塊dojo.event定義的Dojo的事件系統

怎樣引用

設置引用語句

你怎樣才能知道該引用哪個包到dojo.require()?

1. 模塊

首先, 確定你要使用什么模塊, 這個例子我們假定你要使用 dojo.lfx.html

2. 包

搜索代碼后你發現dojo.lfx.html定義在2個文件:

src/lfx/html.js
src/lfx/extras.js
根據你要用到的功能, 你可以

dojo.require("dojo.lfx.html");

dojo.require("dojo.lfx.html");
dojo.require("dojo.lfx.extras");

通配符

新用戶可能會對dojo.lfx.*這樣就可以替代上面2句而感到詫異, 實際上, __package__.js 中已經定義了通配符可以代替的語句, 并且這樣可以讓dojo根據當時的環境而決定加載具體的模塊

Dojo學習筆記(2. djConfig解說)


djConfig是dojo內置的一個全局設置對象,其作用是可以通過其控制dojo的行為

首先我們需要在引用dojo.js前聲明djConfig對象,以便在加載dojo.js的時候才能夠取得所設置的值,雖然在0.3版本以后dojo支持在加載后設置,但是強烈建議你把聲明djConfig的代碼作為第一段script

一個完整的djConfig對象定義如下(值均為dojo的默認值)

<script type="text/javascript">
var djConfig = {
isDebug: false,
debugContainerId: "",
bindEncoding: "",
allowQueryConfig: false,
baseScriptUri: "",
parseWidgets: true
searchIds: [],
baseRelativePath: "",
libraryScriptUri: "",
iePreventClobber: false,
ieClobberMinimal: true,
preventBackButtonFix: true,
};
</script>
isDebug是一個很有用的屬性,顧名思義,如果設置為真,則所有dojo.Debug的輸出有效,開發時應該設置為true,發布時應該設置為false

debugContainerId同樣也是與調試有關的,如果不指定的話,調試信息將會直接利用 document.write輸出,這樣可能會破壞頁面的整體布局,所以你可以指定任何一個可以作為容器的html元素的id作為調試信息輸出容器

allowQueryConfig,這個屬性指明 dojo是否允許從頁面url的參數中讀取djConfig中的相關屬性,當值為true時,dojo會優先從url參數中讀取djConfig的其他屬性,比如: http://server/dojoDemo.htm?djConfig.debugContainerId=divDebug

baseScriptUri,一般不需要設置,dojo會自動根據你引用dojo.js的路徑設置這個值,比如,<script type="text/javascript" src="../dojo/dojo.js"></script>,自動獲取的值便是 ../dojo/
ps: 如果你有多個工程需要同時引用dojo.js的話,建議也把dojo當作一個獨立的工程,引用的時候采用絕對路徑就可以了

parseWidgets,這個是可以控制dojo是否自動解析具有dojoType的html元素為對應的widget,如果你沒有使用任何Widget,建議設置為false以加快dojo的加載速度

searchIds,這是一個字符串數組,定義了所有需要解析為widget的html元素的ID,如果ID不在其中的html元素是不會被解析的,當數組為空數組時,則所有具有dojoType的元素都會被解析

還有一個bindEncoding,是用來設置默認的bind請求的編碼方式

至于其它的屬性,不是用處不大,就是不知道有什么作用

在實際開發中,可以把djConfig的定義放在一個js文件里,并將其作為第一個引用的js文件,這樣應該是最方便的。

Dojo學習筆記(3. Dojo的基礎對象和方法)

這里所說的基礎對象和方法是指的不Require任何包就能夠調用的對象和方法

匿名函數

在開始前,我想介紹一下js里的匿名函數,這個在閱讀dojo的源代碼的時候,會發現到處都有匿名函數

;(function(){
alert(123);
})();
//前面的分號是一個空語句,是可以不要的
匿名函數。一個匿名函數就是一個沒有名字的函數。

你可以認為他們是一次性函數。當你只需要用一次某個函數時,他們就特別有用。通過使用匿名函數,沒有必要把函數一直放在內存中,所以使用匿名函數更加有效率。

當然你也可以根本不定義函數,但是使用匿名函數可以把你的代碼分段,就像C#中的#region一樣

dojo.byId

非常有用的一個方法,與prototype.js的著名的$一樣

似乎以前的版本還有dojo.byIdArray, 不過最新的版本已經找不到這個函數了(除了src\compat\0.2.2.js)

如果有多個元素具有指定的id,則返回的是一個集合

Usage Example:

dojo.byId("divTest");
dojo.byId("divTest", document);
dojo.byId(document.getElementById("divTest"));


dojo.version

dojo的版本,可以取得major, minor, patch, flag和revision

這個對象沒什么太大用處,除非你要根據dojo的版本選擇執行你的代碼

dojo.raise

拋出一個異常

dojo.errorToString

將異常轉換為字符串

Usage Example:

try
{
dojo.raise("打印失敗", new Error("文件不存在"));
}
catch(e)
{
alert(dojo.errorToString(e));
}


dojo.render

系統環境對象

dojo.render.name 返回 browser ,說明是工作在瀏覽器下
dojo.render.ver 返回 4 ,似乎沒什么用
dojo.os.win 返回true說明操作系統是Windows
dojo.os.linux 返回true說明操作系統是Linux
dojo.os.osx 返回true說明操作系統是MacOS
dojo.html.ie 返回true說明瀏覽器是Internet Explorer
dojo.html.opera 返回true說明瀏覽器是Opera
dojo.html.khtml 返回true說明瀏覽器是Konqueror
dojo.html.safari 返回true說明瀏覽器是Safari
dojo.html.moz 返回true說明瀏覽器是Mozilla FireFox
dojo.svg.capable 返回true說明瀏覽器支持svg
dojo.vml.capable 返回true說明瀏覽器支持vml
dojo.swf.capable 返回true說明瀏覽器支持swf
dojo.swt.capable 返回true說明瀏覽器支持swt (IBM開發的Standard Widget Toolkit)
如果dojo.html.ie為true的話

dojo.html.ie50 返回true說明瀏覽器是IE 5.0
dojo.html.ie55 返回true說明瀏覽器是IE 5.5
dojo.html.ie60 返回true說明瀏覽器是IE 6.0
dojo.html.ie70 返回true說明瀏覽器是IE 7.0


dojo.addOnLoad

可以加載指定函數到window.load時執行,好處就是可以很方便的在window.load時執行多個函數

Usage Example:

dojo.addOnLoad(init); //init是一個函數
dojo.addOnLoad(myObject, init); //init是myObject對象的一個方法


dojo.require

如果你想調用一個模塊的對象的時候,你應該首先用dojo.require來請求這個模塊,dojo會根據你的請求自動取得相應的js文件,并加載到內存中,這樣你才能調用或創建其中的對象

dojo會自動維護已加載的模塊列表,所以是不會重復加載模塊的

Usage Example:

dojo.require("dojo.event");
dojo.requireIf=dojo.requireAfterIf

可以根據指定的條件來決定是否加載指定的模塊

Usage Example:

dojo.requireIf(dojo.html.ie, "dojo.html"); //如果dojo.html.ie為true,才會加載dojo.html模塊


dojo.provide

除非你要開發自己的模塊,不然是用不到這個方法的,你可以這句看成是向系統注冊這個模塊名稱

Usage Example:

dojo.provide("dojo.custom");
dojo.exists

判斷指定對象是否具有指定名稱的方法

Usage Example:

dojo.exists(dojo, "exists"); //will return true


dojo.hostenv.getText

返回指定url的內容

PS: 由于瀏覽器的安全限制,因此只能用于取得同域名的url的內容,否則會報告權限不夠

Usage Example:

aSync = false; //同步,確保返回內容不為null
silent = true; //不拋出錯誤
s = dojo.hostenv.getText("http://www.google.com/", aSync, silent); //返回Google的首頁的HTML
alert(s);
dojo.debug

輸出調試信息,如果在djConfig中指定了debugContainerId,則輸出到指定的console容器中,否則直接document.write

所有的調試信息均以 DEBUG: 開頭

Usage Example:

dojo.debug("這是調試信息");


dojo.hostenv.println

與dojo.debug類似,不同的是,輸出內容沒有 DEBUG:

Usage Example:

dojo.hostenv.println("這是一般的輸出信息");


dojo.debugShallow

輸出指定對象的全部信息(Shallow說明并不會遍歷到下一級別的對象屬性)以供調試

Usage Example:

dojo.debugShallow(dojo.render.html);
Dojo學習筆記(4. dojo.string & dojo.lang)

模塊: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"
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"
模塊:dojo.lang.common / dojo.langdojo.lang.common 和 dojo.lang 是一樣的,只要require其中一個就可以使用以下方法
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>1); //will return truedojo.lang.isNumber判斷輸入的類型是否為數值,根據注釋所說,此函數使用不太可靠,但是可替換使用的系統函數isNaN也不太可靠dojo.lang.isUndefined判斷輸入是否為未定義,根據注釋所說,此函數有可能會導致拋出異常,推薦使用 typeof foo == "undefined" 來判斷
模塊: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以上全部是自己閱讀源代碼寫的總結,如有錯誤,還請指明。



飛雪(leo) 2007-10-18 00:31 發表評論
]]>
DOJO試用手記2--Event System http://www.aygfsteel.com/Jiangzy/archive/2007/10/18/153723.html飛雪(leo)飛雪(leo)Wed, 17 Oct 2007 16:28:00 GMThttp://www.aygfsteel.com/Jiangzy/archive/2007/10/18/153723.htmlhttp://www.aygfsteel.com/Jiangzy/comments/153723.htmlhttp://www.aygfsteel.com/Jiangzy/archive/2007/10/18/153723.html#Feedback0http://www.aygfsteel.com/Jiangzy/comments/commentRss/153723.htmlhttp://www.aygfsteel.com/Jiangzy/services/trackbacks/153723.html閱讀全文

飛雪(leo) 2007-10-18 00:28 發表評論
]]>
主站蜘蛛池模板: 定日县| 石河子市| 大石桥市| 达尔| 庄河市| 淳化县| 邵东县| 额尔古纳市| 乐亭县| 阳信县| 个旧市| 沅陵县| 稻城县| 岳阳县| 安乡县| 长宁区| 通榆县| 彰化县| 峨眉山市| 丰顺县| 武乡县| 伊金霍洛旗| 柳林县| 玛多县| 京山县| 北川| 甘洛县| 枣强县| 郑州市| 陕西省| 呼玛县| 米易县| 阳泉市| 连城县| 尉犁县| 鄂温| 寿阳县| 霍邱县| 长乐市| 登封市| 青川县|