|
| 1 | +/** |
| 2 | + * popover |
| 3 | + * shulkme |
| 4 | + * v0.0.1 |
| 5 | + * 2019-11-04 |
| 6 | + * https://github.com/shulkme/popover |
| 7 | + */ |
| 8 | +(function ($) { |
| 9 | + 'use strict'; |
| 10 | + var defaults = { |
| 11 | + //public options |
| 12 | + trigger : 'hover',//触发方式,'hover','click','focus' |
| 13 | + autoPlace : true,//自动放置,防止内容遮挡 |
| 14 | + delay : 10, //显示隐藏延时 |
| 15 | + placement : 'top', //放置偏好,'top', 'topLeft', 'topRight', |
| 16 | + // 'right', 'rightTop', 'rightBottom', |
| 17 | + // 'bottom', 'bottomLeft', 'bottomRight', |
| 18 | + // 'left', 'leftTop', 'leftBottom' |
| 19 | + //private options |
| 20 | + title : '', |
| 21 | + content : '' |
| 22 | + }; |
| 23 | + var Popover = function (element,options) { |
| 24 | + this.ele = $(element); |
| 25 | + this.wrapper = null; |
| 26 | + this.product = null; |
| 27 | + this.pid = 'popover_' + (new Date()).getTime(); |
| 28 | + this.timer_in = null; |
| 29 | + this.timer_out = null; |
| 30 | + this.mouse = false; |
| 31 | + //允许放置的方位名称 |
| 32 | + this.posMap = ['topLeft','top','topRight','rightTop','right','rightBottom','bottomLeft','bottom','bottomRight','leftTop','left','leftBottom']; |
| 33 | + this.posId = 1;//默认偏好放置索引 |
| 34 | + this.opts = $.extend({}, defaults, options); |
| 35 | + for (var i = this.posMap.length-1; i >=0;i--){ |
| 36 | + if (this.opts.placement === this.posMap[i]){ |
| 37 | + this.posId = i; |
| 38 | + break; |
| 39 | + } |
| 40 | + } |
| 41 | + this.init(); |
| 42 | + }; |
| 43 | + //初始化 |
| 44 | + Popover.prototype.init = function () { |
| 45 | + this.bind(); |
| 46 | + }; |
| 47 | + //渲染 |
| 48 | + Popover.prototype.render = function(){ |
| 49 | + var _this = this, |
| 50 | + _html, |
| 51 | + _pid = this.pid, |
| 52 | + _content, |
| 53 | + _container = $(document.body); |
| 54 | + if (typeof _this.opts.content == 'function') { |
| 55 | + _content = _this.opts.content.call(this); |
| 56 | + }else if (typeof _this.opts.content == 'object') { |
| 57 | + _content = $(_this.opts.content).html(); |
| 58 | + }else{ |
| 59 | + _content = _this.opts.content; |
| 60 | + } |
| 61 | + _html = '<div>'+ |
| 62 | + '<div class="popover" id="'+_pid+'">'+ |
| 63 | + '<div class="popover-container">'+ |
| 64 | + '<div class="popover-inner">'+ |
| 65 | + '<div class="popover-title">'+_this.opts.title+'</div>'+ |
| 66 | + '<div class="popover-content">'+_content+'</div>'+ |
| 67 | + '</div>'+ |
| 68 | + '<div class="popover-arrow"></div>'+ |
| 69 | + '</div>'+ |
| 70 | + '</div>'+ |
| 71 | + '</div>'; |
| 72 | + _container.append(_html); |
| 73 | + _this.product = $('#'+_pid);//渲染产品 |
| 74 | + _this.wrapper = _this.product.parent('div');//获取包裹容器 |
| 75 | + this.place(); |
| 76 | + }; |
| 77 | + //放置 |
| 78 | + Popover.prototype.place = function(){ |
| 79 | + var _this = this, |
| 80 | + _result,//最终输出的放置方案 |
| 81 | + _plan = [],//自动优化放置后的可选方案 |
| 82 | + _trigger = this.ele, |
| 83 | + _targets = this.wrapper, |
| 84 | + _product = this.product, |
| 85 | + _container = $(window), |
| 86 | + _gutter = 8; |
| 87 | + var _t = { |
| 88 | + x : _trigger.offset().left, |
| 89 | + y : _trigger.offset().top, |
| 90 | + w : _trigger.outerWidth(), |
| 91 | + h : _trigger.outerHeight() |
| 92 | + };//触发器的规格 |
| 93 | + var _v = { |
| 94 | + x : _container.scrollLeft(), |
| 95 | + y : _container.scrollTop(), |
| 96 | + w : _container.outerWidth(true), |
| 97 | + h : _container.outerHeight(true) |
| 98 | + };//视图容器的规格 |
| 99 | + var _p = { |
| 100 | + w : _product.outerWidth(true), |
| 101 | + h : _product.outerHeight(true) |
| 102 | + };//待放置物的规格 |
| 103 | + //计算所有放置方案 |
| 104 | + //所有宽度 |
| 105 | + var _W_ = { |
| 106 | + w1 : _v.w - (_t.x - _v.x), //t-l,b-l |
| 107 | + w2 : _v.w - (_t.x - _v.x) - _t.w, //r-tcb |
| 108 | + w3 : (_t.x - _v.x) + _t.w, //t-r,b-r |
| 109 | + w4 : _t.x - _v.x, //l-tcb |
| 110 | + w5 : (Math.min((_t.x - _v.x),(_v.w - _t.w - _t.x + _v.x)) + _t.w / 2) * 2 //t-c,b-c |
| 111 | + }; |
| 112 | + //所有高度 |
| 113 | + var _H_ = { |
| 114 | + h1 : _t.y - _v.y, //t-lcr |
| 115 | + h2 : _v.h - (_t.x - _v.x), //l-t,r-t |
| 116 | + h3 : _v.h - (_t.y - _v.y) - _t.h,//b-lcr |
| 117 | + h4 : (_t.y - _v.y) + _t.h,//l-b,r-b |
| 118 | + h5 : (Math.min((_t.y - _v.y),(_v.h - _t.h - _t.y + _v.y)) + _t.h / 2) * 2//l-c,r-c |
| 119 | + }; |
| 120 | + //所有top |
| 121 | + var _T_ = { |
| 122 | + t1 : _t.y - _p.h, //t-lcr |
| 123 | + t2 : _t.y - _gutter, //l-t,r-t |
| 124 | + t3 : _t.y + _t.h,//b-lcr |
| 125 | + t4 : _t.y + _t.h - _p.h + _gutter,//l-b,r-b |
| 126 | + t5 : _t.y + (_t.h - _p.h) / 2 //l-c,r-c |
| 127 | + }; |
| 128 | + //所有left |
| 129 | + var _L_ = { |
| 130 | + l1 : _t.x - _gutter, //t-l,b-l |
| 131 | + l2 : _t.x + _t.w,//r-tcb |
| 132 | + l3 : _t.x + _t.w - _p.w + _gutter,//t-r,b-r |
| 133 | + l4 : _t.x - _p.w,//l-tcb |
| 134 | + l5 : _t.x + (_t.w - _p.w) / 2//t-c,b-c |
| 135 | + }; |
| 136 | + //所有区域参数 |
| 137 | + var _area = [ |
| 138 | + { |
| 139 | + name : 'topLeft', |
| 140 | + width : _W_.w1, |
| 141 | + height : _H_.h1, |
| 142 | + top : _T_.t1, |
| 143 | + left : _L_.l1 |
| 144 | + },{ |
| 145 | + name : 'top', |
| 146 | + width : _W_.w5, |
| 147 | + height : _H_.h1, |
| 148 | + top : _T_.t1, |
| 149 | + left : _L_.l5 |
| 150 | + },{ |
| 151 | + name : 'topRight', |
| 152 | + width : _W_.w3, |
| 153 | + height : _H_.h1, |
| 154 | + top : _T_.t1, |
| 155 | + left : _L_.l3 |
| 156 | + },{ |
| 157 | + name : 'rightTop', |
| 158 | + width : _W_.w2, |
| 159 | + height : _H_.h2, |
| 160 | + top : _T_.t2, |
| 161 | + left : _L_.l2 |
| 162 | + |
| 163 | + },{ |
| 164 | + name : 'right', |
| 165 | + width : _W_.w2, |
| 166 | + height : _H_.h5, |
| 167 | + top : _T_.t5, |
| 168 | + left : _L_.l2 |
| 169 | + |
| 170 | + },{ |
| 171 | + name : 'rightBottom', |
| 172 | + width : _W_.w2, |
| 173 | + height : _H_.h4, |
| 174 | + top : _T_.t4, |
| 175 | + left : _L_.l2 |
| 176 | + },{ |
| 177 | + name : 'bottomLeft', |
| 178 | + width : _W_.w1, |
| 179 | + height : _H_.h3, |
| 180 | + top : _T_.t3, |
| 181 | + left : _L_.l1 |
| 182 | + },{ |
| 183 | + name : 'bottom', |
| 184 | + width : _W_.w5, |
| 185 | + height : _H_.h3, |
| 186 | + top : _T_.t3, |
| 187 | + left : _L_.l5 |
| 188 | + },{ |
| 189 | + name : 'bottomRight', |
| 190 | + width : _W_.w3, |
| 191 | + height : _H_.h3, |
| 192 | + top : _T_.t3, |
| 193 | + left : _L_.l3 |
| 194 | + },{ |
| 195 | + name : 'leftTop', |
| 196 | + width : _W_.w4, |
| 197 | + height : _H_.h2, |
| 198 | + top : _T_.t2, |
| 199 | + left : _L_.l4 |
| 200 | + },{ |
| 201 | + name : 'left', |
| 202 | + width : _W_.w4, |
| 203 | + height : _H_.h5, |
| 204 | + top : _T_.t5, |
| 205 | + left : _L_.l4 |
| 206 | + },{ |
| 207 | + name : 'leftBottom', |
| 208 | + width : _W_.w4, |
| 209 | + height : _H_.h4, |
| 210 | + top : _T_.t4, |
| 211 | + left : _L_.l4 |
| 212 | + } |
| 213 | + ]; |
| 214 | + $.each(_area,function (i,res) { |
| 215 | + //筛选所有符合放置的方案 |
| 216 | + if (res.width >= _p.w && res.height >= _p.h){ |
| 217 | + _plan.push(res); |
| 218 | + } |
| 219 | + }); |
| 220 | + if (_this.opts.autoPlace) { |
| 221 | + if (_plan.length){ |
| 222 | + //启用自动优化放置方案 |
| 223 | + _result = _plan[0]; |
| 224 | + for (var i = _plan.length-1; i>=0;i--) { |
| 225 | + if (_plan[i].name === _this.opts.placement){ |
| 226 | + _result = _plan[i];//找到一条既符合优化放置,又符合用户规定的方案 |
| 227 | + break; |
| 228 | + } |
| 229 | + } |
| 230 | + } else{ |
| 231 | + //没有找到符合优化放置方案,选择默认偏好放置 |
| 232 | + _result = _area[_this.posId]; |
| 233 | + } |
| 234 | + }else{ |
| 235 | + //不启用自动优化放置方案,选择默认偏好放置 |
| 236 | + _result = _area[_this.posId]; |
| 237 | + } |
| 238 | + _targets.css({ |
| 239 | + 'position' : 'absolute', |
| 240 | + 'top' : _result.top + 'px', |
| 241 | + 'left': _result.left + 'px' |
| 242 | + }); |
| 243 | + _product.addClass('popover-'+_result.name); |
| 244 | + //为渲染的产品绑定事件 |
| 245 | + _targets.mouseenter(function () { |
| 246 | + _this.show() |
| 247 | + }); |
| 248 | + if (_this.opts.trigger !== 'click' && _this.opts.trigger !== 'focus'){ |
| 249 | + _targets.mouseleave(function () { |
| 250 | + _this.destroy() |
| 251 | + }); |
| 252 | + } |
| 253 | + }; |
| 254 | + //绑定事件 |
| 255 | + Popover.prototype.bind = function(){ |
| 256 | + var _this = this, |
| 257 | + _trigger = this.opts.trigger, |
| 258 | + _element = $(this.ele); |
| 259 | + switch (_trigger) { |
| 260 | + case "click": |
| 261 | + _element.on('click',function (e) { |
| 262 | + e.stopPropagation(); |
| 263 | + _this.product = $('#'+_this.pid); |
| 264 | + if (!_this.product.length){ |
| 265 | + _this.mouse = false; |
| 266 | + _this.show(); |
| 267 | + }else{ |
| 268 | + _this.destroy(); |
| 269 | + } |
| 270 | + }); |
| 271 | + $(document).on('click',function (e) { |
| 272 | + var _trigger = $(e.target); |
| 273 | + if (!_trigger.closest('.popover').length){ |
| 274 | + $('.popover').parent('div').remove(); |
| 275 | + } |
| 276 | + }); |
| 277 | + break; |
| 278 | + case "focus": |
| 279 | + _element.on({ |
| 280 | + 'focus' : function () { |
| 281 | + _this.product = $('#'+_this.pid); |
| 282 | + if (!_this.product.length){ |
| 283 | + _this.mouse = false; |
| 284 | + _this.show() |
| 285 | + } |
| 286 | + }, |
| 287 | + 'blur' : function () { |
| 288 | + _this.product = $('#'+_this.pid); |
| 289 | + if (_this.product.length){ |
| 290 | + _this.destroy(); |
| 291 | + } |
| 292 | + } |
| 293 | + }); |
| 294 | + break; |
| 295 | + default : |
| 296 | + _element.hover(function () { |
| 297 | + _this.show() |
| 298 | + },function () { |
| 299 | + _this.destroy() |
| 300 | + }); |
| 301 | + } |
| 302 | + }; |
| 303 | + //显示 |
| 304 | + Popover.prototype.show = function(){ |
| 305 | + var _this = this; |
| 306 | + window.clearTimeout(_this.timer_out); |
| 307 | + if (!_this.mouse){ |
| 308 | + _this.timer_in = window.setTimeout(function () { |
| 309 | + _this.mouse = true; |
| 310 | + _this.render(); |
| 311 | + },_this.opts.delay); |
| 312 | + } |
| 313 | + }; |
| 314 | + //销毁 |
| 315 | + Popover.prototype.destroy = function(){ |
| 316 | + var _this = this; |
| 317 | + window.clearTimeout(_this.timer_in); |
| 318 | + _this.timer_out = window.setTimeout(function () { |
| 319 | + _this.mouse = false; |
| 320 | + $('.popover').parent('div').remove(); |
| 321 | + _this.product = null; |
| 322 | + },_this.opts.delay); |
| 323 | + }; |
| 324 | + $.fn.popover = function(options) { |
| 325 | + var _this = this; |
| 326 | + return _this.each(function () { |
| 327 | + return new Popover(this, options); |
| 328 | + }); |
| 329 | + }; |
| 330 | +})(jQuery); |
1 | 331 | /**
|
2 | 332 | * Created by toplan on 15/7/11.
|
3 | 333 | */
|
|
0 commit comments