ExtJS 6 的数据功能

| 分类 Programming  | 标签 Programming  《Ext JS 6 By Example》  Sencha  ExtJS  Javascript 

Model

一个 Model 定义了项,项类型,验证,关联和 proxy,它是通过扩展 Ext.data.Model 类来定义的。

类型、验证、关联和 proxy 都是可选的,若项没有指定类型,则默认为 auto 类型。proxy 一般在 data store 中指定,但是也可以在 Model 中指定。

Field

Ext.data.field.Field 用于向 Model 添加属性。项即可以使用预定义的类型,也可以用自定义的类型。

预定义的类型有:

  • auto
  • boolean
  • date
  • int
  • number
  • string

数据的转换

当项指定类型后,在保存项时,数据会默认自动转换成相应的类型。这种转换是由内置的 convert 函数完成的。auto 类型的项没有 convert 方法,因而不进行数据转换。

其它类型的项都有 convert 方法,若想提高性能而禁用转换功能,可以在项配置信息中将 convert 属性设置为 null

验证器

Model 支持对 Model 数据进行验证。以下是支持的验证器:

  • presence: 确保项值不空
  • format: 可使用正则表达式来验证格式
  • length: 最小长度和最大长度验证
  • exclusion, inclusion: 可以传入一组值到这些验证器中,来验证值是否在该集合内

以下是一个具有验证器的 Model:

Ext.define('Employee', {
    extend: 'Ext.data.Model',
    fields: [
        { name: 'id', type: 'int', convert: null },
        { name: 'firstName', type: 'string'},
        { name: 'lastName', type: 'string'},
        { name: 'fulltime', type: 'boolean', defaultValue: true, convert: null },
        { name: 'gender', type: 'string'},
        { name: 'phoneNumber', type: 'string'}
    ],
    validators: {
        firstName: [
            { type: 'presence' },
            { type: 'length', min: 2 }
        ],
        lastName: [
            { type: 'presence' },
            { type: 'length', min: 2 }
        ],
        phoneNumber: {
            type: 'format',
            matcher: '/^[(+{1})|(00{1})]+([0-9]){7,10}$/'
        },
        gender: {
            type: 'inclusion',
            list: ['Male', 'Female']
        }
    }
});

Ext.create 创建 Model 的实例:

var newEmployee = Ext.create('Employee', {
    id: 1,
    firstName: 'Shiva',
    lastName: 'Kumar',
    fulltime: true,
    gender: 'Male',
    phoneNumber: '123-456-7890'
});

var lastName = newEmployee.get('lastName'); // get()
newEmployee.set('gender', 'Female'); // set()

关联性

One-to-One

Ext.define('Address', {
    extend: 'Ext.data.Model',

    fields: [
        'address',
        'city',
        'state',
        'zipcode'
    ]
});

Ext.define('Employee', {
    extend: 'Ext.data.Model',

    fields: [{
        name: 'addressId',
        reference: 'Address'
    }]
});

One-to-Many

Ext.define('Department', {
    extend: 'Ext.data.Model',

    fields: [{
        name: 'employeeId', reference: 'Employee'
    }]
});

Ext.define('Division', {
    extend: 'Ext.data.Model',

    fields: [{
        name: 'employeeId', reference: 'Employee'
    }]
});

Many-to-Many

Ext.define('Employee', {
    extend: 'Ext.data.Model',

    fields: [
        { name: 'empId', type: 'int', convert: null },
        { name: 'firstName', type: 'string' },
        { name: 'lastName', type: 'string' }
    ]

    manyToMany: 'Project'
});

Ext.define('Project', {
    extend: 'Ext.data.Model',

    fields: [
        'name'
    ]

    manyToMany: 'Employee'
});

自定义项类型

可以通过扩展 Ext.data.field.Field 创建,例如:

Ext.define('MyApp.field.Email', {
    extend: 'Ext.data.field.Field',
    alias: 'data.field.email',

    validators: {
        type: 'format',
        matcher: /^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/,
        message: 'Wrong Email Format'
    }
});

Store

Store 表示一个 Model 实例的集合,并通过 Proxy 存取数据。Store 还定义了一些集合操作:如排序、过滤等。Store 通过扩展 Ext.data.Store 定义。

通常在定义 Store 时会指定 Proxy,Proxy 配置项告诉 Store 如何进行数据读写。

下面创建的 Store 实例能通过 REST 请求加载 JSON 数据:

var myStore = Ext.create('Ext.data.Store', {
    model: 'Employee',
    storeId: 'mystore',
    proxy: {
        type: 'rest',
        url: '/employee',
        reader: {
            type: 'json',
            rootProperty: 'data'
        }
    },
    autoLoad: true,
    autoSync: true
});

storeId 是该 store 的唯一标识。该 store 有一个 load 方法,它能通过 proxy 加载数据。若设置了 autoLoadtrue, load 方法会在创建 store 后自动调用。

类似地,可以设置 autoSynctrue,从而将对 store 的数据的编辑、添加、删除等操作同步到服务器。若 autoSync 设置为 false,那么可以调用 sync 方法来进行操作同步。

调用 sync 方法将会触发一批操作。因此,如果你添加了一些记录,又删除了一些记录,那么调用 sync 将向服务器触发多个操作请求,以完成这些操作。下面是调用 sync 的例子:

store.sync({
    callback: function(batch, options){
        // will be called upon completion of the sync operations, irrespective of its success or failure
    },
    success: function(batch, options){
        // will be called when all the sync operations are completed without any exception or failure.
    },
    failure: function(batch, options){
        // will be called if one or more operations in the sync fails
        // we can check the batch's exception array to see exactly what operations failed and why.
        // the `options` are original parameters that are passed in the sync.
    },
    scope: this
});

