sencha touch学习笔记二:编写第一个例子

时间:2023-01-27 13:46:01

Sencha Touch官网所给的例子还是很详尽的,只要把代码拷贝粘贴,稍微修改一下,就能用在自己的项目中了,或者仔细看官网给的例子,代码注释给的英文也不难,自学那些代码,完全不需要看什么视频和书籍。有学习过Extjs那就更好了,因为这两个产品都是Sencha公司的,代码风格几乎一样。

先看看Sencha CMD生成的项目中都有些什么。

sencha touch学习笔记二:编写第一个例子

.sencha : 自动生成的配置文件,不知是玩意,先不管。

app : 里面放着空的模型(model),视图(view)和存储(store)文件夹,再等着你编辑文件放进去呢!为什么会有这些文件夹,因为Sencha Touch是以MVC模式来进行开发的。

build : 编译后的文件存放在这个文件夹里面,我们编写完Sencha项目,可以编译成原生的Android项目或者IOS项目的,用Sencha CMD可以,用phonegap更好,这是后话了。

packages :包文件夹,放什么包的吧,我也不知道。

resources:这个比较重要,放css和图片资源的。

touchsdk):Sencha Touch SDK的拷贝,不要修改这个文件夹里面的东西。

剩下的都不是文件夹了

app.js javascript入口

app.json 配置文件,用来创建你的应用的缩小版本

index.html 你的应用的HTML文件

packager.json 配置文件,用来打包成IOSAndroid应用

bootstrap.js 流行的bootstrap框架应用文件

 

当我们访问这个项目时,打开的是根目录下的index.html文件,所以打开这个文件看一下里面的源代码:

<span style="font-size:24px;"><!DOCTYPE HTML>
<html manifest="" lang="en-US">
<head>
<meta charset="UTF-8">
<title>first</title>
<style type="text/css">
/**
* Example of an initial loading indicator.
* It is recommended to keep this as minimal as possible to provide instant feedback
* while other resources are still being loaded for the first time
*/
html, body {
height: 100%;
background-color: #1985D0
}

#appLoadingIndicator {
position: absolute;
top: 50%;
margin-top: -15px;
text-align: center;
width: 100%;
height: 30px;
-webkit-animation-name: appLoadingIndicator;
-webkit-animation-duration: 0.5s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-direction: linear;
}

#appLoadingIndicator > * {
background-color: #FFFFFF;
display: inline-block;
height: 30px;
-webkit-border-radius: 15px;
margin: 0 5px;
width: 30px;
opacity: 0.8;
}

@-webkit-keyframes appLoadingIndicator{
0% {
opacity: 0.8
}
50% {
opacity: 0
}
100% {
opacity: 0.8
}
}
</style>
<!-- The line below must be kept intact for Sencha Command to build your application -->
<script id="microloader" type="text/javascript" src=".sencha/app/microloader/development.js"></script>
</head>
<body>
<div id="appLoadingIndicator">
<div></div>
<div></div>
<div></div>
</div>
</body>
</html></span>

非常简单,只有css样式代码和一个引用的js文件,这样就能丰富地表达我们的例子 ?

按住“ctrl”键,点击development.js。跳转到里面看看。这个文件居然在.sencha文件夹里面的。Javascript对于我来说不是擅长的语言,所以看这些代码开始一头雾水。源代码下面有很多设备的名称,看来是匹配这些设备,让体验更佳的。可是我们所看到的页面的那些文字在这里面一点都没有涉及,难道还有引用文件,仔细一看,不小心还看不到呢,最后看到Ajax技术的异步请求。

sencha touch学习笔记二:编写第一个例子

而在touch\microloader\development.js中,指向的却是

sencha touch学习笔记二:编写第一个例子

前者是CMD编译产生的,后者是自己编写项目用的。

进入bootstrap.json里面

sencha touch学习笔记二:编写第一个例子

Sencha需要引用的文件从这引用。主入口的jscss文件都提示出来了。进入app.js里面

sencha touch学习笔记二:编写第一个例子

这里面居然也没有界面展现的内容,直到Ext.Viewport.add(Ext.create('first.view.Main'));这一行。点击进入Main.js文件,这个文件在app文件夹里面的视图层view文件夹里面。打开

