本文从简的演示利用Composite Pattern来动态创建form,它支持保存和还原上次输入的数据。
第一步,定义接口:
var Composite =
new Interface("Composite", ["add", "remove", "getChild"]);
var FormItem =
new Interface("FormItem", ["save", "restore", "getElement"]);
你懂的,这里是基于single responsibility rule将接口分为2个。
然后,分别来实现2个接口了:
var CompositeForm =
function (id, method, action) {
this.formComponents = [];
this.element = document.createElement("form");
this.element.id = id;
this.element.method = method || "post";
this.element.action = action || "#";
};
CompositeForm.prototype = {
add:
function (child) {
Interface.ensureImplements(child, [Composite, FormItem]);
this.formComponents.push(child);
this.element.appendChild(child.getElement());
},
remove:
function (child) {
for (
var i = 0; i <
this.formComponents.length; i++) {
if (
this.formComponents[i] == child) {
this.formComponents.splice(i, 1);
this.element.removeChild(child.getElement());
break;
}
}
},
getChild:
function (i) {
if (i >=
this.formComponents.length) {
throw
new Error("i is out of range.");
}
return
this.fromComponents[i];
},
save:
function () {
for (index
in formComponents) {
this.formComponents[index].save();
}
},
restore:
function () {
for (index
in formComponents) {
this.formComponents[index].resotre();
}
},
getElement:
function () {
return
this.element;
}
};
CompositeForm.prototype.constructor = CompositeForm;
//
composite fieldset
var CompositeFieldset =
function (id, legendText) {
this.components = {};
this.element = document.createElement("fieldset");
this.element.id = id;
if (legendText) {
this.legend = document.createElement("legend");
this.legend.appendChild(document.createTextNode(legendText));
this.element.appendChild(
this.legend);
}
};
CompositeFieldset.prototype = {
add:
function (child) {
Interface.ensureImplements(child, [Composite, FormItem]);
this.components[child.getElement().id] = child;
this.element.appendChild(child.getElement());
},
remove:
function (child) {
delete
this.components[child.getElement().id];
this.element.removeChild(child.getElement());
},
getChild:
function (id) {
return
this.components[id];
},
save:
function () {
for (index
in components) {
if (components.hasOwnProperty(index)) {
this.fieldset[index].save();
}
}
},
restore:
function () {
for (index
in components) {
if (components.hasOwnProperty(index)) {
this.fieldset[index].resotre();
}
}
},
getElement:
function () {
return
this.element;
}
};
CompositeFieldset.prototype.constructor = CompositeFieldset;
//
field abstract class
var Field =
function (id) {
this.element = document.createElement('div');
this.element.id = id;
this.element.className = 'input-field';
};
Field.prototype = {
add:
function (child) {
},
remove:
function (i) {
},
getChild:
function (i) {
},
save:
function () {
setCookie(
this.id,
this.getValue());
},
resotre:
function () {
var value = getCookie(
this.id);
setValue(value);
},
getElement:
function () {
return
this.element;
},
getValue:
function () {
throw
new Error("Unimplemented on the class Field.");
},
setValue:
function () {
throw
new Error("Unimplemented on the class Field.");
}
};
Field.prototype.constructor = Field;
//
input field class
var InputField =
function (id, label) {
this.superClass.constructor.call(
this, id);
this.input = document.createElement('input');
this.input.id = id + "_input";
this.label = document.createElement('label');
this.label.id = id + "_label";
var labelTextNode = document.createTextNode(label);
this.label.appendChild(labelTextNode);
this.element.appendChild(
this.label);
this.element.appendChild(
this.input);
};
extend(InputField, Field);
InputField.prototype.getValue =
function () {
return
this.input.value;
};
InputField.prototype.getValue =
function (value) {
this.input.value = value;
};
//
textarea field class
var TextAreaField =
function (id, label) {
this.superClass.constructor.call(
this, id);
this.textArea = document.createElement('textarea');
this.textArea.id = id + "_textarea";
this.label = document.createElement('label');
this.label.id = id + "_label";
var labelTextNode = document.createTextNode(label);
this.label.appendChild(labelTextNode);
this.element.appendChild(
this.label);
this.element.appendChild(
this.textArea);
};
extend(TextAreaField, Field);
TextAreaField.prototype.getValue =
function () {
return
this.textArea.value;
};
TextAreaField.prototype.getValue =
function (value) {
this.textArea.value = value;
};
//
select field class
var SelectField =
function (id, label, options) {
this.superClass.constructor.call(
this, id);
this.select = document.createElement('select');
this.select.id = id + "_select";
for(
var i = 0;i<options.length;i++){
var option = document.createElement("option");
option.text = options[i].text;
option.value = options[i].value;
try{
this.select.add(option,
this.select.options[
null]);
}
catch(e){
this.select.add(option,
null);
}
}
this.label = document.createElement('label');
this.label.id = id + "_label";
var labelTextNode = document.createTextNode(label);
this.label.appendChild(labelTextNode);
this.element.appendChild(
this.label);
this.element.appendChild(
this.select);
};
extend(SelectField, Field);
SelectField.prototype.getValue =
function () {
return
this.select.options[
this.select.selectedIndex].value;
};
SelectField.prototype.getValue =
function (value) {
for (index
in
this.select.options) {
if (
this.select.options[index].value == value) {
this.select.selectedIndex = index;
break;
}
}
};
测试代码如下:
var
contactForm =
new
CompositeForm("contactForm", "post", "contact.php");
var nameFieldset =
new CompositeFieldset('nameFieldset', "Name");
nameFieldset.add(
new InputField("firstName", "First Name"));
nameFieldset.add(
new InputField("lastName", "Last Name"));
contactForm.add(nameFieldset);
var addressFieldset =
new CompositeFieldset('addressFieldset', "Address");
addressFieldset.add(
new InputField("address", "Address"));
addressFieldset.add(
new SelectField("state", "State", [{"text": "Alabama", "value": "Alabama"}, {"text": "Seattle", "value": "Seattle"}]));
addressFieldset.add(
new InputField('zip', 'Zip'));
contactForm.add(addressFieldset);
contactForm.add(
new TextAreaField('comments', 'Comments'));
body.appendChild(contactForm.getElement());
addEvent(window, "load", contactForm.restore);
addEvent(window, "unload", contactForm.save);
这里不再详细解释了,注意Field类是abstract的即可。 download