基础

创建一个应用程序

sencha -sdk /path/to/sdk generate app %name% /path/to/app

跑起来

cd /path/to/app

sencha app watch

放心,出错了会出红字,自己退回命令行。

开浏览器,默认地址是 http://localhost:1841

在 watch 模式下,任何对源程序的修改都会自动更新,方便马上看到效果。看起来还挺方便,但是因为过度的 js 对象化包装,使得 Sencha 的应用调试起来无比困难。生产化打包编译以后,更是只有一个 app.js,万一出错了的话,你是找不到源头的了。

目录结构

主要注意下面几个文件夹

app

与具体平台、设备分辨率无关的东东。比如下面要提到的数据模型、Store。

想法挺好,可是缺乏 IDE 支持的情况下(其自家的开发工具还不支持 6.0.2 版本的 Sencha),在各个目录之间跳转切换是非常麻烦的。即便用了 file buffer,你也得记住文件 id。

classic

经典 :) 听上去像极了 IIS Classic。就是传统的网页应用程序。写页面视图就在这里,也是默认的实现。

modern

现代,与经典对应。平板和触碰设备用。

packages

自定义的程序包,比如主题,就放在这里。默认的界面主题如果不能满足需要,那么就可以自定义主题。虽然自定义是非常痛苦的。

resources

图片,通用的文件放在这里。

数据

Model

模型,或者叫数据模型,可以看作数据库存储的结构映射。

定义一个数据模型,继承自 Ext.data.Model

Ext.define("Inventory.model.Band",{
    extend:'Ext.data.Model',
    fields:[
        {name:'Id', type:'int'},
        {name:'Start', type:'float',allowBlank:false },
        {name:'End', type:'float',allowBlank:false},
        {name:'Wavelength', type:'string',allowBlank:false }
    ]
});

顺便说一句,用不同文件夹来存放同一个功能模块各个不同组件的做法非常落后。这本是用 IDE 和命名规范可以轻易解决的问题。而在类名里面加上文件夹的结构,则更是多余:多继承或者引用、实现抽象类的时候,多个文件夹结构你怎么放、怎么起名?

Store

存储。其实是存储代理的定义,即,从哪儿读取数据,又将数据写回哪儿。

其 load 函数在数据读取完成后回调,可以对返回的数据做进一步处理,比较方便。需要绑定数据模型使用。

proxy 属性指明了实际进行数据库(存取)操作的服务地址,这里也就出了 Sencha 的圈儿了,Spring 也可以、ASP.NET 也可以,随意。

Ext.create('Ext.data.Store',{
    model:'Inventory.model.Band',
    id:'remotestore',
    proxy:{
        type : 'rest',
        url:'http://localhost:40544/Band.svc/GetBands',
        reader : {
            type : 'json',
            rootProperty : 'd'
        }
    },
    listeners:{
        load:function ( pageStore, records, successful , pageOperation , eOpts ){
            var bs = {bands:[]};
             for(var i=0;i<records.length;i++){
                 bs.bands.push(records[i].data);
             }
            Ext.getStore('bandstore').setData(bs);
        }
    }
});

ViewModel

视图模型,即对页面上所放字段的映射。可以是数据模型的一部分,也可以是多个关联数据模型的组合。但其实 Sencha 这么搞,是把简单问题弄复杂了,因为 html 页面本身就有表单和字段,直接 parse 其键值对即可;而现在则必须再重新定义一遍这些字段,等于同样的定义在 html 表单和模型视图里面各自写了一遍,重复了。

定义一个视图模型

Ext.define('Inventory.view.main.MainModel', {
    extend: 'Ext.app.ViewModel',
    alias: 'viewmodel.main',
    data: {
        name: 'Inventory'
    }
});

使用的时候,首先在页面里面说明要用到的视图模型是哪个,然后对页面上可以 set 的属性绑定视图模型的字段,比如下面这个,绑定页面的标题:

viewModel: 'main',
header: {
    title: {
        bind: {
            text: '{name}'
        }
    }
}

视图

放在页面上的可视区域,用来显示内容、提供交互操作。类似 SharePoint 上面的 WebPart。但是 WebPart 的本意是让用户也可以自定义页面(这个想法也是挺天真),视图则是让程序员来自定义页面(这个想法更是天真)。

创建一个新视图,名字叫 band.Band,但是放在 main 文件夹里面。这就是我前面说的,文件夹归类法不靠谱的地方。

Ext.define('Inventory.view.band.Band', {
    extend: 'Ext.panel.Panel',
    xtype: 'bandview',
    items :[
        {html:'<h2>hello!</h2>'}
    ]
});

我们也可以用之前定义的视图模型来动态地显示点儿内容:

