燕之庐网站建设 - 优质网站设计公司

Posts Tagged ‘actionscript3’

actionscript3

2009/12/23

Google创始人希望Wave能改变人类通讯方式

Tags: ,

12月21日消息,谷歌联合创始人赛吉布林(Sergey Brin)于12月2日接受美国CNBC电视台采访,在采访中,布林认为谷歌的成功在于提高用户体验。目前,谷歌不仅是一家搜索公司,而是一个平台性公司。

布林重点谈及Android系统,他说:越来越多的手机制造商可以采用它,用户也会购买这些手机。分析称,尽管谷歌自己推出品牌手机,但从布林的话中可以看出,未来谷歌依然定位在提供服务上,走平台路线。

对于云计算,布林称其会改变人们的工作方式。

谈到谷歌的成功,布林认为达到成功的关键是聚焦于终端用户体验。他还高度评价了新项目谷歌波浪,希望借此能改变人们的通讯方式。

以下是采访内容摘要:

谷歌如何为普通用户而改变?

我觉得,我们如今不只投资于搜索,而且包括平台,以更高效、更有吸引力的方式将可找到的内容广泛地提供给用户。其中有一些麻烦,比如因为浏览器支持不够,导致手机搜索结果不佳,或者应用不佳,当你使用手机时,我们就会提供这方面的信息。Android使我们可以弥补鸿沟,它有很好的浏览器,由于开源,它也可以得到广泛应用。

越来越多的手机制造商可以采用它,用户也会购买这些手机。当他们使用时,我们可以提供搜索,新闻,手机的软件足够强大。

能谈谈云计算吗?

云计算正在成为一项业务,使用云计算会真正改变我们的工作方式。有了它,你从一个地方到另一个地方办公,不必再电脑不离手。你依然获取信息,与同事分 享,可以在大厅里办公,也可以在世界其它地方。再也不用担心硬盘挂掉,无论身处何地,你的信息都安全无忧。只要你做,就会改变。

谷歌的成功有何秘诀?

我们明显比其它公司更幸运。但我觉得,让我们达到成功的关键是聚焦于终端用户体验。我们十分幸运,因为我们有能力提高人们生活的一切方面,我们相信可以借此创建一个稳固的业务。我们可以借搜索达成目标。正如我们最近开发的谷歌波浪(Google Wave),它将重新思考沟通方式。我认为,如果我们能改变人们的通讯方式,用户与谷歌将双双获益。

北京网站建设公司

actionscript3

李强:利用JAX-WS开发Web服务

Tags: ,

本文提供了一个使用Java如何开发基于SOAP的Web Services,其客户端可以是Perl、Ruby、Python或Java等。

Java SE 6封装了JAX-WS(Java API for XML-Web Services),而JAX-WS同时支持基于SOAP的Web服务和REST风格的Web服务。JAX-WS通常可简写为JWS,当前,JWS的版本为2.x。

基于SOAP的Web服务可用单个Java类的实现,但是最好是用“接口+实现”的方式来实现最佳。
Web服务的接口称为SEI,即Service Endpoint Interface;
而Web服务的实现称为SIB,即Service Implementation Bean。

SIB可以是一个POJO,也可以是无状态的会话EJB。本文的SIB是普通Java类,通过JDK 6的类库即可实现Web服务的发布。

代码1:服务接口类SEI

view plaincopy to clipboardprint?
package myweb.service;
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
@WebService
@SOAPBinding(style=Style.RPC)
public interface TimeServer {
@WebMethod
String getTimeAsString();
@WebMethod
long getTimeAsElapsed();
}
package myweb.service;
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
@WebService
@SOAPBinding(style=Style.RPC)
public interface TimeServer {
@WebMethod
String getTimeAsString();
@WebMethod
long getTimeAsElapsed();
}

代码2:服务实现类SIB

view plaincopy to clipboardprint?
package myweb.service;
import java.text.DateFormat;
import java.util.Date;
import javax.jws.WebService;

@WebService(endpointInterface = “myweb.service.TimeServer”)
public class TimeServerImpl implements TimeServer {

/**
* 返回从1970年1月1日0点0时0分起的毫秒数
*/
public long getTimeAsElapsed() {
return new Date().getTime();
}

/**
* 返回如“2009-12-21”格式的日期
*/
public String getTimeAsString() {
Date date = new Date();
DateFormat df = DateFormat.getDateInstance();
return df.format(date);
}
}
package myweb.service;
import java.text.DateFormat;
import java.util.Date;
import javax.jws.WebService;

@WebService(endpointInterface = “myweb.service.TimeServer”)
public class TimeServerImpl implements TimeServer {

/**
* 返回从1970年1月1日0点0时0分起的毫秒数
*/
public long getTimeAsElapsed() {
return new Date().getTime();
}

/**
* 返回如“2009-12-21”格式的日期
*/
public String getTimeAsString() {
Date date = new Date();
DateFormat df = DateFormat.getDateInstance();
return df.format(date);
}
}

代码3:服务发布类Publisher

view plaincopy to clipboardprint?
package myweb.service;
import javax.xml.ws.Endpoint;

