Sencha Touch 2 入门 Demo 之一:搭建 Sencha Touch 2 的运行环境

标签: sencha touch demo | 发表时间:2012-03-23 08:06 | 作者:随它去吧
出处:http://www.cnblogs.com/
 前言:

前段时间不才翻译了关于Sencha Touch 2 MVC架构的一系列文章,大家的认可让我备受鼓舞,也坚定了继续分享自己学习Sencha Touch(下文简称ST)过程和经验的决心。

在跟大家交流的过程中,发现很多入门者反映,学习ST最大的障碍有两个:1、官方文档跟进速度不够;2、官方sample集成程度较高,典型性不足。

我认同大家的观点:由于前期ST2版本更新极快,一个多月的时间从Beta到RC再到正式版,这期间小变动相当多,开发组的疯狂精神固然值得钦佩,可是截至目前为止,仍有一些地方未作详尽说明,而这对于刚接触ST的朋友来讲的确很困难。关于官方提供的sample集成度过高的问题,我觉得对从未接触过Ext产品系的朋友来说,这一点也的确棘手。

所以这一阶段我的打算是通过demo的方式,为刚开始学习的朋友们提供一些更具有典型性的实例,同时也尝试对官方说明不够的地方进行一下讲解,希望对大家有帮助。

Sencha Touch 交流 QQ 群 213119459 欢迎您的加入。


 本节目标:加载 ST2 到你的网页,搭建运行环境

这一节的内容其实刚好可以对应官方文档的《Getting Started with Sencha Touch 2》 http://docs.sencha.com/touch/2-0/#!/guide/getting_started

为什么我前面一直没有翻译这一章节,原因也在这里,对于ST2来讲,官方的这篇文档显然缺乏诚意,虽然它可以指点你写出一个hello world,但是对ST2运行环境的搭建细节说明不够,刚好今天我可以用一个完整的Demo来做一个详细说明。

ST1的时候,搭建基于ST的网页运行环境的确非常简单,如官方这篇文档所述已经足够(这也是我认为诚意不够的原因,为嘛不紧跟ST2的步伐呢)。

但是从ST2 Beta版开始,开发组提供了sencha-touch-all.js和sencha-touch.js两个js文件,其目的是允许开发人员选择ST框架是采用“一次性加载全部”的方式(简称all方式)还是“首次运行只加载核心代码,随后按需加载”的方式(简称core方式),在ST2的最终发布版中,core方式只有91k,而all方式有568k,这还都是压缩后的大小,这样的尺寸对比在mobile设备上意味着用户体验可能出现巨大差别,因此根据自身需求来选择加载模式还是很有必要的。

其实ST2的正式版发布后,很多人就开始头疼,因为大家发现下载的sdk包解压缩后,里面的例子无法直接双击在Chrome里运行,这还不算完,ST官方网站上提供的sample源码竟然也变得失去了可读性,没有了css文件的引入,没有了app.js的引入,只是html页面中被加入了一段压缩混淆后的js代码,很多人想不通,其实我当时也想不通:-)。

事情的真相是,正式版使用的那段混淆脚本叫做microloader,它通过异步加载一个app.json文件(这个文件也是正式版才出现的)来读取对运行环境的初始化设定,然后根据app.json中的设定再去加载相应的css和js文件,甚至于设定app缓存等等(还有很多至今搞不清楚的设定),也就是说,采用此种方式,要调用的js和css文件被隐藏了,显而易见,这种方式非常有助于保护你的源码,当然也不是绝对安全的js源码保护方式,但至少还是比什么都不做要强得多。

于是,ST2的正式版最终得以支持两种模式下的四种手段来实现ST2框架文件的加载。而这也是本节的demo所要说明的。

 开发环境说明