Ext.define('Inventory.view.band.Band', {
    extend: 'Ext.panel.Panel',
    xtype: 'bandview',
    viewModel: 'main',
    items :[
        {bind:{html:'<h2>hello,{name}!</h2>'}}
    ]
});

表单

下面来一个复杂点儿的视图模型绑定,将 band 绑定到一个表单 form 上面:

{
    xtype: 'form',
    defaultType: 'textfield',
    viewModel: 'band', //this viewModel will provide default values.
    margin: '5, 0, 20, 0',
    items:[
        { name: 'Id', fieldLabel: 'Id', readOnly: true, bind: { value: '{Id}'} },
        { name: 'Wavelength', fieldLabel: 'Wavelength', bind: { value: '{Wavelength}'} },
        { name: 'Start', fieldLabel: 'Start', bind: { value: '{Start}'} },
        { name: 'End', fieldLabel: 'End', bind: { value: '{End}'} },
        { name: 'Reset', text: 'Reset', xtype: 'button', handler: function() { var form = this.up('form').getForm(); form.reset(); } }
    ]
}

滚动条

有的时候表单内容太多会超出窗口范围,此时可以用滚动条属性(又一个重复的发明):

scrollable: true

列表

列表可以用 store 绑定,哪怕这个 store 是从内存里面读取的预定义的数据。

Sencha 的文档里面对这种绑定描述甚少,值得批评。下面的例子,当选择一条记录的时候,自动将选中的值填充到前面的 form 里面。

//a grid, using store to retreive data
{
    xtype: 'grid',
    border: true,
    width: 600,
    store: {type: 'bandstore' },
    columns: [
        { text: 'Id',  dataIndex: 'Id', width:100 },
        { text: 'Wavelength',  dataIndex: 'Wavelength', width:200 },
        { text: 'Start', dataIndex: 'Start', flex: 1, width:100 },
        { text: 'End', dataIndex: 'End', flex: 1, width:100 }
    ],
    listeners: {
        selectionchange: function(sm, selections){
            if(selections.length==0)return;
            var form = this.up('panel').down('form').getForm();
            form.setValues(selections[0].data);
        }
    }
}

当然,这不是列表和表单的常用方法,只是基础。后面 Jony 会提供更复杂的玩儿法。

高级绑定

比如,上面的那个 listeners 里面的 selectionchange 方法,其实是可以去掉的,只要这样写:

Ext.define('Inventory.view.band.Band', {
    extend: 'Ext.panel.Panel',
    xtype: 'bandview',
    viewModel: 'main',
    items :[
        //a random message showing viewmodel binding
        { bind: { html: '<h2>hello,{name}!</h2>' } },
        //a form, with viewmodel binding as well
        {
            xtype: 'form',
            defaultType: 'textfield',
            margin: '5, 0, 20, 0',
            items:[
                { name: 'Id', fieldLabel: 'Id', readOnly: true , bind: { value: '{bandgrid.selection.Id}'} },
                { name: 'Wavelength', fieldLabel: 'Wavelength' },//, bind: { value: '{Wavelength}'} },
                { name: 'Start', fieldLabel: 'Start' },//, bind: { value: '{Start}'} },
                { name: 'End', fieldLabel: 'End' },//, bind: { value: '{End}'} },
                { name: 'Reset', text: 'Reset', xtype: 'button', handler: function() { var form = this.up('form').getForm(); form.reset(); } }
            ]
        },
        //a grid, using store to retreive data
        {
            xtype: 'grid',
            reference: 'bandgrid',
            border: true,
            width: 600,
            store: {type: 'bandstore' },
            columns: [
                { text: 'Id',  dataIndex: 'Id', width:100 },
                { text: 'Wavelength',  dataIndex: 'Wavelength', width:200 },
                { text: 'Start', dataIndex: 'Start', flex: 1, width:100 },
                { text: 'End', dataIndex: 'End', flex: 1, width:100 }
            ]
        }
    ]
});

Sencha 的思想,是用编程的方式来粘合 Web 应用程序的组件,所以配置属性就能工作是最好的,Sencha 的框架自己知道如何找到关联数据并联系起来。

嗯,想得挺好的。这么做有一个前提:有完整的设计,且几乎不会变更。

调试

如果不幸地,你的 Sencha 项目被集成进了某个服务器环境(比如 weblogic),那么,单独开一个并行的同类 Sencha 应用就变得非常有用了。