public class TimeServerPublisher {
public static void main(String[] args){
// 第一个参数是发布的URL
// 第二个参数是SIB实现
Endpoint.publish(”http://127.0.0.1:10100/myweb“, new TimeServerImpl());
}
}
package myweb.service;
import javax.xml.ws.Endpoint;

public class TimeServerPublisher {
public static void main(String[] args){
// 第一个参数是发布的URL
// 第二个参数是SIB实现
Endpoint.publish(”http://127.0.0.1:10100/myweb“, new TimeServerImpl());
}
}

编译以上代码

javac myweb/service/*.java

运行服务:

java myweb/service/TimeServerPublisher

在浏览器地址栏输入:

http://localhost:10100/myweb?wsdl

显示如下图所示:

也可编写客户端代码测试服务。

Java客户端:

view plaincopy to clipboardprint?
package myweb.client;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import java.net.URL;
import myweb.service.*;
public class TimeClient {
public static void main(String[] args) throws Exception{
URL url = new URL(”http://localhost:10100/myweb?wsdl“);
// 第一个参数是服务的URI
// 第二个参数是在WSDL发布的服务名
QName qname = new QName(”http://service.myweb/”,”TimeServerImplService“);
// 创建服务
Service service = Service.create(url, qname);
// 提取端点接口,服务“端口”。
TimeServer eif = service.getPort(TimeServer.class);
System.out.println(eif.getTimeAsString());
System.out.println(eif.getTimeAsElapsed());
}
}
package myweb.client;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import java.net.URL;
import myweb.service.*;
public class TimeClient {
public static void main(String[] args) throws Exception{
URL url = new URL(”http://localhost:10100/myweb?wsdl“);
// 第一个参数是服务的URI
// 第二个参数是在WSDL发布的服务名
QName qname = new QName(”http://service.myweb/”,”TimeServerImplService“);
// 创建服务
Service service = Service.create(url, qname);
// 提取端点接口,服务“端口”。
TimeServer eif = service.getPort(TimeServer.class);
System.out.println(eif.getTimeAsString());
System.out.println(eif.getTimeAsElapsed());
}
}

运行客户端,显示结果如下:

2009-12-21
1261402511859

也可用Ruby编写客户端,如下:

view plaincopy to clipboardprint?
#!/usr/bin/ruby

# one Ruby package for SOAP-based services
require ’soap/wsdlDriver’

wsdl_url = ‘http://127.0.0.1:10100/myweb?wsdl’

service = SOAP::WSDLDriverFactory.new(wsdl_url).create_rpc_driver

# Save request/response messages in files named ‘…soapmsgs…’
service.wiredump_file_base = ’soapmsgs’

# Invoke service operations.
result1 = service.getTimeAsString
result2 = service.getTimeAsElapsed

# Output results.
puts “Current time is: #{result1}”
puts “Elapsed milliseconds from the epoch: #{result2}”
#!/usr/bin/ruby

# one Ruby package for SOAP-based services
require ’soap/wsdlDriver’

wsdl_url = ‘http://127.0.0.1:10100/myweb?wsdl’
service = SOAP::WSDLDriverFactory.new(wsdl_url).create_rpc_driver

# Save request/response messages in files named ‘…soapmsgs…’
service.wiredump_file_base = ’soapmsgs’

# Invoke service operations.
result1 = service.getTimeAsString
result2 = service.getTimeAsElapsed

# Output results.
puts “Current time is: #{result1}”
puts “Elapsed milliseconds from the epoch: #{result2}”

运行结果相同!

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/chszs/archive/2009/12/21/5050756.aspx

北京网站建设公司

actionscript3

在MySQL中使用XML数据—数据格式化

Tags: ,

北京网站建设公司

在上一篇文章中,我介绍了MySQL对XML支持的部分功能,包括–xml命令行选项,以及MySQL 5.1.5中开始引入的新功能。今天我将介绍如何更好地格式化XML输出内容。

在MySQL中使用XML数据 http://tech.it168.com/a2009/1211/822/000000822827.shtml

在ExtractValue()函数输出中添加我们自己的标题

在上一篇文章中,我们使用LOAD_FILE()函数导入了一个XML文档,然后使用ExtractValue()函数提取了某些字段。

CREATE TEMPORARY TABLE client_citizenship (

id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,

xml_data TEXT NOT NULL

);

SET @xml = LOAD_FILE(”c:\\client_citizenships.xml”);

INSERT INTO client_citizenship VALUES (NULL, @xml);

SELECT xml_data FROM client_citizenship LIMIT 1 INTO @xml;

SELECT ExtractValue(@xml, ‘//row[2]/field[1]/@name’),

ExtractValue(@xml, ‘//row[2]/field[1]‘);

最后一个SELECT语句提取的是第二个节点中的第一个。


</row>
<row>(row[2])
<fieldname=”client_id”>2</field>(field[1])
<fieldname=”date_of_birth”>1944-01-15</field>

其结果集如下:

+———————————————-+—————————————-+
|ExtractValue(@xml, “//row[2]/field[1]/@name”) |ExtractValue(@xml, ‘//row[2]/field[1]‘) |
+———————————————-+—————————————-+
|client_id                                     |2                                       |
+———————————————-+—————————————-+

注意MySQL使用的是表达式作为列的标题,为了使用列字段名格式化结果集的标题,我们需要使用Prepared Statement,Prepared Statement是一种特殊类型的SQL语句,它是预编译的,这意味着Prepared Statement执行时,数据库不用再编译SQL了,这样可以有效减少执行时间。在这个例子中,使用Prepared Statement的好处是可以设置标题,然后连接到我们的查询字符串中。

SET @header = SELECT ExtractValue(@xml, “//row[2]/field[1]/@name”);
SET @qry = CONCAT(”SELECT ExtractValue(@xml, \”//row[2]/field[1]\”) AS “, @header, “;”);
PREPARE stmt FROM @qry;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

现在我们看到的数据格式就是和我们平时看到的一样了。

+———–+
| client_id |
+———–+
| 2           |
+———–+

actionscript3

如何在MySQL数据库中使用XML数据

Tags: ,

通过XML使系统之间的数据交换变得更简单,因为它与编程语言无关,刚引入XML的概念时,是通过一个脚本或应用程序解析XML数据,将其转换为适合于数据库和底层系统的有效格式,后来,随着数据库技术的发展,数据库开始支持XML数据,这样就不用转换程序了。今天我将给大家介绍一下MySQL数据库对XML的支持,着重介绍如何导入XML数据到MySQL数据库中,以及如何从MySQL数据库导出XML格式数据。

使用–xml选项将数据导出为XML格式

在MySQL 5.0之前的版本中,使用MySQL命令行客户端以XML格式导出数据时有诸多限制,执行一个命令或查询时使用–xml或-X选项告诉MySQL客户端将结果输出为XML数据,例如,下面的命令将输出所有以version开头的数据库变量。

C:\>mysql -u<userid>-p<password>-e     “SHOW VARIABLES LIKE ‘%version%’” –-xml

最终输出的XML包括下面的标准格式:

整个数据集都包括在节点中;

每一行对应一个节点;

所有列包括在一个节点中;

列名出处在name属性中;

列值是一个文本节点。

<?xml version=”1.0″?>
<resultsetstatement=”SHOW VARIABLES LIKE ‘%version%’”
xmlns:xsi
=”http://www.w3.org/2001/XMLSchema-instance”>
<row>
<fieldname=”Variable_name”>protocol_version</field>
<fieldname=”Value”>10</field>
</row>
<row>
<fieldname=”Variable_name”>version</field>
<fieldname=”Value”>5.1.30-community</field>
</row>
<row>
<fieldname=”Variable_name”>version_comment</field>
<fieldname=”Value”>MySQL Community Server (GPL)</field>
</row>
<row>
<fieldname=”Variable_name”>version_compile_machine</field>
<fieldname=”Value”>ia32</field>
</row>
<row>
<fieldname=”Variable_name”>version_compile_os</field>
<fieldname=”Value”>Win32</field>
</row>
</resultset>

为了便于对比,下面给出上面的命令表格化输出结果。

+————————-+———————+
| Variable_name             | Value                  |
+————————-+———————+
| protocol_version          | 10                     |
| version                     | 5.1.22-beta-debug   |
| version_comment           | Source distribution |
| version_compile_machine | x86_64                 |
| version_compile_os       | suse-linux-gnu        |
+————————-+———————+

同样的语法可以应用到SELECT语句中,在我以前的一篇文章“借助临时表让你的MySQL查询效率更高”中,最开始的查询中我就用logical_delete_indicator=0的记录填充client_citizenship临时表。

INSERT INTO client_citizenship
SELECT     cl.client_id,
cl.date_of_birth,
cl.gender,
cit.citizenship_id,
cit.country_code,
cit.primary_citizenship
FROM      temp_table_article.client AS cl,
temp_table_article.citizenship AS cit,
temp_table_article.client_citizenship_rel AS rel
WHERE   cl.client_id                 = rel.client_id
AND     cit.citizenship_id           = rel.citizenship_id
AND     cit.logical_delete_indicator = 0
AND     cl.logical_delete_indicator  = 0;

在这个临时表上执行“SELECT *”查询返回下面的记录:

client_id, date_of_birth, gender, citizenship_id, country_code, primary_citizenship
2,         1944-01-15,    F,      4,              20,           0
2,         1944-01-15,    F,      7,              77,           1

当我加上–xml选项后,“SELECT *”查询将返回下面的XML格式结果:

<?xml version=”1.0″?>
<resultsetstatement=”SELECT * FROM client_citizenship”
xmlns:xsi
=”http://www.w3.org/2001/XMLSchema-instance”>
<row>
<fieldname=”client_id”>2</field>
<fieldname=”date_of_birth”>1944-01-15</field>
<fieldname=”gender”>F</field>
<fieldname=”citizenship_id”>4</field>
<fieldname=”country_code”>20</field>
<fieldname=”primary_citizenship”>0</field>
</row>
<row>
<fieldname=”client_id”>2</field>
<fieldname=”date_of_birth”>1944-01-15</field>
<fieldname=”gender”>F</field>
<fieldname=”citizenship_id”>7</field>
<fieldname=”country_code”>77</field>
<fieldname=”primary_citizenship”>1</field>
</row>
</resultset>

使用–xml选项的缺点是从关联的数据到XML的映射是固定的,因此无法修改输出。如果你想做某些字符串操作,可以去掉–xml选项,按你自己的方式生成XML代码。

继续沿用前面的查询,我们再来看看如何修改输出的XML,使其符合下面的格式要求:

<client>
<client_id>2</client_id>
<date_of_birth>1944-01-15</date_of_birth>
<gender>F</gender>
<citizenship_id>7</citizenship_id>
<country_code>77</country_code>
<primary_citizenship>1</primary_citizenship>
</client>

其中一个可行的办法是使用CONCAT() 和 GROUP_CONCAT()字符串函数

mysql>SELECT CONCAT(’\n<client>\n’,
->GROUP_CONCAT(’
<client_id>‘, client_id, ‘</client_id>\n’ SEPARATOR ”),
->GROUP_CONCAT(’
<date_of_birth>‘,date_of_birth,’</date_of_birth>\n’ SEPARATOR ”),
->GROUP_CONCAT(’
<gender>‘,gender,’</gender>\n’ SEPARATOR ”),
->GROUP_CONCAT(’
<citizenship_id>‘,citizenship_id,’</citizenship_id>\n’ SEPARATOR ”),
->GROUP_CONCAT(’
<country_cd>‘,country_cd,’</country_cd>\n’ SEPARATOR ”),
->GROUP_CONCAT(’
<primary_citizenship>‘,primary_citizenship,’</primary_citizenship>\n’ SEPARATOR ”),
->’
</client>‘) AS xmldoc
->FROM client_citizenship\G

虽然我们使用这种变通的方法达到了目标,但这样做还不如使用脚本或编程语言执行格式化,当然这得看你是否熟悉相关脚本或编程语言了。

北京网站建设公司

actionscript3

dom4j开源XML处理框架学习手记

Tags: ,

API帮助文档:http://www.dom4j.org/dom4j-1.6.1/apidocs/index.html

处理DEMO整理:

DEMO一:使用API生成XML文档

packagexml.utils;

importorg.dom4j.DocumentHelper;
importorg.dom4j.Element;
importorg.dom4j.Document;
publicclassFoo {
publicDocument createDocument() {
Document document
=DocumentHelper.createDocument();
Element root
=document.addElement(root);
Element author1
=root.addElement(author)
.addAttribute(
name,job)
.addAttribute(
location,US)
.addText(
HKEBAO);
returndocument;
}
publicstaticvoidmain(String[] args) {
Document document
=newFoo().createDocument();
System.out.println(document.asXML());
}
}

输出的结果:

<?xml version=1.0encoding=UTF-8?>
<root><author name=joblocation=US>HKEBAO</author></root>

直接通过内置的API输出一段XML出来!

DEMO2 :通过使用API进行读取XML里面的数据

原理:将XML解析到内存然后生成一棵DOCUMENT树!

解析的方法有多种

/**
*
@paramFile
*
@returnDocument
*
@throwsDocumentException
*
*/
publicDocument parse(File aFile)throwsDocumentException {
SAXReader xmlReader
=newSAXReader();
returnxmlReader.read(aFile);
}

注意:JAVA里面的File路径问题需要做一个专题讲一下!!!

publicstaticvoidmain(String[] args)throwsMalformedURLException, DocumentException {
File file
=newFile(dom4j.xml);
Document document
=newFoo().parse(file);
newFoo().bar(document);
System.out.println(document.asXML());
}

我们可以通过这样的方法来读出来一个XML文档。读出来了之后就可以方便进行解析了!

DEMO3

publicvoidmodifyDocumet(File inputxml) {
try{
SAXReader saxReader
=newSAXReader();
Document document
=saxReader.read(inputxml);
List list
=document.selectNodes(//article/@level);//使用了XPath语法
Iterator iter=list.iterator();
while(iter.hasNext()) {
Attribute attribute
=(Attribute) iter.next();
if(attribute.getValue().equals(Intermediate)) {
attribute.setValue(
Introductory);
}
}
list
=document.selectNodes(//article/@date);
iter
=list.iterator();
while(iter.hasNext()) {
Attribute attribute
=(Attribute) iter.next();
if(attribute.getValue().equals(December-2001))
attribute.setValue(
2002);
}
list
=document.selectNodes(//article);
iter
=list.iterator();
while(iter.hasNext()){
Element element
=(Element)iter.next();
Iterator iterator
=element.elementIterator(title);
while(iterator.hasNext()){
Element titleElement
=(Element)iterator.next();
if(titleElement.getText().equals(Java configuration with XMLSchema))
titleElement.setText(
Create flexible and extensible XML schema);
}
}
}
catch(Exception e) {
//TODO: handle exception
}

actionscript3

W3C开始为HTML语言加入硬件操作功能

Tags: ,

负责为网页编程语言提供标准化服务的W3C组织(World Wide Web Consortium)近日开始修改超文本标记语言的定义,计划为该语言加入HTML设备标识。根据12月11日发布的新版超文本标记语言定义草案的规定:HTML设备标识符可以让用户使用网页与摄像头等硬件设备打交道。

这次标准修改计划意味着超文本标记语言的应用范围将再一次被扩展。对这次扩展行动表示支持的成员同时希望这次扩展不应仅仅面向静态网页,而是要更多考虑到互动式的动态网页应用程序的需求,以便后者能直接操作用户电脑上的硬件。

目前对HTML标准有修改和维护权利的主要是两个大组织:W3C组织以及正规程度稍逊的WHATWG(网络超文本应用技术工作组)组织。当年W3C组织对HTML标准尤其是HTML5的开发力度大为减弱,转而重视XML标准,于是一些对此不满的公司便联合起来成立了WHATWG组织,继续完善HTML5的工作。

反观 WHATWG的HTML设备标识定义标准,则比W3C组织涉及的范围更为广泛,前者支持的接口甚至还包括USB接口的媒体播放器以及较旧的RS232串口。

北京网站建设公司

actionscript3

用jQuery、Ajax选项卡和照片carousel 改进现有的站点

Tags: ,

本文讲解用 Ajax 技术改进一个 Web 1.0 购物站点的步骤。可以下载改进之前和之后的示例应用程序源代码。还可以在作者的 Web 站点上看到这两个版本的运行效果。除了 Ajax 技术和最佳实践之外,还要学习如何通过渐进式改进、易用性和用户体验设计(UxD)原理用 Ajax 改进用户体验。

本文假设读者充分了解 HTML 和 CSS,至少基本了解 JavaScript 和 Ajax 编程技术。示例应用程序是只使用客户端代码构建的;但是,演示的技术也可以应用于任何服务器端应用程序框架。要想运行示例站点,至少需要在本地主机上运行一个基本的 Web 服务器。您也可以研究源代码并在作者的 Web 站点上查看示例站点的运行效果。

本系列的第 1 部分第 2 部分介 绍了示例应用程序 Customize Me Now,并开始从 Web 1.0 版本到 Ajax 支持的 Web 2.0 版本的改进过程。它们讨论了这种改进的业务原因和易用性原因。它们还帮助您设置几个开放源码工具,包括 jQuery JavaScript 框架以及它的几个插件。通过使用这些库,把弹出消息、离站链接和导航边栏替换为模态对话框、工具提示和 lightbox,从而改进了 Customize Me Now 的用户操作流。在这个过程中,采用了渐进式改进原理;在禁用 JavaScript 的情况下,改进的 Web 2.0 应用程序的页面会自动退化到 Web 1.0 体验。

第 3 部分的目标

在 本期中,我们将把产品细节页面的内容放到一个选项卡式界面中,从而提高它的可管理性。还要在一个图像 carousel 中显示产品图像,从而提高对图像的控制能力。您将学习如何通过简单的 Dynamic HTML(DHTML)或比较复杂的 Ajax 代码应用这两种技术。无论采用哪种方法,都应用渐进式改进原理,使页面在禁用 JavaScript 时仍然是可访问的。为了实现这些目标,将使用另外两个 jQuery 插件:用于实现图像幻灯片的 jCarousel 和用于实现选项卡的 jQuery UI Tabs。

为了理解本期中的概念,先请看一下Customize Me Now 1.1,这是原示例站点稍加改进后的版本。我们将通过修改 1.1 版创建 Customize Me Now 2.1,这个版本包含整个系列介绍的所有改进。

两种产品细节页面:单页面和多页面

在电子商务 Web 站点中,最复杂的部分之一是产品细节部分。站点会把大量关于产品的信息集中在一起,从简单的说明和技术规格到从用户社区收集的内容(比如用户评论)。当然,还有产品图像,而且每种产品常常有多个图像。从用户体验的角度来看,难题在于向用户显示决定购买产品所需的数据,同时避免过多的信息困扰用户。

在 某种程度上,Customize Me Now 1.0 比较容易进行 Ajax 改造。它显示的产品细节内容很容易放在单一页面上。在 Customize Me Now 2.0 中,通过使用 jQuery 和 Thickbox,把原来的页面替换为一个模态对话框。这有助于改进从搜索到购买的用户操作流程。

但是,现在需求改变了。 Customize Me Now 1.1 显示的产品细节信息远远多于 1.0 版。这些内容包括许多很长的文本块和许多大照片(图像来自流行的 Web 2.0 照片共享站点 Flickr)。在 Ajax 技术出现之前,有两种方法可以显示如此多的内容:一个很长的滚动页面(见图 1图 2),或者把页面分割为多个小页面,每个文本块或照片各有一个页面(见图 3图 4)。

在 Web 浏览器中访问 Customize Me Now 1.1,比较一下 Product Details 页面的版本 A 和 B 以及老版本(Customize Me Now 1.0)之间的差异。页眉和页脚中有这三个版本的链接。可以看到,版本 A 和 B 在易用性方面的困难比老版本大得多。显然,对于 Product Details 页面的这些新版本,Thickbox 模态对话框并不合适。

版 本 A 不但可能困扰用户,还会给浏览器和服务器的处理造成麻烦。用户会被大量信息所困扰(假设他们注意所有信息的话)。同时,浏览器和服务器必须处理大量数据, 造成很大负担。目前,这个页面只有 6 张照片,所以在使用宽带连接时页面装载速度相当快。但是,如果有 16 张甚至 60 张照片,会怎么样呢?如果还有 150 条用户评论,又会怎么样呢?如果用户使用的网络比较慢呢?如果同时装载与一个产品相关的所有数据,性能就会严重受损,而且用户也难以一下子吸收这么多的内 容。

版本 B 在每个页面上只显示少量信息,从而避免用户被大量信息困扰。但是,每当用户要查看更多信息时,他们必须单击链接并等待装载新页面。另外,版本 B 中的每个子页面包含大量让人糊涂的链接。虽然数据少了,但是导航过程很复杂。

改造单页面版本

因 为所有内容都在一个页面上,所以很容易用图像幻灯片和选项卡式界面改进版本 A。这不需要 Ajax,只使用老式的 DHTML 就可以实现。这种方法的优点是它使用了渐进式改进。提供给浏览器的内容仍然是很长的滚动页面,但是 JavaScript 代码把它转换为更现代更容易使用的界面。如果使用不支持 JavaScript 的浏览器,用户只能看到原来的页面。当然,这种方法没有解决单页面方法的带宽问题。

下载和安装开放源码工具

为了开始 Ajax 改造,首先要下载 jQuery 的最新版本,它是所有新功能基础(参见参考资料)。如果您已经学习了本系列的第 1 部分和第 2 部分,应该已经安装了 jQuery 1.2.1。到编写本文时,当前版本是 1.2.3,其中增加了一些 bug 补丁。

还需要从参考资料小节下载两个插件。jQuery UI Tabs 是 jQuery UI 的一部分,jQuery UI 是一组可配置的用户界面部件和组件。jQuery UI Tabs 把ul元素转换为选项卡式界面,并把内联内容和 Ajax 标记转换为这些选项卡的内容。jCarousel 是一个单独的插件,它把图像集转换为幻灯片。与 jQuery UI Tabs 一样,这些幻灯片的内容可以是内联内容或是 Ajax。

下载这些组件之后,把它们放在应用程序目录结构中的适当位置。每个下载包都包含代码示例和其他多余的文件,可以根据自己的需要保留或删除它们。每个 JavaScript 库的简化版适用于生产环境,但是您可能希望获得完整的源代码,这样就可以通读代码,更好地了解每个组件:

  • 对于 jQuery,需要的惟一文件是库本身的简化版。
  • 对 于 jQuery UI Tabs,应该获取库的简化版、附带的 CSS 文件和两个图像:loading.gif 和 tab.png。因为 tab.png 假设您的站点采用白色背景,可能需要在 Adobe Photoshop 或其他图像编辑程序中修改它,使它的圆角效果与 Customize Me Now 的实际背景颜相匹配。
  • 对于 jCarousel,需要库的简化版和附带的 CSS 文件,以及库附带的三种预打包的 skin 之一的完整目录。在 jCarousel 中,skin 由一个 CSS 文件和一组图像组成,用来控制 carousel 的视觉样式。对于 Customize Me Now,我们使用 Tango skin,但是把目录重命名为 “tango-modified”;我们将对默认的 Tango 方案做一些修改。

以上文件就位之后,要把它们插入 detailA.html 的开头。结果见清单 1:
清单 1. 部署 jQuery 及其插件

<!--jquery assets-->
<script type="text/javascript"
	src="../js/jquery-1.2.3.minjs"></script>

<!--jquery.ui.tabs assets-->
<script type="text/javascript"
	src="./ui.tabs/ui.tabs.pack.js"></script>
<link rel="stylesheet" href="../ui.tabs/ui.tabs.css"
	type="text/css" media="print, projection, screen">

<!--jcarousel assets-->
<script type="text/javascript"
	src="../jcarousel/lib/jquery.jcarousel.pack.js"></script>
<link rel="stylesheet" type="text/css"
	href="../jcarousel/lib/jquery.jcarousel.css" />
<link rel="stylesheet" type="text/css"
	href="../jcarousel/skins/tango-modified/skin.css" />

创建 DHTML 图像 carousel

要 想创建 DHTML 图像 carousel,首先要修改 jCarousel 的外观。因为 jCarousel 可以配置为显示水平或垂直的图像 carousel,所以它的样式表包含用来实现这两种类型的规则。我们的幻灯片是水平的,所以可以删除与垂直幻灯片相关的所有 CSS 声明。另外,需要修改许多元素的宽度、高度、填充和空白边。在默认情况下,jCarousel 创建的幻灯片在任何时候都显示三个小的缩略图。在我们的幻灯片中,图像大得多(宽 500 像素),所以应该每次只显示一个图像。完成这些修改之后,skin.css 应该像清单 2 这样:
清单 2. 幻灯片的 CSS 代码

..jcarousel-skin-tango.jcarousel-container {
    -moz-border-radius: 10px;
    background: #F0F6F9;
    border: 1px solid #346F97;
}

..jcarousel-skin-tango.jcarousel-container-horizontal {
    width: 502px;
    padding: 20px 125px !important;
}

.jcarousel-skin-tango .jcarousel-clip-horizontal {
    width:  502px;
    height: 410px;
}

..jcarousel-skin-tango .jcarousel-item {
    width: 502px;
    height: 410px;
}

..jcarousel-skin-tango .jcarousel-item-horizontal {
    margin-right: 125px;
}

..jcarousel-skin-tango .jcarousel-item-placeholder {
    background: #fff;
    color: #000;
}

/**
 *  Horizontal Buttons
 */
..jcarousel-skin-tango .jcarousel-next-horizontal {
    position: absolute;
    top: 43px;
    right: 5px;
    width: 32px;
    height: 32px;
    cursor: pointer;
    background: transparent url(next-horizontal.png) no-repeat 0 0;
}

..jcarousel-skin-tango .jcarousel-next-horizontal:hover {
    background-position: -32px 0;
}

..jcarousel-skin-tango .jcarousel-next-horizontal:active {
    background-position: -64px 0;
}

..jcarousel-skin-tango .jcarousel-next-disabled-horizontal,
..jcarousel-skin-tango .jcarousel-next-disabled-horizontal:hover,
..jcarousel-skin-tango .jcarousel-next-disabled-horizontal:active {
    cursor: default;
    background-position: -96px 0;
}

..jcarousel-skin-tango .jcarousel-prev-horizontal {
    position: absolute;
    top: 43px;
    left: 5px;
    width: 32px;
    height: 32px;
    cursor: pointer;
    background: transparent url(prev-horizontal.png) no-repeat 0 0;
}

..jcarousel-skin-tango .jcarousel-prev-horizontal:hover {
    background-position: -32px 0;
}

..jcarousel-skin-tango .jcarousel-prev-horizontal:active {
    background-position: -64px 0;
}

..jcarousel-skin-tango .jcarousel-prev-disabled-horizontal,
..jcarousel-skin-tango .jcarousel-prev-disabled-horizontal:hover,
..jcarousel-skin-tango .jcarousel-prev-disabled-horizontal:active {
    cursor: default;
    background-position: -96px 0;
}

接下来,对 detailAhtml 的标记做一处小修改。页面原来版本中的图像已经组织成一个ul元素。需要在这个 HTML 列表外添加一个div。在这个包装器div中添加一个值为jcarousel-skin-tangoclass属性,这样就会把 Tango skin 中的样式规则应用于这个 carousel。还要在这个div中添加一个值为imageCarouselid属性,让 jQuery 可以解析文档对象模型(DOM)并找到要转换的元素。完成修改之后,HTML 如清单 3 所示:
清单 3. 幻灯片的 HTML 代码

<div id="imageCarousel">
	<ul>
		<li>
			<img alt="product photo"
				width="500" height="375" src="http://www.phpchina.com/../img/pizza1.jpg" />
			Photo credit: <a target="_blank"
			href="http://www.flickr.com/photos/kankan/">Kanko*</a>,
			Flickr, Creative Commons Attribution License
		</li>
		<!--additional <li> items, images and photo credits here-->
	</ul>
</div>

最后,创建幻灯片的 JavaScript 代码。由于有 jCarousel 的帮助,这只需要几行代码。在 HTML 文档的顶部,包含的 JavaScript 和 CSS 文件的下面,添加清单 4 所示的内联脚本块:
清单 4. 幻灯片的 JavaScript 代码

<script type="text/javascript">
$(document).ready(function() {

	$('#imageCarousel').jcarousel({
		scroll: 1
	});

});
</script>

这段 JavaScript 代码看起来简单,但是它会完成所有复杂的工作。它通过调用 jQuery 的ready事件处理函数,指示 jQuery 等待页面的 DOM 装载完成,然后执行其他任务。通过调用 jQuery 的选择符机制($函数),让 jQuery 找到id属性值为imageCarousel的 DOM 元素。然后,调用包含这个 DOM 节点的对象上的jcarousel方法,这让 jCarousel 把这个节点中的所有标记转换为一个图像幻灯片。需要向jcarousel方法传递一个参数:配置参数的散列。jCarousel 的大多数默认选项是合适的,所以这个散列只包含一个键-值对:scroll,值为 1,这让 jCarousel 每次只显示一个图像。

现在,图像幻灯片完成了。

创建 DHTML 选项卡

接下来,为页面上的每部分内容创建 DHTML 选项卡。首先,把每部分内容包装在一个新的div中,并在其中添加惟一的id属性和值为tabContentclass属性。修改后的内容见清单 5。这些包装器的作用是为 jQuery UI Tabs 提供钩子,让它知道把哪些标记转换为选项卡的内容。
清单 5. detailA.html 中五部分内容的 HTML

<div id="introduction">

	<h2>Introduction</h2>

	<!--paragraphs of text content here-->

</div>

<div id="moreDetails">

	<h2>More Details</h2>

	<!--paragraphs of text content here-->

</div>

<div id="userReviews">

	<h2>User Reviews</h2>

	<!--paragraphs of text content here-->

</div>

<div id="techSpecs">

	<h2>Technical Specifications</h2>

	<!--paragraphs of text content here-->

</div>

<div id="productImages">

	<h2>Product Images</h2>

	<div id="imageCarousel">
    	<ul>
			<!--<li> items from your image slideshow here-->
		</ul>
	</div>

</div>

接下来,在 HTML 文档中添加一些标记:一个无序的链接列表。这会出现在文档顶部,就在实际内容的第一部分前面。jQuery UI Tabs 会把这些标记转换为新的内容选项卡界面。尽管链接的href属性看起来像内部文档锚,但是它们实际上与前面创建的包装器divid属性匹配。这些标记见清单 6:
清单 6. detailA.html 中增加的 HTML 内容

<ul>
    <li><a href="#introduction"><span>Introduction</span></a></li>
    <li><a href="#moreDetails"><span>More Details</span></a></li>
    <li><a href="#userReviews"><span>User Reviews</span></a></li>
    <li><a href="#techSpecs"><span>Technical Specifications</span></a></li>
    <li><a href="#productImages"><span>Product Images</span></a></li>
</ul>

接下来,创建两组样式,分别用于启用和不启用 JavaScript 的浏览器。在启用 JavaScript 的浏览器中,用户会看到新的选项卡式界面,所以需要调整选项卡内容的外观。首先,添加一定的填充和边框。然后,在每个选项卡中禁止显示h2元素;在新界面中,这些标题会显示为选项卡的文本标签,所以不需要重复显示。这些样式规则应该添加在全局样式表中。

禁用 JavaScript 的用户不会看到选项卡式界面。对于这些用户,需要隐藏前面添加的无序列表,删除在内容部分中添加的边框和填充,恢复显示h2元素。幸运的是,通过使用noscript标记很容易完成这些任务。为了在禁用 JavaScript 的浏览器中覆盖全局样式,在noscript标记中添加一些 CSS 规则。这些样式只在关闭 JavaScript 支持的情况下应用。

最终结果是一组外观漂亮的标记,它们会根据浏览器的功能显示非常不一样的界面。完成之后,两个 CSS 代码块见清单 7 和清单 8:
清单 7. 在 customizemenow.css 中添加的 CSS 样式

#CMN .tabContent {
	padding: 14px;
	border: 1px solid #97a5b0;
}
#CMN .tabContent h2{
	display: none;
}

清单 8. 在 detailA.html 的noscript块中添加的样式

<noscript>
	<style type="text/css">
		#CMN .tabContent {
			padding: 0;
			border: 0;
		}
		#CMN .tabContent h2 {
			display: block;
		}
		#CMN ul.nav {
			display: none;
		}
	</style>
</noscript>

最后,添加用来创建 DHTML 选项卡的定制 JavaScript。为此,需要在前面创建的内联脚本块(见清单 4)中添加代码。清单 9 给出内联脚本块:
清单 9. detailA.html 中的定制 JavaScript

$(document).ready(function() {

	/*earlier jCarousel code goes first*/

	/*create tabs from an unordered list using jquery.ui.tabs*/
	$('ul.navTabs').tabs(
		{ fx: { height: 'toggle', opacity: 'toggle' } }
	);

});

与使用 jCarousel 时一样,jQuery UI Tabs 的定制 JavaScript 也非常简单。同样使用 jQuery 的选择符机制寻找一个 DOM 元素(在这里是无序的链接列表)。然后,jQuery UI Tabs 的tabs方法把这个ul及其li子元素转换为选项卡式界面。tabs方法检查无序列表中的链接,并把每个选项卡与对应的包含内容的div匹配起来。每个div最初被隐藏,直到用户单击对应的li元素(显示为选项卡)。与jcarousel方法一样,可以通过传递初始化参数的散列来定制tabs方法的行为。在这里,我们添加一些视觉效果,让选项卡在浏览器中的表现更酷。最后注意一点:需要在创建选项卡界面之前创建 jCarousel 图像幻灯片;如果先创建选项卡界面,jCarousel 就会在图像 carousel 的 CSS 属性方面产生混乱。

检查单页面版本

如果看一下 Customize Me Now 2.1 的 Product Details 页面的版本 A,就会看到 DHTML 选项卡(图 5)和图像 carousel(图 6)的显示效果。为了看到淡出和窗帘效果等视觉效果,在 Web 浏览器中装载页面。

与 1.1 版相比,2.1 版的 Product Details 页面版本 A 有几个优点。它对用户隐藏了庞大复杂的信息,提供了更加简洁的界面。选项卡式导航方法使用户能够有条理地吸收理解各部分内容。如果在浏览器中禁用 JavaScript 并重新装载页面,就会看到与 1.1 版几乎完全一样的页面。这就是渐进式改进的作用。但不幸的是,这个版本没有解决单页面方法的带宽问题。用户仍然必须下载所有文本和图像,即使他们可能根本 不查看这些内容。下面就来解决这个问题。

改造多页面版本

既 然已经在单页面版本的 Product Details 页面中添加了选项卡和图像 carousel,下面就对多页面版本进行相似的改进。这里的代码比较复杂,因为选项卡和 carousel 的内容要通过 Ajax 动态地装载到页面中。但是,这会换来更快的页面装载速度并节省带宽。额外的内容只在需要时动态地装载。

创建 Ajax 图像 carousel

要 想用多页面的 Product Details 内容创建一个图像 carousel,第一步是构建一个新的 JavaScript Object Notation(JSON)文档。JSON 是一种与 XML 相似的数据传输格式,但是更轻量。这种格式非常适合 Ajax,因为 jQuery 和其他 Ajax 框架可以可靠地把 JSON 文档转换为 JavaScript 对象,而且速度非常快。我们的 JSON 文档不包含任何标记,只包含要转换为幻灯片的图像的 URL 和元数据。创建这个文档之后,把它保存为 detailB5-fragment.html,见清单 10
清单 10. detailB5-fragment.html 中的 JSON 数据

{"items": [
	{
		"url": "pizza1.jpg",
		"width": "500",
		"height": "375",
		"creditURL": "kankan",
		"creditLabel": "Kanko*"
	},
	{
		"url": "pizza2.jpg",
		"width": "500",
		"height": "374",
		"creditURL": "lenore-m",
		"creditLabel": "L. Marie"
	},
	{
		"url": "pizza3.jpg",
		"width": "500",
		"height": "375",
		"creditURL": "roadhunter",
		"creditLabel": "Topato"
	},
	{
		"url": "pizza4.jpg",
		"width": "500",
		"height": "369",
		"creditURL": "sgt_spanky",
		"creditLabel": "Kevitivity"
	},
	{
		"url": "pizza5.jpg",
		"width": "500",
		"height": "368",
		"creditURL": "fooey",
		"creditLabel": "foéöÞoooey"
	},
	{
		"url": "pizza6.jpg",
		"width": "500",
		"height": "334",
		"creditURL": "pancakejess",
		"creditLabel": "jsLander"
	}
]}

接下来,按照前面处理 detailA.html 的方式(参见清单 1), 在 detailB1.html 的顶部添加 jQuery、jQuery UI Tabs 和 jCarousel 文件。然后,向 detailB1.html(它为图像幻灯片创建占位符)的文档体添加 HTML;jCarousel 将用图像内容填充这个空的无序列表。占位符的 HTML 见清单 11
清单 11. detailB1.html 中的占位符

<div id="productImages">

