Sencha Cmd创建Ext JS示例项目

Sencha提供了免费的Cmd工具,可以用来创建Ext JS项目并提供了一些便利的功能。
Sencha也在官方文档中提供了一个示例来演示如何创建一个Sample Login App。
本文就介绍一下这个官网示例。

准备工作
  • 下载Sencha Ext JS的SDK,本文中使用的是开源的GPL的6.0.1版本
  • 下载Sencha Cmd,这个是免费的,本文中使用的是Windows 64-bit带JRE的6.1.2版本

一些废话:
也许Sencha是为了更好地推它的商用版本吧,从6.0.0版本开始,就把GPL版本的下载位置藏的很深,而且还需要通过发送邮件的方式来提供下载。

安装
  • SDK解压缩放到一个指定目录,本文中为D:\ext-6.0.1
  • Cmd安装到默认位置即可

一些废话:
6.x版本从以前方便很多,如果你使用的是5.x版本,那还需要额外安装JDK, ANT, Ruby, SASS, COMPASS,这里就不啰嗦了。

本文创建的示例项目的路径为D:\TutorialApp


那我们开始创建程序吧。
打开cmd命令行,使用sencha [-sdk SDK所在目录] generate app [-classic|-modern] AppName App目录命令来创建项目。

sencha -sdk D:\ext-6.0.1 generate app -classic TutorialApp D:\TutorialApp
  • -sdk D:\ext-6.0.1指明Ext JS SDK的所在目录,如果运行命令行的所在目录就是SDK目录(D:\ext-6.0.1),则可以省略
  • -classic|-modern可以省略,Ext JS的6.0版本其中一个主要的更新就是把Ext JS和Touch合并,在创建时可以选择哪一种类型,classic对应Ext JS,而modern对应Touch。如果省略,则创建所谓的universal类型,即classic和modern并存。在本文中演示的是桌面端程序,所以我们选择classic。
  • TutorialApp是项目名称,也将作为该项目的namespace。
  • D:\TutorialApp是项目名录

一些废话:
运行命令后,可以去倒一杯水,起来活动活动,因为这个过程大概会持续几分钟。完成之后,看下TutorialApp目录的大小,会发现大概500M,真够大的。

从命令进入项目目录D:\TutorialApp,并输入命令sencha app watch

cd D:\TutorialApp
sencha app watch

一些废话:
运行命令后,可以再起来活动活动。

sencha app watch会启动内置的jetty服务器,可以使我们方便地通过http://localhost:1841/ 来查看页面。而且watch会监听项目目录中的文件变化而自动build。

这时候打开http://localhost:1841/ 会看到Cmd自动创建的默认首页长这样子。6.x版新增加的Triton主题和以前的主题有明显的不同。

打开D:\TutorialApp目录,看下Cmd自动创建的目录和文件:

.sencha/                        # 里面存放的大多都是配置相关的文件,一般不需要修改
ext/                            # Ext JS SDK的一份copy,所以才会这么大
index.html                      # 首页
app.json                        # 项目主配置文件
app.js                          # 项目主程序
app/                            # 项目源码目录
    model/                      # Model目录
    store/                      # Store目录
    view/                       # View目录
        main/                   # 首页的目录
            Main.js             # 首页的View
            MainModel.js        # 首页的ViewModel
            MainController.js   # 首页的ViewController
    Application.js              # Ext.Application
packages/                       # Sencha Cmd packages
workspace.json                  # Workspace的描述文件
build/                          # 保存项目最终的build结果

还有一些目录和文件没有列举出来,那些目录和文件一般都不需要我们去修改,前期可以忽略。
对我们来说,最重要的目录就是app目录,这是项目的源码目录,我们写的代码都保存在里面。
app目录下包含三个子目录:

  • model: 保存Model对象,Cmd也提供了命令来创建Ext JS中的Model对象。比如User,它包含id,name,email三个字段。在命令行中运行:
cd D:\TutorialApp
sencha generate model user.User id:int,name,email

运行Cmd的命令需要先进入项目目录,运行之后会看到model目录里多了一个子目录user,user目录里有新建的User.js文件。

app/                          # 项目源码目录
    model/                      # Model目录
        user/                   # user子目录
            User.js             # User.js定义了User的字段

