ExtJS 4.2 教程:从零开始构建你的第一个应用
第一部分:准备工作与核心概念
什么是 ExtJS?
ExtJS 是一个功能强大的 JavaScript 框架,专门用于构建跨浏览器、跨平台的桌面级 Web 应用,它提供了一套完整的 UI 组件库,包括数据网格、表单、树、图表等,让你可以像开发桌面软件一样开发 Web 应用。
环境准备
-
下载 ExtJS 4.2:
- 访问 Sencha 的历史版本仓库:https://www.sencha.com/legal/extjs-software-license/
- 找到 ExtJS 4.2 的下载链接并下载,你会得到一个压缩包,解压后结构如下:
ext-4.2.1.883/ ├── build/ // 生产环境打包后的文件 ├── examples/ // 官方示例 ├── ext-all.js // 核心库文件(包含所有组件) ├── ext-all-debug.js // 调试版本的核心库文件(推荐开发时使用) ├── resources/ // CSS、图片等资源文件 │ └── themes/ │ └── classic/ // 经典主题 └── license.txt // 许可证文件 -
创建项目目录: 在你的工作空间中创建一个新的项目文件夹,
my-first-extjs-app。 -
复制必要文件: 将
ext-4.2.1.883文件夹中的以下内容复制到你的my-first-extjs-app目录中:ext-all.js(或ext-all-debug.js)resources文件夹build文件夹(可选)
你的项目目录现在看起来像这样:
my-first-extjs-app/ ├── ext-all.js ├── resources/ └── index.html
核心概念
在开始写代码前,必须理解 ExtJS 的几个核心概念:
- 组件:这是 ExtJS 的一切,按钮、面板、窗口、表单都是组件,组件可以嵌套,形成一个复杂的 UI 树,组件有自己的属性、方法和事件。
- 容器:一种特殊的组件,用于容纳其他组件。
Ext.panel.Panel、Ext.container.Viewport、Ext.tab.Panel等。 - 布局:定义了容器中子组件的排列方式,常见的有
fit(填充整个容器)、border(边框布局,分上、下、左、中、右)、vbox(垂直排列)、hbox(水平排列)等。 - 数据模型:使用
Ext.data.Model来定义你的数据结构,它类似于数据库中的一张表,定义了字段(如 name, age, email)和数据类型。 - 数据存储:使用
Ext.data.Store来管理一个Model实例的集合,它负责数据的加载、排序、过滤、分页等操作,Store 是连接 UI 组件和数据源的桥梁。 - 视图:负责展示数据的 UI 组件,如
Ext.grid.Panel(数据网格)、Ext.form.Panel(表单)。 - 控制器:在 MVVM 模式中,控制器负责处理用户交互(如点击按钮),并协调 Model 和 View 的更新,它连接了用户操作和业务逻辑。
- ViewModel:一个特殊的 Store,它为 View 提供数据,View 和 ViewModel 是双向绑定的,当 View 中的数据改变时,ViewModel 会自动更新,反之亦然,这是 ExtJS 4 的精髓之一。
第二部分:第一个 Hello World 程序
让我们从一个最简单的例子开始:在页面上显示一个窗口。
创建 index.html
在你的项目根目录下创建 index.html 文件,内容如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">My First ExtJS App</title>
<!-- 1. 引入 CSS 文件 -->
<link rel="stylesheet" type="text/css" href="resources/themes/classic/ext-all.css">
<!-- 2. 引入核心 JS 文件 (使用调试版本方便调试) -->
<script type="text/javascript" src="ext-all-debug.js"></script>
<!-- 3. 引入你的应用主 JS 文件 -->
<script type="text/javascript" src="app.js"></script>
</head>
<body>
<!-- ExtJS 会将整个页面渲染成一个视口,body 初始内容可以为空 -->
</body>
</html>
创建 app.js
这是我们的应用入口文件,在 ExtJS 4 中,我们使用 Ext.onReady 来确保 DOM 加载完成后再执行我们的代码。
// app.js
// Ext.onReady 是 ExtJS 的入口函数,类似于 jQuery 的 $(document).ready()
Ext.onReady(function() {
// 创建一个简单的窗口
var win = Ext.create('Ext.window.Window', {
title: 'Hello ExtJS 4.2!',
width: 400,
height: 200,
html: '<p>这是我的第一个 ExtJS 窗口!</p>',
renderTo: Ext.getBody() // 将窗口渲染到 body 上
});
});
运行
直接用浏览器打开 index.html 文件,你应该能看到一个弹出的窗口,上面写着 "Hello ExtJS 4.2!"。
代码解释:
Ext.create(): 这是 ExtJS 中创建组件实例的标准方法。'Ext.window.Window': 这是我们要创建的组件类名,代表一个窗口。- 这是一个配置对象,用于设置窗口的各种属性,如
title)、width(宽度)、height(高度)、html)。 renderTo: Ext.getBody(): 指定将这个窗口渲染到哪个 DOM 元素上。Ext.getBody()返回整个<body>元素。
第三部分:构建一个完整的应用(MVVM 实践)
我们来构建一个更复杂的示例:一个带有数据网格的应用,展示一个用户列表,这个例子将完整地展示 Model、Store、View 和 Controller 的协作。
修改 index.html
我们需要引入 app.js 的地方保持不变,但为了更好的组织,我们将使用 ExtJS 的 bootstrap 方式。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">ExtJS User App</title>
<link rel="stylesheet" type="text/css" href="resources/themes/classic/ext-all.css">
<!-- 引入 ext-all-debug.js -->
<script type="text/javascript" src="ext-all-debug.js"></script>
<!-- 使用 ExtJS 的 bootstrap 来启动应用 -->
<script type="text/javascript">
Ext.Loader.setConfig({
enabled: true // 启用动态加载
});
Ext.application({
name: 'MyApp', // 应用名称
// 应用启动后要加载的主类
launch: function() {
Ext.create('MyApp.view.main.MainView', {
renderTo: Ext.getBody()
});
}
});
</script>
</head>
<body>
</body>
</html>
创建应用目录结构
为了让代码更有条理,我们按照 ExtJS 的约定创建目录结构:
my-first-extjs-app/
├── index.html
├── ext-all.js
├── resources/
└── app/ // 我们的应用代码都放在这里
├── application.js // 应用主类 (上面 bootstrap 中的 MyApp)
├── model/ // 数据模型
│ └── User.js
├── store/ // 数据存储
│ └── UserStore.js
├── view/ // 视图
│ └── main/
│ └── MainView.js
└── controller/ // 控制器
└── MainController.js
编写代码
a. 应用主类 app/application.js
// app/application.js
Ext.define('MyApp.Application', {
name: 'MyApp', // 必须和 Ext.application 中的 name 一致
// 应用启动时,会自动加载 app/view/main/MainView.js
// 因为 ExtJS 的约定是自动加载 "应用名.view.路径" 的文件
requires: [
'MyApp.view.main.MainView'
]
});
b. 数据模型 app/model/User.js
// app/model/User.js
Ext.define('MyApp.model.User', {
extend: 'Ext.data.Model', // 继承自 Ext.data.Model
// 定义字段
fields: [
{ name: 'id', type: 'int' },
{ name: 'name', type: 'string' },
{ name: 'email', type: 'string' },
{ name: 'phone', type: 'string' }
]
});
c. 数据存储 app/store/UserStore.js
// app/store/UserStore.js
Ext.define('MyApp.store.UserStore', {
extend: 'Ext.data.Store', // 继承自 Ext.data.Store
// 关联的数据模型
model: 'MyApp.model.User',
// 数据代理,这里使用本地内存数据
proxy: {
type: 'memory',
reader: {
type: 'json',
root: 'users'
}
},
// 初始数据
data: {
users: [
{ id: 1, name: '张三', email: 'zhangsan@example.com', phone: '13800138000' },
{ id: 2, name: '李四', email: 'lisi@example.com', phone: '13900139000' },
{ id: 3, name: '王五', email: 'wangwu@example.com', phone: '13700137000' }
]
}
});
d. 视图 app/view/main/MainView.js
这是一个面板,内部包含一个网格。
// app/view/main/MainView.js
Ext.define('MyApp.view.main.MainView', {
extend: 'Ext.panel.Panel', // 继承自面板
'用户列表',
width: 800,
height: 500,
layout: 'fit', // 使用 fit 布局,让网格填充整个面板
// 需要的组件
requires: [
'MyApp.store.UserStore',
'Ext.grid.Panel',
'Ext.grid.column.Column',
'Ext.grid.View'
],
// items 是一个数组,包含此面板内的所有子组件
items: {
xtype: 'gridpanel', // 使用 xtype 可以更简洁地创建组件
title: '所有用户',
store: 'UserStore', // 关联我们创建的 UserStore
// 定义列
columns: [
{ text: 'ID', dataIndex: 'id', width: 50 },
{ text: '姓名', dataIndex: 'name', flex: 1 },
{ text: '邮箱', dataIndex: 'email', flex: 1 },
{ text: '电话', dataIndex: 'phone', flex: 1 }
]
}
});
e. 控制器 app/controller/MainController.js (可选)
这个例子很简单,控制器可能不是必须的,但为了演示,我们添加一个,在窗口显示时打印一条日志。
// app/controller/MainController.js
Ext.define('MyApp.controller.MainController', {
extend: 'Ext.app.Controller', // 继承自 Ext.app.Controller
// 控制器需要监听的视图事件
// 格式: '视图的别名#事件名'
refs: [
{
ref: 'mainView', // 给这个视图引用起个名字
selector: 'mainview' // 通过 xtype 'mainview' 来查找
}
],
init: function() {
// 监听 mainview 的 afterrender 事件(视图渲染完成后)
this.control({
'mainview': {
afterrender: this.onMainViewRendered
}
});
},
onMainViewRendered: function(panel) {
console.log('MainView has been rendered!');
// 你可以在这里添加更多逻辑,比如加载数据、监听按钮点击等
}
});
f. 修改 application.js 以包含控制器
为了让控制器被加载,我们需要在 application.js 中声明它。
// app/application.js (修改后)
Ext.define('MyApp.Application', {
name: 'MyApp',
requires: [
'MyApp.view.main.MainView',
'MyApp.controller.MainController' // 添加控制器
]
});
运行
再次用浏览器打开 index.html,你应该能看到一个包含用户列表的窗口,打开浏览器的开发者工具(F12),在 Console 标签下,你会看到打印出的 "MainView has been rendered!"。
第四部分:进阶学习与资源
Sencha Cmd (强烈推荐)
手动管理文件和依赖在项目变大后会变得非常痛苦。Sencha Cmd 是 Sencha 官方的命令行工具,它可以:
- 生成项目骨架:自动创建规范的目录结构。
- 代码压缩与合并:将所有 JS 和 CSS 文件合并并压缩,用于生产环境。
- 生成类:使用
generate命令快速创建 Model、View、Controller 等文件。 - SASS 编译:支持使用 SASS 来定制主题。
对于任何正式的项目,都应该使用 Sencha Cmd 来管理。
官方文档
ExtJS 4.2 的官方文档是最好的学习资源,它包含了所有组件的详细 API 说明、配置项和示例。
- API 文档: ExtJS 4.2 API Documentation
- 示例:
ext-4.2.1.883/examples/目录下有大量官方示例,是学习组件用法的绝佳材料。
学习路径建议
- 掌握基础:理解组件、容器、布局、Model、Store、View 的基本概念。
- 精通常用组件:重点学习
Ext.panel.Panel,Ext.grid.Panel,Ext.form.Panel,Ext.window.Window,Ext.tab.Panel。 - 学习数据绑定:深入理解
ViewModel和Ext.data.Model的使用,这是实现响应式 UI 的关键。 - 学习控制器:掌握如何通过控制器来处理业务逻辑和组件间的通信。
- 学习 Sencha Cmd:学会使用工具来提高开发效率。
- 阅读源码和示例:遇到问题多查 API,多看官方示例,尝试修改示例代码来理解其工作原理。
希望这份教程能帮助你顺利入门 ExtJS 4.2!虽然它已经是一个比较老的版本,但其核心思想(组件化、数据绑定)在现代前端框架(如 Vue, React)中依然非常受用,学好 ExtJS 对理解前端架构设计大有裨益。
