l2Overlay: 原生 JavaScript 实现 Hoverpop 效果插件

最近想给自己做的项目加上类似于 Facebook 的 Namecard 效果,即鼠标移动到制定目标后浮现一个信息卡,在鼠标移开目标或者信息卡后则自动隐藏。

搜索了一下好像没有现成的插件可用,找到过几个仿 Facebook Style 的代码片段,但是感觉代码质量比我的还要糟糕,而且也不完全符合自己的要求,所以就花了一个下午的时间,用原生 JavaScript 写了一个类 Facebook Style 的 Namecard (hoverpop)插件。

l2Overlay

参看演示效果可以到:l2Overlay 演示

l2Overlay 的 CSS 代码

l2Overlay 的样式主要是模仿 Facebook 的 Namecard,下面是根据我的 l2Overlay 编写的 CSS 样式:

  1. .l2OverlayWrapper {
  2. font-size:12px;
  3. color:#333333;
  4. line-height:1.8;
  5. background-color:#FFFFFF;
  6. border:1px solid #8C8C8C;
  7. box-shadow:0010px#C8C8C8;
  8. margin:9px0;
  9. position: relative;
  10. max-width:300px;
  11. _width:300px;
  12. }
  13. .l2OverlayArrow {
  14. position: absolute;
  15. width:16px;
  16. height:9px;
  17. background:url("arrow.png") no-repeat -50px0px transparent;
  18. }
  19. .arrow-lt .l2OverlayArrow {
  20. left:15px;
  21. top:-9px;
  22. }
  23. .arrow-rt .l2OverlayArrow {
  24. right:15px;
  25. top:-9px;
  26. }
  27. .arrow-lb .l2OverlayArrow {
  28. background-position:-17px0;
  29. left:15px;
  30. bottom:-9px;
  31. _bottom:-15px;
  32. }
  33. .arrow-rb .l2OverlayArrow {
  34. background-position:-17px0;
  35. right:15px;
  36. bottom:-9px;
  37. _bottom:-15px;
  38. }
  39. .l2OverlayContent {
  40. margin:10px;
  41. }
  42. .l2Action {
  43. padding:010px;
  44. margin:10px-10px-10px;
  45. background-color:#F2F2F2;
  46. border-top:1px solid #CCCCCC;
  47. line-height:34px;
  48. height:34px;
  49. }
  50. .l2Title {
  51. border-bottom:1px dotted #CCCCCC;
  52. font-size:14px;
  53. font-weight: bold;
  54. margin:0010px;
  55. }

l2Overlay 的 Javascript 代码