<span style="font-size:24px;">Ext.define('first.view.Main', {
extend: 'Ext.tab.Panel',
xtype: 'main',
requires: [
'Ext.TitleBar',
'Ext.Video'
],
config: {
tabBarPosition: 'bottom',

items: [
{
title: 'Welcome',
iconCls: 'home',

styleHtmlContent: true,
scrollable: true,

items: {
docked: 'top',
xtype: 'titlebar',
title: 'Welcome to Sencha Touch 2'
},

html: [
"You've just generated a new Sencha Touch 2 project. What you're looking at right now is the ",
"contents of <a target='_blank' href=\"app/view/Main.js\">app/view/Main.js</a> - edit that file ",
"and refresh to change what's rendered here."
].join("")
},
{
title: 'Get Started',
iconCls: 'action',

items: [
{
docked: 'top',
xtype: 'titlebar',
title: 'Getting Started'
},
{
xtype: 'video',
url: 'http://av.vimeo.com/64284/137/87347327.mp4?token=1330978144_f9b698fea38cd408d52a2393240c896c',
posterUrl: 'http://b.vimeocdn.com/ts/261/062/261062119_640.jpg'
}
]
}
]
}
});</span>

到此一切都明朗了!

我们打开index页面,index加载的development.js,适配我们的设备,然后页面展现进度的过程同时,异步请求bootstrap.json中的js文件和CSS文件,加载Senchajs文件和样式文件,加载进根目录下的app.js文件,触发first.view.Main,加载Main.js文件,从而真正展现Sencha的页面出来,Main.js里面的内容和我们看到的文字是一样的,所以稍微修改一些内容,就会展现不同的内容出来。

<span style="font-size:24px;">Ext.define('first.view.Main', {
extend: 'Ext.tab.Panel',
xtype: 'main',
requires: [
'Ext.TitleBar',
'Ext.Video'
],
config: {
tabBarPosition: 'bottom',

items: [
{
title: '欢迎',
iconCls: 'home',

styleHtmlContent: true,
scrollable: true,

items: {
docked: 'top',
xtype: 'titlebar',
title: '欢迎来到 Sencha Touch'
},

html: [
"这是个Sencha Touch页面"
].join("")
},
{
title: '视频',
iconCls: 'action',

items: [
{
docked: 'top',
xtype: 'titlebar',
title: '请看视频'
},
{
xtype: 'video',
url: 'http://av.vimeo.com/64284/137/87347327.mp4?token=1330978144_f9b698fea38cd408d52a2393240c896c',
posterUrl: 'http://b.vimeocdn.com/ts/261/062/261062119_640.jpg'
}
]
}
]
}
});</span>

sencha touch学习笔记二:编写第一个例子


=================================================================================


sencha touch学习笔记二:编写第一个例子

先不管其他的东西,app.js文件是我们的入口,按照MVC模式来编写的,你仔细一看,还是能看到模型,控制,视图分开的风格。Main.js是我们的视图展示层,只不过需要单独引用而已。要学习Sencha,对app.js这个文件进行修改,我们就可以简单地学Sencha Touch了。

 

下面我们来学习并改一下demo中的源代码,以list为例子。

在手机上的表现是这样的:

sencha touch学习笔记二:编写第一个例子

源代码在touch-2.3.0\examples\list中。其中加入了一些个人理解的中文注释,英语还可以的可看官方的注释,写得很简单明白。

<span style="font-size:24px;">//<debug>
Ext.Loader.setPath({
'Ext': '../../src'
});
//</debug>

/**
* This simple example shows the ability of the Ext.List component.
*
* In this example, it uses a grouped store to show group headers in the list. It also
* includes an indicator so you can quickly swipe through each of the groups. On top of that
* it has a disclosure button so you can disclose more information for a list item.
*/

