基于DataTables寫一個(gè)可編輯Table插件

源代碼地址:https://github.com/upcyoung/dtEditor

在Web項(xiàng)目中皮官,用于呈現(xiàn)數(shù)據(jù)時(shí)经柴,一般都會(huì)選擇Table。完全自己手寫Table是一項(xiàng)特別繁雜的事情,所以一般會(huì)選擇Table插件燎含。在項(xiàng)目中提鸟,如果需要使用Table時(shí)军援,我一般會(huì)首選jquery datatables,datatables支持豐富的配置称勋、API及擴(kuò)展(Buttion, Selected, Fixedcolumn等)胸哥。

在有些項(xiàng)目中會(huì)要求數(shù)據(jù)可新增、編輯赡鲜,在DataTables的官網(wǎng)中可以找到Editor擴(kuò)展空厌,該擴(kuò)展提供了對(duì)數(shù)據(jù)的編輯功能,但是此擴(kuò)展是收費(fèi)的银酬。由于我已經(jīng)習(xí)慣了使用DataTables嘲更,并不想換到其他的Table插件,所以決定自己寫一個(gè)支持編輯的插件揩瞪。

在編寫插件前赋朦,首先要確定一個(gè)實(shí)現(xiàn)插件的大體思路。在表單錄入中,由哪種方式(輸入宠哄、下拉壹将、日期等)進(jìn)行編輯及驗(yàn)證是多樣化的,如果考慮把這部分也在插件中就太復(fù)雜了(如果有興趣可查看x-editable)毛嫉。所以瞭恰,我希望這個(gè)插件要功能單一,僅提供一個(gè)基架狱庇,編輯的行為在外部實(shí)現(xiàn)惊畏,同時(shí)支持行內(nèi)和彈出兩種編輯方式。

在實(shí)現(xiàn)插件我想到的是在原有的row上為每個(gè)可編輯列生成相應(yīng)的控件密任,還是clone當(dāng)前row并添加到tbody中再為每個(gè)可編輯列生成控件颜启。這里,我選擇了后種方式浪讳。接下要解決的問題是如何為可編輯列生成控件并在結(jié)束時(shí)銷毀各個(gè)控件缰盏。這里借鑒DataTalbe中columnDefs的定義方式,用target來聲名列的位置淹遵,使用render方式返回控件口猜;考慮到控件的數(shù)據(jù)可能是異步加載,增加renderAfter方法透揣;考慮到控件的銷毀和事件的移除济炎,增加destroy方法;為值的獲取增加get方法辐真。這樣編輯列的配置如下须尚。

//可編輯列的配置
window.UpcEditorSetting = function (options) {
    var self = this;
    self.target = options.target;
    self.field = options.field;
    self.title = options.title;
   if (options.noField) {
       self.noField = true;
   }
   self.$dom = null;
   self.handlers = [];
   self.render = function () { return ''; };
   if (!self.noField) {
        self.get = function () {
            return $.trim(this.$dom.val());
        };
   }
   if (options.render) {
            this.render = options.render;
   }
   if (options.get) {
        this.get = options.get;
   }
   if (options.destroy) {
        this.destroy = options.destroy;
   }
   if (options.renderAfter) {
        this.renderAfter = options.renderAfter;
   }
   return this;
};

其中,noField用于標(biāo)識(shí)此列為非編輯列侍咱,$dom用于保存想要在上下文中要使用的對(duì)象耐床,handlers保存綁定的事件,用于在銷毀時(shí)移除事件綁定楔脯,field和title用于彈出編輯的支持撩轰。如果不需要上下文this時(shí),可僅聲名具有以上屬性的對(duì)象即可昧廷。
在定好編輯列配置后堪嫂,就可以開始搭主要的架子了。將插件命名為dtEditor麸粮,插件主要實(shí)現(xiàn)編輯溉苛、保存镜廉、取消弄诲、新增、獲取編輯數(shù)據(jù)功能。jquery插件的實(shí)現(xiàn)方式就是要在jquery原型上聲名function就可以了齐遵,如下方式:

//jquery插件的聲名方式
$.prototype.dtEditor=function(options){}
//or
$.fn.dtEditor=function(options){}
//or
$.fn.extend({
    dtEditor:function(options){}
})

以下貼出inline編輯模式下可編輯列的初始化和獲取值相關(guān)的代碼寂玲。

var tools = {
   getRowData:function() {
       if (this.oTrIndex >= 0) {
           var dt = this.oDataTable;
           var rd = dt.row(this.oTrIndex).data();
           var node = dt.row(this.oTrIndex).node();
           var tr = $(node).next()[0];
           var aoColumns = dt.settings()[0].aoColumns;
           var columns = this.columns;
           for (var i = columns.length - 1; i >= 0; i--) {
               if (columns[i].get) {
                   var td = $(tr).find("td")[[columns[i].target]];
                   var d = columns[i].get($(td), $(tr));
                   rd[aoColumns[columns[i].target].data] = d; 
               }

           }
           return rd;
       }
       return null;
   },
   inlineAccessor: function (index, tr, row, cache) {
       var dt = cache.oDataTable;
       var rowClone = $(row.node()).clone(); //clone當(dāng)前行的node
       var columns = cache.columns;
       $(row.node()).hide();
       $(row.node()).after(rowClone);
       var tds = rowClone.find("td");
       var rd = row.data();
       //對(duì)每一列,激活編輯模式
       for (var i = cache.columns.length - 1; i >= 0; i--) {
           var coordinate = { row: index, column: columns[i].target };
           var cell = dt.cell(coordinate); //取得cell
           var td = tds[columns[i].target];
           var cd = null;
           if (!columns[i].noField) {
               cd = cell.data();
           }
           var html = columns[i].render(cd, rd, $(tr)); //調(diào)用render方法梗摇,獲取填充td的html
           if (typeof html == "string") {
               td.innerHTML = html; //填充td拓哟,編輯狀態(tài)
           } else {
               $(td).empty().append(html); //jquery對(duì)象,直接append
           }
           if (columns[i].renderAfter) { //html渲染完之后伶授,執(zhí)行回調(diào)
               columns[i].renderAfter(cd, rd, $(tr));
           }
       }
   }
};