ST的开发说到底还是web开发,因此它对开发环境和开发工具其实并不挑剔,小到notepad,中到notepad++/editplus,大到eclipse/visual studio都可以,当然如果考虑到方便性的话,最好还是有自动格式、关键字高亮、自动补齐功能,但无论怎样,目前似乎还没有可以像Aptana通过插件来支持jQuery那样完全支持ST的开发工具,我们期盼以后eclipse或者visual studio出现相应的插件吧。

对于普通开发者而言,我推荐notepad++,轻便的同时功能还算强大,如果你不怕块头大,Aptana和eclipse也是不错的选择。不过我用的是Visual Studio 2010,因为电脑上就有,无需安装了。

 Demo代码完整结构

下面对上述结构做一详细说明:

最顶级是Demo和SenchaTouch两个文件夹,分别用来放置Demo程序代码和ST框架代码:

SenchaTouch文件夹下面的2.0.0文件夹表明当前ST框架的版本号,再下面就是ST2框架的所有相关资源文件;

  • 以sencha-touch开头的4个js文件分别是ST2框架的all版和core版及其各自的debug版;
  • css里面放置了ST2的几套皮肤样式文件;
  • src文件夹下是ST2的所有源文件代码,该文件夹内文件主要供core加载方式调用;
  • 还有一个microloader文件夹,里面提供了刚才我们前面提到过的ST2正式版所采用最新加载方式所需js文件。

Demo文件夹下就是我们此次编写的全部代码文件:

  • 1.LoadSenchaTouchDirectly文件夹下面有两个html页面和各自匹配的js文件,分别对ST传统的主页面直接嵌入js和css模式下,如何采用all和core两种手段载入框架文件进行了示范;
  • 2.LoadSenchaTouchWithMicroloader文件夹下有两个html页面、一个app.js外加一个app.json文件,演示了如何在html页面中通过inline或者code-behind方式引用microloader实现ST的设定和加载。

 Demo所实现的效果:文本框与Picker结合实例

虽然本文目的是分别演示不同模式不同手段来加载ST2所需框架,但页面上若只写一个干巴巴的Hello World还是有些对不起观众,所以这里我实现了一个比较有实际使用价值的效果,那就是一个不可编辑文本框,该文本框的值只能通过一个Picker来选择。效果图如下:

下面开始一一介绍四种加载方式:

 A.直接加载完整框架文件(all方式)

这种加载方式跟ST1开始的方式是一样的,即在html页面中明确引入sencha-touch的完整框架js文件、css文件以及应用程序代码。

sencha-touch-all.html代码:

晕死!博客园将我的相对路径都自动转成了站内绝对路径,请自行将后面所有代码中的" http://www.cnblogs.com/"改成"。。/。。/"(。换成.)

<!DOCTYPE html>   
<html>
<head>
<title>Hello Mobile</title>
<link rel="stylesheet" href="http://www.cnblogs.com/SenchaTouch/2.0.0/css/sencha-touch.css" type="text/css">
<script type="text/javascript" src="http://www.cnblogs.com/SenchaTouch/2.0.0/sencha-touch-all-debug.js"></script>
<script type="text/javascript" src="app-all.js"></script>
</head>
<body></body>
</html>

app-all.js代码(代码逻辑很简单,看注释即可):