//define the application
//定义程序,入口
Ext.application({
//define the startupscreens for tablet and phone, as well as the icon
//根据移动设备的分辨率来选择不同的图片
startupImage: {
'320x460': 'resources/startup/Default.jpg', // Non-retina iPhone, iPod touch, and all Android devices
'640x920': 'resources/startup/640x920.png', // Retina iPhone and iPod touch
'640x1096': 'resources/startup/640x1096.png', // iPhone 5 and iPod touch (fifth generation)
'768x1004': 'resources/startup/768x1004.png', // Non-retina iPad (first and second generation) in portrait orientation
'748x1024': 'resources/startup/748x1024.png', // Non-retina iPad (first and second generation) in landscape orientation
'1536x2008': 'resources/startup/1536x2008.png', // : Retina iPad (third generation) in portrait orientation
'1496x2048': 'resources/startup/1496x2048.png' // : Retina iPad (third generation) in landscape orientation
},

isIconPrecomposed: false,
icon: {
57: 'resources/icons/icon.png',
72: 'resources/icons/icon@72.png',
114: 'resources/icons/icon@2x.png',
144: 'resources/icons/icon@144.png'
},

//require any components/classes what we will use in our example
//需要用到的组件
requires: [
'Ext.MessageBox',
'Ext.data.Store',
'Ext.List',
'Ext.plugin.PullRefresh'
],

/**
* The launch method is called when the browser is ready, and the application can launch.
*
* Inside our launch method we create the list and show in in the viewport. We get the lists configuration
* using the getListConfiguration method which we defined below.
*
* If the user is not on a phone, we wrap the list inside a panel which is centered on the page.
*/
//触发,英文上说得很浅显易懂
launch: function() {
//get the configuration for the list
//list界面对象
var listConfiguration = this.getListConfiguration();

//if the device is not a phone, we want to create a centered panel and put the list
//into that
//phone与其他设备是有区别的,源于iphone的分辨率比较特殊
if (!Ext.os.is.Phone) {
//use Ext.Viewport.add to add a new component into the viewport
Ext.Viewport.add({
//give it an xtype of panel
xtype: 'panel',

//give it a fixed witdh and height
width: 350,
height: 370,

//make it centered
centered: true,

//make the component modal so there is a mask around the panel
modal: true,

//set hideOnMaskTap to false so the panel does not hide when you tap on the mask
hideOnMaskTap: false,

//give it a layout of fit so the list stretches to the size of this panel
layout: 'fit',

//insert the listConfiguration as an item into this panel
items: [listConfiguration]
});
} else {
//if we are a phone, simply add the list as an item to the viewport
Ext.Viewport.add(listConfiguration);
}
},

/**
* Returns a configuration object to be used when adding the list to the viewport.
*/
//界面对象,返回到面板里面填充,从而有内容展现
getListConfiguration: function() {
//create a store instance
//存储器
var store = Ext.create('Ext.data.Store', {
//give the store some fields
fields: ['firstName', 'lastName'],

//filter the data using the firstName field
sorters: 'firstName',

//autoload the data from the server
autoLoad: true,

//setup the grouping functionality to group by the first letter of the firstName field
grouper: {
groupFn: function(record) {
return record.get('firstName')[0];
}
},

//setup the proxy for the store to use an ajax proxy and give it a url to load
//the local contacts.json file
//异步加载数据,这里可以改编成与后台的controller交互,controller从数据库中获取数据
proxy: {
type: 'ajax',
url: 'contacts.json'
}
});

return {
//give it an xtype of list for the list component
xtype: 'list',

id: 'list',

// scrollable: {
// indicators: false
// },

//set the itemtpl to show the fields for the store
//从store里面提取的数据怎么展现
itemTpl: '{firstName} {lastName}',

//enable disclosure icons
//disclosure: true,

//group the list
//分组
grouped: true,

//enable the indexBar
indexBar: true,

infinite: true,

useSimpleItems: true,

variableHeights: true,

striped: true,
//ui主题
ui: 'round',

//set the function when a user taps on a disclsoure icon
// onItemDisclosure: function(record, item, index, e) {
// //show a messagebox alert which shows the persons firstName
// e.stopEvent();
// Ext.Msg.alert('Disclose', 'Disclose more info for ' + record.get('firstName'));
// },

//bind the store to this list
store: store
};
}
});</span>


看一下存储器store请求的异步数据,这是一个静态数据contacts.json文件,这里我们当然可以用各种后台技术把关系型数据库转换为json数据传到这里来,或者一些key-value数据库直接传过来,也可以经过过滤。

