總是頭疼javascript的代碼寫起來不可維護,那麼看看下麵的代碼: 代碼其實很簡單,其基本思路就是,將數據、函數、事件監聽和回調都封裝在一個對象中,那麼我們可以簡單的把這個對象理解為一個組件。 封裝的難點:事件監聽和回調 封裝的難點其實在於事件的監聽和回調,先看一個簡單的實現: 就是以匿名函數的 ...
總是頭疼javascript的代碼寫起來不可維護,那麼看看下麵的代碼:
1 (function (w, $) { 2 var app = { 3 init: function () { 4 var me = this; 5 me.render(); 6 me.bind(); 7 }, 8 datas: { 9 num: 1 10 }, 11 render: function () { 12 var me = this; 13 me.test = $('#table td'); 14 }, 15 bind: function () { 16 var me = this; 17 me.test.on('click', $.proxy(me['_do'], this)); 18 }, 19 _do: function (e) { 20 var m = $(e.target).text(); 21 var me = this; 22 m = me.datas.num + m; 23 var s = '<input type="text" value="' + m + '">'; 24 $(e.target).html(s); 25 } 26 }; 27 28 app.init(); 29 exports = app; 30 })(window, jQuery);
代碼其實很簡單,其基本思路就是,將數據、函數、事件監聽和回調都封裝在一個對象中,那麼我們可以簡單的把這個對象理解為一個組件。
封裝的難點:事件監聽和回調
封裝的難點其實在於事件的監聽和回調,先看一個簡單的實現:
1 bind: function () { 2 var me = this; 3 me.test.on('click', function(e) { 4 // 操作 5 }); 6 },
就是以匿名函數的形式寫回調函數,可以滿足需求,但如果有大量的事件需要監聽、綁定回調函數時,這種方式顯然就不太合理了:bind方法會變得過長而不好維護,那麼以傳入具名函數函數名的方式就可以解決這個問題,但是會遇到回調函數中的this不是指向app對象而指向觸發元素的問題:
1 bind: function () { 2 var me = this; 3 me.test.on('click', me['_do']); 4 }, 5 _do: function(e) { 6 // 這裡的this指向誰? 7 var targetEle = $(e.target); 8 // 這裡的this顯然指的是觸發事件的元素,在這裡是一個jQuery對象 9 var me = this; 10 // 下麵這句就會報錯 11 m = me.datas.num + m; 12 }
那麼如何解決上面的問題,答案就是$.proxy(fn, contenxt),這個方法可以改變函數執行時的上下文:
1 bind: function () { 2 var me = this; 3 me.test.on('click', $.proxy(me['_do'], this)); 4 },
上面的代碼使me['_do']被調用時,this指向app,那麼在me['_do']中就可以獲取app中的數據,從而解決了上面this的指向問題。
總結
上面的js代碼實現了一個簡陋的可編輯表格的功能,這段代碼是京程一燈袁志佳在騰訊視頻公開課上講的代碼,我貼在這裡來提醒自己:前端javascript的編寫還有許多要學習和挖掘的地方。代碼中主要用到了jQuery.proxy()這個強大的函數,另外就是這種對象封裝的思想。
存在的問題
雖然$.proxy()解決了this的指向問題,但它也不是完美的。這裡在使用事件委托時就要小心了:
1 render: function () { 2 var me = this; 3 me.document= $(document); 4 }, 5 bind: function() { 6 document.on('click', 'ul li', $.proxy(me['_do2'], this)); 7 }, 8 _do2: function(e) { 9 var eleTarget = $(e.target); 10 }
因為_do2中的this不再指向綁定事件的元素ul li,所以要想在_do2中獲取ul li就有些麻煩,尤其是li中嵌套比較多的子元素時:
1 <ul> 2 <li> 3 <div><span></span>...</div> 4 </li> 5 </ul>
_do2中的eleTarget由於事件冒泡的原因可能是:span、div、li,那麼該如何解決這個問題?很遺憾我沒有想到好的解決方法,提供兩個思路:1,如果li中嵌套了太多的子元素,那麼事件委托在這裡就不是一個好的解決方案了。2,如果嵌套的子元素不多,那麼還可以通過查找的方法找到ul li,這個也是可行的。當然,如果拋開本文章,單純使用事件委托還是可以的:
1 $(document).on('click', 'ul li', function(e) { 2 var this = $(this); 3 });
因為這裡的this始終指向ul li,即委托的元素ul li。