开发一个完整的JavaScript组件

简介: JavaScript 组件

作为一名开发者,大家应该都知道在浏览器中存在一些内置的控件:Alert,Confirm等,但是这些控件通常根据浏览器产商的不同而形态各异,视觉效果往往达不到UI设计师的要求。更重要的是,这类内置控件的风格很难与形形色色的各种风格迥异的互联网产品的设计风格统一。因此,优秀的前端开发者们各自开发自己的个性化控件来替代浏览器内置的这些控件。当然,这类组件在网络上已经有不计其数相当优秀的,写这篇文章的目的不是为了说明我开发的这个组件有多优秀,也不是为了炫耀什么,只是希望通过这种方式,与更多的开发者互相交流,互相学习,共同进步。好,废话不多说,言归正传。

功能介绍

  • 取代浏览器自带的Alert、Confirm控件
  • 自定义界面样式
  • 使用方式与内置控件基本保持一致

开发过程

1. 组件结构设计

首先,我们来看下内置组件的基本使用方法:

1 alert("内置Alert控件");

2if (confirm("关闭内置Confirm控件?")) {

3     alert("True");

4 } else {

5     alert("False");

6 }

为了保证我们的组件使用方式和内置控件保持一致,所以我们必须考虑覆盖内置控件。考虑到组件开发的风格统一,易用,易维护,以及面向对象等特性,我计划将自定义的alert和confirm方法作为一个类(Winpop)的实例方法,最后用实例方法去覆盖系统内置控件的方法。为了达到目的,我的基本做法如下:

1var obj = new Winpop(); // 创建一个Winpop的实例对象

2// 覆盖alert控件

3 window.alert = function(str) {

4    obj.alert.call(obj, str);

5};

6// 覆盖confirm控件

7 window.confirm = function(str, cb) {

8    obj.confirm.call(obj, str, cb);

9 };

需要注意的是,由于浏览器内置的控件可以阻止浏览器的其他行为,而我们自定义的组件并不能具备这种能力,为了尽可能的做到统一,正如预览图上看到的,我们在弹出自定义组件的时候使用了一个全屏半透明遮罩层。也正是由于上述原因,confirm组件的使用方式也做了一些细微的调整,由内置返回布尔值的方式,改为使用回调函数的方式,以确保可以正确的添加“确定”和“取消”的逻辑。因此,自定义组件的使用方式就变成了下面这种形式:

1 alert("自定义Alert组件");

2 confirm("关闭自定义Confirm组件?", function(flag){

3     if (flag) {

4         alert("True");

5     } else {

6         alert("False");

7    }

8 });

2. 组件代码设计

在正式介绍Winpop组件的代码之前,我们先来看一下一个Javascript组件的基本结构:

1 (function(window, undefined) {

2     function JsClassName(cfg) {

3         var config = cfg || {};

4         this.get = function(n) {

5             return config[n];

6        }

7         this.set = function(n, v) {

8             config[n] = v;

9        }

10         this.init();

11    }

12     JsClassName.prototype = {

13         init: function(){},

14         otherMethod: function(){}

15    };

16     window.JsClassName = window.JsClassName || JsClassName;

17 })(window);

使用一个自执行的匿名函数将我们的组件代码包裹起来,尽可能的减少全局污染,最后再将我们的类附到全局window对象上,这是一种比较推荐的做法。

构造函数中的get、set方法不是必须的,只是笔者的个人习惯而已,觉得这样写可以将配置参数和其他组件内部全局变量缓存和读取的调用方式统一,似乎也更具有面向对象的型。欢迎读者们说说各自的想法,说说这样写到底好不好。

