popup.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. window.Popup = (function(d) {
  2. var _instance = null,
  3. _progressInstance = null,
  4. doc = d.body,
  5. docWidth = doc.clientWidth,
  6. docHeight = doc.clientHeight;
  7. function Dialog() {
  8. this.title = '标题';
  9. this.content = '内容';
  10. this.btns = [
  11. {name : '确定', ac : function() {}},
  12. {name : '取消', ac : function() {}}
  13. ];
  14. this.type = 'alert';
  15. this.hasTitle = true;
  16. this.timeout = 500;
  17. this.dialogWrapper = null;
  18. this.mask = null;
  19. this.fadeTime = 250;
  20. this.fadeInTime = 0;
  21. this.hasDialog = false;
  22. // loading
  23. this.loadingText = '正在加载';
  24. this.hasLoadingText = false;
  25. this.spinNumber = 8; // 菊花瓣数
  26. this.loadingRadius = 18; // 菊花半径
  27. this.startAngle = 90; // 正上方菊花角度
  28. this.spinMargin = 2;
  29. }
  30. Dialog.prototype = {
  31. /**
  32. * 创建mask
  33. *
  34. * @return {[type]} [description]
  35. */
  36. _createMask : function() {
  37. var _this = this;
  38. if (!this.mask) {
  39. this.mask = document.createElement('div');
  40. this.mask.className = 'ui-mask fade';
  41. doc.appendChild(this.mask);
  42. // 在创建了mask之后250ms,给其设置透明度为1,达到动画效果
  43. setTimeout(function() {
  44. _this.mask.className = 'ui-mask fade in';
  45. }, this.fadeInTime);
  46. }
  47. },
  48. /**
  49. * 移除mask
  50. *
  51. * @return {[type]} [description]
  52. */
  53. _removeMask : function() {
  54. var _this = this;
  55. if (this.mask) {
  56. // 移除dom之前,给其设置className,达到动画过渡效果
  57. this.mask.className = 'ui-mask fade';
  58. setTimeout(function() {
  59. _this.mask.remove();
  60. _this.mask = null;
  61. }, this.fadeTime);
  62. }
  63. },
  64. /**
  65. * 创建弹窗的容器
  66. *
  67. * @return {[type]} [description]
  68. */
  69. _createWrapper : function() {
  70. if (!this.dialogWrapper) {
  71. this.dialogWrapper = document.createElement('div');
  72. }
  73. },
  74. /**
  75. * 移除弹窗的容器
  76. *
  77. * @return {[type]} [description]
  78. */
  79. _removeWrapper : function() {
  80. var _this = this;
  81. if (this.dialogWrapper) {
  82. if (this.type === 'toast') {
  83. this.dialogWrapper.className = 'ui-dialog ui-toast fade';
  84. } else if(this.type === 'loading') {
  85. this.dialogWrapper.className = 'ui-dialog ui-loading fade';
  86. } else if(this.type === 'progress') {
  87. this.dialogWrapper.className = 'ui-dialog ui-progress fade';
  88. } else {
  89. this.dialogWrapper.className = 'ui-dialog fade';
  90. }
  91. setTimeout(function() {
  92. _this.dialogWrapper.remove();
  93. _this.dialogWrapper = null;
  94. _this.hasDialog = false;
  95. }, this.fadeTime);
  96. }
  97. },
  98. /**
  99. * 如果存在标题,则创建标题容器
  100. *
  101. * @return {[type]} [description]
  102. */
  103. _createTitle : function() {
  104. var title = document.createElement('div');
  105. title.className = 'ui-title';
  106. title.textContent = this.title;
  107. return title;
  108. },
  109. /**
  110. * 创建内容区域
  111. *
  112. * @return {[type]} [description]
  113. */
  114. _createContent : function() {
  115. var content = document.createElement('div');
  116. content.className = 'ui-content';
  117. content.textContent = this.content;
  118. return content;
  119. },
  120. /**
  121. * 创建按钮组
  122. *
  123. * @return {[type]} [description]
  124. */
  125. _createBtns : function() {
  126. var buttons = document.createElement('div'), _this = this;
  127. buttons.className = 'ui-btns';
  128. this.btns && this.btns.forEach(function(btn, index) {
  129. var link = document.createElement('a');
  130. link.href = 'javascript:void(0)';
  131. link.textContent = btn.name;
  132. buttons.appendChild(link);
  133. link.addEventListener('click', function() {
  134. _this.close();
  135. btn.ac && btn.ac();
  136. });
  137. });
  138. return buttons;
  139. },
  140. /**
  141. * 创建loading文字
  142. *
  143. * @return {[type]} [description]
  144. */
  145. _createLoadingText : function() {
  146. var text = document.createElement('div');
  147. text.className = 'ui-text';
  148. text.textContent = this.loadingText;
  149. return text;
  150. },
  151. /**
  152. * 创建loading菊花
  153. *
  154. * @return {[type]} [description]
  155. */
  156. _createLoadingContent : function() {
  157. var content = document.createElement('div'),
  158. lineSpin = document.createElement('div'),
  159. deltaAngle = 360 / this.spinNumber;
  160. content.className = 'ui-content';
  161. if (!this.hasLoadingText) {
  162. content.style.height = '86px';
  163. content.style.borderRadius = '5px';
  164. }
  165. lineSpin.className = 'ui-line-spin';
  166. lineSpin.style.width = (this.loadingRadius * 2 + this.spinMargin * 2) + 'px';
  167. lineSpin.style.height = (this.loadingRadius * 2 + this.spinMargin * 2) + 'px';
  168. for (var i = 0; i < this.spinNumber; i++) {
  169. var div = document.createElement('div');
  170. var angle = this.startAngle + i * (-deltaAngle),
  171. rotateAngle = i * deltaAngle,
  172. p = Math.PI * 2 * (angle / 360);
  173. div.style.top = this.loadingRadius * (1 - Math.sin(p)) + 'px';
  174. div.style.left = this.loadingRadius * (1 + Math.cos(p)) + 'px';
  175. div.style.transform = 'rotate('+rotateAngle+'deg)';
  176. div.style.WebkitTransform = 'rotate('+rotateAngle+'deg)';
  177. div.style.MozTransform = 'rotate('+rotateAngle+'deg)';
  178. div.style.msTransform = 'rotate('+rotateAngle+'deg)';
  179. div.style.OTransform = 'rotate('+rotateAngle+'deg)';
  180. lineSpin.appendChild(div);
  181. }
  182. content.appendChild(lineSpin);
  183. return content;
  184. },
  185. /**
  186. * 渲染弹窗
  187. *
  188. * @return {[type]} [description]
  189. */
  190. _renderDialog : function() {
  191. this._createWrapper();
  192. switch (this.type) {
  193. case 'confirm':
  194. this.dialogWrapper.className = 'ui-dialog fade';
  195. var title, content, btns, _this = this;
  196. content = this._createContent();
  197. btns = this._createBtns();
  198. if (this.hasTitle) {
  199. title = this._createTitle();
  200. this.dialogWrapper.appendChild(title);
  201. }
  202. this.dialogWrapper.appendChild(content);
  203. this.dialogWrapper.appendChild(btns);
  204. doc.appendChild(this.dialogWrapper);
  205. setTimeout(function() {
  206. _this.dialogWrapper.className = 'ui-dialog fade in';
  207. }, this.fadeInTime);
  208. break;
  209. case 'toast':
  210. this.dialogWrapper.className = 'ui-dialog ui-toast fade';
  211. var content = this._createContent(), _this = this;
  212. this.dialogWrapper.appendChild(content);
  213. doc.appendChild(this.dialogWrapper);
  214. setTimeout(function() {
  215. _this.dialogWrapper.className = 'ui-dialog ui-toast fade in';
  216. }, this.fadeInTime);
  217. setTimeout(function() {
  218. _this.close();
  219. }, this.timeout);
  220. break;
  221. case 'loading':
  222. this.dialogWrapper.className = 'ui-dialog ui-loading fade';
  223. var text, content, _this = this;
  224. content = this._createLoadingContent();
  225. if (this.hasLoadingText) {
  226. text = this._createLoadingText();
  227. this.dialogWrapper.appendChild(text);
  228. }
  229. this.dialogWrapper.appendChild(content);
  230. doc.appendChild(this.dialogWrapper);
  231. setTimeout(function() {
  232. _this.dialogWrapper.className = 'ui-dialog ui-loading fade in';
  233. }, this.fadeInTime);
  234. break;
  235. default:
  236. break;
  237. }
  238. },
  239. /**
  240. * confirm/alert 弹窗,返回供外部使用
  241. *
  242. * @return {[type]} [description]
  243. */
  244. confirm : function() {
  245. var args = arguments && arguments[0],
  246. length = args && args.length;
  247. if (length === 3) {
  248. // 有标题
  249. this.title = args[0];
  250. this.content = args[1];
  251. this.btns = args[2];
  252. this.hasTitle = true;
  253. } else if(length === 2) {
  254. this.content = args[0];
  255. this.btns = args[1];
  256. this.hasTitle = false;
  257. } else {
  258. // alert
  259. this.hasTitle = false;
  260. this.content = args[0];
  261. this.btns = [{name : '确定'}]
  262. }
  263. this.type = 'confirm';
  264. this._create();
  265. },
  266. /**
  267. * toast弹窗,返回供外部使用
  268. *
  269. * @return {[type]} [description]
  270. */
  271. toast : function() {
  272. var args = arguments && arguments[0],
  273. length = args && args.length;
  274. if (length === 2) {
  275. this.content = args[0];
  276. this.timeout = args[1];
  277. } else if(length === 1) {
  278. this.content = args[0];
  279. }
  280. this.type = 'toast';
  281. if (!this.hasDialog) {
  282. this._create();
  283. }
  284. this.hasDialog = true;
  285. },
  286. /**
  287. * loading弹窗,返回供外部使用
  288. *
  289. * @return {[type]} [description]
  290. */
  291. showLoading : function() {
  292. var args = arguments && arguments[0],
  293. length = args && args.length;
  294. // 带有参数
  295. if (length === 1) {
  296. this.loadingText = args[0];
  297. this.hasLoadingText = true;
  298. }
  299. this.type = 'loading';
  300. this._create();
  301. },
  302. /**
  303. * 创建弹窗
  304. *
  305. * @return {[type]} [description]
  306. */
  307. _create : function() {
  308. this._createMask();
  309. this._renderDialog();
  310. },
  311. /**
  312. * 关闭弹窗
  313. *
  314. * @return {[type]} [description]
  315. */
  316. close : function() {
  317. this._removeMask();
  318. this._removeWrapper();
  319. _instance = null;
  320. _progressInstance = null;
  321. }
  322. };
  323. function Progress() {
  324. Dialog.call(this);
  325. this.percent = 0;
  326. this.text = '正在更新程序';
  327. this.innerBar = null;
  328. }
  329. /**
  330. * 继承
  331. * @param {[type]} subClass [description]
  332. * @param {[type]} superClass [description]
  333. * @return {[type]} [description]
  334. */
  335. function inherit(subClass, superClass) {
  336. function F() {}
  337. F.prototype = superClass.prototype;
  338. subClass.prototype = new F();
  339. subClass.prototype.constructor = subClass;
  340. }
  341. /**
  342. * 继承条用
  343. */
  344. inherit(Progress, Dialog);
  345. /**
  346. * 创建进度条文字
  347. * @return {[type]} [description]
  348. */
  349. Progress.prototype._createProgressText = function() {
  350. var text = document.createElement('div');
  351. text.className = 'ui-text';
  352. text.textContent = this.text;
  353. return text;
  354. }
  355. /**
  356. * 创建进度条
  357. * @return {[type]} [description]
  358. */
  359. Progress.prototype._createProgressContent = function() {
  360. var content = document.createElement('div'),
  361. outer = document.createElement('div'),
  362. inner = document.createElement('div');
  363. content.className = 'ui-content';
  364. outer.className = 'ui-outer';
  365. inner.className = 'ui-inner';
  366. outer.appendChild(inner);
  367. content.appendChild(outer)
  368. this.innerBar = inner;
  369. return content;
  370. }
  371. /**
  372. * 进度条初始化
  373. * @return {[type]} [description]
  374. */
  375. Progress.prototype.init = function() {
  376. var text, content, bar, _this = this;
  377. // 创建mask
  378. this._createMask();
  379. // 创建warpper
  380. this._createWrapper();
  381. this.dialogWrapper.className = 'ui-dialog ui-progress fade';
  382. // 1. 创建文字
  383. text = this._createProgressText();
  384. // 2. 创建内容
  385. content = this._createProgressContent();
  386. // 3. 将文字和content加入到warpper中
  387. this.dialogWrapper.appendChild(text);
  388. this.dialogWrapper.appendChild(content);
  389. // 4. 将warpper加入到body中
  390. doc.appendChild(this.dialogWrapper);
  391. setTimeout(function() {
  392. _this.dialogWrapper.className = 'ui-dialog ui-progress fade in';
  393. }, this.fadeInTime);
  394. }
  395. /**
  396. * 创建进度条
  397. * @return {[type]} [description]
  398. */
  399. Progress.prototype.create = function() {
  400. var args = arguments && arguments[0],
  401. length = args && args.length;
  402. if (length === 1) {
  403. this.text = args[0];
  404. }
  405. this.type = 'progress';
  406. this.init();
  407. return this;
  408. }
  409. /**
  410. * 更新进度条进度
  411. * @return {[type]} [description]
  412. */
  413. Progress.prototype.update = function(percent) {
  414. if (this.percent === 100) {
  415. this.close();
  416. }
  417. this.percent = percent;
  418. this.innerBar.style.width = percent + '%';
  419. }
  420. /**
  421. * 关闭进度条
  422. * @return {[type]} [description]
  423. */
  424. Progress.prototype.closeBar = function() {
  425. this.percent = 0;
  426. this.close();
  427. }
  428. /**
  429. * 获取dialog实例
  430. * @return {[type]} [description]
  431. */
  432. function _getInstance() {
  433. if (!_instance) {
  434. _instance = new Dialog();
  435. }
  436. return _instance;
  437. }
  438. /**
  439. * 获取进度条实例
  440. * @return {[type]} [description]
  441. */
  442. function _getProgressInstance() {
  443. if (!_progressInstance) {
  444. _progressInstance = new Progress();
  445. }
  446. return _progressInstance;
  447. }
  448. /**
  449. * return 调用
  450. */
  451. return {
  452. alert : function() {
  453. return _getInstance().confirm(arguments);
  454. },
  455. confirm : function() {
  456. return _getInstance().confirm(arguments);
  457. },
  458. toast : function() {
  459. return _getInstance().toast(arguments);
  460. },
  461. showLoading : function() {
  462. return _getInstance().showLoading(arguments);
  463. },
  464. progress : function() {
  465. return _getProgressInstance().create(arguments);
  466. },
  467. close : function() {
  468. return _getInstance().close();
  469. }
  470. }
  471. })(document);