MVC application architecture in ExtJs 4_html/css_WEB-ITnose

WBOY
Release: 2016-06-24 12:34:37
Original
911 people have browsed it

1. Principle and function of ExtJs 4.x MVC model

Large-scale client applications are usually difficult to implement, organize and maintain. Because of the continuous increase in functions and manpower, the scale of these applications It will soon be beyond your control. ExtJS4 brings a new application architecture that not only organizes the code, but also reduces the content to be implemented.

The new application architecture follows an MVC-like pattern, with Models and Controllers introduced for the first time. There are many MVC architectures in the industry, which are basically the same. The definition of ExtJS4 is as follows:

a.Model model: A model is a collection of fields and their data. For example, the User model has username and password fields. The model knows how to persist. It can transform its own data and can be associated with other models. The model is somewhat similar to the Record class in ExtJS 3 (the difference is that Record is just a simple flat structure, while Model can be nested). It is usually used in the Store to display grid and other The component's data.

b. View: View is a type of component, focusing on interface display? Grid, tree, and panel are all views.

c.Controllers: A place to put all the code that makes your app work correctly. Specifically, it should be all actions, such as how to render the view, how to initialize the model, and other logic of the app.

Please note: MVC is a framework, not a design pattern. For more information, please refer to: Baidu Encyclopedia

Although frameworks and design patterns are similar, they are fundamentally different. Design patterns are descriptions of recurring problems and solutions to the problems in a certain environment. They are more abstract than frameworks; frameworks can be represented by code and can be directly executed or reused, while only instances can be used for patterns. Expressed in code; a design pattern is a smaller element than a framework. A framework often contains one or more design patterns. A framework is always aimed at a specific application field, but the same pattern can be applied to various applications. It can be said that the framework is the software, and the design pattern is the knowledge of the software.

In short: Design patterns are great wisdom, used to divide labor in software design; framework patterns are small skills, proposing solutions to specific problems to increase code reuse and reduce coupling.

2. ExtJs 4 MVC framework construction 2.1, file structure

ExtJS 4 applications follow a unified directory structure, each should be in the same MVC, and all classes are placed in the app directory. This directory can have Subdirectories represent namespaces (one subdirectory corresponds to a namespace), and different directories are used to store views, models, controllers, and stores. When we complete the example, the directory structure should be as shown below:

The necessary files for ExtJS SDK are in the directory ext4. Therefore, index.html should import the necessary js and css for extjs , and the app.js file

2.2. Create an application in app.js

Each ExtJS 4 application starts with an instance of the Application class, which contains the global configuration of the application (such as the name of the application). This instance is also responsible for maintaining references to all models, views, and controllers, as well as a launch function that will be called after all add-ins are loaded.