Js 代码不压缩只有 9.88 kb,YUI 压缩后只有 4.15 kb,对于不想只为了一个效果而引用一个库的来说,绝对是很好的选择。

  1. /**
  2. * Plugin Name: l2Overlay
  3. * Plugin Author: LOO2K
  4. * Plugin Address: http://loo2k.com/blog/l2overlay-a-javascript-based-hoverpop-plugin/
  5. * Plugin Edition: 0.1
  6. * Last updated: 2012.05.19
  7. */
  8. function l2Overlay(){
  9. this.initialize.apply(this, arguments);
  10. }
  11.  
  12. l2Overlay.prototype ={
  13. /*
  14. * object 要应用 l2Overlay 的元素 对象或者数组
  15. * content 显示内容 'function|html|string|target'
  16. * option 选项
  17. * option = {
  18. * 'title' = 'string', // defalut undefied
  19. * 'pos' = 'auto|lt|lb|rt|tb', // default auto
  20. * 'cache' = 'true|false' // default false
  21. * }
  22. */
  23. initialize:function(object, content, option){
  24. this.id =(newDate()).getTime();
  25. this.createElement();
  26. var _this =this;
  27. this.object = object;
  28. this.content = content;
  29. this.option ={
  30. 'title': option.title ||undefined,
  31. 'pos': option.pos ||'auto',
  32. 'cache': option.cache ||false
  33. };
  34. this.hidel2Overlay;
  35. this.l2Overlay.onmouseover =function(){
  36. _this.cancleHide();
  37. }
  38. this.l2Overlay.onmouseout =function(){
  39. _this.hideOverlay();
  40. }
  41. if(typeofthis.object ==='object'&&typeofthis.object.length ==='number'){
  42. for(var i =0; i <this.object.length; i++){
  43. this.addEvent(this.object[i]);
  44. }
  45. }elseif(typeofthis.object =='object'&&!(this.object instanceof Array)){
  46. this.addEvent(this.object);
  47. }else{
  48. alert('传入对象错误');
  49. }
  50. },
  51. createElement:function(){
  52. // 生成基本模版
  53. if(!document.getElementById('l2Overlay_'+this.id)){
  54. var overlay = document.createElement('div');
  55. overlay.id ='l2Overlay_'+this.id;
  56. overlay.style.position ='absolute';
  57. overlay.style.zIndex ='9999';
  58. overlay.style.display ='none';
  59. var wrapper = document.createElement('div');
  60. wrapper.className ='l2OverlayWrapper';
  61. var arrow = document.createElement('div');
  62. arrow.className ='l2OverlayArrow';
  63.  
  64. var content = document.createElement('div');
  65. content.className ='l2OverlayContent';
  66. wrapper.appendChild(arrow);
  67. wrapper.appendChild(content);
  68. overlay.appendChild(wrapper);
  69. document.getElementsByTagName('body')[0].appendChild(overlay);
  70. }
  71. this.l2Overlay = document.getElementById('l2Overlay_'+this.id);
  72. var wrapper =this.l2Overlay.getElementsByTagName('div')[0].getElementsByTagName('div');
  73. this.l2Content = wrapper[1];
  74. this.l2Arrow = wrapper[0];
  75. },
  76. getPos:function(el){
  77. var ua = navigator.userAgent.toLowerCase();
  78. var isOpera =(ua.indexOf('opera')!=-1);
  79. var isIE =(ua.indexOf('msie')!=-1&&!isOpera);
  80. if( el.parentNode ===null|| el.style.display =='none'){
  81. returnfalse;
  82. }
  83. var parent =null;
  84. var pos =[];
  85. var box;
  86.  
  87. if( el.getBoundingClientRect ){
  88. // For IE
  89. box = el.getBoundingClientRect();
  90. var scrollTop =Math.max(document.documentElement.scrollTop, document.body.scrollTop);
  91. var scrollLeft =Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
  92. return{
  93. x: box.left + scrollLeft,
  94. y: box.top + scrollTop
  95. };
  96. }elseif( document.getBoxObjectFor ){
  97. // For FF
  98. box = document.getBoxObjectFor(el);
  99. var borderLeft =(el.style.borderLeftWidth)? parseInt(el.style.borderLeftWidth):0;
  100. var borderTop =(el.style.borderTopWidth)? parseInt(el.style.borderTopWidth):0;
  101. pos =[box.x - borderLeft, box.y - borderTop];
  102. }else{
  103. // For Safari & Opera
  104. pos =[el.offsetLeft, el.offsetTop];
  105. parent = el.offsetParent;
  106. if( parent != el ){
  107. while(parent){
  108. pos[0]+= parent.offsetLeft;
  109. pos[1]+= parent.offsetTop;
  110. parent = parent.offsetParent;
  111. }
  112. }
  113. if( ua.indexOf('opera')!=-1||(ua.indexOf('safari')!=-1&& el.style.position =='absolute')){
  114. pos[0]-= document.body.offsetLeft;
  115. pos[1]-= document.body.offsetTop;
  116. }
  117. }
  118. if( el.parentNode ){
  119. parent = el.parentNode;
  120. }else{
  121. parent =null;
  122. }
  123. // account for any scrolled ancestors
  124. while(parent && parent.tagName !='BODY'&& parent.tagName !='HTML'){
  125. pos[0]-= parent.scrollLeft;
  126. pos[1]-= parent.scrollTop;
  127. if(parent.parentNode){
  128. parent = parent.parentNode;
  129. }else{
  130. parent =null;
  131. }
  132. }
  133. return{
  134. x: pos[0],
  135. y: pos[1]
  136. };
  137. },
  138. getSize:function(element){
  139. if(element.offsetWidth !==0){
  140. /* 元素不是display:none的情况,这个时候是能得到尺寸的 */
  141. return{
  142. 'width': element.offsetWidth,
  143. 'height': element.offsetHeight
  144. };
  145. }
  146. var old ={};
  147. /* 将display:none元素设成visibility:hidden */
  148. var options ={
  149. position:"absolute",
  150. visibility:"hidden",
  151. display:"block"
  152. }
  153. for(var name in options ){
  154. old[ name ]= element.style[ name ];
  155. element.style[ name ]= options[ name ];
  156. }
  157. var temp ={
  158. 'width': element.offsetWidth,
  159. 'height': element.offsetHeight
  160. };
  161. for(var name in options ){
  162. element.style[ name ]= old[ name ];
  163. }
  164. return temp;
  165. },
  166. hideOverlay:function(){
  167. var _this =this;
  168. this.hidel2Overlay = setTimeout(function(){
  169. _this.l2Overlay.style.display ='none';
  170. },100);
  171. },
  172. cancleHide:function(){
  173. if(this.hidel2Overlay ){
  174. clearTimeout(this.hidel2Overlay);
  175. }
  176. },
  177. getBrowser:function(){
  178. var offset ={
  179. 'top': document.documentElement.scrollTop || document.body.scrollTop,
  180. 'left': document.documentElement.scrollLeft || document.body.scrollLeft
  181. }
  182. return offset;
  183. },
  184. addEvent:function(object){
  185. var _this =this;
  186. //var _object = this.object;
  187. var _object = object;
  188. _object.onmouseover =function(){
  189. _this.cancleHide();
  190. // 缓存模块
  191. if( _this.option.cache &&this.l2cache ){
  192. _this.l2Content.innerHTML =this.l2cache;
  193. }elseif(typeof _this.content ==='function'){
  194. _this.l2Content.innerHTML = _this.content.apply(this, arguments);;
  195. //console.log(_this.content());
  196. }else{
  197. _this.l2Content.innerHTML = _this.content;
  198. }
  199. if( _this.option.cache &&!this.l2cache ){
  200. this.l2cache = _this.l2Content.innerHTML;
  201. }
  202. // 定位模块
  203. var position = _this.getPos(this);
  204. var curTop = position.y;
  205. var curLeft = position.x;
  206. var offset = _this.getSize(_this.l2Overlay);
  207. var self = _this.getSize(this);
  208. var browser = _this.getBrowser();
  209. var pos ='';
  210. if( _this.option.pos ==='auto'){
  211. if((curLeft - browser.left - offset.width)>0){
  212. pos +='r';
  213. }else{
  214. pos +='l';
  215. }
  216. if((curTop - browser.top - offset.height)>0){
  217. pos +='b';
  218. }else{
  219. pos +='t';
  220. }
  221. }else{
  222. pos = _this.option.pos;
  223. }
  224. switch(pos){
  225. case'lt':
  226. _this.l2Overlay.className ='arrow-lt';
  227. oTop = curTop + self.height;
  228. oLeft = curLeft;
  229. break;
  230. case'rt':
  231. _this.l2Overlay.className ='arrow-rt';
  232. oTop = curTop + self.height;
  233. oLeft = curLeft - offset.width + self.width;
  234. break;
  235. case'rb':
  236. _this.l2Overlay.className ='arrow-rb';
  237. oTop = curTop - offset.height;
  238. oLeft = curLeft - offset.width + self.width;
  239. break;
  240. case'lb':
  241. default:
  242. _this.l2Overlay.className ='arrow-lb';
  243. oTop = curTop - offset.height;
  244. oLeft = curLeft;
  245. break;
  246. }
  247. _this.l2Overlay.style.top = oTop +'px';
  248. _this.l2Overlay.style.left = oLeft +'px';
  249. _this.l2Overlay.style.display ='';
  250. }
  251. _object.onmouseout =function(){
  252. _this.hideOverlay();
  253. }
  254. }
  255. }