	<h2>Product Images</h2>

	<div id="imageCarousel">
    	<ul>
		</ul>
	</div>

</div>

最后,在 HTML 文档头中这些文件下面的脚本块中添加定制的 JavaScript 代码。这个脚本块见清单 12
清单 12. detailB1.html 中的 JavaScript 代码

<script type="text/javascript">

window.alert = function() {
	return;
};

$(document).ready(function() {

	/*
		create an image slideshow from a JS array of URLs using
		jcarousel
	*/
	var itemLoadCallback = function(carousel, state) {
		if (state != 'init') {
			return;
		}
		jQuery.getJSON("detailB5-fragment.html", function(data){
	 		itemAddCallback(carousel, carousel.first,
				carousel.last, data.items);
		});
	};

	var itemAddCallback = function(carousel, first, last, data) {
	    for (i = 0, j = data.length; i < j; i++) {
	        carousel.add(i, getItemHTML(data[i]));
	    }
	    carousel.size(data.length);
	};

	var getItemHTML = function(d) {
		return '<img alt="product photo" width="' +
			d.width + '" height="' +
			d.height + '" src="../img/' +
			d.url + '" />Photo credit: <a target="_blank"' +
			' href="http://www.flickr.com/photos/' +
			d.creditURL + 's/">' +
			d.creditLabel + '</a>, Flickr, ' +
			'Create Commons Attribution License'
		;
	};

	jQuery('#imageCarousel').jcarousel({
		itemLoadCallback: itemLoadCallback,
		scroll: 1
	});

	jQuery('ul.productImages').css("width","3012px");

});
</script>

这段 JavaScript 比前面创建的代码都复杂。它包含以下函数:

  • itemLoadCallback。使用 Ajax 从前面创建的 JSON 文档读取数据,然后把数据传递给itemAddCallback
  • itemAddCallBack。解析itemLoadCallback装载的 JSON 数据并把每个图像添加到 carousel 中。
  • getItemHTML。把 JSON 数据转换成插入 DOM 所需的 jCarousel 标记。

为了调用这些函数,要把itemLoadCallback作为选项散列的一部分传递给jcarousel方法。这告诉 jCarousel,它应该用 Ajax 数据动态地构建幻灯片,而不是使用 DOM 中现有的标记。itemLoadCallback和它的辅助函数会自动完成这个任务。但是,jCarousel 在采用这种方式时会产生两个奇怪的现象。

首先,jCarousel 似乎会错误地计算动态装载的内容的 CSS 属性。结果是在幻灯片中有几个图像根本不出现。调试表明,jCarousel 弄错了包含图像的ul的宽度。您可以花时间调试这个问题并扩展 jCarousel 代码来纠正它,但是有一个更简便的方法:在构建 carousel 之后,用 jQuery 的css方法调整它的宽度,使它与 Product Details 版本 A 中非动态生成的 carousel 的宽度匹配。

jCarousel 的第二个问题与第一个问题相关:因为 jCarousel 对 DOM 元素宽度的计算不正确,所以每当用户调整浏览器窗口大小时,它会显示一个错误消息。这个错误消息以 JavaScript 警告框的形式出现,这绝对不是很好的用户体验。要想纠正这种行为,可以用一个哑函数替换 JavaScript 内置的window.alert方法。

创建 Ajax 选项卡

要 想在多页面的 Product Details 上使用 jQuery UI Tabs,应该混合使用内联内容和动态的 Ajax 内容。用 detailB1.html 文件作为所有内容的包装器页面(内容以前包含在 detailB2.html、detailB3.html 和 detailB4.html 中)。通过 Ajax 把这些文件的内容装载到 detailB1.html 中的问题是,每个页面都包含一个完整的 HTML 文档;而我们真正需要的是每个页面有一个对应的div。 为了解决这个问题,我们要创建这些页面的另一个版本:复制每个文件,修改文件名,删除多余的标记。结果是三个新文件,detailB2- fragment.html、detailB3-fragment.html 和 detailB4-fragment.html。这些文件与清单 13相 似。当然,在真实环境中,可以用服务器端模板引擎生成完整 HTML 版和片段版两种内容。例如,Ruby on Rails 等框架可以根据请求是正常请求还是 Ajax 调用,自动地对相同的内容应用不同的包装器。但是,因为这个示例只使用客户端代码,所以我们用单独的文件模拟这种效果。
清单 13. HTML 片段文件的标记

<div id="moreDetails">

