[Ext JS6]檢視模型和資料繫結
文章目錄
ViewModel
ViewModel是一個管理資料物件的類, 它執行對它感興趣的元件繫結它並在變化的時候得到通知。ViewModel和ViewController一樣,是屬於某個 View的。子檢視可以繼承父的檢視模型。
使用 bind的配置來繫結資料,當資料發生改變時,會呼叫對應的 setter方法。
元件繫結
元件是資料繫結的主要方式。
繫結的配置需要有setter方法,比如Panel 的title配置,title有setTitle()方法, 所有可以繫結資料。
以width為例(有setWidth()方法)
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。
如果繫結布林型別的值的話,
bind: {
hidden: '{!name}' // negated
}
name也可是一個String型別。
繫結的優先順序
資料繫結一般要優先於靜態配置。
子元件的繫結
一個元件的所有子元件可以訪問這個元件的 viewModel
看例項:
Ext.create('Ext.panel.Panel', { title: 'Simple Form', viewModel: { type: 'test' }, layout: 'form', defaultType: 'textfield', items: [{ fieldLabel: 'First Name', bind: '{firstName}' // uses "test" ViewModel from parent },{ fieldLabel: 'Last Name', bind: '{lastName}' }] });
雙向繫結
雙向繫結意味著檢視和模型的資料實時同步。 檢視的資料改變自動寫到模型中。這回自動更新繫結到同一資料的其他元件。
需要注意的是並不是所有的配置都會將其更改釋出到 ViewModel。
定義publish和twoWayBindable會將改動寫回ViewModel。使用publishState方法也可以在元件和應用邏輯之間釋出資料。
publish和twoWayBindable是元件的配置項。支援一個或多個屬性。看個例子:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>View Model</title>
<script type="text/javascript" src="../ext/build/ext-all-debug.js"></script>
<link href="../build/development/Extjs6App/classic/resources/Extjs6App-all.css" rel="stylesheet" type="text/css" />
<script>
//1.定義使用者的檢視模型
Ext.define('Osxm.view.UserViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.user', // 使用hello獲取該model
data: {
firstName: 'chen',
lastName: 'oscar'
},
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 || '');
}
}
});
//2.定義使用者的檢視元件
Ext.define('MyApp.view.UserView', {
extend: 'Ext.panel.Panel',
layout: 'form',
viewModel: {
type: 'user' // 使用檢視模型的alias屬性:"viewmodel.user"
},
bind: {
title: 'Hello {name}'
},
defaultType: 'textfield',
items: [{
fieldLabel: 'First Name',
bind: '{firstName}'
},{
fieldLabel: 'Last Name',
bind: '{lastName}'
},{
xtype: 'button',
text: 'Submit',
bind: {
hidden: '{!name}'
}
}]
});
</script>
<script>
Ext.onReady(function() {
Ext.create('MyApp.view.UserView', {
renderTo : Ext.getBody(),
width : 400
});
});
</script>
</head>
<body>
</body>
</html>
例項效果如下:
標題的顯示和按鈕是否顯示會根據輸入框的值動態改變。
也就是:
檢視模型的值改變了, 會反應到檢視上。
檢視上的值進行修改, 檢視模型的值也會修改。
繫結和元件狀態
某些時候元件的狀態, 類似checkbox是否選中或是 Gird中選擇一行,對其他的元件會有影響。當一個元件有使用reference?來表示,這個元件會在檢視模型中釋出一些關鍵的屬性。
Ext.create('Ext.panel.Panel', {
title : 'Login Form',
width : 200,
viewModel : {
},
renderTo : Ext.getBody(),
items : [ {
xtype : 'checkbox',
boxLabel : 'Manual Login',
reference : 'manualLogin'
}, {
xtype : 'textfield',
fieldLabel : 'User Name',
bind : {
disabled : '{!manualLogin.checked}'
}
} ]
});
之上只有’Manual Login’這個複選框選中, 才可以在輸入框中進行輸入。
這裡雖然viewModel中沒有設定, 但是viewModel不能少, 好的做法是定義實際的viewModel型別。
多值繫結
也可以繫結多個值
Ext.create('Ext.Component', {
bind: {
data: {
fname: '{firstName}',
lname: '{lastName}'
}
}
});
繫結記錄
也可以繫結一個Store中的記錄
Ext.create('Ext.Component', {
bind: {
data: {
reference: 'User',
id: 42
}
}
})
User是Ext.data.Session型別。
關聯繫結
Ext.create('Ext.Component', {
bind: {
data: {
reference: 'User',
id: 42,
association: 'address'
}
}
});
繫結的選項設定
bindTo
繫結一個值後自動斷開連線
Ext.create('Ext.Component', {
bind: {
data: {
bindTo: '{name}',
single: true
}
}
});
deep-物件屬性改變得到通知
Ext.create('Ext.Component', {
bind: {
data: {
bindTo: '{someObject}',
deep: true
}
}
});
檢視模型公式
公式例項:
Ext.define('Osxm.view.FormulasViewMode', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.formulavm',
data:{
x:1,
y:2
},
formulas: {
x2y: function (get) {
return get('x2') * get('y');
},
x2: function (get) {
return get('x') * 2;
}
}
});
Ext.create('Ext.panel.Panel', {
title : 'Formulas View Model',
width : 200,
viewModel : {
type : 'formulavm'
},
renderTo : Ext.getBody(),
defaultType : 'textfield',
items : [ {
xtype : 'textfield',
fieldLabel : 'x',
bind : '{x}'
} ,{
xtype : 'textfield',
fieldLabel : 'y',
bind : '{y}'
} ,{
xtype : 'textfield',
fieldLabel : 'x*2',
bind : '{x2}'
} ,{
xtype : 'textfield',
fieldLabel : 'x*2*y',
bind : '{x2y}'
}]
});
比較好的是使用顯式繫結:
x3:{
bind: {
x: '{x}',
y: '{y}'
},
get: function (data) {
return data.x + data.y; //這裡是字串相加
}
}
雙向公式
可以通過set方法實現雙向公式, 類似:
Ext.define('MyApp.view.TestViewModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.test',
formulas: {
name: {
get: function (get) {
var fn = get('firstName'), ln = get('lastName');
return (fn && ln) ? (fn + ' ' + ln) : (fn || ln || '');
},
set: function (value) {
var space = value.indexOf(' '),
split = (space < 0) ? value.length : space;
this.set({
firstName: value.substring(0, split),
lastName: value.substring(split + 1)
});
}
}
}
});
開發建議
為避免濫用和記憶體洩漏, 一些最佳實踐:
- 使用 type來配置使用檢視模型
Ext.define('MyApp.view.TestView', {
//...
viewModel: {
type: 'test'
},
});
-
命名顯而易見
-
不必要的話不要在物件中巢狀資料
-
使用子的檢視模型,在元件需要的時候可以清理資料
-
若非必要,不要建立子檢視模型
6.使用公式替換重複繫結 -
公式不要太深
-
雙向公式需要穩定。