l2Overlay 的使用方法

l2Overlay 创建了一个函数对象 l2Overlay,接受三个参数。分别为:

  1. object: 传入的必须是 HTML 元素,或者是 HTML 元素数组;
  2. content: 显示内容,可以是函数,HTML 代码,或者字符串,作用域为 object;
  3. option: option 对象可以设置 l2Overlay 显示的位置以及是否启用缓存;
  1. var applyLinks = document.getElementById('demo').getElementsByTagName('a');
  2. var content =function(){
  3. var html ='<div class="l2Title">这是一个标题</div>';
  4. html +='Function 内的作用域为该链接,如执行 this.href 可以得到该链接的地址:';
  5. html +=this.href;
  6. html +='<div class="l2Action"><a href="#">添加</a> | <a href="#">修改</a> | <a href="#">删除</a></div>';
  7. return html;
  8. }
  9. var options ={'pos':'','cache':true};
  10. new l2Overlay(applyLinks, content, options);

参看演示效果可以到:l2Overlay 演示

下载插件可以到:l2Overlay 下载

小总结

第一次写 JavaScript 插件,功夫不到家,代码仅供参考 :P

其实这个用 jQuery 等库实现会简单很多,而且代码行数也会少很多,但是为了熟悉原生的 JavaScript 还是自己动手写了一遍。

posted on 2012-10-16 16:34  p-Flower  阅读(298)  评论(0编辑  收藏  举报

导航