	<h2>More Details</h2>

	<!--paragraphs of text content here-->

</div>

接 下来,需要修改 detailB1.html 中的一些标记。在 Customize Me Now 1.1 中,这个页面包含一个辅助导航菜单,帮助用户在页面之间移动,见清单 14。对这些标记做一些修改,让 jQuery UI Tabs 把它转换为选项卡界面。修改后的标记见清单 15。
清单 14. detailB1.html 中原来的导航菜单标记

<ul>
	<li><a href="detailB1.html">Introduction</a></li>
	<li><a href="detailB2.html">More Details</a></li>
	<li><a href="detailB3.html">User Reviews</a></li>
	<li><a href="detailB4.html">Technical Specifications</a></li>
	<li><a href="detailB5a.html">Photos</a></li>
</ul>

清单 15. detailB1.html 中修改后的 Ajax 选项卡标记

<ul>
    <li><a href="detailB1.html"><span>Introduction</span></a></li>
    <li><a href="detailB2.html"><span>More Details</span></a></li>
    <li><a href="detailB3.html"><span>User Reviews</span></a></li>
    <li><a href="detailB4.html"><span>Technical Specifications</span></a></li>
    <li><a href="detailB5a.html"><span>Product Images</span></a></li>
</ul>

接下来,在页面上的内联脚本块中添加 JavaScript 代码。完成之后,脚本块类似于清单 16:
清单 16. 用来创建 Ajax 选项卡的内联脚本块

$(document).ready(function() {

	/*transform urls for tabs with inline content*/
	$('ul.nav > li:first > a').attr("href", "#introduction");
	$('ul.nav > li:last > a').attr("href", "#productImages");

	/*transform urls for tabs with ajax content*/
	$('ul.nav > li:not(:first):not(:last) > a').each(function (i) {
		var el = $(this);
		el.attr("href", el.attr("href").replace(".html",
			"-fragment.html"));
	});

	/*earlier jCarousel code goes here*/

	/*
		replace ul classname of "nav" with "navTabs" to
		reset styling to a blank state
	*/
	$('ul.nav').attr({"class":"navTabs"});

	/*create tabs from an unordered list using jquery.ui.tabs*/
	$('ul.navTabs').tabs(
		{ fx: { height: 'toggle', opacity: 'toggle' } }
	);

});

用来创建 Ajax 选项卡的 JavaScript 代码比前面的 DHTML 选项卡代码复杂得多。同样,这也是因为我们需要渐进式改进。在前面修改辅助导航菜单的标记时(见清单 15), 没有修改链接 URL。这样的话,在关闭 JavaScript 支持时,这些链接仍然表现正常。但是,为了创建 Ajax 选项卡,这些链接需要转换为 jQuery UI Tabs 可以理解的格式。对于包含内联内容的 Introduction 和 Product Images 选项卡,href属性采用#wrapperDivIDAttribute格式。对于其他三个选项卡(其内容是通过 Ajax 获得的),href属性需要引用前面创建的 HTML 片段文件。幸运的是,jQuery 很容易转换这些链接。

也很容易修改辅助导航菜单的class属性。许多样式规则与组成菜单的ul相关联。在把li元素转换为选项卡时,需要取消原来的样式。为此,使用 jQuery 把ul元素的class属性值由nav改为navTabs。完成之后,可以用 jQuery 选择符机制($函数)选择这个ul元素并对它应用tabs方法。

现在基本上完成了,但是还有一些 CSS 问题要处理。首先,需要覆盖所有不应该应用于页面的 Ajax 版本的样式。为此,与前面一样在页面顶部添加一个noscript样式块。但是,这一次需要用一个额外的样式规则隐藏前面添加的哑图像幻灯片标记。完成之后,noscript样式块如清单 17 所示:
清单 17. detailB1.html 的 noscript 样式

<noscript>
	<style type="text/css">
		#CMN .tabContent {
			padding: 0;
			border: 0;
		}
		#CMN .tabContent h2 {
			display: block;
		}
		#CMN #productImages {
			display: none;
		}
	</style>