Sencha, the nightmare!的更多相关文章

  1. Sencha ExtJS 6 Widget Grid 入门

    最近由于业务需要,研究了一下Sencha ExtJS 6 ,虽然UI和性能上据相关资料说都有提升,但是用起来确实不太顺手,而且用Sencha cmd工具进行测试和发布,很多内部细节都是隐藏的,出了问题 ...

  2. sencha ext js 6 入门

    Sencha Ext JS号称是目前世界上最先进和最强大的.支持多平台多设备的JavaScript应用程序开发框架.首先看一下Ext JS的发展简史. 1 Ext JS发展简史 YUI-Ext的作者J ...

  3. sencha touch的开源插件和例子

    写了好久的sencha touch,没想到换工作竟然一年多没有搞了.因为项目的缘故收集了好多的组件,由于懒惰,没有整理,现在想想有点后悔了,再加上如果就这样丢弃,感觉有些遗憾,今天整理了一下放在git ...

  4. 解读sencha touch移动框架的核心架构(一)

    sencha的前身就是Extjs了,sencha 框架是世界上第一个基于HTML5的Mobile App框架 那么何谓框架,传统软件工程对于库和框架的区分主要着眼于对应用运行流程的控制权,框架提供架构 ...

  5. 亲手使用Sencha Touch + phonepag开发Web APP随笔 -- 第一个APP

    参考博文: [Phonegap+Sencha Touch] 移动开发1.准备工作 [Phonegap+Sencha Touch] 移动开发2.PhoneGap/Cordova初步使用   经过差不多1 ...

  6. 亲手使用Sencha Touch + phonepag开发Web APP随笔 -- 环境安装篇

    最近因为有个项目需要制作APP,考虑到需要兼容Android和IOS,所以想采用WebAPP的方式来开发.现在是从零开始学习之路,走起-   通过网上博客和论坛,开始安装了一堆软件: 1. Sench ...

  7. HDU 1072 Nightmare

    Description Ignatius had a nightmare last night. He found himself in a labyrinth with a time bomb on ...

  8. mac下使用sencha cmd+extjs6

    笔者刚接手公司一个项目,后台是使用extjs6做前端,php做api接口,两者通过ajax交互 没办法,不管接手的项目多么的挫逼,都还是要上的,拿人钱财替人消灾嘛 首先是安装sencha cmd ,百 ...

  9. sencha touch打包成安装程序

    为了更好地向大家演示如何打包一个sencha touch的项目,我们用sencha cmd创建一个演示项目,如果你的sencha cmd环境还没有配置,请参照 sencha touch 入门系列 (二 ...

随机推荐

  1. 我的MYSQL学习心得(十六) 优化

    我的MYSQL学习心得(十六) 优化 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...

  2. logstash服务启动脚本

    logstash服务启动脚本 最近在弄ELK,发现logstash没有sysv类型的服务启动脚本,于是按照网上一个老外提供的模板自己进行修改 #添加用户 useradd logstash -M -s ...

  3. 一步步开发自己的博客 .NET版 剧终篇(6、响应式布局 和 自定义样式)

    前言 这次开发的博客主要功能或特点:    第一:可以兼容各终端,特别是手机端.    第二:到时会用到大量html5,炫啊.    第三:导入博客园的精华文章,并做分类.(不要封我)    第四:做 ...

  4. Angular2学习笔记——路由器模型(Router)

    Angular2以组件化的视角来看待web应用,使用Angular2开发的web应用,就是一棵组件树.组件大致分为两类:一类是如list.table这种通放之四海而皆准的通用组件,一类是专为业务开发的 ...

  5. ABP源码分析二十六:核心框架中的一些其他功能

    本文是ABP核心项目源码分析的最后一篇,介绍一些前面遗漏的功能 AbpSession AbpSession: 目前这个和CLR的Session没有什么直接的联系.当然可以自定义的去实现IAbpSess ...

  6. C++ std::queue

    std::queue template <class T, class Container = deque<T> > class queue; FIFO queue queue ...

  7. JavaScript dom 动态创建标记

    此前的大多数DOM都是用来查找元素,getElementById和getElementsByTagName都可以方便快捷的找到文档中的某个或者某些特定的元素节点,这些元素随后可以用诸如setAttri ...

  8. WCF学习之旅—WCF服务部署到IIS7.5(九)

    上接   WCF学习之旅—WCF寄宿前的准备(八) 四.WCF服务部署到IIS7.5 我们把WCF寄宿在IIS之上,在IIS中宿主一个服务的主要优点是在发生客户端请求时宿主进程会被自动启动,并且你可以 ...

  9. C#多线程之基础篇2

    在上一篇C#多线程之基础篇1中,我们主要讲述了如何创建线程.中止线程.线程等待以及终止线程的相关知识,在本篇中我们继续讲述有关线程的一些知识. 五.确定线程的状态 在这一节中,我们将讲述如何查看一个线 ...

  10. 有向无环图的应用—AOV网 和 拓扑排序

    有向无环图:无环的有向图,简称 DAG (Directed Acycline Graph) 图. 一个有向图的生成树是一个有向树,一个非连通有向图的若干强连通分量生成若干有向树,这些有向数形成生成森林 ...