接下来我们一起看下Winpop组件的完整代码:

 1 (function(window, jQuery, undefined) {

 2

 3     var HTMLS = {

 4         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>',

 5         alert: '<input type="button" class="J_AltBtn pop-btn alert-button" value="确定">',

 6         confirm: '<input type="button" class="J_CfmFalse pop-btn confirm-false" value="取消">' + '<input type="button" class="J_CfmTrue pop-btn confirm-true" value="确定">'

 7    }

 8

 9     function Winpop() {

10         var config = {};

11         this.get = function(n) {

12             return config[n];

13        }

14

15         this.set = function(n, v) {

16             config[n] = v;

17        }

18         this.init();

19    }

20

21     Winpop.prototype = {

22         init: function() {

23             this.createDom();

24             this.bindEvent();

25        },

26         createDom: function() {

27             var body = jQuery("body"),

28                 ovl = jQuery("#J_WinpopBox");

29

30             if (ovl.length === 0) {

31                body.append(HTMLS.ovl);

32            }

33

34             this.set("ovl", jQuery("#J_WinpopBox"));

35             this.set("mask", jQuery("#J_WinpopMask"));

36        },

37         bindEvent: function() {

38             var _this = this,

39                 ovl = _this.get("ovl"),

40                 mask = _this.get("mask");

41             ovl.on("click", ".J_AltBtn", function(e) {

42                _this.hide();

43            });

44             ovl.on("click", ".J_CfmTrue", function(e) {

45                 var cb = _this.get("confirmBack");

46                _this.hide();

47                 cb && cb(true);

48            });

49             ovl.on("click", ".J_CfmFalse", function(e) {

50                 var cb = _this.get("confirmBack");

51                _this.hide();

52                 cb && cb(false);

53            });

54             mask.on("click", function(e) {

55                _this.hide();

56            });

57             jQuery(document).on("keyup", function(e) {

58                 var kc = e.keyCode,

59                     cb = _this.get("confirmBack");;

60                 if (kc === 27) {

61                    _this.hide();

62                 } elseif (kc === 13) {

63                    _this.hide();

64                     if (_this.get("type") === "confirm") {

65                         cb && cb(true);

66                    }

67                }

68            });

69        },

70         alert: function(str, btnstr) {

71             var str = typeof str === 'string' ? str : str.toString(),

72                 ovl = this.get("ovl");

73             this.set("type", "alert");

74             ovl.find(".J_WinpopMain").html(str);

75             if (typeof btnstr == "undefined") {

76                 ovl.find(".J_WinpopBtns").html(HTMLS.alert);

77             } else {

78                 ovl.find(".J_WinpopBtns").html(btnstr);

79            }

80             this.show();

81        },

82         confirm: function(str, callback) {

83             var str = typeof str === 'string' ? str : str.toString(),

84                 ovl = this.get("ovl");

85             this.set("type", "confirm");

86             ovl.find(".J_WinpopMain").html(str);

87             ovl.find(".J_WinpopBtns").html(HTMLS.confirm);

88             this.set("confirmBack", (callback || function() {}));

89             this.show();

90        },

91         show: function() {

92             this.get("ovl").show();

93             this.get("mask").show();

94        },

95         hide: function() {

96             var ovl = this.get("ovl");

97             ovl.find(".J_WinpopMain").html("");

98             ovl.find(".J_WinpopBtns").html("");

99            ovl.hide();

100             this.get("mask").hide();

101        },

102         destory: function() {

103             this.get("ovl").remove();

104             this.get("mask").remove();

105             delete window.alert;

106             delete window.confirm;

107        }

108    };

109

110     var obj = new Winpop();

111     window.alert = function(str) {

112        obj.alert.call(obj, str);

113    };

114     window.confirm = function(str, cb) {

115        obj.confirm.call(obj, str, cb);

116    };

117 })(window, jQuery);

代码略多,关键做以下几点说明:

  • 笔者偷了懒,使用了jQuery,使用之前请先保证已经引入了jQuery
  • 自定义组件结构最终是追加到body中的,所以在引入以上js之前,请先确保文档已经加载完成
  • 组件添加了按ESC、点遮罩层隐藏组件功能
  • 注意:虽然本例中未用到 destory 方法,但读者朋友可以注意一下该方法中的 delete window.alertdelete window.confirm ,这样写的目的是保证在自定义组件销毁后,将Alert、Confirm控件恢复到浏览器内置效果
  • 组件最后如果加上 window.Winpop = Winpop ,就可以将对象全局化供其他类调用了

最后

作为一个前端开发工程师,个人觉得Javascript组件开发是一件很有意思的事情,其中乐趣只有自己亲自动手尝试了才会体会得到。

