根据对MVVM中ViewModel的理解写的一个前端脚本

这几天对MVVM模式做了简单的理解. MVVM中的MV是MVC中的MV, 而VM是在View之前添加了一层前端的逻辑层ViewModel. 该Model中的对象针对前端显示提供数据和接口.  VM中有一部分功能是实现ViewModel和前端控件的自动绑定,包括读取和写入,我根据这个理解写了个简单的脚本,并进行了一次重构,写在这儿,权当整理.

1: 展示对象

展示对象很简单,本例中是一个用户信息,包括用户编号,用户名称和用户中文名称.所以对象应该如下定义:

js脚本:

function user_item() {
	this.no = "";
	this.name = "";
	this.cname = "";
	
	this.class_name = "user_item";
}

注: 本处class_name属性用来设置业务对象的名称. ViewModel和前端之间的映射关系当前约定为: viewMode.class_name + "." + viewMode.property为前端对象的id,例如: user_item的no属性,对应前端控件为:

创建ViewModel代码:

var user = new user_item();

2: 根据展示对象,设置3个前端控件

no:
name:
cname:

3: 在前端页面中,实现两个功能,自动读取页面控件的值写入ViewModel对象,将ViewModel对象中的值赋值给页面控件.

3.1 js代码:为user_item添加两个函数read和write.

其中read将页面控件值写入对象,write将对象属性设置到页面控件上.

为类添加成员函数,在js中需要使用prototype(我当前只会这一种)

3.1.1首先添加遍历成员变量的函数.

该函数有两个参数:要遍历的对象(obj)和对对象属性进行的操作(回调函数:ondo),并根据成员变量找到对应的控件,并将对象(obj),成员变量名称(field)和控件(control)作为回调函数的参数调用回调函数(ondo)

(注意: 遍历时,跳过函数成员和class_name变量)

function on_obj_properties(obj, ondo) {
	for (i in obj) {
		if (i != obj.class_name && typeof(obj[i]) != "function") {
			var name = "#" + obj.class_name + "\\." + i;
			var control = $(name);
			if (control != undefined) {
				ondo(obj, control, i);
			}
		}
	}
}

3.1.2 read函数

user_item.prototype.read = function() {
	on_obj_properties(this, function(obj, control, field){
		obj[field] = control.val();
	});
	return this;
}

3.1.3 write函数

user_item.prototype.write = function() {
	on_obj_properties(this, function(obj, control, field){
		control.val(obj[field]);
	});
}

3.1.4 完整的js代码(为data.js):

function user_item() {
	this.no = "";
	this.name = "";
	this.cname = "";
	
	this.class_name = "user_item";
}

function on_obj_properties(obj, ondo) {
	for (i in obj) {
		if (i != obj.class_name && typeof(obj[i]) != "function") {
			var name = "#" + obj.class_name + "\\." + i;
			var control = $(name);
			if (control != undefined) {
				ondo(obj, control, i);
			}
		}
	}
}

user_item.prototype.read = function() {
	on_obj_properties(this, function(obj, control, field){
		obj[field] = control.val();
	});
	return this;
}

user_item.prototype.write = function() {
	on_obj_properties(this, function(obj, control, field){
		control.val(obj[field]);
	});
}

3.2 前端测试

3.2.1要进行测试,需要在前端添加读取和写入的功能.添加read和write两个按钮:


3.2.2为按钮添加代码

点击页面中的write按钮会发现数据已经写入到控件,点击read按钮,会发现控件中的值已经写入ViewModel.

3.2.3 完整的前端代码



js test






no:
name:
cname:

4: 重构

每个ViewModel都会需要read和write,所以需要为ViewModel提供基类,ViewModel集成该类,read,write自动就有了,就不需要每个ViewModel都写了.

所以添加一个ViewModel的javascript基类:item_class, 代码如下

function item_class() {
}

item_class.on_obj_properties = function(obj, ondo) {
	for (i in obj) {
		if (i != obj.class_name && typeof(obj[i]) != "function") {
			var name = "#" + obj.class_name + "\\." + i;
			var control = $(name);
			if (control != undefined) {
				ondo(obj, control, i);
			}
		}
	}
}

item_class.prototype.read = function() {
	item_class.on_obj_properties(this, function(obj, control, field){
		obj[field] = control.val();
	});
	return this;
}

item_class.prototype.write = function() {
	item_class.on_obj_properties(this, function(obj, control, field){
		control.val(obj[field]);
	});
}

