[Ext JS6]视图模型和数据绑定

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/oscar999/article/details/85310641

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. 双向公式需要稳定。

猜你喜欢

转载自blog.csdn.net/oscar999/article/details/85310641
今日推荐