插件使用方式如下断序。

var option = {
    pop: $('#pop-form'), //彈出編輯列的父容器
    columns: [
        new UpcEditorSetting({
            target: 0,
            noField: true
        }),
        new UpcEditorSetting({
            target: 2,
            field: 'text',
            title: '簡短描述',
            render: function(cd) {
                this.$dom = $('<input type="text" class="form-control"/>').val(cd);
                return this.$dom;
            },
            renderAfter: function() {
                this.$dom.focus();
            }
        }),
        new UpcEditorSetting({
            target: 3,
            field: 'amount',
            title: '數(shù)量',
            render: function(cd) {
                this.$dom = $('<input type="text" class="form-control"/>').val(cd);
                return this.$dom;
            }
        }),
        new UpcEditorSetting({
            target: 4,
            field: 'meins',
            title: '計(jì)量單位',
            destroy: function() {
                this.$dom.chosen('destroy');
            },
            get: selectGetter,
            render: function(cd, full) {
                this.$dom = $('<select type="text" class="form-control"></select>').val(cd);
                return this.$dom;
            },
            renderAfter: function(cd) {
                var self = this;
                //使用jquery chosen
                self.$dom.chosen(chosenOp);
                //異步加載數(shù)據(jù)
                setTimeout(() => {
                    var options = [],data=[{"name":"百分比","code":"%"},{"name":"每千","code":"%O"}];
                    for (var i = 0, l = data.length; i < l; i++) {
                        options.push('<option data-t="' + data[i].name + '" value="' + data[i].code + '">' + data[i].code + '-' + data[i].name + '</option>');
                    }
                    self.$dom.empty().append(options.join('')).val();
                    if (v) {
                        self.$dom.val(v);
                    }
                    self.$dom.trigger("chosen:updated");
                }, 0);
            }
        }),
        new UpcEditorSetting({
            target: 5,
            field: 'date',
            title: '交貨日期',
            render: function(cd) {
                this.$dom = $('<input type="text" class="form-control"/>');
                if (cd) {
                    this.$dom.val(cd);
                } else {
                    this.$dom.val((new Date()).format());
                }
                var options = {
                    autoclose: true,
                    language: 'zh-CN',
                    minView: 2,
                    pickerPosition: 'bottom-left',
                    format: "yyyy-mm-dd"
                };
                if (editMode == 0) {
                    options.pickerPosition = 'top-right';
                }
                //使用bootstrap datetimepicker
                this.$dom.datetimepicker(options);
                return this.$dom;

            },
            destroy: function($td) {
                this.$dom.datetimepicker('remove');
            }
        }),
        new UpcEditorSetting({ target: 11, noField: true })
    ],
    defaultValue: { text: '', amount: 1, meins: '',date:'' },
    message: messageService.warning
};
$('table').dtEditor(option);  //初始化dtEditor
$('table').dtEditor().triggerAdd(); //新增
$('table').dtEditor().triggerEdit(row); //編輯
$('table').dtEditor().triggerCancel(); //取消
$('table').dtEditor().getRowData(); //獲取行數(shù)據(jù)
$('table').dtEditor().triggerSave(); //保存數(shù)據(jù)

效果圖如下。


inline.jpg

pop.jpg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末糜烹,一起剝皮案震驚了整個(gè)濱河市违诗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌疮蹦,老刑警劉巖诸迟,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異愕乎,居然都是意外死亡阵苇,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門感论,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绅项,“玉大人,你說我怎么就攤上這事比肄〕谜” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵薪前,是天一觀的道長润努。 經(jīng)常有香客問我,道長示括,這世上最難降的妖魔是什么铺浇? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮垛膝,結(jié)果婚禮上鳍侣,老公的妹妹穿的比我還像新娘。我一直安慰自己吼拥,他們只是感情好倚聚,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著凿可,像睡著了一般惑折。 火紅的嫁衣襯著肌膚如雪授账。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天惨驶,我揣著相機(jī)與錄音白热,去河邊找鬼。 笑死粗卜,一個(gè)胖子當(dāng)著我的面吹牛屋确,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播续扔,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼攻臀,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了纱昧?” 一聲冷哼從身側(cè)響起茵烈,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎砌些,沒想到半個(gè)月后呜投,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡存璃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年仑荐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纵东。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡粘招,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出偎球,到底是詐尸還是另有隱情洒扎,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布衰絮,位于F島的核電站袍冷,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏猫牡。R本人自食惡果不足惜胡诗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望淌友。 院中可真熱鬧煌恢,春花似錦、人聲如沸震庭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽器联。三九已至二汛,卻和暖如春婿崭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背习贫。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留千元,地道東北人苫昌。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像幸海,于是被迫代替她去往敵國和親祟身。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容