Ext.application({   
name: 'Demo',
viewport: {
autoMaximize: true // 该属性可以设置页面自动最大化(隐藏地址栏)
},

launch: function () {
Ext.create("Ext.Panel", {
fullscreen: true,
items: [
{
xtype: 'fieldset',
margin: 10,
title: '文本框与Picker结合实例',
items: [
{
xtype: 'textfield',
name: 'aTextField',
id: 'aTextField',
readOnly: true, // 把文本框设为只读,禁止输入
label: '取值结果',
clearIcon: true,
listeners: {
// 侦听文本框的focus事件,获取到焦点时触发
focus: function () {
this.disable(); // 先禁用文本框,防止系统调出软键盘
Ext.getCmp('aPicker').show(); // 然后显示用来选择内容的Picker
}
}
}
]
}
]
});

// 定义一个Picker供文本框联动
aPicker = Ext.create('Ext.Picker', {
name: 'aPicker',
id: 'aPicker',
hidden: true,
listeners: {
// 侦听change事件,Picker的值改变同时也设定文本框的值
change: function () {
Ext.getCmp('aTextField').setValue(aPicker.getValue().question);
},
// 侦听hide事件,当Picker消失时将文本框状态恢复为enable
hide: function () {
Ext.getCmp('aTextField').enable();
}
},
slots: [
{
name: 'question',
data: [
{
text: '无',
value: ''
},
{
text: '最喜欢的颜色',
value: 'color'
},
{
text: '最喜欢的运动',
value: 'sport'
},
{
text: '最喜欢的明星',
value: 'star'
}
]
}
]
});

// 前面定义的Picker控件必须显式加入Viewport,否则无法被调用显示
// Ext.Viewport是Sencha Touch自动创建的一个顶级容器
Ext.Viewport.add(aPicker);
}
});

 B.先加载核心框架文件,然后按需加载其他组件(core方式)

此种加载方式是ST2新增的,他为我们提供了更多地选择,避免每个app都要加载巨大的sencha-touch-all.js。

不过具体使用的时候你会发现,这种core方式虽然相比all方式需要下载的文件小了,但同样存在一些弊端:

  • 单页面加载文件的个数大大增加,这毫无疑问会加大服务器的并发压力;
  • 按需加载方式还将导致页面渲染时间(指页面所需文件下载完成到页面渲染完成中间这段页面显示白屏的时长)变长,用户体验未见明显提升。

所以最终选择哪中方式,还要经过你自己仔细测算和评估自身需求而定。