这样,user_item只需要集成该类即可, 代码如下:

user_item.prototype = new item_class();

5: 本例代码

5.1完成的js代码(data.js)

function item_class() {
}

item_class.on_obj_properties = function(obj, ondo) {
	for (i in obj) {
		if (i != obj.class_name && typeof(obj[i]) != "function") {
			var name = "#" + obj.class_name + "\\." + i;
			var control = $(name);
			if (control != undefined) {
				ondo(obj, control, i);
			}
		}
	}
}

item_class.prototype.read = function() {
	item_class.on_obj_properties(this, function(obj, control, field){
		obj[field] = control.val();
	});
	return this;
}

item_class.prototype.write = function() {
	item_class.on_obj_properties(this, function(obj, control, field){
		control.val(obj[field]);
	});
}

function user_item() {
	this.no = "";
	this.name = "";
	this.cname = "";
	
	this.class_name = "user_item";
}

user_item.prototype = new item_class();

前端代码



js test






no:
name:
cname:

6: 用Vue实现

VUE应该是天生支持 ViewModel的,使用VUE会使上面的代码更简单.

6.1 定义用户信息组件

6.1.1 定义组件模板

    

是必须的,否则,通不过编译.

在该组件中使用user_item作为参数.

需要使用v-model绑定参数的属性,否则(如果使用v-bind),属性不会与控件值自动绑定,特别是读取时.

6.1.2注册组件

 Vue.component('user-item', {
	props: ['user_item'],
	template: '#user-item'
});

6.1.3 HTML中使用组件

    
12

6.1.4 定义VUE

var save = new Vue({
	el: '#save_div',
	data: {
		user_item: {
			no : "a",
			name : "b",
			cname : "c",
		}
	}
});

定义事件:

function write_value() {
	save.user_item.no = "id1";
	save.user_item.name = "name2";
	save.user_item.cname = "cname3";
}

function read_value() {
	var text = "";
	for (i in save.user_item) {
		text += i + ":" + save.user_item[i] + ";";
	}
	alert(text);
}

6.1.5 完整代码

HTML:




    js test
    
    



    
12

data.js:

 Vue.component('user-item', {
	props: ['user_item'],
	template: '#user-item'
});

var save = new Vue({
	el: '#save_div',
	data: {
		user_item: {
			no : "a",
			name : "b",
			cname : "c",
		}
	}
});

function write_value() {
	save.user_item.no = "id1";
	save.user_item.name = "name2";
	save.user_item.cname = "cname3";
}

function read_value() {
	var text = "";
	for (i in save.user_item) {
		text += i + ":" + save.user_item[i] + ";";
	}
	alert(text);
}

7.vue 在组件中引用子组件

在当前的代码基础上,继续写着玩.

7.1 思考

在本案例中,no,name,cname是文本输入项.它们属于同一类, 可以概括为: 

前端显示标签或名称,中间是输入控件,后面可能会有提示信息等.而且可能会发生变化,例如将

no:

修改为:

*no:不可为空,只能是数字或字母

而且可能每个输入项都需要这样修改,应该怎么办呢?将其抽象为组件.

7.2 输入项组件

我们将输入项组件抽象为是否允许为空的注,输入项的标签, 输入项(例如input控件等:此处变化比较大,使用者应该可以根据需要自己决定怎么输入)

7.2.1 输入项组件的模板

注意: 模板中使用了slot,类似于freemarker中的nestat

7.2.2 组件注册

Vue.component('row-item', {
	props: ['ismust', 'label', 'user_item'],
	template: '#row-item'
});

7.3.3 修改user-item组件模板

   

7.4完整代码

7.4.1 HTML




    js test
    
    
 


    
12

7..4.2 data.js

Vue.component('user-item', {
	props: ['user_item'],
	template: '#user-item'
});

Vue.component('row-item', {
	props: ['ismust', 'label', 'user_item'],
	template: '#row-item'
});

var save = new Vue({
	el: '#save_div',
	data: {
		user_item: {
			no : "a",
			name : "b",
			cname : "c",
		}
	}
});

function write_value() {
	save.user_item.no = "id1";
	save.user_item.name = "name2";
	save.user_item.cname = "cname3";
}

function read_value() {
	var text = "";
	for (i in save.user_item) {
		text += i + ":" + save.user_item[i] + ";";
	}
	alert(text);
}

 

你可能感兴趣的:(前端开发,javascript,面向对象,继承,类,MVVM)