sync 方法还有一个参数 params,可用来传入额外的参数。

inline data store

不依赖服务器或外部存储器(如浏览器的 LocalStorage),只使用硬编码的静态数据,如:

Ext.create('Ext.data.Store', {
    model: 'Employee',
    data: [
        {
            firstName: 'Shiva',
            lastName: 'Kumar',
            gender: 'Male',
            fulltime: true,
            phoneNumber: '123-456-7890'
        },
        {
            firstName: 'Vishwa',
            lastName: 'Anand',
            gender: 'Male',
            fulltime: true,
            phoneNumber: '123-456-7890'
        }
    ]
});

过滤和排序

store 支持本地和远程的过滤和排序。下面是一个本地排序的例子:

Ext.create('Ext.data.Store', {
    model: 'Employee',
    sorters: [
        {
            property: 'firstName',
            direction: 'ASC'
        },
        {
            property: 'fulltime',
            direction: 'DESC'
        }
    ],
    filters: [{
        property: 'firstName',
        value: /an/
    }]
});

要进行服务端排序和过滤,将 remoteSortremoteFilter 设置为 true。

store 的存取

可以将 store 保存在独立的文件中,然后在应用中访问。

使用 StoreManager 存取 store

使用 Ext.data.StoreManagerlookup 方法及 storeId 可存取 store。该方法还有一个别名为 Ext.getStore

storeId 是在创建 Store 实例时设置的一个属性值,需要注意的是,如果 store 是在 Controller 中被初始化的,那么其 storeId 值会重载为其 name 值。

使用如下:

var myStore = Ext.data.StoreManager.lookup('myStore'); // or
var myStore = Ext.getStore('myStore'); 

使用 ViewModel 存取 store

可通过 Ext.app.ViewModelgetStore 方法存取。当在 ViewController 中时,最好使用这种方式:

var myStore = this.getViewModel().getStore('myStore');

View 中也定义了 getStore,也可以使用。

Store 的可监听事件

  • add: 在记录添加后触发
  • beforeload: 在加载数据前触发
  • beforesync: 在同步操作前触发
  • datachanged: 当记录添加或删除后触发
  • load: 当从远程加载后触发
  • remove: 当记录删除后触发
  • update: 当某条记录更新后触发

监听事件的例子如下:

Ext.create('Ext.data.Store', {
    model: 'Employee',
    storeId: 'mystore',
    proxy: {
        type: 'rest',
        url: '/employee',
        reader: {
            type: 'json',
            rootProperty: 'data'
        }
    },
    listeners: {
        load: function(store, records, options){
        }
    }
});

如果想在 Controller 中添加 store 事件监听,可以:

init: function(){
    this.getViewModel().getStore('myStore').on('load',
        this.onStoreLoad, this);
}

在 ViewModel 中的 store

通常可在 ViewModel 中定义 Store,例如:

Ext.define('MyApp.view.employee.EmployeeModel', {
    extend: 'Ext.app.ViewModel',
    alias: 'viewmodel.employee',
    stores: {
        employee: {
            fields: [
                { name: 'id', type: 'string' },
                { name: 'firstName', type: 'string' },
                { name: 'lastName', type: 'string' }
            ],
            autoLoad: false,
            sorters: [{
                property: 'firstName',
                direction: 'ASC'
            }],
            proxy: {
                type: 'rest',
                url: 'employee',
                reader: {
                    type: 'json'
                },
                writer: {
                    type: 'json'
                }
            }
        }
    }
});

Proxy

Store 和 Model 使用 Proxy 进行数据加载和保存。有两种类型的 Proxy: 客户端的和服务器端的 Proxy。

客户端的 Proxy

有 3 种: memory, LocalStorage, SessionStorage。

memory Proxy

数据来自本地内存中的变量,如:

var data = {
    data: [
        {
            firstName: 'Shiva',
            lastName: 'Kumar',
            gender: 'Male',
            fulltime: true,
            phoneNumber: '123-456-7890'
        },
        {
            firstName: 'Vishwa',
            lastName: 'Anand',
            gender: 'Male',
            fulltime: true,
            phoneNumber: '123-456-7890'
        }
    ]
};

var myStore = Ext.create('Ext.data.Store', {
    model: 'Employee',
    data: data,
    proxy: {
        type: 'memory',
        reader: {
            type: 'json',
            rootProperty: 'data'
        }
    }
});

LocalStorage proxy

用于存取 HTML5 浏览器的 LocalStorage,这是一个 KV 对存储器,如:

var myStore = Ext.create('Ext.data.Store', {
    model: 'Benefits',
    autoLoad: true,
    proxy: {
        type: 'localstorage',
        id: 'benefits'
    }
});

SessionStorage proxy

用于存取 HTML5 浏览器的 SessionStorage,里面的数据在 Session 过期后会自动销毁,如:

var myStore = Ext.create('Ext.data.Store', {
    model: 'Benefits',
    autoLoad: true,
    proxy: {
        type: 'sessionstorage',
        id: 'benefits'
    }
});

服务器端 proxy

Proxy 与服务器通讯来完成数据读取和保存操作,共有 4 种:

  • Ajax: 异步请求
  • Direct: 使用 Ext.Direct 与服务器通讯
  • JSONP(JSON with padding): 用于跨域发放请求的情况
  • REST。

例如:

var myStore = Ext.create('Ext.data.Store', {
    model: 'Products',
    proxy: {
        type: 'jsonp',
        url: 'http://domain.com/products',
        callbackKey: 'productsCallback'
    }
});

参考


上一篇     下一篇