目录
相关文章
|
16天前
|
Web App开发 JavaScript 前端开发
Node.js开发
Node.js开发
32 13
|
23天前
|
存储 JavaScript 前端开发
深入浅出Node.js后端开发
在数字化时代的浪潮中,后端开发作为连接用户与数据的桥梁,扮演着至关重要的角色。本文将以Node.js为例,深入探讨其背后的哲学思想、核心特性以及在实际项目中的应用,旨在为读者揭示Node.js如何优雅地处理高并发请求,并通过实践案例加深理解。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供新的视角和思考。
|
20天前
|
Web App开发 开发框架 JavaScript
深入浅出Node.js后端开发
本文将带你领略Node.js的魅力,从基础概念到实践应用,一步步深入理解并掌握Node.js在后端开发中的运用。我们将通过实例学习如何搭建一个基本的Web服务,探讨Node.js的事件驱动和非阻塞I/O模型,以及如何利用其强大的生态系统进行高效的后端开发。无论你是前端开发者还是后端新手,这篇文章都会为你打开一扇通往全栈开发的大门。
|
23天前
|
Web App开发 开发框架 JavaScript
深入浅出Node.js后端开发
在这篇文章中,我们将一起探索Node.js的奇妙世界。无论你是刚接触后端开发的新手,还是希望深化理解的老手,这篇文章都适合你。我们将从基础概念开始,逐步深入到实际应用,最后通过一个代码示例来巩固所学知识。让我们一起开启这段旅程吧!
|
19天前
|
Web App开发 JavaScript 前端开发
深入浅出Node.js后端开发
本文将带领读者从零基础开始,一步步深入到Node.js后端开发的精髓。我们将通过通俗易懂的语言和实际代码示例,探索Node.js的强大功能及其在现代Web开发中的应用。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供新的见解和技巧,让你的后端开发技能更上一层楼。
|
22天前
|
JavaScript 前端开发 API
深入理解Node.js事件循环及其在后端开发中的应用
本文旨在揭示Node.js的核心特性之一——事件循环,并探讨其对后端开发实践的深远影响。通过剖析事件循环的工作原理和关键组件,我们不仅能够更好地理解Node.js的非阻塞I/O模型,还能学会如何优化我们的后端应用以提高性能和响应能力。文章将结合实例分析事件循环在处理大量并发请求时的优势,以及如何避免常见的编程陷阱,从而为读者提供从理论到实践的全面指导。
|
23天前
|
Web App开发 JavaScript 前端开发
深入浅出Node.js后端开发
本文将带你走进Node.js的世界,从基础到进阶,逐步解析Node.js在后端开发中的应用。我们将通过实例来理解Node.js的异步特性、事件驱动模型以及如何利用它处理高并发请求。此外,文章还会介绍如何搭建一个基本的Node.js服务器,并探讨如何利用现代前端框架与Node.js进行交互,实现全栈式开发。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供新的视角和深入的理解。
17 4
|
移动开发 JavaScript 前端开发
8个最佳的JavaScript移动应用开发框架
随着智能手机和平板电脑的普及,移动应用的开发越来越流行,基于JavaScript的移动开发框架也逐渐成为主流。移动开发与桌面应用的开发相比,有个显著的不同,那就是,移动应用绝大多数是基于触摸屏的应用。
1217 0
|
移动开发 JavaScript 前端开发
8个最佳的JavaScript移动应用开发框架
版权声明:本文为博主chszs的原创文章,未经博主允许不得转载。 https://blog.csdn.net/chszs/article/details/9935445 《8个最佳的JavaScript移动应用开发框架》 作者:chszs,转载需注明。
1059 0
|
28天前
|
JavaScript 前端开发
JavaScript中的原型 保姆级文章一文搞懂
本文详细解析了JavaScript中的原型概念,从构造函数、原型对象、`__proto__`属性、`constructor`属性到原型链,层层递进地解释了JavaScript如何通过原型实现继承机制。适合初学者深入理解JS面向对象编程的核心原理。
25 1
JavaScript中的原型 保姆级文章一文搞懂