自开发vue插件笔记 2》可编辑表格表单

403 阅读2分钟

思路描述

  • 创建一个动态的Component(输入框,日期选择,下拉框)列表,与table的列绑定(动态的Component见1)
  • 声明一个EditRowModel与Component对应绑定当Component组件变化时,双向绑定到EditRowModel中
  • 编辑某一行时,将该行锁绑定的row对象值复制到EditRowModel中,同时将Component组件复制到对应的tableCell中,此时就会显示编辑行
  • 结束编辑时,将EditRowModel复制倒正在编辑行对应的row对象中。

代码TableFormRowEdit

//表格编辑
function TableFormRowEdit(option, formCom, dataTag, pro_tableId,isMul) {
    //配置
    var self = this;
    var fieldCtrls = []; //编辑列
   // var tempCtrlComponent = {};//临时组件列表
   // option.data.FormModel.DeleteRows = [];
    //增加行
    option.methods["FormModel_"+dataTag+"_addRow"] = function (newRow,index) {
        //如果非编辑状态不触发
        if (!formCom.vm.isEditing) return false;  
        if (isMul) {
            self.initEditDataModel(function () {
                if (index == undefined) { index = formCom.vm.DataModel[dataTag].DataRows.length; }
                var curRow = formCom.addRow(dataTag, newRow, index);
                    Vue.nextTick(function () {
                        self.editRow(curRow, index);
                    });                                           
            });           
        } else {          
            self.endEdit();
            formCom.vm.selectedIndex = -1;
            self.initEditDataModel(function () {
                index = formCom.vm.DataModel[dataTag].DataRows.length;
                formCom.addRow(dataTag, newRow, index);
            });
        }
    };

    //编辑行
    option.methods["FormModel_" + dataTag + "_modifyRow"]= function (mRow, index) {
        //如果非编辑状态不触发
      
        var vm = this;
        if (!vm.isEditing) return false;
        self.endEdit();
        if (mRow.DataState == "UA") {
            mRow.DataState == "A";
        } else if (mRow.DataState == "U") {
            mRow.DataState == "M";
        }
        self.beginEdit(mRow, index);

    }

    //选中行
    option.methods["FormModel_" + dataTag + "_selectRow"] = function (mRow, index) {
        var e = window.event; //当前事件
        var vm = this;
        //判断
        if (vm.selectedIndex == index) { return false; }

        //
        vm.selectedIndex = index;

        vm["FormModel_" + dataTag + "_modifyRow"](mRow, index);
        //获取焦点
        window.setTimeout(function () {
            var el = e.target;
            if (el.tagName == "DIV") { el = el.parentNode; }
            $(el).find("input").trigger("focus");
        }, 0);
    }

    //移除行
    option.methods["FormModel_" + dataTag + "_removeRow"] = function (index) {
        if (!formCom.vm.isEditing) return false;
        if (index == undefined) index = formCom.vm.selectedIndex;
        var dataX= formCom.vm.DataModel[dataTag];
        if (dataX.DataRows.length>index > -1) {
            if (!dataX.deletedRows) dataX.deletedRows = [];
            var mRow = dataX.DataRows[index];
            if (mRow.DataState == "A" || mRow.DataState == "UA") {           
            } else {
                mRow.DataState = "D";
                dataX.deletedRows.push(mRow);
            }
            self.removeRow(index);
        }
    }
    //设置编辑列  
    this.setFieldCtrl = function (fieldIndex, ctrl) {
        if (typeof (fieldIndex) != "number") { return; }
        if (fieldIndex < 0) return;     
        if (fieldIndex > fieldCtrls.length - 1) { //填充生成序列
            for (var i = fieldCtrls.length - 1; i < fieldIndex; i++) {
                fieldCtrls.push("");
            }
        }
        //插入
        var oCtrl = ctrl;
        if (oCtrl) fieldCtrls.splice(fieldIndex, 1, oCtrl);
    }
    //开启编辑
    var obj_tb;
    var oldRow;
    this.beginEdit = function (mRow, index) {

        //缓存原对象
        if (!mRow || oldRow == mRow) {
            return;
        }
        oldRow = mRow;
        var rootVM = formCom.vm;
      
        rootVM.FormModel[dataTag].EditRowModel = JSON.parse(JSON.stringify(mRow));
         obj_tb = $("#" + pro_tableId)[0];
        if (!obj_tb) { return; }

        //以下生成编辑框
        var iLen = fieldCtrls.length;
        var oCells = obj_tb.tBodies[0].rows[index].cells;
        for (var i = 0; i < iLen; i++) {
            var o = fieldCtrls[i];
            if (!o || !o.type) { continue; } //o不存不处理
            var currentCell = oCells[i];
            //生成插入元素
            if (o.type == "DropList" || o.type == "TextBox" || o.type == "DatePick" || o.type == "CheckBox" ) {             
                var $ov = $(oCells[i].firstChild); //原内容隐藏
                if ($ov) { $ov.hide() } else { $(currentCell).text(""); };

                (function (o, currentCell) {
                    var component;
                    if (!o.component) {
                        var cOption = {
                            propsData: {
                                myValue: mRow.DataRow[o.fieldName],
                                valueEmit: function (val) {  //与外面mrow联动
                                  //  .DataRow[o.fieldName] = val;
                                var editRow = rootVM.FormModel[dataTag].EditRowModel;
                                    return editRow;
                                }
                            }
                        };
                            o.component = new o.extendComponent(cOption).$mount()
                        }
                    component = o.component;
                    component.myValue = mRow.DataRow[o.fieldName];

                    currentCell.appendChild(component.$el);
                })(o, currentCell);
             
                
            }

        }

      
    };

    //结束编辑
    this.endEdit = function (mRow, index) {
        if (!obj_tb) obj_tb = $("#" + pro_tableId)[0];
        if (!obj_tb) { return; }
        var iLen = fieldCtrls.length;
      //  var oCells = obj_tb.tBodies[0].rows[index].cells;
        //恢复现场
        var editRow = formCom.vm.FormModel[dataTag].EditRowModel
        if (editRow) {
            if (oldRow.DataRow) oldRow.DataRow = JSON.parse(JSON.stringify(editRow.DataRow));
        }
        for (var i = 0; i < iLen; i++) {
            var o = fieldCtrls[i];
            if (o && o.component && o.component.$el) {
                var oCell = o.component.$el.parentNode; //td
                if (!oCell) continue;
                oCell.removeChild(oCell.lastChild);

                var $ov = $(oCell.firstChild); //原内容恢复
                $ov.show();
                //if (mRow) {
                //    mRow.DataRow[o.name] = o.component.myValue;
                //} else {
                //if ($ov.length > 0) {
                //    $ov.text(o.component.myValue);
                //} else {
                //    oCell.innerText = o.component.myValue;
                //}
               // }
            }
        }

        oldRow = {};

    };

    //移除行并返回移除的对象(传入index或对象row)
    this.removeRow = function (x) {
        var datarows = formCom.vm.DataModel[dataTag].DataRows;
        var index = -1;
        var mRow = null;
        if (typeof x == "number") {
            index = x; mRow = datarows[index];
        }
        if (typeof x == "object") {
            mRow = x;
            for (var i = datarows.length; i > 0; i--) {
                if (datarows[i - 1] == mRow) {
                    index = i - 1; break;
                }
            }
        }
        if (index > -1 && mRow) { 
            datarows.splice(index, 1);
        }
    }
    //初始化编辑行,制造一个空的datarow
    this.initEditDataModel = function (callBack) {
        if (!window.tempObjModel) {
            window.tempObjModel = {};
        }
        if (window.tempObjModel[dataTag]) { if (typeof (callBack) == "function") callBack(); return; }

        var dataRows = formCom.vm.DataModel[dataTag].DataRows;
        if (dataRows.length > 0) {
            var tempObj = {};
            $.extend(true, tempObj, window["CustomerModel_" + dataTag] || dataRows[0]);
            tempObj.DataState = "UA"; //中间态
            delete tempObj["IsOpenEdit"]; delete  tempObj["_uid"]; //删除附加属性
            formCom.clearTemplateModel(tempObj);
            window.tempObjModel[dataTag] = tempObj;
            if (typeof (callBack) == "function") callBack();
        } else {
            var url = formCom._baseUrl;
            var action = formCom.getAction;
            if (!action) action = "/addData";
            url = url + action;
            Vue.$http.get(url, {}, function (data, status) {
                var tempObj = {}; ;
                $.extend(true, tempObj, window["CustomerModel_" + dataTag] || data[dataTag].DataRows[0]);
                tempObj.DataState = "UA"; //中间态
                formCom.clearTemplateModel(tempObj);
                window.tempObjModel[dataTag] = tempObj;
                if (typeof (callBack) == "function") callBack();
            });
        }
    }



     //******以下单表格编辑start*******************
    if (isMul) {
    var oldRowModels = {}; //缓存编辑的旧值
    //关闭编辑框--允许多行有用
    //this.closeEdit = function (mRow, index) {
    //    if (!obj_tb) obj_tb = $("#" + pro_tableId)[0];
    //    if (!obj_tb) { return; }
    //    var iLen = fieldCtrls.length;
    //    //恢复现场-还原现场
    //    for (var i = 0; i < iLen; i++) {
    //        var o = fieldCtrls[i];
    //        var component = tempCtrlComponent["row_" + mRow._uid  + "_index_" + i];
    //        if (o && component && component.$el) {
    //            var oCell = component.$el.parentNode; //td
    //            if (!oCell) continue;

    //            oCell.removeChild(oCell.lastChild); //解除引用
    //            var $ov = $(oCell.firstChild); //原内容恢复
    //            if ($ov) { $ov.show(); } else { $(oCell).text(mRow[o.DataRow.name]); }

    //            component = null;//销毁对象
    //            tempCtrlComponent["row_" + mRow._uid + "_index_" + i] = null;
    //        }
    //    }

    //    //释放缓存
    //    oldRowModels["index_" + mRow._uid] = undefined;
    //    oldRow = {};
    //    }
    option.methods["FormModel_" + dataTag + "_cancelEdit"] = function (mRow, index) {
            var oRow = oldRowModels["index_" + mRow._uid];
            if (oRow) {
                mRow.DataRow = oRow.DataRow;
              //  self.closeEdit(mRow, index);
                self.switchEditBtn(mRow, index);

            }
        };

    //切换编辑按钮就
    this.switchEditBtn = function (mRow, index) {
        if (mRow.IsOpenEdit == undefined) {
            Vue.set(mRow, "IsOpenEdit", true);
        } else if (mRow.IsOpenEdit) {
            mRow.IsOpenEdit = false;
        } else {
            mRow.IsOpenEdit = true;;
        }
        };
    var _uidIndex = 0;
    //编辑行
    this.editRow = function (mRow, index) {
        mRow._uid = ++_uidIndex; //作为标识
       // self.beginEdit(mRow, index);      
        oldRowModels["index_" + mRow._uid] = jQuery.extend(true, {}, mRow); //缓存编辑行
        self.switchEditBtn(mRow, index);
        if (mRow.DataState == "U") {
            mRow.DataState = "M";
        }
    };
   option.methods["FormModel_" + dataTag + "_editRow"] = self.editRow;

   //**********配置相关start***********
    formCom.setVerifyFormula(dataTag);
    formCom.injectVerifyMethod(function (newData, vm) {
            var msg = ""
            if (!window.verifyFormula) { return msg; }
            var selfRegular = window.verifyFormula;  //获取验证
        if (newData[dataTag] && selfRegular[dataTag] && selfRegular[dataTag].length > 0) {
            Vue.verifyData(newData[dataTag].DataRows, selfRegular[dataTag], function (f, i) {
                  //  vm.ErrorModel[datatag][f.compareColumn] = f.msg;  //通过
                    msg = msg + f.msg + '<br>';
                }, function (f, i) {
                   // vm.ErrorModel[datatag][f.compareColumn] = ""; //不通过
                });
        }
        if (msg) { dialogBox.openDialog(msg) };
            return msg
        });

   //**********配置相关 end**********
    //保存单行
    this.saveData = function (mRows, backFunc) {
            //组织数据
            var newData = { DataState: 'M' };
            newData[dataTag] = {
                DataRows: [],
                DataState: "U",
                Type: ""
            };
            for (var i = 0; i < mRows.length; i++) {
                var newRow = jQuery.extend(true, {}, mRows[i]);
                newData[dataTag].DataRows.push(newRow);
        }
        if (!formCom.fireEvent("On_SaveData", newData)) return;  //事前savedata
            //以下验证
            var isVerify = formCom.verifyData(newData, formCom.vm);
            if (isVerify) { return; }
            var url = formCom._baseUrl;
            if (formCom.postAction) url += formCom.postAction;
            var jsonString = JSON.stringify(newData);
            formCom.post(url, jsonString
                , formCom["whenSaveData"]
                , function (data) {
                    dialogBox.openDialog(data.MsgErr);
                    if (formCom["whenSaveDataFail"]) formCom["whenSaveData"](data);
                }
                , backFunc);
        }
    this.saveRow = function (mRow,index) {   
        var iLen = fieldCtrls.length;
        //获取新数据
        //for (var i = 0; i < iLen; i++) {
        //    var o = fieldCtrls[i];
        //    var component = tempCtrlComponent["row_" + mRow._uid + "_index_" + i];
        //    if(o && component && component.$el) {
        //        mRow.DataRow[o.name] = component.myValue;
        //    }
        //}
  
        self.saveData([mRow], function (data) {
            //保存成功后
            mRow.DataRow = data[dataTag].DataRows[0].DataRow;
           // self.closeEdit(mRow, index);
            self.switchEditBtn(mRow, index);
        });
   
        }
    option.methods["FormModel_" + dataTag + "_saveRow"] = self.saveRow;
   //删除行
     this.deleteRow = function (mRows, callBack) {      
        //一 
        if (Object.prototype.toString.call(mRows) != '[object Array]') {
            mRows = [mRows];
        }
        var newRows = [];
        for (var i = 0; i < mRows.length; i++) {
            var mRow = mRows[i];
            if (mRow.DataState == "A" || mRow.DataState == "UA") {
                self.removeRow(mRow);//直接移除
            } else {
                mRow.DataState = "D";
                newRows.push(mRow);
            }
        }
         if (newRows.length == 0) { return; }
         if (!confirm("确认要删除吗?")) {
             return;
         }
         self.saveData(newRows, function (data) {
            //保存成功后
            if (typeof callBack == "function") { callBack(data); };
            formCom.fireEvent("When_DeleteRow", data); //删除成功后抛出
        });

        }
    option.methods["FormModel_" + dataTag + "_deleteRow"] = self.deleteRow;
   //重写formCom的search 防止
    var oldSearch = formCom.searchData;
    formCom.searchData = function (searchItem, callBack) {
            //是否有编辑状态
            var rows = formCom.vm.DataModel.DataA.DataRows;
            for (var i = 0, len = rows.length; i < len; i++) {
                var row = rows[i];
                if (row.IsOpenEdit) {
                    alert("还有正在编辑的行,请保存或取消后继续");
                    return;
                }
            }

            oldSearch(searchItem, callBack);
        }

    }
    //******单表格编辑end*******************

   
}