关于Ext JS的Model的具体用法,请参照官方API文档:Ext.data.Model

  • store: Ext JS的Store可以理解为Model对应的数据集合,在Store中可以定义怎么去读取Model。具体用法,请参照官方API文档:Ext.data.Store
  • view:所有和UI相关的代码都保存在这里,比如窗口,表格,图表等。可以为每个UI创建对应的ViewController(Ext.app.ViewController)和ViewModel(Ext.app.ViewModel)。

由于这个示例程序要演示的是创建一个登录窗口,只有等登录完成之后才会显示首页。所以首先要打开项目根目录下的app.js,将和TutorialApp.view.main.Main相关的代码删除。修改后的app.js长这样:

Ext.application({
    name: 'TutorialApp',
    extend: 'TutorialApp.Application
});

如果你仍然保持sencha app watch的运行状态,则Cmd会检测到你对app.js的修改。此时访问首页,就会看到一片空白。

接着来创建用户的登录窗口,它是长这样子的:

可以在app\view目录里手动创建login子目录,并在login目录下手动创建Login.js和LoginController.js。也可以在命令行中运行以下命令来让Cmd自动创建:

cd D:\TutorialApp
sencha generate view -base Ext.window.Window login.Login

-base参数用来设置创建的UI是哪种类型,由于我们要创建的是窗口,所以继承的是Ext.window.Window。

Login.js是登录窗口的代码,最后长这样:

Ext.define('TutorialApp.view.login.Login', {
    extend: 'Ext.window.Window',
    xtype: 'login',

    //Login窗口会包含一个表单(Ext.form.Panel)
    //LoginController里定义了Login窗口会使用到的方法onLoginClick
    //requires可以确保这2个类会在Login初始化完成之前先被初始化
    requires: [
        'TutorialApp.view.login.LoginController',
        'Ext.form.Panel'
    ],
    //绑定controller,绑定时使用的是别名
    controller: 'login',
    //padding: 10px
    bodyPadding: 10,
    //窗口的标题栏文字
    title: 'Login Window',
    //隐藏窗口右上角的关闭按钮"x"
    closable: false,
    //Window的autoShow默认为false
    //Window可以用show()和hide()来手动显示和隐藏
    //把autoShow设为true, 则在Window创建之后会自动显示
    autoShow: true,
    //把窗口里的UI组件放在items里
    items: {
        //表单
        xtype: 'form',
        reference: 'form',
        //把表单里的UI组件放在表单的items里
        items: [{
            //供用户输入用户名的文本框
            xtype: 'textfield',
            name: 'username',
            //fieldLabel是显示在文本框前的标签文字
            fieldLabel: 'Username',
            //打开非空校验,即要求输入的用户名不能为空
            allowBlank: false
        }, {
            //供用户输入密码的文本框
            xtype: 'textfield',
            name: 'password',
            //inputType设为password,则用户输入的内容会以*回显在屏幕上
            inputType: 'password',
            fieldLabel: 'Password',
            allowBlank: false
        }, {
            //显示在密码输入框下方的文字
            xtype: 'displayfield',
            hideEmptyLabel: false,
            value: 'Enter any non-blank password'
        }],
        //表单的按钮
        buttons: [{
            //按钮上的显示文字
            text: 'Login',
            //设为true,则Login按钮在表单通过校验前是不能被点击的
            formBind: true,
            listeners: {
                //当按钮被点击时
                click: 'onLoginClick'
            }
        }]
    }
});

LoginController.js是Login的Controller,最后长这样:

Ext.define('TutorialApp.view.login.LoginController', {
    extend: 'Ext.app.ViewController',
    //定义别名为login
    alias: 'controller.login',
    //当Login按钮被点击时
    onLoginClick: function() {

        //这本例中使用localStorage来保存用户的登录状态
        //这里省略了用户信息的远程校验过程
        //只要用户输入用户名和密码,点击Login按钮即认为用户成功登陆
        localStorage.setItem("TutorialLoggedIn", true);
        //getView()返回的是controller绑定的view, 在本例中就是Login窗口
        //登录后不再需要Login窗口,所以调用destroy()来删除
        this.getView().destroy();
        //关闭Login窗口后,需要显示首页
        //使用Ext.create()来创建view\main\Main.js
        Ext.create({
            xtype: 'app-main'
        });

    }
});