<span style="font-size:24px;">[
{ "firstName": "Tommy", "lastName": "Maintz" },
{ "firstName": "Ed", "lastName": "Spencer" },
{ "firstName": "Jamie", "lastName": "Avins" },
{ "firstName": "Aaron", "lastName": "Conran" },
{ "firstName": "Dave", "lastName": "Kaneda" },
{ "firstName": "Michael", "lastName": "Mullany" },
{ "firstName": "Abraham", "lastName": "Elias" },
{ "firstName": "Jay", "lastName": "Robinson" },
{ "firstName": "Tommy", "lastName": "Maintz" },
{ "firstName": "Ed", "lastName": "Spencer" },
{ "firstName": "Jamie", "lastName": "Avins" },
{ "firstName": "Aaron", "lastName": "Conran" },
{ "firstName": "Ape", "lastName": "Evilias" },
{ "firstName": "Dave", "lastName": "Kaneda" },
{ "firstName": "Michael", "lastName": "Mullany" },
{ "firstName": "Abraham", "lastName": "Elias" },
{ "firstName": "Jay", "lastName": "Robinson" },
{ "firstName": "Tommy", "lastName": "Maintz" },
{ "firstName": "Ed", "lastName": "Spencer" },
{ "firstName": "Jamie", "lastName": "Avins" },
{ "firstName": "Aaron", "lastName": "Conran" },
{ "firstName": "Dave", "lastName": "Kaneda" },
{ "firstName": "Michael", "lastName": "Mullany" },
{ "firstName": "Abraham", "lastName": "Elias" },
{ "firstName": "Jay", "lastName": "Robinson" },
{ "firstName": "Tommy", "lastName": "Maintz" },
{ "firstName": "Ed", "lastName": "Spencer" },
{ "firstName": "Jamie", "lastName": "Avins" },
{ "firstName": "Aaron", "lastName": "Conran" },
{ "firstName": "Dave", "lastName": "Kaneda" },
{ "firstName": "Michael", "lastName": "Mullany" },
{ "firstName": "Abraham", "lastName": "Elias" },
{ "firstName": "Jay", "lastName": "Robinson" },
{ "firstName": "Tommy", "lastName": "Maintz" },
{ "firstName": "Ed", "lastName": "Spencer" },
{ "firstName": "Jamie", "lastName": "Avins" },
{ "firstName": "Aaron", "lastName": "Conran" },
{ "firstName": "Dave", "lastName": "Kaneda" },
{ "firstName": "Michael", "lastName": "Mullany" },
{ "firstName": "Abraham", "lastName": "Elias" },
{ "firstName": "Jay", "lastName": "Robinson" },
{ "firstName": "Tommy", "lastName": "Maintz" },
{ "firstName": "Ed", "lastName": "Spencer" },
{ "firstName": "Jamie", "lastName": "Avins" },
{ "firstName": "Aaron", "lastName": "Conran" },
{ "firstName": "Ape", "lastName": "Evilias" },
{ "firstName": "Dave", "lastName": "Kaneda" },
{ "firstName": "Michael", "lastName": "Mullany" },
{ "firstName": "Abraham", "lastName": "Elias" },
{ "firstName": "Jay", "lastName": "Robinson" },
{ "firstName": "Tommy", "lastName": "Maintz" },
{ "firstName": "Ed", "lastName": "Spencer" },
{ "firstName": "Jamie", "lastName": "Avins" },
{ "firstName": "Aaron", "lastName": "Conran" },
{ "firstName": "Dave", "lastName": "Kaneda" },
{ "firstName": "Michael", "lastName": "Mullany" },
{ "firstName": "Abraham", "lastName": "Elias" },
{ "firstName": "Jay", "lastName": "Robinson" },
{ "firstName": "Tommy", "lastName": "Maintz" },
{ "firstName": "Ed", "lastName": "Spencer" },
{ "firstName": "Jamie", "lastName": "Avins" },
{ "firstName": "Aaron", "lastName": "Conran" },
{ "firstName": "Dave", "lastName": "Kaneda" },
{ "firstName": "Michael", "lastName": "Mullany" },
{ "firstName": "Abraham", "lastName": "Elias" },
{ "firstName": "Jay", "lastName": "Robinson" },
{ "firstName": "Tommy", "lastName": "Maintz" },
{ "firstName": "Ed", "lastName": "Spencer" },
{ "firstName": "Jamie", "lastName": "Avins" },
{ "firstName": "Aaron", "lastName": "Conran" },
{ "firstName": "Dave", "lastName": "Kaneda" },
{ "firstName": "Michael", "lastName": "Mullany" },
{ "firstName": "Abraham", "lastName": "Elias" },
{ "firstName": "Jay", "lastName": "Robinson" },
{ "firstName": "Tommy", "lastName": "Maintz" },
{ "firstName": "Ed", "lastName": "Spencer" },
{ "firstName": "Jamie", "lastName": "Avins" },
{ "firstName": "Aaron", "lastName": "Conran" },
{ "firstName": "Ape", "lastName": "Evilias" },
{ "firstName": "Dave", "lastName": "Kaneda" },
{ "firstName": "Michael", "lastName": "Mullany" },
{ "firstName": "Abraham", "lastName": "Elias" },
{ "firstName": "Jay", "lastName": "Robinson" },
{ "firstName": "Tommy", "lastName": "Maintz" },
{ "firstName": "Ed", "lastName": "Spencer" },
{ "firstName": "Jamie", "lastName": "Avins" },
{ "firstName": "Aaron", "lastName": "Conran" },
{ "firstName": "Dave", "lastName": "Kaneda" },
{ "firstName": "Michael", "lastName": "Mullany" },
{ "firstName": "Abraham", "lastName": "Elias" },
{ "firstName": "Jay", "lastName": "Robinson" },
{ "firstName": "Tommy", "lastName": "Maintz" },
{ "firstName": "Ed", "lastName": "Spencer" },
{ "firstName": "Jamie", "lastName": "Avins" },
{ "firstName": "Aaron", "lastName": "Conran" },
{ "firstName": "Dave", "lastName": "Kaneda" },
{ "firstName": "Michael", "lastName": "Mullany" },
{ "firstName": "Abraham", "lastName": "Elias" },
{ "firstName": "Jay", "lastName": "Robinson" },
{ "firstName": "Tommy", "lastName": "Maintz" },
{ "firstName": "Ed", "lastName": "Spencer" },
{ "firstName": "Jamie", "lastName": "Avins" },
{ "firstName": "Aaron", "lastName": "Conran" },
{ "firstName": "Dave", "lastName": "Kaneda" },
{ "firstName": "Michael", "lastName": "Mullany" },
{ "firstName": "Abraham", "lastName": "Elias" },
{ "firstName": "Jay", "lastName": "Robinson" },
{ "firstName": "Tommy", "lastName": "Maintz" },
{ "firstName": "Ed", "lastName": "Spencer" },
{ "firstName": "Jamie", "lastName": "Avins" },
{ "firstName": "Aaron", "lastName": "Conran" },
{ "firstName": "Ape", "lastName": "Evilias" },
{ "firstName": "Dave", "lastName": "Kaneda" },
{ "firstName": "Michael", "lastName": "Mullany" },
{ "firstName": "Abraham", "lastName": "Elias" },
{ "firstName": "Jay", "lastName": "Robinson" },
{ "firstName": "Tommy", "lastName": "Maintz" },
{ "firstName": "Ed", "lastName": "Spencer" },
{ "firstName": "Jamie", "lastName": "Avins" },
{ "firstName": "Aaron", "lastName": "Conran" },
{ "firstName": "Dave", "lastName": "Kaneda" },
{ "firstName": "Michael", "lastName": "Mullany" },
{ "firstName": "Abraham", "lastName": "Elias" },
{ "firstName": "Jay", "lastName": "Robinson" },
{ "firstName": "Tommy", "lastName": "Maintz" },
{ "firstName": "Ed", "lastName": "Spencer" },
{ "firstName": "Jamie", "lastName": "Avins" },
{ "firstName": "Aaron", "lastName": "Conran" },
{ "firstName": "Dave", "lastName": "Kaneda" },
{ "firstName": "Michael", "lastName": "Mullany" },
{ "firstName": "Abraham", "lastName": "Elias" },
{ "firstName": "Jay", "lastName": "Robinson" },
{ "firstName": "Zed", "lastName": "Zacharias "}
]</span>

