【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();
});
到此我們的自定義表單算是完成了,當然還有其他的一些地方要做,比如這樣的情況
還有這樣的
還有最常用的表單驗證,這些這就需要你來修改一下代碼,動動小腦筋了。還有如何適應多種表單情況都需要自己不斷的嘗試