做为一名开发者,你们应该都知道在浏览器中存在一些内置的控件:Alert,Confirm等,可是这些控件一般根据浏览器产商的不一样而形态万千,视觉效果每每达不到UI设计师的要求。更重要的是,这类内置控件的风格很难与形形色色的各类风格迥异的互联网产品的设计风格统一。所以,优秀的前端开发者们各自开发本身的个性化控件来替代浏览器内置的这些控件。固然,这类组件在网络上已经有不可胜数至关优秀的,写这篇文章的目的不是为了说明我开发的这个组件有多优秀,也不是为了炫耀什么,只是但愿经过这种方式,与更多的开发者互相交流,互相学习,共同进步。好,废话很少说,言归正传。html
一、Alert控件前端
二、Confirm控件浏览器
三、完整代码,在线预览(见底部,提供压缩包下载)缓存
首先,咱们来看下内置组件的基本使用方法:网络
alert("内置Alert控件"); if (confirm("关闭内置Confirm控件?")) { alert("True"); } else { alert("False"); }
为了保证咱们的组件使用方式和内置控件保持一致,因此咱们必须考虑覆盖内置控件。考虑到组件开发的风格统一,易用,易维护,以及面向对象等特性,我计划将自定义的alert和confirm方法做为一个类(Winpop)的实例方法,最后用实例方法去覆盖系统内置控件的方法。为了达到目的,个人基本作法以下:app
var obj = new Winpop(); // 建立一个Winpop的实例对象 // 覆盖alert控件 window.alert = function(str) { obj.alert.call(obj, str); }; // 覆盖confirm控件 window.confirm = function(str, cb) { obj.confirm.call(obj, str, cb); };
须要注意的是,因为浏览器内置的控件能够阻止浏览器的其余行为,而咱们自定义的组件并不能具有这种能力,为了尽量的作到统一,正如预览图上看到的,咱们在弹出自定义组件的时候使用了一个全屏半透明遮罩层。也正是因为上述缘由,confirm组件的使用方式也作了一些细微的调整,由内置返回布尔值的方式,改成使用回调函数的方式,以确保能够正确的添加“肯定”和“取消”的逻辑。所以,自定义组件的使用方式就变成了下面这种形式:ide
alert("自定义Alert组件"); confirm("关闭自定义Confirm组件?", function(flag){ if (flag) { alert("True"); } else { alert("False"); } });
在正式介绍Winpop组件的代码以前,咱们先来看一下一个Javascript组件的基本结构:函数
(function(window, undefined) { function JsClassName(cfg) { var config = cfg || {}; this.get = function(n) { return config[n]; } this.set = function(n, v) { config[n] = v; } this.init(); } JsClassName.prototype = { init: function(){}, otherMethod: function(){} }; window.JsClassName = window.JsClassName || JsClassName; })(window);
使用一个自执行的匿名函数将咱们的组件代码包裹起来,尽量的减小全局污染,最后再将咱们的类附到全局window对象上,这是一种比较推荐的作法。学习
构造函数中的get、set方法不是必须的,只是笔者的我的习惯而已,以为这样写能够将配置参数和其余组件内部全局变量缓存和读取的调用方式统一,彷佛也更具备面向对象的型。欢迎读者们说说各自的想法,说说这样写到底好很差。this
接下来咱们一块儿看下Winpop组件的完整代码:
(function(window, jQuery, undefined) { var HTMLS = { ovl: '<div class="J_WinpopMask winpop-mask" id="J_WinpopMask"></div>' + '<div class="J_WinpopBox winpop-box" id="J_WinpopBox">' + '<div class="J_WinpopMain winpop-main"></div>' + '<div class="J_WinpopBtns winpop-btns"></div>' + '</div>', alert: '<input type="button" class="J_AltBtn pop-btn alert-button" value="肯定">', confirm: '<input type="button" class="J_CfmFalse pop-btn confirm-false" value="取消">' + '<input type="button" class="J_CfmTrue pop-btn confirm-true" value="肯定">' } function Winpop() { var config = {}; this.get = function(n) { return config[n]; } this.set = function(n, v) { config[n] = v; } this.init(); } Winpop.prototype = { init: function() { this.createDom(); this.bindEvent(); }, createDom: function() { var body = jQuery("body"), ovl = jQuery("#J_WinpopBox"); if (ovl.length === 0) { body.append(HTMLS.ovl); } this.set("ovl", jQuery("#J_WinpopBox")); this.set("mask", jQuery("#J_WinpopMask")); }, bindEvent: function() { var _this = this, ovl = _this.get("ovl"), mask = _this.get("mask"); ovl.on("click", ".J_AltBtn", function(e) { _this.hide(); }); ovl.on("click", ".J_CfmTrue", function(e) { var cb = _this.get("confirmBack"); _this.hide(); cb && cb(true); }); ovl.on("click", ".J_CfmFalse", function(e) { var cb = _this.get("confirmBack"); _this.hide(); cb && cb(false); }); mask.on("click", function(e) { _this.hide(); }); jQuery(document).on("keyup", function(e) { var kc = e.keyCode, cb = _this.get("confirmBack");; if (kc === 27) { _this.hide(); } else if (kc === 13) { _this.hide(); if (_this.get("type") === "confirm") { cb && cb(true); } } }); }, alert: function(str, btnstr) { var str = typeof str === 'string' ? str : str.toString(), ovl = this.get("ovl"); this.set("type", "alert"); ovl.find(".J_WinpopMain").html(str); if (typeof btnstr == "undefined") { ovl.find(".J_WinpopBtns").html(HTMLS.alert); } else { ovl.find(".J_WinpopBtns").html(btnstr); } this.show(); }, confirm: function(str, callback) { var str = typeof str === 'string' ? str : str.toString(), ovl = this.get("ovl"); this.set("type", "confirm"); ovl.find(".J_WinpopMain").html(str); ovl.find(".J_WinpopBtns").html(HTMLS.confirm); this.set("confirmBack", (callback || function() {})); this.show(); }, show: function() { this.get("ovl").show(); this.get("mask").show(); }, hide: function() { var ovl = this.get("ovl"); ovl.find(".J_WinpopMain").html(""); ovl.find(".J_WinpopBtns").html(""); ovl.hide(); this.get("mask").hide(); }, destory: function() { this.get("ovl").remove(); this.get("mask").remove(); delete window.alert; delete window.confirm; } }; var obj = new Winpop(); window.alert = function(str) { obj.alert.call(obj, str); }; window.confirm = function(str, cb) { obj.confirm.call(obj, str, cb); }; })(window, jQuery);
代码略多,关键作如下几点说明:
destory
方法,但读者朋友能够注意一下该方法中的delete window.alert
和delete window.confirm
,这样写的目的是保证在自定义组件销毁后,将Alert、Confirm控件恢复到浏览器内置效果window.Winpop = Winpop
,就能够将对象全局化供其余类调用了做为一个前端开发工程师,我的以为Javascript组件开发是一件颇有意思的事情,其中乐趣只有本身亲自动手尝试了才会体会获得。前端组件开发每每须要Javascript、CSS和html相互配合,才能事半功倍,上面提到的Winpop也不例外,这里给你们提供一个完整的demo压缩包,有兴趣的读者朋友,欢迎传播。
做者博客:百码山庄