看到这里,事情就变得很简单了,按照这个例子稍微改一下就可以用了,至于各个参数的含义,还有其他的各种参数,要参考官网的API文档才可以。Sencha Touch在这一点不够Extjs好,Extjs可以离线看整个API文档,浏览速度非常快,可是Sencha Touch却要联网到它的官网上查看,我所在的这个地方浏览官网非常慢,不知是不是地区网络的问题,反正想看一下API文档非常困难,以后想办法找个离线的才好,即使低版本的也好!

 

我们改这个例子,成为中文的通讯录列表。

先修改contacts.json文件,这些都是静态数据,纯粹无脑机械编辑,这应该留给后台灵活返回数据显示出来的,不过刚入门,还是以静态数据为例子吧!把这个文件放到我们的项目的根目录下。

[
{ "name": "李四", "age": 23, "address":"中山路1号" },
{ "name": "王五", "age": 26, "address":"中山路12号" },
{ "name": "王五1", "age": 34, "address":"中山路18号" },
{ "name": "王五2", "age": 55, "address":"中山路156号" },
{ "name": "王五3", "age": 34, "address":"解放路34号" },
{ "name": "王五4", "age": 12, "address":"解放路45号" },
{ "name": "王五5", "age": 89, "address":"解放路67号" },
{ "name": "王五6", "age": 45, "address":"解放路93号" },
{ "name": "赵六", "age": 67, "address":"解放路57号" },
{ "name": "王7", "age": 23, "address":"白云路3号" },
{ "name": "张三", "age": 67, "address":"昆明路78号" },
{ "name": "赵霁", "age": 34, "address":"解放路98号" },
{ "name": "周丽", "age": 56, "address":"解放路175号" },
{ "name": "李贤", "age": 34, "address":"解放路876号" },
{ "name": "孙琦", "age": 56, "address":"解放路32号" },
{ "name": "黄连", "age": 28, "address":"解放路78号" },
{ "name": "张丽", "age": 25, "address":"解放路45号" },
{ "name": "里人", "age": 22, "address":"解放路89号" },
{ "name": "方琪", "age": 23, "address":"解放路23号" },
{ "name": "李燕", "age": 34, "address":"中山路4号" }

]

