Ext JS - Ext JS 4 MVC 模式 - 以一个 grid 来演示 MVC 之间的联系和作用,以及涉及到的部分函数、事件参数的应用
文件结构:

文件加载顺序:

index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/"; %> <!DOCTYPE html> <html> <head> <base href="<%=basePath%>" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script type="text/javascript" src="ext-4/bootstrap.js"></script> <script type="text/javascript" src="ext-4/locale/ext-lang-zh_CN.js"></script> <link type="text/css" rel="stylesheet" href="ext-4/resources/css/ext-all.css" /> <script type="text/javascript" src="extjs/app.js"></script> <title>Ext JS</title> <style type="text/css"> .x-grid-cell.greencard { background-color: #B6FFA8; } </style> </head> <body> </body> </html>
app.js
Ext.Loader.setConfig({ enabled: true }); Ext.Loader.setPath({ 'Ext.ux': 'ext-4/ux', 'Ext': 'ext-4' }); Ext.application({ /** * 全局命名空间,所有ExtJS4应用都需要有一个全局命名空间,以让所有应用中的类安放到其中 * 自动创建一个全局变"MyApp",并自动注册命名空间"MyApp"到Ext.Loader */ name: 'MyApp', appFolder: 'app', // 存放Application涉及的文件路径 controllers: ['userCtrl'], // 引用Controller /** * 应用从这里开始 */ launch: function () { /** * 初始化QuickTips就是为了使带有data-qtip属性的html标签能够在鼠标移上去的时候显示其内容,作用类似于HTML标签的title的功能 */ Ext.QuickTips.init(); /** * 创建一个 Viewport,在其中添加子项 userView */ Ext.create('Ext.container.Viewport', { layout: 'fit', // userView充满整个Viewport autoScroll: false, items: { xtype: 'userView' // alias: 'widget.userView' } }); } });
userCtrl.js
Ext.define('MyApp.controller.userCtrl', {
extend: 'Ext.app.Controller',
// refs的作用在于在Controller可以直接getUserView()可以直接获取到userView
refs: [{
ref: 'userView',
selector: 'userView'
}
],
// Controller下面的views数组里添加的对应的是View的别名(widget),这样控制器就可以对视图上的操作进行监控!
// 同时views配置等同于requires: ['MyApp.view.userView', 'MyApp.view.editUser'],
// 同理:stores,models配置同理也是等同于requires,动态加载组件!
views: ['userView', 'editUserView'],
stores: ['userStore'], // store会被自动加载到页面并赋予一个storeId,这让视图中使用store变的容易
models: ['userModel'],
/**
* 通过index.jsp查看应用时,userCtrl会被自动加载
* 因为在app.js的Application中增加了引用,并且userCtrl的init方法会在Application的launch方法之前调用
* init方法用来设置如何和View交互,通常都使用Controller的一个方法control,control方法使得监听View的事件变的容易
*/
init: function () {
// 全局变量userCtrl,当前Controller(this)赋值给userCtrl,则可以在View或者Store中,利用变量userCtrl进行操作!
// 前提是在Controller里的Views和Stores配置里,将需要操作的项添加进去!
userCtrl = this;
/**
* 使用this.control给视图设置监听器,这个controll方法,使用最新的组件查询引擎(ComponentQuery)可以快速方便的找到页面上的组件
*/
this.control({
'userView': {
itemdblclick: this.editUser // 想了解可用参数,可以在Ext的API里搜索关键字itemdblclick查阅View的双击事件!!
},
'editUserView button[action=save]': { // xytpe是editUserView的组件下的所有action属性是save的按钮
click: this.updateUser // View下的Button,可以去查阅Button下面的Events的click单击事件
}
});
},
/**
* itemdblclick(this, record, item, index, e, eOpts)
*
* grid: Ext.view.View
* 当前View视图
* record: Ext.data.Model
* The record that belongs to the item (当前行的数据记录)
* itme: HTMLElement
* The item's element (HTML元素)
* index: Number
* The item's index (序号)
* e: Ext.EventObject
* The raw event object (事件对象)
* eOpts: Object
* The options object passed to Ext.util.Observable.addListener
*/
// !!!因为在此Controller中, this对象指代当前控制器userCtrl, 所以itemdblclick函数中的参数, 用grid来代替this
// 替换 editUser: function (this, record, item, index, e)中的参数名称, this 替换为 grid
editUser: function (grid, record, item, index, e) {
/**
* arguments: js参数的特殊性,一般是有一个内置的参数数组arguments存放参数
*/
var argsLength = arguments.length; // 5
console.log('argsLength: ' + argsLength);
console.log('=====打印arguments start=====');
for(var i in arguments){
console.log('第 '+i+' 个参数: ');
console.log(arguments[i]);
}
console.log('=====打印arguments end=====');
/**
* 参数: grid
* getSelectionModel(): Ext.selection.Model -> Gets the selection model for this view
* 所以是当前的View来调用getSelectionModel方法
* 此处的grid就是View的this(鉴于此文件下this已指代为Controller userCtrl对象,所以此处grid代替View的this)
* 方法调用格式: viewObj.getSelectionModel();
*/
console.log('=====grid=====');
console.log(grid);
var selectionModel = grid.getSelectionModel(); // 选择模式
var rec = selectionModel.getLastSelected();// 即record
var name = rec.get('name');
console.log('grid.getSelectionModel().getLastSelected().get(\'name\'): ' + name);
/**
* 参数: record
* record下面的属性: data,events,hasListeners,id,index,internalId,modified,phantom,raw,store,stores
* record下面的属性下面还有属性,可以一层一层的引用来获取数据!
* 例如: record.data.name,或者record.data['name'],这样就获得了当前grid双击行的name值
*/
console.log('record.get(\'name\'): ' + record.get('name'));
console.log('record.data.name: ' + record.data.name);
console.log('record.data[\'name\']: ' + record.data['name']);
console.log('record.raw.name: ' + record.raw.name);
/**
* refs配置里的view,自动赋予了ctrl的getter方法,this.getXxx()既可以直接获得!
*/
var $grid = this.getUserView(); // 获取到的$grid等同于参数中的grid!
var $name = $grid.getSelectionModel().getLastSelected().get('name');
console.log('this.getUserView().getSelectionModel().getLastSelected().get(\'name\'): ' + $name);
/**
* refs配置的东西,则可以直接this.getUserView(this此处是userCtrl)
* views和stores配置的东西,获得的方式则是this.getXxxView()或者this.getXxxStore()
*/
var $userView = this.getUserView();
console.log('this.getUserView(): ');
console.log($userView);
var $editUserView = this.getEditUserViewView();
console.log('this.getEditUserViewView(): ');
console.log($editUserView);
var userStore = this.getUserView().store;
console.log('this.getUserView().store: ');
console.log(userStore);
var $store = this.getUserStoreStore();
console.log('this.getUserStoreStore(): ');
console.log($store);
/**
* 双击事件处理程序在这里..
* 通过别名获得编辑用户信息的view,然后用down方法,向下寻找form组件,将grid选中行的数(record)据,loadRecord加载到form的文本框中!
*/
var view = Ext.widget('editUserView'); // 这个方法等同于Ext.create('widget.editUserView')
/**
* 区分下Ext.widget('#alias'),Ext.getCmp('#id')
* Ext.widget('#alias'): 参数是组件的alias(别名),只要组件存在,就能获得到(所以这里需要用这个方式来获取编辑用户的View)
* Ext.getCmp('#id'): 获得一个Ext组件(一个已经在页面中初始化了的Component或其子类的对象!!),唯一参数是组件的id
*/
console.log('Ext.widget(\'editUserView\'): ');
console.log(view);
/**
* loadRecord() 圈起来,重点!!
* 参数: record 选中行数据
*/
view.down('form').loadRecord(record);
},
/**
* 点击保存按钮事件
*/
updateUser: function (button) {
console.log('button: ');
console.log(button);
var win = button.up('window'); // up()向上寻找window组件
var form = win.down('form'); // down()向下寻找window下面的form组件
var record = form.getRecord(); // 从form得到record,和editUser里面的record是同一个!!
var values = form.getValues(); // 从form得到values(即可获取更新后的数据)
record.set(values); // 给record赋值,这样修改后的数据就会显示在视图上了
win.close();
this.getUserStoreStore().sync();
}
});
userModel.js
Ext.define('MyApp.model.userModel', {
extend: 'Ext.data.Model',
fields: [{
name: 'name',
type: 'string'
}, {
name: 'email',
type: 'string'
}, {
name: 'comments',
type: 'string'
}]
});
userView.js
// 自定义grid选择模式 var selModel = Ext.create('Ext.selection.CheckboxModel', { checkOnly: false // 设置为true,只能点击复选框选中,默认情况下,单击数据行或者点击复选框均可! }); Ext.define('MyApp.view.userView', { extend: 'Ext.grid.Panel', alias: 'widget.userView', selModel: selModel, // 一个selection model实例或配置对象,在后一种情况下,selType配置选项确定此配置应用于哪种类型的选择模型。 // selType: 'rowmodel', // 所使用到的选择模型的xtype,默认为'rowmodel' renderTo: Ext.getBody(), title: 'All Users', store: 'userStore', // initComponent函数里,所有组件都是this.item的形式添加 initComponent: function () { /*this.store = { fields: ['name', 'email'], data: [{ name: 'Ed', email: 'ed@sencha.com' }, { name: 'Tommy', email: 'tommy@sencha.com' } ] };*/ this.columns = [{ text: 'Name', dataIndex: 'name', flex: 1, renderer: function(value, metaData, record, rowIndex, colIndex, store, view){ console.log('value:' + value + ', rowIndex:' + rowIndex + ', ' + ', colIndex:' + colIndex); console.log('metaData:'); console.log(metaData); console.log('record:'); console.log(record); console.log(record.get('name')); console.log(record.data.name); console.log(record.data['name']); console.log(record.raw.name); console.log(record.raw['name']); console.log('view:'); console.log(view); console.log('store'); console.log(store); return value; } }, { text: 'Email', dataIndex: 'email', flex: 1, renderer: function(value, metaData, record, rowIndex, colIndex, store, view){ metaData.tdCls = 'greencard'; return value; } }, { text: 'Comments', dataIndex: 'comments', flex: 1, renderer: function(value, metaData, record, rowIndex, colIndex, store, view){ console.log('..............'); console.log('view.getStore(): '); console.log(view.getStore()); console.log('..............'); return value; } } ]; this.dockedItems = [{ xtype: 'pagingtoolbar',// 分页工具栏 store: 'userStore', dock: 'bottom',// 停靠位置: 底部 displayInfo: true, // displayMsg: '显示 {0} - {1} 条,共 {2} 条',// displayInfo: true,这里不添加displayMsg也可以 emptyMsg: '没有数据' }]; // initComponent里面必加这句!! this.callParent(arguments); } });
editUserView.js
Ext.define('MyApp.view.editUserView', {
extend : 'Ext.window.Window',// 继承自window,弹出窗口对话框
alias : 'widget.editUserView',
id: 'editUserView',
title : 'Edit User',
layout : 'fit',// 布局: 填充
autoShow : true,
/**
* 用到初始化组件initComponent的话,都是this.items
*/
initComponent : function() {
// window下子项form表单
this.items = [ {
xtype : 'form',
// 表单里2个文本框xtype: textfield,name属性值要和被编辑view的columns的dataIndex值一致,可以接收双击grid之后,传递过来的值!
items : [ {
xtype : 'textfield',
name : 'name',
fieldLabel : 'name'
}, {
xtype : 'textfield',
name : 'email',
fieldLabel : 'Email'
} ]
} ];
// window里面,设置按钮配置buttons数组,分配2个按钮
this.buttons = [ {
text : 'Save',
action : 'save'
}, {
text : 'Cancel',
scope : this,
handler : this.close
} ];
this.callParent(arguments);
}
});
userStore.js
Ext.define('MyApp.store.userStore', {
extend: 'Ext.data.Store',
model: 'MyApp.model.userModel',// model的完整路径!
autoLoad: true,
proxy: {
type: 'ajax',
// url: 'data/users.json',
api: {
read: 'data/users.json',// 从users.json读取数据
update: 'data/updateUsers.json',// store数据发生变更(数据必须变化)会发送到updateUsers.json,返回updateUsers.json作为应答包
},
reader: {
type: 'json',
root: 'users',
successProperty: 'success',// Defaults to: "success"
totalProperty: 'total'// Defaults to: "total"
}
}
// 内联数据
// data: [{
// name: 'Ed',
// email: 'ed@sencha.com'
// }, {
// name: 'Tommy',
// email: 'tommy@sencha.com'
// }
// ]
});
users.json
{ "success": true, "total": 3, "users": [ { "id": 1, "name": "Ed", "email": "ed@sencha.com", "comments": "Edison" }, { "id": 2, "name": "Tommy", "email": "tommy@sencha.com", "comments": "Tom" }, { "id": 3, "name": "Red-Haired Shanks", "email": "shanks@sencha.com", "comments": "Shanks" } ] }
updateUsers.json
{ "success": true }
视图

itemdblclick 事件:

修改:

Save


浙公网安备 33010602011771号