</noscript>

最 后,需要解决 jQuery Tabs UI 把 Ajax 内容插入选项卡界面时的一个怪异现象。如果在 Web 浏览器中看看这个页面,会看到选项卡和 Ajax 选项卡内容之间的边框厚度是预期厚度的两倍。这是因为 jQuery UI Tabs 把每部分 Ajax 内容放在一个具有顶边框的包装器div中;但是,在包装器内部,已经对 HTML 片段应用了边框,所以会看到双重边框。为了纠正这个问题,在 HTML 片段文件的包装器div中添加另一个类,然后添加一个样式规则,从具有这个类的元素上删除顶边框。代码见清单 18 和清单 19:
清单 18. 纠正双重边框问题的 CSS 声明

#CMN .tabContent.noTop {
	border-top: 0;
}

清单 19. 应用于 HTML 片段文件的 CSS 类

<div id="moreDetails">

	<h2>More Details</h2>

	<!--paragraphs of text content here-->

</div>

检查多页面版本

现在,可以在 Web 浏览器中查看 2.1 版的 Product Details 页面版本 B。它的外观和表现应该很像版本 A(图 5图 6)。 但是在幕后,版本 B 的效率高得多。在用户单击对应的选项卡之前,并不装载 Ajax 内容,这会节省带宽。但是,这并不会节省传输图像所需的带宽。按照定制 Ajax 代码的工作方式,会默认装载 jCarousel 幻灯片中的所有图像。尽管如此,页面的装载时间仍然得到了改进。直到显示页面的其余部分之后,浏览器才会向服务器请求这些图像。对于使用慢速连接的用户, 这会显著改进用户体验。

