Web页面多对象多文档事件冲突的解决方案
这段时间写了很多基于js和jquery的前端控件,每一个的功能都很复杂,事件也很多。
因为都是单独封装的,单独使用没有问题,但把他们放到一个页面使用,就经常发生事件冲突的问题。
这几天一直在考虑用一个什么比较好的方法解决,今天把其中一个解决方案实验了一下,感觉很不错,现在发出来,大家一起探讨下。
window.UE_EVENT = window.UE_EVENT || { Key: 1, ClipBoard: null, CurrElement: null, CurrKey: 0, Events: { 'mousemove': [], 'mousedown': [], 'keypress': [], 'dblclick': [], 'mouseup': [], 'keydown': [], 'keyup': [], 'click': [], 'resize': [], 'copy': [], 'paste': [] }, Delete: function (event, key) { if (!event || !key) return false; var e = event.toLowerCase(),l = this.Events[e]; for (var i in l) { if (l[i].KEY == key) { l.splice(i, 1); break; } } }, Add: function (dom, event, callback) { if (!dom || !event || !callback) return false; UE_EVENT.IsRun || UE_EVENT.Run(); var key = UE_EVENT.SetEventKey(dom), isExists = false, e = event.toLowerCase(), l = this.Events[e]; for (var i in l) { if (l[i].KEY == key) { l[i].FUN = callback; isExists = true; } } if (!isExists) { l.push({ 'KEY': key, 'EVENT': e, 'DOM': dom[0] || dom, 'FUN': callback }); } }, Excute: function (event, e) { var l = this.Events[event]; if (event == 'resize') { for (var i in l) { var t = l[i], d = t.DOM; if (t.width != $(d).width() || t.height != $(d).height()) { t.width = $(d).width(); t.height = $(d).height(); l[i].FUN(t.width, t.height, null, d); } } } else { e = e || window.event; var t = e.srcElement || e.target, k = parseInt($(t).attr('eventkey'), 10); for (var i in l) { if (l[i].KEY == k || l[i].KEY == this.CurrKey) { l[i].FUN(e, t, l[i].KEY, l[i].DOM); } } } }, Download: function (url, json) { var form = $('<form style="display:none" target="ue_download_iframe" method="post" action="' + url + '"><iframe id="ue_download_iframe" name="ue_download_iframe" onload=""></iframe><input name="JsonData" value="' + JSON.stringify(json).replace(/"/g, "'") + '" /></form>').appendTo('body'); var iframe = document.getElementById('ue_download_iframe'); if (document.readyState) { iframe.onreadystatechange = function () { if (this.readyState && this.readyState == 'complete') { form.remove(); } } } else { iframe.onload = function () { form.remove(); } } form.submit(); }, SetEventKey: function (obj) { if (!obj) return; var dom = obj[0] || obj, isDOM = (typeof HTMLElement === 'object') ? (dom instanceof HTMLElement) : dom && typeof dom === 'object' && dom.nodeType === 1, key = isDOM ? parseInt($(dom).attr('eventkey'), 10) : dom.eventKey; key = key || UE_EVENT.Key++; if (isDOM) { $(dom).attr('eventkey', key) } else { dom.eventKey = key; } return key; }, Run: function (obj) { if (!this.IsRun) { $(document).on('mousemove', function (e) { UE_EVENT.Excute('mousemove', e); }).on('mousedown', function (e) { UE_EVENT.Excute('mousedown', e); }).on('keypress', function (e) { UE_EVENT.Excute('keypress', e); }).on('dblclick', function (e) { UE_EVENT.Excute('dblclick', e); }).on('mouseup', function (e) { UE_EVENT.Excute('mouseup', e); }).on('keydown', function (e) { UE_EVENT.Excute('keydown', e); }).on('keyup', function (e) { UE_EVENT.Excute('keyup', e); }).on('click', function (e) { UE_EVENT.CurrKey = 0; UE_EVENT.Excute('click', e); }); setInterval(function () { UE_EVENT.Excute('resize', null); }, 200); //$(window).on('resize', function (e) { // UE_EVENT.Excute('resize', e); //}); $('body').on({ copy: function (e) { var d = window.clipboardData || e.originalEvent.clipboardData; var txt = ""; UE_EVENT.Excute('copy', txt); d.setData('Text', txt); return false; }, paste: function (e) { var d = window.clipboardData || e.originalEvent.clipboardData; UE_EVENT.Excute('paste', d.getData('Text')); } }); } UE_EVENT.IsRun = true; return true; } }; $.fn.SetEvent = function (event, callback) { return UE_EVENT.Add(this, event, callback); }; $.fn.ActiveEvent = function () { UE_EVENT.CurrKey = UE_EVENT.SetEventKey(this); };
这个方案的思路就是用单例模式,建立一个事件方法列表,就像系统的注册表一样(事实上灵感也是来自注册表),
然后所有的插件控件的文档事件,都向这个列表集合里注册,这样需要用的时候,就能统一调度,互不冲突。
今天做了一点调整,就是添加了dom对象的保存,同时注册的事件改为保存事件名称,这样可能比较灵活
一改:添加了resize事件
二改:这次改为每添加一个事件,都指定一个key值
三改:修改resize事件为实时监控标签size变化,取消绑定body的resize事件
添加copy和poaste事件