First you need to select a global namespace. All ExtJS4 applications need to have a global namespace so that all classes in the application can be placed in it:

 Ext.application({    requires: ['Ext.container.Viewport'],      name: 'FWY',//定义的命名空间    appFolder: 'app',//指明应用的根目录    launch: function() {        Ext.create('Ext.container.Viewport', {            layout: 'fit',            items: [                {                    xtype: 'panel',                    title: '标题',                    html : '内容'                }            ]        });    }});    
Copy after login
2.3. Define a controller

Controllers are the glue of the application. What they do is listen to events and perform actions. Continue with our application and create a controller. Create the app/controller/Students.js file and add the following code:

 Ext.define('FWY.controller.Students', {    extend: 'Ext.app.Controller',    init: function() {        console.debug("trigger controller init event");    }});    
Copy after login

Next, add a reference to the Students controller in app.js:

 Ext.application({...controllers: [    'Students'  //对应于controller文件夹下面的Students.js],...});
Copy after login

When we view the application through index.html, the Students controller will be automatically loaded (because a reference is added to the Application in app.js), and the init method of Students will be before launch call.

The init method is an excellent place to set how to interact with the view. Usually, a method of the Controller, control, is used. The control method makes it easy to monitor the events of the view. Update the controller and let it Tell us when the panel is rendered:

 Ext.define('FWY.controller.Students', {    extend: 'Ext.app.Controller',    init: function() {        this.control({            'viewport > panel': {                render: this.onPanelRendered            }        });    },    onPanelRendered: function() {        console.debug('该panel被渲染了');    }});
Copy after login

We have updated the init method to set a listener for the view using this.controll. This control method uses the latest component query engine (ComponentQuery) to quickly and easily find components on the page. If you are not familiar with ComponentQuery, you can check out the ComponentQuery documentation to learn more. Briefly, ComponentQuery allows us to find components using a CSS selector-like method.

In the init method of the example we apply 'viewport > panel', which can be interpreted as "find all Panel components in the direct descendants of the Viewport", and then we provide an object matching the event name (in this example Only render) is used to provide the response function. The entire impact is that no matter which component matches our selector, when its render event fires, our onPanelRendered function will be called.

三、创建ExtJs4 MVC应用 1、定义一个视图

直到现在,我们的应用只有很少代码,只有两个文 件 app.js 和 app/controller/Students.js,现在我们想增加一个grid显示所有系统中的学生列表,修改3处:

(1)、添加view/List.js视图

是时候更好的组织一下逻辑并开始使用视图了。

视图也是组件,通常都是ExtJS现有组件的子类,现在准备创建学生表,先创建 app/view/student/List.js ,添加代码:

 Ext.define('FWY.view.student.List' ,{    extend: 'Ext.grid.Panel',    alias : 'widget.studentlist',    title : '学生信息列表',    initComponent: function() {        this.store = {            fields: ['id','name', 'age','sex'],            data  : [                {id:1,name: 'zhangsan',    age: 18,sex:'boy'},                {id:2,name: 'lishi',    age: 20,sex:'girl'}        ]};        this.columns = [            {header: '编号',  dataIndex: 'id',  flex: 1},            {header: '姓名',  dataIndex: 'name',  flex: 1},            {header: '年龄', dataIndex: 'age', flex: 1},            {header: '性别', dataIndex: 'sex', flex: 1}        ];        this.callParent(arguments);    }});
Copy after login
(2)、修改controller/Students.js

我们的视图类就是一个普通的类,这个例子中我们扩展了 Grid 组件,并设置了别名,这样我们可以用 xtype 的方式调用这个组件,另外我们也添加了 store 和 columns 的配置。 接下来我们需要添加这个视图到 Students控制器。因为我们用 'widget.studentlist' 设置了别名,所以我们可以使用 studentlist 作为xtype,就像我们使用之前使用的 'panel'

 Ext.define('FWY.controller.Students', {    extend: 'Ext.app.Controller',    views: [        'student.List'//添加view视图    ],    init: ...    onPanelRendered: ...});
Copy after login
(3)、修改app.js,加载视图

接下来修改 app.js 让视图在viewport中渲染,需要修改 launch 方法

 Ext.application({    ...    launch: function() {        Ext.create('Ext.container.Viewport', {            layout: 'fit',            items: {                xtype: 'studentlist'            }        });    }});
Copy after login

唯一需要注意的是我们在views数组中指定了 'student.List' ,这告诉应用去自动加载对应的文件,ExtJS4 的动态加载系统会根据规则从服务器自动拉取文件,例如student.List就是规则,把.替换成/就是文件存放路径。刷新一下页面即可看到效果

2、添加对列表的控制

分三步完成对对编辑窗体的控制

(1)、为grid绑定双击事件

注意 onPanelRendered 方法依然被调用,因为我们的grid依然满足 'viewport > panel' 选择器,因为我们的视图继承自 Grid ,从而继承自 Panel。现在我们需要收紧一下选择器,我们使用xtype作为选择器替换之前的 'viewport > panel' ,监听双击事件,以便继续做编辑用户信息:

 Ext.define('FWY.controller.Students', {    extend: 'Ext.app.Controller',    views: [            'student.List'    ],    init: function() {        this.control({            'studentlist': {                itemdblclick: this. editStudent//添加行双击事件            }        });    },    editStudent: function(grid, record) {        console.log('Double clicked on ' + record.get('name'));    }});
Copy after login

注意我们更换了组件查询选择器为 'studentlist' ,监听的事件更改为 'itemdblclick' ,响应函数设置为 editStudent,现在只是简单的日志出双击行的name属性。

(2)、创建view/student/Edit.js视图

可以看到日志是正确的,但我们实际想做的是编辑用户信息,让我们现在做,创建一个新的视图 app/view/student/Edit.js

 Ext.define('FWY.view.student.Edit', {    extend: 'Ext.window.Window',    alias : 'widget.studentedit',    title : '修改学生信息',    layout: 'fit',    autoShow: true,    initComponent: function() {        this.items = [            {                xtype: 'form',                items: [                    {                        xtype: 'textfield',                        name : 'name',                        fieldLabel: '姓名'                    },                    {                        xtype: 'textfield',                        name : 'age',                        fieldLabel: '年龄'                    },                    {                        xtype: 'textfield',                        name : 'sex',                        fieldLabel: '性别'                    }                ]            }        ];        this.buttons = [            {                text: '保存',                action: 'save'            },            {                text: '取消',                scope: this,                handler: this.close            }        ];        this.callParent(arguments);    }});
Copy after login
(3)、修改控制器加载视图

接下来我们要做的就是在控制器加载这个视图,渲染并且加载用户信息:

 Ext.define('FWY.controller.Students', {    extend: 'Ext.app.Controller',    views: [        'student.List',        'student.Edit'//添加edit视图    ],    init: ...    editStudent: function(grid, record) {        var view = Ext.widget('studentedit');//注册组件,显示窗口        view.down('form').loadRecord(record);//加载数据到表单中    }});
Copy after login

首先我们用 Ext.widget 方法创建了视图,这个方法等同于 Ext.create('widget.studentedit') ,然后我们又一次借助组件查询找到了窗口中的表单,每个ExtJS4中的组件都有一个 down方法,可以借助组件查询支持的选择器来迅速找到任意下层的组件,双击表格中的一行可以看到弹窗效果。

3、创建Store和Model进行重构

现在我们有了表单,可以开始编辑和保存用户信息了,但是这之前需要做一点点重构。 FWY.view.student.List 创建了一个内联的 Store ,这样可以工作但是我们需要把 Store 分离出来以便我们在应用的其他位置可以引用并更新其中的信息,我们把它放在它应该在的文件中 app/store/Students.js :

 Ext.define('FWY.store.Students', {    extend: 'Ext.data.Store',    fields: ['id','name', 'age','sex'],    data: [        {id:1,name: '张三',    age: 30,sex:'男'},        {id:2,name: '李四',    age: 20,sex:'女'}    ]});
Copy after login

现在我们需要做两处变更,首先我们需要让 Students 初始化的时候加载这个 Store :

 Ext.define('FWY.controller.Students', {    extend: 'Ext.app.Controller',    stores: ['Students'],//加载store    ...});
Copy after login

然后我们要把之前直接在视图中内联的store更改掉,

 Ext.define('FWY.view.student.List' ,{    extend: 'Ext.grid.Panel',    alias : 'widget.studentlist',    store: 'Students',//引用Store    ...});
Copy after login

控制器的代码中中引入了store,store会被自动加载到页面并赋予一个storeId,这让视图中使用store变的容易(这个例子中,只要配置 store: 'Students' 就可以了) 现在我们只是在store中内联的定义了四个字段 (id,name,age,sex),这样可以工作了。

进一步重构:

ExtJS4中有一个强大的 Ext.data.Model类,在编辑用户的时候我们可以借助它,使用Model重构下Store,在 app/model/Student.js中创建一个Model:

 Ext.define('FWY.model.Student', {    extend: 'Ext.data.Model',    fields: ['id','name','age','sex']});
Copy after login

这就是定义我们的Model需要做的,现在需要让Store引用Model替换掉使用内联字段的方式,并且让控制器也引用Model:

 //修改控制器,引用ModelExt.define('FWY.controller.Students', {    extend: 'Ext.app.Controller',    stores: ['Students'],    models: ['Student'],    ...});//修改store,引用ModelExt.define('FWY.store.Students', {    extend: 'Ext.data.Store',    model: 'FWY.model.Student',    data: [        {id:1,name: '张三1',    age: 30,sex:'男'},        {id:2,name: '李四1',    age: 21,sex:'女'}    ]});
Copy after login
4、利用模型保存数据

现在我们有了一个用户数据表,双击每?一行都能打开一个编辑窗口,现在要做的是保存编辑变更,编辑窗口有一个编辑表单,还有保存按钮,现在我们更新一下控制器让保存按钮有响应:

 Ext.define('FWY.controller.Students', {    init: function() {        this.control({            'viewport > studentlist': {                itemdblclick: this.editStudent            },            'studentedit button[action=save]': {//获取studentedit视图中的button配置action=‘save’的按钮事件                click: this.updateStudent            }        });    },    updateStudent: function(button) {        console.log('clicked the Save button');    }});    
Copy after login

接下来填充 updateStudent 真正的逻辑。我们需要把数据从表单中取出,再 设置回store中:

 updateStudent: function(button) {    var win    = button.up('window'),    form   = win.down('form'),    record = form.getRecord(),    values = form.getValues();    record.set(values);    win.close();}
Copy after login
5、保存到服务器

让我们增加和服务器端的交互完成这个例子。现在我们还是应编码了两行表格的数 据,现在让我们通过ajax加载:

 Ext.define('FWY.store.Students', {    extend: 'Ext.data.Store',    model: 'FWY.model.Student',    autoLoad: true,    proxy: {        type: 'ajax',        url: 'data/students.json',        reader: {            type: 'json',            root: 'students',            successProperty: 'success'        }    }});
Copy after login

这里我们去除了 'data' 属性,替换成 proxy ,代理是让Store或者Model加载和保存数据的一个方式,有AJAX,JSONP,HTML5的localStorage本地存储等。这里我们使用了一个简单的AJAX代理,让它通过URL 'data/students.json' 加载数据。

我们同时给代理附加了一个reader,reader是用来把服务器返回的数据解码成Store能理解的格式,这次我们使用了JSON reader,并且指定了root和 successProperty 配置(JSON reader的详细配置看文档),最后我们创建一下数据文件 data/students.json ,输入内容:

 {    success: true,    users: [        {id: 1, name: 'zhang',    email: 'zhang@126.com'},        {id: 2, name: 'lishi', email: 'lishi@126.com'}  ]}
Copy after login

其他的变更就是我们给Store设置了 autoLoad 属性并设置为 true ,这意味着Store生成之后会自动让Proxy加载数据,刷新?一下页面应该是看到和之前同样的结果,不同的是现在不是在程序中存在硬编码数据了,最后的事情是将变更传回服务器端,这个例子中我们使用静态的JSON文件,没有使用数据库,但足够说明我们例子的了,首先做一点点变化告知proxy用于更新的url:

 proxy: {    type: 'ajax',    api: {        read: 'data/students.json',        update: 'data/updateStudents.json',    },    reader: {        type: 'json',        root: 'students',        successProperty: 'success'    }}
Copy after login

依然从 students.json 读取数据,但是变更会发送到 updateStudents.json ,这里我们做?个模拟的应答回包以让我们知道程序可以正确工作, updateStudents.json 只需要包含{"success":true},其他要做的就是让Store在编辑之后进行同步,需要在 updateStudent 函数中增加一行代码:

     updateStudent: function(button) {    var win    = button.up('window'),    form   = win.down('form'),    record = form.getRecord(),    values = form.getValues();    record.set(values);    win.close();    this.getStudentsStore().sync();//将数据同步到store中}
Copy after login

最后附上本篇的代码:点击下载

--本篇完--

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!