备份app.js文件,接着改app.js文件内容。不熟悉的话一个个敲,培养一下敲码的感觉。

sencha touch学习笔记二:编写第一个例子

虽然是照抄右边的,可是边敲边加深了理解。这里推荐用intellij这个IDE,因为不用安装插件就可以提示Sencha Touch函数、参数等信息了,非常智能!

改的app.js如下:

<span style="font-size:24px;">Ext.application({
startupImage: {
'320x460': 'resources/startup/Default.jpg',
'640x920': 'resources/startup/640x920.png',
'640x1096': 'resources/startup/640x1096.png',
'768x1004': 'resources/startup/768x1004.png',
'748x1024': 'resources/startup/748x1024.png',
'1536x2008': 'resources/startup/1536x2008.png',
'1496x2048': 'resources/startup/1496x2048.png'
},

isIconPrecomposed: false,
icon: {
57: 'resources/icons/icon.png',
72: 'resources/icons/icon@72.png',
114: 'resources/icons/icon@2x.png',
144: 'resources/icons/icon@144.png'
},

requires: [
'Ext.MessageBox',
'Ext.data.Store',
'Ext.List',
'Ext.plugin.PullRefresh'
],
launch : function() {

var listConfiguration = this.getListConfiguration();

if (!Ext.os.is.Phone) {
Ext.Viewport.add({
xtype: 'panel',
width: 350,
height: 370,
centered: true,
modal: true,
hideOnMaskTap: false,
layout: 'fit',
items: [listConfiguration]
});
} else {
Ext.Viewport.add(listConfiguration);
}
},

getListConfiguration : function() {
var store = Ext.create('Ext.data.Store',{
fields:['name','age','address'],
sorters:'name',
autoLoad:true,
grouper:{
groupFn:function(record) {
return record.get('name')[0];
}
},
proxy:{
type:'ajax',
url:'contacts.json'
}
});

return {
xtype:'list',
id:'list',
itemTpl:'{name}{age}{address}',
grouped:true,
indexBar:true,
infinite:true,
useSimpleItems:true,
variableHeights:true,
striped:true,
ui:'round',
store:store
}
}
});</span>


在电脑上显示如下:

sencha touch学习笔记二:编写第一个例子

在手机上显示如下:

sencha touch学习笔记二:编写第一个例子