登录窗口写好了,但还不会显示,需要修改app\Application.js。
Application.js最后长这样:

Ext.define('TutorialApp.Application', {
    extend: 'Ext.app.Application',
    
    name: 'TutorialApp',

    stores: [
        // TODO: add global / shared stores here
    ],

    views: [
        'TutorialApp.view.login.Login',
        'TutorialApp.view.main.Main'
    ],
    
    launch: function () {
        var loggedIn;
        //从localStorage读取用户登录状态
        loggedIn = localStorage.getItem("TutorialLoggedIn");
        //如果用户已登录,则显示首页,否则显示Login窗口
        Ext.create({
            xtype: loggedIn ? 'app-main' : 'login'
        });
    },

    onAppUpdate: function () {
        Ext.Msg.confirm('Application Update', 'This application has an update, reload?',
            function (choice) {
                if (choice === 'yes') {
                    window.location.reload();
                }
            }
        );
    }
});

最后在首页上加上一个Logout按钮,修改后的app\main\Main.js长这样:

Ext.define('TutorialApp.view.main.Main', {
    extend: 'Ext.tab.Panel',
    xtype: 'app-main',

    requires: [
        'Ext.plugin.Viewport',
        'Ext.window.MessageBox',

        'TutorialApp.view.main.MainController',
        'TutorialApp.view.main.MainModel',
        'TutorialApp.view.main.List'
    ],

    controller: 'main',
    viewModel: 'main',
    plugins: 'viewport',

    ui: 'navigation',

    tabBarHeaderPosition: 1,
    titleRotation: 0,
    tabRotation: 0,

    header: {
        layout: {
            align: 'stretchmax'
        },
        title: {
            bind: {
                text: '{name}'
            },
            flex: 0
        },
        iconCls: 'fa-th-list',
        //添加Logout按钮
        items: [{
            xtype: 'button',
            text: 'Logout',
            margin: '10 0',
            handler: 'onClickButton'
        }]
    },

    tabBar: {
        flex: 1,
        layout: {
            align: 'stretch',
            overflowHandler: 'none'
        }
    },

    responsiveConfig: {
        tall: {
            headerPosition: 'top'
        },
        wide: {
            headerPosition: 'left'
        }
    },

    defaults: {
        bodyPadding: 20,
        tabConfig: {
            plugins: 'responsive',
            responsiveConfig: {
                wide: {
                    iconAlign: 'left',
                    textAlign: 'left'
                },
                tall: {
                    iconAlign: 'top',
                    textAlign: 'center',
                    width: 120
                }
            }
        }
    },

    items: [{
        title: 'Home',
        iconCls: 'fa-home',
        items: [{
            xtype: 'mainlist'
        }]
    }, {
        title: 'Users',
        iconCls: 'fa-user',
        bind: {
            html: '{loremIpsum}'
        }
    }, {
        title: 'Groups',
        iconCls: 'fa-users',
        bind: {
            html: '{loremIpsum}'
        }
    }, {
        title: 'Settings',
        iconCls: 'fa-cog',
        bind: {
            html: '{loremIpsum}'
        }
    }]
});

在首页的对应的Controller,app\main\MainController.js中添加Logout对应的click方法

Ext.define('TutorialApp.view.main.MainController', {
    extend: 'Ext.app.ViewController',

    alias: 'controller.main',

    onItemSelected: function (sender, record) {
        Ext.Msg.confirm('Confirm', 'Are you sure?', 'onConfirm', this);
    },

    onConfirm: function (choice) {
        if (choice === 'yes') {
            //
        }
    },
    //点击Logout按钮
    onClickButton: function () {
        //删除保存在localStorage中的登录状态
        localStorage.removeItem('TutorialLoggedIn');
        //删除首页
        this.getView().destroy();
        //创建Login窗口
        Ext.create({
            xtype: 'login'
        });
    }
});

写代码到此就完成了,运行sencha app build命令

cd D:\TutorialApp
sencha app build

运行结束后,在build目录下会生成production子目录,可以把该目录下的TutorialApp目录发布到其他服务器上,比如Apache HTTP Server的htdocs目录里。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容