还可以进一步改进这个页面:让浏览器在用户选择 Product Images 选项卡之前不自动装载图像。这样的话,如果用户不打算查看图像,就不必浪费带宽来装载它们。这样的解决方案会增加 JavaScript 代码的复杂性,但是如果产品的图像比较多,这样做就是值得的。

当关闭 JavaScript 支持时,Product Details 的版本 A 和 B 之间的根本差异就会表现出来。版本 A 会退化为单一滚动页面,而版本 B 退化为多页面版本。

结束语

在 本系列的第 3 部分中,学习了如何应用渐进式改进原理实现现代的便于使用的 Ajax 界面。还进一步了解了 jQuery 及其插件。可以使用在本文中学到的技能进一步改进您的站点。例如,可以使用 jQuery Cookie 插件让浏览器在用户下一次访问页面时记住原来选择的选项卡。还可以在 Purchase Confirmation 页面上构建选项卡式界面:交叉销售、订单重放和帐单重放各有一个选项卡。改进的机会是无限的。

在真实环境中,可能根本用不到构建 Product Details 页面的三个版本。对于这样的简单功能,这样做花的时间太多了。另外,混合使用不同的界面会把用户弄糊涂。尽管如此,本文说明了在 jQuery 等开放源码工具的帮助下,很容易实现 Ajax、渐进式改进和以用户为中心的设计。


北京网站建设公司

actionscript3

2009/12/22

as3.0全屏代码

Tags:

在场景上创建一个MC(MC指的是影片),给MC命为btn,然后在时间轴上写代码
代码如下
var isFull:Boolean=false
btn.addEventListener(MouseEvent.CLICK,onClick)
function onClick(e){
if(isFull==false){
  fscommand(”fullscreen”,”true”)
  isFull=true
  }else if(isFull==true){
   fscommand(”fullscreen”,”false”)
  isFull=false
   }
}

actionscript3

while 和 do…while循环

Tags: ,

while循环中,i的值在循环外设置,但在循环的代码块中递增

var i:int = 0;
while(i<5){

trace(i);
i++;
}

var i:int = 0;

do{

trace(i);
i++;
}while(i<=5);

actionscript3

for each … in循环获取对象的属性

Tags: ,

for each … in循环存储了引用的属性或者元素的实际值,而不仅仅是元素或者属性的引用

var employeeInfo:Object = new Object();

employeeInfo.name = ‘changyan’;
employeeInfo.age = ‘26′;
employeeInfo.id = 9999;

for each(var prop in employeeInfo){
trace(prop);
}