视图实体模型和数据绑定-View Models and Data Binding
数据绑定和 ViewModel 是 Ext JS 的强大功能。组合应用这两个技术,可以用声明的方式编写更少量的代码,而且更便于维护。
ViewModel 是管理数据对象的类。允许其他对象绑定到该数据,当数据发生变更时通知对象。与视图控制器一样,ViewModel 也属于它关联的视图。通过组件的层次结构也可以关联到上级组件的 ViewModel。这使得子视图可以继承父视图 ViewModel 的数据。
组件有个 bind
配置属性,可以将组件的许多配置属性绑定到 ViewModel 的数据。通过数据绑定,当数据发生变化时,可以确保调用组件配置属性的 setter
方法,不用编写自定义的事件处理。
组件绑定-Component Binding
理解数据绑定和 ViewModel 最好的方法是了解一下组件绑定的各种方式。组件是使用数据绑定的主要对象。要使用数据绑定,首先要有引用一个 VieModel。
绑定和配置-Binding and Configs
组件的数据绑定,实际上就是将 Ext.app.ViewModel
的数据对象链接到组件的配置属性(config properties)的处理。组件的所有配置属性都可以绑定,只要该属性有一个 setter
方法。例如:Ext.panel.Panel
有一个 setTitle()
方法,所以可以绑定 title
配置项。
Ext.create('Ext.panel.Panel', {
title: 'Simple Form',
viewModel: {
type: 'test' // we will define the "test" ViewModel soon
},
bind: {
html: '<p>Hello {name}</p>',
width: '{someWidth}'
}
});
数据绑定的语法与 Ext.Template
的语法非常相似,将文本放在大括号内("braces")。也可以像 Ext.Template
那样使用格式化。
绑定布尔属性-Binding Boolean Configs
一些配置属性要求绑定布尔值,例如:visible
、hidden
、disabled
、checked
、pressed
等。 绑定模板支持以内联的方式( inline
)求 非
。其他的数学运算可以使用公式,但是布尔求非运算可以用 !
符号。例如:
Ext.create('Ext.panel.Panel', {
title: 'Simple Form',
viewModel: {
type: 'test'
},
items: [{
xtype: 'button',
bind: {
// negated
hidden: '{!name}'
}
}]
});
绑定优先级-Binding and Priority
数据绑定的配置属性将总是覆盖直接设置的配置属性。换句话说,绑定的数据比静态配置优先级高,但是会存在一定的延迟(需要获取数据)。
Ext.create('Ext.panel.Panel', {
title: 'Simple Form',
viewModel: {
type: 'test'
},
bind: {
title: 'Hello {name}'
}
});
当绑定的属性 name
有值时,原标题就会被替换。
绑定和子组件-Binding and Child Components
数据绑定非常有用的功能是,组件的所有子组件都可以访问组件的 ViewModel 的数据。例如:
Ext.create('Ext.panel.Panel', {
title: 'Simple Form',
viewModel: {
type: 'test'
},
layout: 'form',
defaultType: 'textfield',
items: [{
fieldLabel: 'First Name',
// uses "test" ViewModel from parent
bind: '{firstName}'
},{
fieldLabel: 'Last Name',
bind: '{lastName}'
}]
});
双向绑定-Two Way Binding
数据绑定允许使用双向绑定,在视图和实体模型之间同步数据。视图上发生变化的数据自动回写到模型中。这也将自动更新使用这些数据的其他组件。
备注:不是所有的配置属性在发生变更时都发布其变更值("publish")。
在 publish
和 twoWayBindable
数组中定义的配置属性才能自动回写到 ViewModel。也可以使用组件或应用的 publishState
方法发布变更值。完整的示例如下:
Ext.define('MyApp.view.TestViewModel', {
extend: 'Ext.app.ViewModel',
// connects to viewModel/type below
alias: 'viewmodel.test',
data: {
firstName: 'John',
lastName: 'Doe'
},
formulas: {
// We'll explain formulas in more detail soon.
name: function (get) {
var fn = get('firstName'), ln = get('lastName');
return (fn && ln) ? (fn + ' ' + ln) : (fn || ln || '');
}
}
});
Ext.define('MyApp.view.TestView', {
extend: 'Ext.panel.Panel',
layout: 'form',
// Always use this form when defining a view class. This
// allows the creator of the component to pass data without
// erasing the ViewModel type that we want.
viewModel: {
// references alias "viewmodel.test"
type: 'test'
},
bind: {
title: 'Hello {name}'
},
defaultType: 'textfield',
items: [{
fieldLabel: 'First Name',
bind: '{firstName}'
},{
fieldLabel: 'Last Name',
bind: '{lastName}'
},{
xtype: 'button',
text: 'Submit',
bind: {
hidden: '{!name}'
}
}]
});
Ext.onReady(function () {
Ext.create('MyApp.view.TestView', {
renderTo: Ext.getBody(),
width: 400
});
});
绑定和组件状态-Binding and Component State
有时一些组件的状态,例如:复选框的 checked
状态或者 grid
选择的记录等,与其他组件相关。当组件使用 reference
配置标识时,组件将在 ViewModel 中发布一些关键的属性。这种方法非常适用于动态表单。例如:
Ext.create('Ext.panel.Panel', {
title: 'Sign Up Form',
viewModel: {
type: 'test'
},
items: [{
xtype: 'checkbox',
boxLabel: 'Is Admin',
reference: 'isAdmin'
},{
xtype: 'textfield',
fieldLabel: 'Admin Key',
bind: {
disabled: '{!isAdmin.checked}'
}
}]
});
绑定描述符-Bind Descriptors
上述示例已经演示了三种绑定说明符:
- {firstName} - 直接绑定到 ViewModel 的一些值。
- Hello {name} - 绑定模板("bind template")。使用一些绑定表达式处理一些文本值,也可以使用格式化,例如:
'Hello {name:capitalize}'
。 - {!isAdmin.checked} - 布尔运算。
除了这些基本形式,还可以使用一些特殊的形式。
多重绑定-Multi-Bind
如果绑定描述符使用对象或数据,那么 ViewModel 将生成相同形式的对象或数组,用绑定的结果替换各个属性,例如:
Ext.create('Ext.Component', {
bind: {
data: {
fname: '{firstName}',
lname: '{lastName}'
}
}
});
记录绑定-Record Bind
当需要一个特殊记录时,绑定说明符可以是一个对象,并且设置 "reference" 属性。例如:
Ext.create('Ext.Component', {
bind: {
data: {
reference: 'User',
id: 42
}
}
});
上述示例中,组件的 tpl
接收 User 实体记录。这种方式需要使用 Ext.data.Session
。
关联绑定-Association Bind
与记录绑定相似,可以绑定关联的实体记录,例如:用户地址:
Ext.create('Ext.Component', {
bind: {
data: {
reference: 'User',
id: 42,
association: 'address'
}
}
});
绑定选项-Bind Options
最后一种形式是绑定选项。下述示例演示了如何从一个绑定只接收一个值,然后自动断开连接:
Ext.create('Ext.Component', {
bind: {
data: {
bindTo: '{name}',
single: true
}
}
});