使用

   var tableEdit = new TableFormRowEdit(option, formCom, "DataB", "proof_table"); 
     tableEdit.setFieldCtrl(1, comfactory.createTextBox(formCom, "CellPhone"));

//option vue参数
//formCom 表单编辑对象》下面讲
//"DataB",列表行对应的key
//"proof_table"  tableid

//html如下
<tr v-for="(p,$index) in DataModel.DataB.DataRows" :key="p.DataRow.CompanyContactsID"
                        v-on:click="FormModel_DataB_selectRow(p,$index)">
                        <td>
                            <div class="tab_inner_txt" vfrequired="/\S/" vferrormsg="[姓名]必填"
                                 v-text="p.DataRow.ContactsName">
                            </div>
                        </td>
                        <td>
                            <div vfrequired="/^$|^1(3|4|5|6|7|8|9)\d{9}$/" vferrormsg="[联系人号码]格式错误" class="tab_inner_txt" v-text="p.DataRow.CellPhone"></div>
                        </td>
                        <td>
                            <div class="tab_inner_txt" v-text="p.DataRow.Email"></div>
                        </td>
                        <td>
                            <div class="tab_inner_txt" v-text="p.DataRow.QQ"> </div>
                        </td>
                        <td>
                            <div class="tab_inner_txt" v-text="p.DataRow.WeChat"> </div>
                        </td>
                        <td>
                            <div class="tab_inner_txt" v-text="p.DataRow.JobDescription"> </div>
                        </td>
                        <td>
                            <div class="tab_inner_txt" v-text="p.DataRow.IsPublic==1?'是':'否'"> </div>
                        </td>

                    </tr>

整体类描述

- vf-*** vue插件,实现基本下拉框,日期选择等vue组件
- VueFormComponent 利用Vue.extend()动态生产VueComponent
- TableFormRowEdit 绑定table、VueComponent、vue.Data,实现表格编辑
- VueFormModel 表单基本操作对象-负责实际操作从后台获取数据绑定页面,从页面获取数据发送到后台,自动绑定vue.data与页面组件,实现get、set、search、verifyData等功能,
- SingleFormModel 组合VueFormModel实现单表
- ItemFormModel 组合VueFormModel实现表头表体
- VueManager 分为初始化vue,配置参数,provide,等各项功能
- DataSetModel 装载数据类