1. 程式人生 > >[Ext JS6]檢視模型和資料繫結

[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)
                });
            }
        }
    }
});

開發建議

為避免濫用和記憶體洩漏, 一些最佳實踐:

  1. 使用 type來配置使用檢視模型
Ext.define('MyApp.view.TestView', {
      //...
      viewModel: {
          type: 'test'
      },
  });

  1. 命名顯而易見

  2. 不必要的話不要在物件中巢狀資料

  3. 使用子的檢視模型,在元件需要的時候可以清理資料

  4. 若非必要,不要建立子檢視模型
    6.使用公式替換重複繫結

  5. 公式不要太深

  6. 雙向公式需要穩定。