sencha-touch-core.html代码(相比A所采用的all方式,仅仅改变了对应用程序代码文件(app-core.js取代了app-all.js)和框架js文件(sencha-touch-debug.js文件取代sencha-touch-all-debug.js文件)的引用:

<!DOCTYPE html>   
<html>
<head>
<title>Hello Mobile</title>
<link rel="stylesheet" href="http://www.cnblogs.com/SenchaTouch/2.0.0/css/sencha-touch.css" type="text/css">
<script type="text/javascript" src="http://www.cnblogs.com/SenchaTouch/2.0.0/sencha-touch-all-debug.js"></script>
<script type="text/javascript" src="app-core.js"></script>
</head>
<body></body>
</html>

app-core.js代码(着重观察开始的部分,后面的代码与all方式没有区别):

// 第一件事就是给src这个源文件目录指定一个命名空间(具体参见官方文档翻译中的External Dependencies,即外部依赖)   
Ext.Loader.setPath({
'Ext': 'http://www.cnblogs.com/SenchaTouch/2.0.0/src'
});

// 然后根据application用到的控件来添加对以下组件的引用(有人说Ext.TitleBar没用到啊,其实用到了,在Picker里面)
// 大家请注意,其实这里的Ext命名空间指的就是上面Ext.Loader.setPath方法中指定的外部依赖命名空间
Ext.require(['Ext.form.FieldSet', 'Ext.picker.Picker', 'Ext.TitleBar']);

// 下面的代码部分跟all方式完全保持了一致,故省略……
Ext.application({
name: 'Demo',
……


注意:A和B两种方式由于对js和css文件采用了相对路径的直接引用,所以直接在资源管理器双击运行就可以看到效果。

 C.通过Microloader加载ST框架(Code-behind方式)

前文说过,Microloader是ST2正式版加入的新功能, 通过这种模式加载ST2框架的话,在Chrome浏览器里无法直接查看效果,Safari可以。

采用Microloader模式又可以细分为Code-Inline和Code-behind两种方式,Code-inline指的是把js脚本直接写在html页面里,Code-behind指的是链接外部js文件来实现。先看第一种(这也是官方sdk例子当中采用的方式):

JsCodeBehind.html代码(简单的不能再简单了,只引用了microloader文件夹下的development.js文件,经测试,其他两个文件均无效,注意这里给script加了一个id):

<!DOCTYPE HTML>   
<html>
<head>
<meta charset="UTF-8">
<title>Microloader</title>
<script id="microloader" type="text/javascript" src="http://www.cnblogs.com/SenchaTouch/2.0.0/microloader/development.js"></script>
</head>
<body>
</body>
</html>

我们知道这个microloader的功能是加载并读取app.json文件里的设置,那么当然有必要看一下 app.json代码

{   
"name": "Demo", // app名称
"js": [
{
"path": "http://www.cnblogs.com/SenchaTouch/2.0.0/sencha-touch-all-debug.js" // 引用的ST框架文件,这里我们选用all模式
},
{
"path": "app.js", // 引用的应用程序代码文件
"update": "delta"
}
],
"css": [
{
"path": "http://www.cnblogs.com/SenchaTouch/2.0.0/css/sencha-touch.css", // 引用的css文件
"update": "delta"
}
],
"appCache": {
"cache": [
"JsCodeBehind.html",
"JsCodeInline.html"
],
"network": [
"*"
],
"fallback": []
},
"extras": [
],
"archivePath": "archive",
"buildPaths": {
"testing": "http://www.cnblogs.com/deploy/testing/Demo",
"production": "http://www.cnblogs.com/deploy/production/Demo",
"package": "http://www.cnblogs.com/deploy/package/Demo",
"native": "http://www.cnblogs.com/deploy/native/Demo"
},
"buildOptions": {
"product": "touch",
"minVersion": 3,
"debug": false,
"logger": "no"
},
"id": "3a867610-670a-11e1-a90e-4318029d18bb"
}

由于官方尚未对app.json文件中的其他配置做详细说明,因此我们在这里只关注前面3个配置,这些已经足够我们正常运行ST应用程序了。为了方便起见,该文件中指定了调用的ST框架文件是sencha-touch-all-debug.js(all方式),应用程序代码文件是app.js,它的代码跟A中的没有任何区别,这里就不再贴了。

 D.通过Microloader加载ST框架(Code-inline方式)

Code-inline方式,顾名思义,把js代码直接写在html文件里,这是目前ST官网实例中所采用的方式(您可能已经注意到了,官方的例子与提供下载的sdk包中同一个例子所采取的方式并不相同)!

我们先随便找一个官网部署的例子来看一下它的代码(这里选择的是正式版新增的例子TouchStyle http://dev.sencha.com/deploy/touch/examples/production/touchstyle/index.html):

<!DOCTYPE HTML>   
<html manifest="cache.manifest" lang="en-US">
<head>
<meta charset="UTF-8">
<title>TouchStyle</title>
<script type="text/javascript">(function(n){function r(a){function b(a,j){var c=a.length,b,e;for(b=0;b<c;b++){e=a[b];var d=a,J=b,k=void 0;"string"==typeof e&&(e={path:e});e.shared?(e.version=e.shared,k=e.shared+e.path):(y.href=e.path,k=y.href);e.uri=k;e.key=g+"-"+k;f[k]=e;d[J]=e;e.type=j;e.index=b;e.collection=a;e.ready=!1;e.evaluated=!1}return a}var c;"string"==typeof a?(c=a,a=z(c)):c=JSON.stringify(a);var g=a.id,d=g+"-"+A+o,f={};this.key=d;this.css=b(a.css,"css");this.js=b(a.js,"js");this.assets=this.css.concat(this.js);this.getAsset=
function(a){return f[a]};this.store=function(){s(d,c)}}function v(a,b){i.write('<meta name="'+a+'" content="'+b+'">')}function p(a,b,c){var g=new XMLHttpRequest,d,c=c||B;try{g.open("GET",a,!0),g.onreadystatechange=function(){4==g.readyState&&(d=g.status,200==d||304==d||0==d?b(g.responseText):c())},g.send(null)}catch(f){c()}}function K(a,b){var c=i.createElement("iframe");m.push({iframe:c,callback:b});c.src=a+".html";c.style.cssText="width:0;height:0;border:0;position:absolute;z-index:-999;visibility:hidden";
i.body.appendChild(c)}function C(a,b,c){var g=!!a.shared;if(!g)var d=b,f=a.version,h,b=function(j){h=j.substring(0,f.length+4);h!=="/*"+f+"*/"?confirm("Requested: '"+a.uri+"' with checksum: "+f+" but received: "+h.substring(2,f.length)+"instead. Attemp to refresh the application?")&&L():d(j)};(g?K:p)(a.uri,b,c)}function D(a){var b=a.data,a=a.source.window,c,g,d,f;for(c=0,g=m.length;c<g;c++)if(d=m[c],f=d.iframe,f.contentWindow===a){d.callback(b);i.body.removeChild(f);m.splice(c,1);break}}function E(a){"undefined"!=
typeof console&&(console.error||console.log).call(console,a)}function s(a,b){try{l.setItem(a,b)}catch(c){if(c.code==c.QUOTA_EXCEEDED_ERR){var g=t.assets.map(function(a){return a.key}),d=0,f=l.length,h=!1,j;for(g.push(t.key);d<=f-1;)j=l.key(d),-1==g.indexOf(j)?(l.removeItem(j),h=!0,f--):d++;h&&s(a,b)}}}function u(a){try{return l.getItem(a)}catch(b){return null}}function L(){F||(F=!0,p(o,function(a){(new r(a)).store();n.location.reload()}))}function G(a){function b(a,b){var d=a.collection,e=a.index,
g=d.length,f;a.ready=!0;a.content=b;for(f=e-1;0<=f;f--)if(a=d[f],!a.ready||!a.evaluated)return;for(f=e;f<g;f++)if(a=d[f],a.ready)a.evaluated||c(a);else break}function c(a){a.evaluated=!0;if("js"==a.type)try{eval(a.content)}catch(b){E("Error evaluating "+a.uri+" with message: "+b)}else{var c=i.createElement("style"),e;c.type="text/css";c.textContent=a.content;"id"in a&&(c.id=a.id);"disabled"in a&&(c.disabled=a.disabled);e=document.createElement("base");e.href=a.path.replace(/\/[^\/]*$/,"/");w.appendChild(e);
w.appendChild(c);w.removeChild(e)}delete a.content;0==--f&&g()}function g(){function c(){d&&b()}function b(){var a=q.onUpdated||B;if("onSetup"in q)q.onSetup(a);else a()}function f(){l.store();e.forEach(function(a){s(a.key,a.content)});b()}var e=[],d=!1,g=!1,k=function(){g=!0},i=function(){h.swapCache();d=!0;k()},m;n.removeEventListener("message",D,!1);h.status==h.UPDATEREADY?i():h.status==h.CHECKING||h.status==h.DOWNLOADING?(h.onupdateready=i,h.onnoupdate=h.onobsolete=k):k();!1!==navigator.onLine&&
p(o,function(b){t=l=new r(b);var d;l.assets.forEach(function(b){d=a.getAsset(b.uri);(!d||b.version!==d.version)&&e.push(b)});m=e.length;0==m?g?c():k=c:e.forEach(function(b){function c(){C(b,function(a){b.content=a;0==--m&&(g?f():k=f)})}var d=a.getAsset(b.uri),e=b.path,h=b.update;!d||!h||null===u(b.key)||"delta"!=h?c():p("deltas/"+e+"/"+d.version+".json",function(a){try{var c=b,d;var e=u(b.key),h=z(a),a=[],j,i,l;if(0===h.length)d=e;else{for(i=0,l=h.length;i<l;i++)j=h[i],"number"===typeof j?a.push(e.substring(j,
j+h[++i])):a.push(j);d=a.join("")}c.content=d;0==--m&&(g?f():k=f)}catch(n){E("Malformed delta content received for "+b.uri)}},c)})})}var d=a.assets,f=d.length,l;t=a;H("message",D,!1);0==f?g():d.forEach(function(a){var c=u(a.key);null===c?C(a,function(c){s(a.key,c);b(a,c)},function(){b(a,"")}):b(a,c)})}function I(a){null!==i.readyState.match(/interactive|complete|loaded/)?G(a):H("DOMContentLoaded",function(){G(a)},!1)}var B=function(){},m=[],i=n.document,w=i.head,H=n.addEventListener,l=n.localStorage,
h=n.applicationCache,z=JSON.parse,y=i.createElement("a"),x=i.location,A=x.origin+x.pathname+x.search,o="app.json",F=!1,t;if("undefined"===typeof q)var q=n.Ext={};q.blink=function(a){var b=u(a.id+"-"+A+o);v("viewport","width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no");v("apple-mobile-web-app-capable","yes");v("apple-touch-fullscreen","yes");b?(a=new r(b),I(a)):p(o,function(b){a=new r(b);a.store();I(a)})}})(this);
;Ext.blink({"id":"3a867610-670a-11e1-a90e-4318029d18bb"})</script>
</head>
<body>
</body>
</html>

虽然只是经过了简单混淆,可还是看得人很凌乱,不过我们可以轻易地找到app.json这个字符串。

对比之后,你会发现官网部署的几乎所有例子都采用了这一段代码,而且没有一点的区别。那么理论上这段代码就应该是通用的,所以我尝试在自己的页面中同样拷贝加入这一段代码,但可悲的事实告诉我NO!想不通啊想不通……

当然活人不能被尿憋死,这段代码不行我就把microloader文件夹下三个js文件中的代码依次拷贝过来测试,最后只有development.js这个文件中的代码有效(因为Code-behind模式就只有它能行,所以这个结果是显而易见的),于是最终的 JsCodeInline.html代码如下

<!DOCTYPE HTML>   
<html>
<head>
<meta charset="UTF-8">
<title>Microloader</title>
<script type="text/javascript">
(function () {
function write(content) {
document.write(content);
}

function meta(name, content) {
write('<meta name="' + name + '" content="' + content + '">');
}

var xhr = new XMLHttpRequest();
xhr.open('GET', 'app.json', false);
xhr.send(null);

var options = eval("(" + xhr.responseText + ")"), scripts = options.js || [], styleSheets = options.css || [], i, ln, path;

meta('viewport', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no');
meta('apple-mobile-web-app-capable', 'yes');
meta('apple-touch-fullscreen', 'yes');

for (i = 0, ln = styleSheets.length; i < ln; i++) {
path = styleSheets[i];

if (typeof path != 'string') {
path = path.path;
}

write('<link rel="stylesheet" href="' + path + '">');
}

for (i = 0, ln = scripts.length; i < ln; i++) {
path = scripts[i];

if (typeof path != 'string') {
path = path.path;
}

write('<script src="' + path + '"></' + 'script>');
}

})();

</script>
</head>
<body>
</body>
</html>

当然了,app.json和app.js文件没有任何不同,最终测试效果也完全一致。

 结语:

到这里,我们完整解析了全部的ST2框架加载模式和手段,希望通过这篇文章可以帮助你理解ST2带来的新功能。

为了方便大家自己调试,在这里奉上此Demo的全部源码: 猛击这里下载


注意:此系列文章属博主原创,转载请注明作者信息和原始链接,谢谢合作。

Sencha Touch 交流 QQ 群 213119459 欢迎您的加入。

本文链接

相关 [sencha touch demo] 推荐:

Sencha Touch 2 入门 Demo 之一:搭建 Sencha Touch 2 的运行环境

- - 博客园_首页
前段时间不才翻译了关于Sencha Touch 2 MVC架构的一系列文章,大家的认可让我备受鼓舞,也坚定了继续分享自己学习Sencha Touch(下文简称ST)过程和经验的决心. 在跟大家交流的过程中,发现很多入门者反映,学习ST最大的障碍有两个:1、官方文档跟进速度不够;2、官方sample集成程度较高,典型性不足.

HTML 5移动web开发指南中sencha touch笔记

- - ITeye博客
《HTML 5移动web开发指南》,是UC公司著名前端开发师唐俊开(网名:三桥). 的新书,介绍了jquery mobile,sencha touch,phonegap的开发,内容很丰富,. 最后还有一个小的实例,推荐阅读,给分85分,下面是其中sencha touch的. 一些本人新学到的知识点小结.

Sencha Touch 2.0发布:比最好的Framework还要好

- - Tech2IPO
比最好的Framework还要好. Sencha Touch 2.0版发布. 与v1.1版相比,滚动、启动和纵横切换的速度都有很大提高;同时与AT&T合作,整合运营商计费、位置等API;并提供更多Native设备API支持. Sencha Touch 2.0的官方介绍页大标题赫然写着:比最好的Framework还要好.

零基础学习Sencha Touch(资料和教程集合)

- - CSDN博客推荐文章
译者注:本篇文章为开发者提供了零基础使用Sencha Touch的一些资料. Sencha Touch是专门为移动设备开发应用的Javascrt框架. 通过Sencha Touch你可以创建非常像native app的web app,用户界面组件和数据管理全部基于HTML5和CSS3的web标准,全面兼容Android和Apple iOS.

【翻译】使用Sencha Touch开发Google Glass应用程序

- - CSDN博客推荐文章
原文: Developing for Google Glass with Sencha Touch. 作者:Ross Gerbasi. He specializes in new and emerging media including video and graphics production and has contributed to the open source community on emerging interactive solutions.

【转发】使用 Sencha Touch 开发超炫的跨平台移动 Web 应用

- - HTML5研究小组
胡 沙, IBM CSTL 软件工程师, IBM. Sencha Touch 是由  Sencha 公司开发的移动 Web 应用开发框架,用以提升主流移动设备在浏览器上的触碰操作,增强用户体验. 该框架以久负盛名的 Ext JS 富客户端框架为基础,并支持最新的 HTML5 及 CSS3 标准,与流行的 Apple iOS 和 Andriod 设备兼容.

Sencha Touch 2 官方指南中文翻译系列 — 来自移动Web开发社区

- - ITeye论坛最新讨论
Sencha Touch 2是一个HTML5移动Web开发框架,是基于ExtJS4核心类库在移动设备的扩展,针对移动设备提供良好的触摸屏操控体验. 在 @范凯robbin微博上看到ITEye在2012年要重点发展移动技术领域,作为JavaEye(请原谅我用这个名字,亲切啊)的老粉丝特贡献一下资料.

Activiti工作流demo

- - CSDN博客综合推荐文章
继上篇《 Activiti工作流的环境配置》.        前几篇对Activiti工作流进行了介绍,并讲解了其环境配置. 本篇将会用一个demo来展示Activiti工作流具体的体现,直接上干货.        以HelloWorld程序为例.       首先说一下业务流程,员工张三提交了一个申请,然后由部门经理李四审核,审核通过后再由总经理王五审核,通过则张三申请成功.

kindle touch简单说

- - GeoWHY
好吧,最右边的是kindle3,去年买的,后来送丫头,给她在国外看书用了. 最左边的是kindle4,小巴童鞋的,中间那个是我的,kindle touch. touch是99刀,托人从国外带回来,所以很便宜,630块而已,感觉上比kindle3小很多,盈盈可握,倒是蛮适合女孩子用的(领导你拿去用吧,把kindle3换给我就好).

测试touch事件

- - Kejun's Blog
进入触屏时代意味一切要对触屏友好. 今天仅仅测试了ios6,其它版本包括android还不清楚差别有多大. 看了PPK的touch兼容表(http://www.quirksmode.org/mobile/tableTouch.html),深感刚准备告别ie6,又迎来了一个新的混乱时代,苦逼的前端工程师们永远摆脱不了兼容的魔咒.