【MUI晋级】开发MUI自定义表单插件一,基础插件模板搭建
【MUI晋级】开发MUI自定义表单插件二,插件封装
上一篇我们讲了基本的插件模板和mui的样式重置,今天来说一下如何在插件模板的基础上封装成插件!
使用自定义表单有如下好处
- 可以后台配置表单内容
- 新增页、编辑页可以共用一段代码
- 方便表单内容的获取
首先要说明一下我们的自定义表单要实现哪些功能,才能更好去封装
- 通过JS生成form表单,表单类型、默认值、样式、提示文字都可以自由定义
- 每个表单项都可以绑定多个事件
- 要有表单提交事件,可以实时的获取表单的值
一、通过JS生成form表单
我们首先先观察一些DOM结构
可以得出以下结论
- 存放表单的容器是必须的,初始化参数一定要有
- form节点只有一个,但是class需要设置
- 每一项的BOX容器是多个,所以初始化参数一定是一个数组
- 标题元素需要设置class和文字
- input需要设置的就比较多了,各种属性,而且还不仅仅是 input
根据以上结论,我们先写一个初始化参数,打开 customForm.js ,编写原来写好的defaultConfig 的值
//默认参数
var defaultConfig = {
storageBox:null, //存放表单的容器
formNode:{ //表单节点
id:"", //表单的ID
className:"", //表单的样式,多个样式用空格隔开
submitFn:null //表单提交事件
},
formItems:[{ //表单列表项
boxClass:"", //box容器的样式名
titleText:"", //标题元素的文字
titleClass:"", //标题元素的样式
input:{ //input的一些配置项
tagName:"", //input的标签名,如input、select、textarea
attr:{ //input的属性配置项,键为属性名,值为属性值
id:'',
name:'' //只要是合法的input属性都可以写到这里,还有很多就不列举了
},
event:{ //事件列表,只要是合法的事件名都可以
tap:function(){
},
focus:function(){
}
},
value:"", //input和textarea用字符串格式
value:[{ //select的用数组格式
text:"", //显示的文字
value:'', //值
isSelected:true //是否选中
}]
}
defaultClass:{ //在未设置样式的情况下使用默认样式
formNodeClass:"mui-input-group", //form节点默认样式
formItemClass:'mui-input-row', //表单每一项的box容器样式
inputClass:'mui-input-clear' //input的样式
}
}]
};
我们把 defaultConfig 分为了4大块
- storageBox 存放表单的容器,Element类型
- formNode 表单节点
- formItems 表单列表项
- defaultClass 默认样式
但是我们的默认值只能存一个 defaultClass 默认样式,其他的都需要作为初始化参数传进来,所以将我们刚才写的 defaultConfig注释掉,重新写一个并更改为如下
var defaultConfig = {
defaultClass:{ //在未设置样式的情况下使用默认样式
formNodeClass:"mui-input-group", //form节点默认样式
formItemClass:"mui-input-row", //表单每一项的box容器样式
inputClass:"mui-input-clear" //input的样式
}
};
更改init方法
我们需要更改一下插件模板的init方法,来检查下初始化参数的正确性并打印一下合并默认参数之后的值
init:function(arg){
var self = this;
if(arg) {
if(arg.storageBox && arg.storageBox.nodeType === 1) {
//将初始化参数和默认参数合并,并存放到对象的config属性下
self.config = $.extend(arg, defaultConfig);
console.log(self.config);
} else {
self._logError("初始化参数[storageBox]参数未设置或者不是Element类型", true);
}
} else {
self._logError("初始化参数不存在");
}
return self;
}
前台调用方法
//初始化参数
var customFormCg = {
storageBox:mui(".mui-content")[0]
};
//实例化
var customForm = new mui.customForm(customFormCg);
谷歌浏览器下截图,编辑器的控制台只能输出一个 "[object Object]",没法查看详细信息
当做到这一步就说明你的插件初始化已经成功了,接下来我们写一个 _InitHtml 方法来创建form表单,并修改init方法让其调用_InitHtml方法;
/** 实例化调用函数
* -------------------------
* @param {Object} arg 插件配置参数
*/
init:function(arg){
var self = this;
if(arg) {
if(arg.storageBox && arg.storageBox.nodeType === 1) {
//将初始化参数和默认参数合并,并存放到对象的config属性下
self.config = $.extend(arg, defaultConfig);
self._InitHtml();
} else {
self._logError("初始化参数[storageBox]参数未设置或者不是Element类型", true);
}
} else {
self._logError("初始化参数不存在");
}
return self;
},
/**
* 内部方法,初始化html
*/
_InitHtml:function(){
var self = this, //缓存this
cg = self.config; //取到配置信息
alert(1);
return self;
},
如果能弹出个1说明你又成功了~,接下来继续编写 _InitHtml方法
/**
* 内部方法,初始化html
*/
_InitHtml:function(){
var self = this, //缓存this
cg = self.config; //取到配置信息
/* 1. 创建form节点存到对象配置信息里面的formNode下的node里面,并设置样式 */
!cg.formNode && (cg.formNode = {});
var form = cg.formNode['node'] = dom.createElement('form');
form.className = cg.formNode.className || cg.defaultClass.formNodeClass || "";
/* 2.创建表单项 */
if(cg.formItems && Array.isArray(cg.formItems)){
for(var i = 0,l = cg.formItems.length;i<l;i++){
var item = cg.formItems[i], //缓存当前循环条目
itemInput = item.input, //input配置项
itemBox = item['itemBox'] = dom.createElement("div"), //每一项的box容器
titleEl = item['titleEl'] = dom.createElement("label"), //标题元素
inputEl = item['inputEl'] = dom.createElement(itemInput.tagName || 'input');//input元素
//设置class
itemBox.className = item.boxClass || cg.defaultClass.formItemClass || '';
titleEl.className = item.titleClass || '';
inputEl.className = cg.defaultClass.inputClass || '';
//设置标题文字信息
titleEl.innerText = item.titleText || '';
//设置input属性
for(var key in itemInput.attr){
inputEl.setAttribute(key,itemInput.attr[key]);
}
//设置input的value
if(itemInput.value){
switch(inputEl.tagName.toLowerCase()){
case 'select':
if(Array.isArray(itemInput.value)){
//注意此处不要用i来当做循环索引了
for(var x = 0;x<itemInput.value.length;x++){
var option = dom.createElement('option');
option.setAttribute("value", itemInput.value[x].value);
option.innerText = itemInput.value[x].text;
itemInput.value[x].isSelected && option.setAttribute('selected', 'selected');
inputEl.appendChild(option);
}
}else{
self._logError("当tagName为select时,input下的value属性必须为数组格式");
}
break;
default:
inputEl.value = itemInput.value;
}
}
//追加元素
itemBox.appendChild(titleEl);
itemBox.appendChild(inputEl);
form.appendChild(itemBox);
}
}
//将form节点追加到存放表单的容器里面
cg.storageBox.appendChild(form);
return self;
}
将前台“mui-content”里面的内容注释掉,然后修改前台初始化参数 customFormCg
//初始化参数
var customFormCg = {
storageBox:mui(".mui-content")[0],
formNode:{
id:"mainForm"
},
formItems:[{
titleText:'客户名称',
input:{
attr:{
type:"text",
id:"clientName",
name:"clientName",
placeholder:"请输入客户名称"
}
}
},{
titleText:'客户地址',
input:{
attr:{
type:"text",
id:"clientAddress",
name:"clientAddress",
readonly:"readonly",
placeholder:"点击选择客户地址"
}
}
},{
titleText:'客户电话',
input:{
attr:{
type:"number",
id:"clientTel",
name:"clientTel",
placeholder:"请输入客户联系电话"
},
value:"18866655444"
}
},{
titleText:'客户级别',
input:{
tagName:'select',
attr:{
type:"number",
id:"clientTel",
name:"clientTel",
placeholder:"请输入客户联系电话"
},
value:[{
text:"A级",
value:1
},{
text:"B级",
value:2
},{
text:"C级",
value:3,
isSelected:true
}]
}
},{
titleText:'备注',
input:{
tagName:"textarea",
attr:{
id:"clientTel",
name:"clientTel",
placeholder:"请输入备注信息"
},
}
}]
};
如果你得得到如下截图就说明你成功了~
接下来我们写一个 getValues 的外部方法用来获取表单参数,我们接受一个input的id组成的数组,可以指定返回结果,如果不传则返回表单全部内容;
/** 获取表单内容
* @param {array} ids 指定的input ID数组
* @return {JSON} id为键,value值为值
*/
getValues:function(ids){
var self = this,
cg = self.config;
var data = {},
isAge = ids && Array.isArray(ids);
for(var i = 0; i < cg.formItems.length; i++) {
var item = cg.formItems[i],
inputEl = item['inputEl'],
inputElId = inputEl.getAttribute("id");
if(isAge && ids.indexOf(inputElId) == -1) {
continue;
} else {
data[inputElId] = inputEl.value;
}
}
return data;
},
为前台的header里面的保存按钮增加一个id “saveBtn”
在index.html里面的JS部分为其绑定事件
document.getElementById("saveBtn").addEventListener("tap",function(){
console.log(JSON.stringify(customForm.getValues()));
});
在浏览器里面点下保存看能否正常打印出信息
附带参数测试
console.log(JSON.stringify(customForm.getValues(['clientName','clientTel','clientLv'])));
到此初始化HTML就完结了,接下来该绑定事件了
二、绑定事件
绑定的事件主要有两个一个是form提交事件,另一个是input的事件,我们写一个内部方法 _EventInit
_EventInit:function(){
var self = this,
cg = self.config;
//表单提交事件
cg.formNode['node'].addEventListener("submit",function(e){
e.preventDefault(); //阻止提交
cg.formNode.submitFn && cg.formNode.submitFn(self);
});
//为input绑定事件
for(var i = 0;i<cg.formItems.length;i++){
var item = cg.formItems[i];
for(var key in item.input.event){
bindEvent(item.inputEl,key,item.input.event[key]);
}
}
/** 内部调用函数
* --------------
* @param {Object} eNode 事件节点
* @param {Object} eName 事件名
* @param {Object} eFn 事件函数
*/
function bindEvent(eNode,eName,eFn){
eNode.addEventListener(eName,eFn);
}
return self;
}
更改 init 方法,这就是我们之前说的链式调用
self._InitHtml()._EventInit();
前台为客户地址添加一个 tap 事件,看能否正常弹出一个1
{
titleText:'客户地址',
input:{
attr:{
type:"text",
id:"clientAddress",
name:"clientAddress",
readonly:"readonly",
placeholder:"点击选择客户地址"
},
event:{
tap:function(){
alert(1);
}
}
}
}
如果成功了,其他的事件添加方法类似,比如focus、blur、change等事件。接下来我们来测试一下表单提交事件!
将初始化参数 formNode 修改为如下
formNode:{
id:"mainForm",
submitFn:function(){
alert("我触发了表单提交事件!");
}
}
然后将 saveBtn 绑定事件修改一下
document.getElementById("saveBtn").addEventListener("tap",function(){
customForm.config.formNode.node.submit();
});
然后你会发现.......尼玛竟然没反应,这是正常的,因为submit()并不会触发onsubmit(在绑定事件的时候on都是去掉的,所以我们绑定的是submit事件),我们换一个思路,我们直接触发表单的submit事件不就可以了吗,正好mui有这个方法 MUI事件触发,我们修改一下代码
document.getElementById("saveBtn").addEventListener("tap",function(){
mui.trigger(customForm.config.formNode.node,'submit');
});
这次可以这场的弹出信息,但是这样的写法太麻烦了,所以我们要为 customForm 在扩展一个 onSubmit 的方法
/**
* 主动触发表单提交
*/
onSubmit: function(){
var self = this;
mui.trigger(self.config.formNode.node,'submit');
return self;
},
然后修改事件绑定
document.getElementById("saveBtn").addEventListener("tap",function(){
customForm.onSubmit();
});
到此我们的自定义表单算是完成了,当然还有其他的一些地方要做,比如这样的情况
还有这样的
还有最常用的表单验证,这些这就需要你来修改一下代码,动动小脑筋了。还有如何适应多种表单情况都需要自己不断的尝试