mui.picker.all.js 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018
  1. /**
  2. * 选择列表插件
  3. * varstion 2.0.0
  4. * by Houfeng
  5. * Houfeng@DCloud.io
  6. */
  7. (function($, window, document, undefined) {
  8. var MAX_EXCEED = 30;
  9. var VISIBLE_RANGE = 90;
  10. var DEFAULT_ITEM_HEIGHT = 40;
  11. var BLUR_WIDTH = 10;
  12. var rad2deg = $.rad2deg = function(rad) {
  13. return rad / (Math.PI / 180);
  14. };
  15. var deg2rad = $.deg2rad = function(deg) {
  16. return deg * (Math.PI / 180);
  17. };
  18. var platform = navigator.platform.toLowerCase();
  19. var userAgent = navigator.userAgent.toLowerCase();
  20. var isIos = (userAgent.indexOf('iphone') > -1 ||
  21. userAgent.indexOf('ipad') > -1 ||
  22. userAgent.indexOf('ipod') > -1) &&
  23. (platform.indexOf('iphone') > -1 ||
  24. platform.indexOf('ipad') > -1 ||
  25. platform.indexOf('ipod') > -1);
  26. //alert(isIos);
  27. var Picker = $.Picker = function(holder, options) {
  28. var self = this;
  29. self.holder = holder;
  30. self.options = options || {};
  31. self.init();
  32. self.initInertiaParams();
  33. self.calcElementItemPostion(true);
  34. self.bindEvent();
  35. };
  36. Picker.prototype.findElementItems = function() {
  37. var self = this;
  38. self.elementItems = [].slice.call(self.holder.querySelectorAll('li'));
  39. return self.elementItems;
  40. };
  41. Picker.prototype.init = function() {
  42. var self = this;
  43. self.list = self.holder.querySelector('ul');
  44. self.findElementItems();
  45. self.height = self.holder.offsetHeight;
  46. self.r = self.height / 2 - BLUR_WIDTH;
  47. self.d = self.r * 2;
  48. self.itemHeight = self.elementItems.length > 0 ? self.elementItems[0].offsetHeight : DEFAULT_ITEM_HEIGHT;
  49. self.itemAngle = parseInt(self.calcAngle(self.itemHeight * 0.8));
  50. self.hightlightRange = self.itemAngle / 2;
  51. self.visibleRange = VISIBLE_RANGE;
  52. self.beginAngle = 0;
  53. self.beginExceed = self.beginAngle - MAX_EXCEED;
  54. self.list.angle = self.beginAngle;
  55. if (isIos) {
  56. self.list.style.webkitTransformOrigin = "center center " + self.r + "px";
  57. }
  58. };
  59. Picker.prototype.calcElementItemPostion = function(andGenerateItms) {
  60. var self = this;
  61. if (andGenerateItms) {
  62. self.items = [];
  63. }
  64. self.elementItems.forEach(function(item) {
  65. var index = self.elementItems.indexOf(item);
  66. self.endAngle = self.itemAngle * index;
  67. item.angle = self.endAngle;
  68. item.style.webkitTransformOrigin = "center center -" + self.r + "px";
  69. item.style.webkitTransform = "translateZ(" + self.r + "px) rotateX(" + (-self.endAngle) + "deg)";
  70. if (andGenerateItms) {
  71. var dataItem = {};
  72. dataItem.text = item.innerHTML || '';
  73. dataItem.value = item.getAttribute('data-value') || dataItem.text;
  74. self.items.push(dataItem);
  75. }
  76. });
  77. self.endExceed = self.endAngle + MAX_EXCEED;
  78. self.calcElementItemVisibility(self.beginAngle);
  79. };
  80. Picker.prototype.calcAngle = function(c) {
  81. var self = this;
  82. var a = b = parseFloat(self.r);
  83. //直径的整倍数部分直接乘以 180
  84. c = Math.abs(c); //只算角度不关心正否值
  85. var intDeg = parseInt(c / self.d) * 180;
  86. c = c % self.d;
  87. //余弦
  88. var cosC = (a * a + b * b - c * c) / (2 * a * b);
  89. var angleC = intDeg + rad2deg(Math.acos(cosC));
  90. return angleC;
  91. };
  92. Picker.prototype.calcElementItemVisibility = function(angle) {
  93. var self = this;
  94. self.elementItems.forEach(function(item) {
  95. var difference = Math.abs(item.angle - angle);
  96. if (difference < self.hightlightRange) {
  97. item.classList.add('highlight');
  98. } else if (difference < self.visibleRange) {
  99. item.classList.add('visible');
  100. item.classList.remove('highlight');
  101. } else {
  102. item.classList.remove('highlight');
  103. item.classList.remove('visible');
  104. }
  105. });
  106. };
  107. Picker.prototype.setAngle = function(angle) {
  108. var self = this;
  109. self.list.angle = angle;
  110. self.list.style.webkitTransform = "perspective(1000px) rotateY(0deg) rotateX(" + angle + "deg)";
  111. self.calcElementItemVisibility(angle);
  112. };
  113. Picker.prototype.bindEvent = function() {
  114. var self = this;
  115. var lastAngle = 0;
  116. var startY = null;
  117. var isPicking = false;
  118. self.holder.addEventListener($.EVENT_START, function(event) {
  119. isPicking = true;
  120. event.preventDefault();
  121. self.list.style.webkitTransition = '';
  122. startY = (event.changedTouches ? event.changedTouches[0] : event).pageY;
  123. lastAngle = self.list.angle;
  124. self.updateInertiaParams(event, true);
  125. }, false);
  126. self.holder.addEventListener($.EVENT_END, function(event) {
  127. isPicking = false;
  128. event.preventDefault();
  129. self.startInertiaScroll(event);
  130. }, false);
  131. self.holder.addEventListener($.EVENT_CANCEL, function(event) {
  132. isPicking = false;
  133. event.preventDefault();
  134. self.startInertiaScroll(event);
  135. }, false);
  136. self.holder.addEventListener($.EVENT_MOVE, function(event) {
  137. if (!isPicking) {
  138. return;
  139. }
  140. event.preventDefault();
  141. var endY = (event.changedTouches ? event.changedTouches[0] : event).pageY;
  142. var dragRange = endY - startY;
  143. var dragAngle = self.calcAngle(dragRange);
  144. var newAngle = dragRange > 0 ? lastAngle - dragAngle : lastAngle + dragAngle;
  145. if (newAngle > self.endExceed) {
  146. newAngle = self.endExceed
  147. }
  148. if (newAngle < self.beginExceed) {
  149. newAngle = self.beginExceed
  150. }
  151. self.setAngle(newAngle);
  152. self.updateInertiaParams(event);
  153. }, false);
  154. //--
  155. self.list.addEventListener('tap', function(event) {
  156. elementItem = event.target;
  157. if (elementItem.tagName == 'LI') {
  158. self.setSelectedIndex(self.elementItems.indexOf(elementItem), 200);
  159. }
  160. }, false);
  161. };
  162. Picker.prototype.initInertiaParams = function() {
  163. var self = this;
  164. self.lastMoveTime = 0;
  165. self.lastMoveStart = 0;
  166. self.stopInertiaMove = false;
  167. };
  168. Picker.prototype.updateInertiaParams = function(event, isStart) {
  169. var self = this;
  170. var point = event.changedTouches ? event.changedTouches[0] : event;
  171. if (isStart) {
  172. self.lastMoveStart = point.pageY;
  173. self.lastMoveTime = event.timeStamp || Date.now();
  174. self.startAngle = self.list.angle;
  175. } else {
  176. var nowTime = event.timeStamp || Date.now();
  177. if (nowTime - self.lastMoveTime > 300) {
  178. self.lastMoveTime = nowTime;
  179. self.lastMoveStart = point.pageY;
  180. }
  181. }
  182. self.stopInertiaMove = true;
  183. };
  184. Picker.prototype.startInertiaScroll = function(event) {
  185. var self = this;
  186. var point = event.changedTouches ? event.changedTouches[0] : event;
  187. /**
  188. * 缓动代码
  189. */
  190. var nowTime = event.timeStamp || Date.now();
  191. var v = (point.pageY - self.lastMoveStart) / (nowTime - self.lastMoveTime); //最后一段时间手指划动速度
  192. var dir = v > 0 ? -1 : 1; //加速度方向
  193. var deceleration = dir * 0.0006 * -1;
  194. var duration = Math.abs(v / deceleration); // 速度消减至0所需时间
  195. var dist = v * duration / 2; //最终移动多少
  196. var startAngle = self.list.angle;
  197. var distAngle = self.calcAngle(dist) * dir;
  198. //----
  199. var srcDistAngle = distAngle;
  200. if (startAngle + distAngle < self.beginExceed) {
  201. distAngle = self.beginExceed - startAngle;
  202. duration = duration * (distAngle / srcDistAngle) * 0.6;
  203. }
  204. if (startAngle + distAngle > self.endExceed) {
  205. distAngle = self.endExceed - startAngle;
  206. duration = duration * (distAngle / srcDistAngle) * 0.6;
  207. }
  208. //----
  209. if (distAngle == 0) {
  210. self.endScroll();
  211. return;
  212. }
  213. self.scrollDistAngle(nowTime, startAngle, distAngle, duration);
  214. };
  215. Picker.prototype.scrollDistAngle = function(nowTime, startAngle, distAngle, duration) {
  216. var self = this;
  217. self.stopInertiaMove = false;
  218. (function(nowTime, startAngle, distAngle, duration) {
  219. var frameInterval = 13;
  220. var stepCount = duration / frameInterval;
  221. var stepIndex = 0;
  222. (function inertiaMove() {
  223. if (self.stopInertiaMove) return;
  224. var newAngle = self.quartEaseOut(stepIndex, startAngle, distAngle, stepCount);
  225. self.setAngle(newAngle);
  226. stepIndex++;
  227. if (stepIndex > stepCount - 1 || newAngle < self.beginExceed || newAngle > self.endExceed) {
  228. self.endScroll();
  229. return;
  230. }
  231. setTimeout(inertiaMove, frameInterval);
  232. })();
  233. })(nowTime, startAngle, distAngle, duration);
  234. };
  235. Picker.prototype.quartEaseOut = function(t, b, c, d) {
  236. return -c * ((t = t / d - 1) * t * t * t - 1) + b;
  237. };
  238. Picker.prototype.endScroll = function() {
  239. var self = this;
  240. if (self.list.angle < self.beginAngle) {
  241. self.list.style.webkitTransition = "150ms ease-out";
  242. self.setAngle(self.beginAngle);
  243. } else if (self.list.angle > self.endAngle) {
  244. self.list.style.webkitTransition = "150ms ease-out";
  245. self.setAngle(self.endAngle);
  246. } else {
  247. var index = parseInt((self.list.angle / self.itemAngle).toFixed(0));
  248. self.list.style.webkitTransition = "100ms ease-out";
  249. self.setAngle(self.itemAngle * index);
  250. }
  251. self.triggerChange();
  252. };
  253. Picker.prototype.triggerChange = function(force) {
  254. var self = this;
  255. setTimeout(function() {
  256. var index = self.getSelectedIndex();
  257. var item = self.items[index];
  258. if ($.trigger && (index != self.lastIndex || force === true)) {
  259. $.trigger(self.holder, 'change', {
  260. "index": index,
  261. "item": item
  262. });
  263. //console.log('change:' + index);
  264. }
  265. self.lastIndex = index;
  266. typeof force === 'function' && force();
  267. }, 0);
  268. };
  269. Picker.prototype.correctAngle = function(angle) {
  270. var self = this;
  271. if (angle < self.beginAngle) {
  272. return self.beginAngle;
  273. } else if (angle > self.endAngle) {
  274. return self.endAngle;
  275. } else {
  276. return angle;
  277. }
  278. };
  279. Picker.prototype.setItems = function(items) {
  280. var self = this;
  281. self.items = items || [];
  282. var buffer = [];
  283. self.items.forEach(function(item) {
  284. if (item !== null && item !== undefined) {
  285. buffer.push('<li>' + (item.text || item) + '</li>');
  286. }
  287. });
  288. self.list.innerHTML = buffer.join('');
  289. self.findElementItems();
  290. self.calcElementItemPostion();
  291. self.setAngle(self.correctAngle(self.list.angle));
  292. self.triggerChange(true);
  293. };
  294. Picker.prototype.getItems = function() {
  295. var self = this;
  296. return self.items;
  297. };
  298. Picker.prototype.getSelectedIndex = function() {
  299. var self = this;
  300. return parseInt((self.list.angle / self.itemAngle).toFixed(0));
  301. };
  302. Picker.prototype.setSelectedIndex = function(index, duration, callback) {
  303. var self = this;
  304. self.list.style.webkitTransition = '';
  305. var angle = self.correctAngle(self.itemAngle * index);
  306. if (duration && duration > 0) {
  307. var distAngle = angle - self.list.angle;
  308. self.scrollDistAngle(Date.now(), self.list.angle, distAngle, duration);
  309. } else {
  310. self.setAngle(angle);
  311. }
  312. self.triggerChange(callback);
  313. };
  314. Picker.prototype.getSelectedItem = function() {
  315. var self = this;
  316. return self.items[self.getSelectedIndex()];
  317. };
  318. Picker.prototype.getSelectedValue = function() {
  319. var self = this;
  320. return (self.items[self.getSelectedIndex()] || {}).value;
  321. };
  322. Picker.prototype.getSelectedText = function() {
  323. var self = this;
  324. return (self.items[self.getSelectedIndex()] || {}).text;
  325. };
  326. Picker.prototype.setSelectedValue = function(value, duration, callback) {
  327. var self = this;
  328. for (var index in self.items) {
  329. var item = self.items[index];
  330. if (item.value == value) {
  331. self.setSelectedIndex(index, duration, callback);
  332. return;
  333. }
  334. }
  335. };
  336. if ($.fn) {
  337. $.fn.picker = function(options) {
  338. //遍历选择的元素
  339. this.each(function(i, element) {
  340. if (element.picker) return;
  341. if (options) {
  342. element.picker = new Picker(element, options);
  343. } else {
  344. var optionsText = element.getAttribute('data-picker-options');
  345. var _options = optionsText ? JSON.parse(optionsText) : {};
  346. element.picker = new Picker(element, _options);
  347. }
  348. });
  349. return this[0] ? this[0].picker : null;
  350. };
  351. //自动初始化
  352. $.ready(function() {
  353. $('.mui-picker').picker();
  354. });
  355. }
  356. })(window.mui || window, window, document, undefined);
  357. //end
  358. /**
  359. * 弹出选择列表插件
  360. * 此组件依赖 listpcker ,请在页面中先引入 mui.picker.css + mui.picker.js
  361. * varstion 1.0.1
  362. * by Houfeng
  363. * Houfeng@DCloud.io
  364. */
  365. (function($, document) {
  366. //创建 DOM
  367. $.dom = function(str) {
  368. if (typeof(str) !== 'string') {
  369. if ((str instanceof Array) || (str[0] && str.length)) {
  370. return [].slice.call(str);
  371. } else {
  372. return [str];
  373. }
  374. }
  375. if (!$.__create_dom_div__) {
  376. $.__create_dom_div__ = document.createElement('div');
  377. }
  378. $.__create_dom_div__.innerHTML = str;
  379. return [].slice.call($.__create_dom_div__.childNodes);
  380. };
  381. var panelBuffer = '<div class="mui-poppicker">\
  382. <div class="mui-poppicker-header">\
  383. <button class="mui-btn mui-poppicker-btn-cancel">取消</button>\
  384. <button class="mui-btn mui-btn-blue mui-poppicker-btn-ok">确定</button>\
  385. <div class="mui-poppicker-clear"></div>\
  386. </div>\
  387. <div class="mui-poppicker-body">\
  388. </div>\
  389. </div>';
  390. var pickerBuffer = '<div class="mui-picker">\
  391. <div class="mui-picker-inner">\
  392. <div class="mui-pciker-rule mui-pciker-rule-ft"></div>\
  393. <ul class="mui-pciker-list">\
  394. </ul>\
  395. <div class="mui-pciker-rule mui-pciker-rule-bg"></div>\
  396. </div>\
  397. </div>';
  398. //定义弹出选择器类
  399. var PopPicker = $.PopPicker = $.Class.extend({
  400. //构造函数
  401. init: function(options) {
  402. var self = this;
  403. self.options = options || {};
  404. self.options.buttons = self.options.buttons || ['取消', '确定'];
  405. self.panel = $.dom(panelBuffer)[0];
  406. document.body.appendChild(self.panel);
  407. self.ok = self.panel.querySelector('.mui-poppicker-btn-ok');
  408. self.cancel = self.panel.querySelector('.mui-poppicker-btn-cancel');
  409. self.body = self.panel.querySelector('.mui-poppicker-body');
  410. self.mask = $.createMask();
  411. self.cancel.innerText = self.options.buttons[0];
  412. self.ok.innerText = self.options.buttons[1];
  413. self.cancel.addEventListener('tap', function(event) {
  414. self.hide();
  415. }, false);
  416. self.ok.addEventListener('tap', function(event) {
  417. if (self.callback) {
  418. var rs = self.callback(self.getSelectedItems());
  419. if (rs !== false) {
  420. self.hide();
  421. }
  422. }
  423. }, false);
  424. self.mask[0].addEventListener('tap', function() {
  425. self.hide();
  426. }, false);
  427. self._createPicker();
  428. //防止滚动穿透
  429. self.panel.addEventListener($.EVENT_START, function(event) {
  430. event.preventDefault();
  431. }, false);
  432. self.panel.addEventListener($.EVENT_MOVE, function(event) {
  433. event.preventDefault();
  434. }, false);
  435. },
  436. _createPicker: function() {
  437. var self = this;
  438. var layer = self.options.layer || 1;
  439. var width = (100 / layer) + '%';
  440. self.pickers = [];
  441. for (var i = 1; i <= layer; i++) {
  442. var pickerElement = $.dom(pickerBuffer)[0];
  443. pickerElement.style.width = width;
  444. self.body.appendChild(pickerElement);
  445. var picker = $(pickerElement).picker();
  446. self.pickers.push(picker);
  447. pickerElement.addEventListener('change', function(event) {
  448. var nextPickerElement = this.nextSibling;
  449. if (nextPickerElement && nextPickerElement.picker) {
  450. var eventData = event.detail || {};
  451. var preItem = eventData.item || {};
  452. nextPickerElement.picker.setItems(preItem.children);
  453. }
  454. }, false);
  455. }
  456. },
  457. //填充数据
  458. setData: function(data) {
  459. var self = this;
  460. data = data || [];
  461. self.pickers[0].setItems(data);
  462. },
  463. //获取选中的项(数组)
  464. getSelectedItems: function() {
  465. var self = this;
  466. var items = [];
  467. for (var i in self.pickers) {
  468. var picker = self.pickers[i];
  469. items.push(picker.getSelectedItem() || {});
  470. }
  471. return items;
  472. },
  473. //显示
  474. show: function(callback) {
  475. var self = this;
  476. self.callback = callback;
  477. self.mask.show();
  478. document.body.classList.add($.className('poppicker-active-for-page'));
  479. self.panel.classList.add($.className('active'));
  480. //处理物理返回键
  481. self.__back = $.back;
  482. $.back = function() {
  483. self.hide();
  484. };
  485. },
  486. //隐藏
  487. hide: function() {
  488. var self = this;
  489. if (self.disposed) return;
  490. self.panel.classList.remove($.className('active'));
  491. self.mask.close();
  492. document.body.classList.remove($.className('poppicker-active-for-page'));
  493. //处理物理返回键
  494. $.back=self.__back;
  495. },
  496. dispose: function() {
  497. var self = this;
  498. self.hide();
  499. setTimeout(function() {
  500. self.panel.parentNode.removeChild(self.panel);
  501. for (var name in self) {
  502. self[name] = null;
  503. delete self[name];
  504. };
  505. self.disposed = true;
  506. }, 300);
  507. }
  508. });
  509. })(mui, document);
  510. /**
  511. * 日期时间插件
  512. * varstion 1.0.5
  513. * by Houfeng
  514. * Houfeng@DCloud.io
  515. */
  516. (function($, document) {
  517. //创建 DOM
  518. $.dom = function(str) {
  519. if (typeof(str) !== 'string') {
  520. if ((str instanceof Array) || (str[0] && str.length)) {
  521. return [].slice.call(str);
  522. } else {
  523. return [str];
  524. }
  525. }
  526. if (!$.__create_dom_div__) {
  527. $.__create_dom_div__ = document.createElement('div');
  528. }
  529. $.__create_dom_div__.innerHTML = str;
  530. return [].slice.call($.__create_dom_div__.childNodes);
  531. };
  532. var domBuffer = '<div class="mui-dtpicker" data-type="datetime">\
  533. <div class="mui-dtpicker-header">\
  534. <button data-id="btn-cancel" class="mui-btn">取消</button>\
  535. <button data-id="btn-ok" class="mui-btn mui-btn-blue">确定</button>\
  536. </div>\
  537. <div class="mui-dtpicker-title"><h5 data-id="title-y">年</h5><h5 data-id="title-m">月</h5><h5 data-id="title-d">日</h5><h5 data-id="title-h">时</h5><h5 data-id="title-i">分</h5></div>\
  538. <div class="mui-dtpicker-body">\
  539. <div data-id="picker-y" class="mui-picker">\
  540. <div class="mui-picker-inner">\
  541. <div class="mui-pciker-rule mui-pciker-rule-ft"></div>\
  542. <ul class="mui-pciker-list">\
  543. </ul>\
  544. <div class="mui-pciker-rule mui-pciker-rule-bg"></div>\
  545. </div>\
  546. </div>\
  547. <div data-id="picker-m" class="mui-picker">\
  548. <div class="mui-picker-inner">\
  549. <div class="mui-pciker-rule mui-pciker-rule-ft"></div>\
  550. <ul class="mui-pciker-list">\
  551. </ul>\
  552. <div class="mui-pciker-rule mui-pciker-rule-bg"></div>\
  553. </div>\
  554. </div>\
  555. <div data-id="picker-d" class="mui-picker">\
  556. <div class="mui-picker-inner">\
  557. <div class="mui-pciker-rule mui-pciker-rule-ft"></div>\
  558. <ul class="mui-pciker-list">\
  559. </ul>\
  560. <div class="mui-pciker-rule mui-pciker-rule-bg"></div>\
  561. </div>\
  562. </div>\
  563. <div data-id="picker-h" class="mui-picker">\
  564. <div class="mui-picker-inner">\
  565. <div class="mui-pciker-rule mui-pciker-rule-ft"></div>\
  566. <ul class="mui-pciker-list">\
  567. </ul>\
  568. <div class="mui-pciker-rule mui-pciker-rule-bg"></div>\
  569. </div>\
  570. </div>\
  571. <div data-id="picker-i" class="mui-picker">\
  572. <div class="mui-picker-inner">\
  573. <div class="mui-pciker-rule mui-pciker-rule-ft"></div>\
  574. <ul class="mui-pciker-list">\
  575. </ul>\
  576. <div class="mui-pciker-rule mui-pciker-rule-bg"></div>\
  577. </div>\
  578. </div>\
  579. </div>\
  580. </div>';
  581. //plugin
  582. var DtPicker = $.DtPicker = $.Class.extend({
  583. init: function(options) {
  584. var self = this;
  585. var _picker = $.dom(domBuffer)[0];
  586. document.body.appendChild(_picker);
  587. $('[data-id*="picker"]', _picker).picker();
  588. var ui = self.ui = {
  589. picker: _picker,
  590. mask: $.createMask(),
  591. ok: $('[data-id="btn-ok"]', _picker)[0],
  592. cancel: $('[data-id="btn-cancel"]', _picker)[0],
  593. y: $('[data-id="picker-y"]', _picker)[0],
  594. m: $('[data-id="picker-m"]', _picker)[0],
  595. d: $('[data-id="picker-d"]', _picker)[0],
  596. h: $('[data-id="picker-h"]', _picker)[0],
  597. i: $('[data-id="picker-i"]', _picker)[0],
  598. labels: $('[data-id*="title-"]', _picker),
  599. };
  600. ui.cancel.addEventListener('tap', function() {
  601. self.hide();
  602. }, false);
  603. ui.ok.addEventListener('tap', function() {
  604. var rs = self.callback(self.getSelected());
  605. if (rs !== false) {
  606. self.hide();
  607. }
  608. }, false);
  609. ui.y.addEventListener('change', function(e) { //目前的change事件容易导致级联触发
  610. if (self.options.beginMonth || self.options.endMonth) {
  611. self._createMonth();
  612. } else {
  613. self._createDay();
  614. }
  615. }, false);
  616. ui.m.addEventListener('change', function(e) {
  617. self._createDay();
  618. }, false);
  619. ui.d.addEventListener('change', function(e) {
  620. if (self.options.beginMonth || self.options.endMonth) { //仅提供了beginDate时,触发day,hours,minutes的change
  621. self._createHours();
  622. }
  623. }, false);
  624. ui.h.addEventListener('change', function(e) {
  625. if (self.options.beginMonth || self.options.endMonth) {
  626. self._createMinutes();
  627. }
  628. }, false);
  629. ui.mask[0].addEventListener('tap', function() {
  630. self.hide();
  631. }, false);
  632. self._create(options);
  633. //防止滚动穿透
  634. self.ui.picker.addEventListener($.EVENT_START, function(event) {
  635. event.preventDefault();
  636. }, false);
  637. self.ui.picker.addEventListener($.EVENT_MOVE, function(event) {
  638. event.preventDefault();
  639. }, false);
  640. },
  641. getSelected: function() {
  642. var self = this;
  643. var ui = self.ui;
  644. var type = self.options.type;
  645. var selected = {
  646. type: type,
  647. y: ui.y.picker.getSelectedItem(),
  648. m: ui.m.picker.getSelectedItem(),
  649. d: ui.d.picker.getSelectedItem(),
  650. h: ui.h.picker.getSelectedItem(),
  651. i: ui.i.picker.getSelectedItem(),
  652. toString: function() {
  653. return this.value;
  654. }
  655. };
  656. switch (type) {
  657. case 'datetime':
  658. selected.value = selected.y.value + '-' + selected.m.value + '-' + selected.d.value + ' ' + selected.h.value + ':' + selected.i.value;
  659. selected.text = selected.y.text + '-' + selected.m.text + '-' + selected.d.text + ' ' + selected.h.text + ':' + selected.i.text;
  660. break;
  661. case 'date':
  662. selected.value = selected.y.value + '-' + selected.m.value + '-' + selected.d.value;
  663. selected.text = selected.y.text + '-' + selected.m.text + '-' + selected.d.text;
  664. break;
  665. case 'time':
  666. selected.value = selected.h.value + ':' + selected.i.value;
  667. selected.text = selected.h.text + ':' + selected.i.text;
  668. break;
  669. case 'month':
  670. selected.value = selected.y.value + '-' + selected.m.value;
  671. selected.text = selected.y.text + '-' + selected.m.text;
  672. break;
  673. case 'hour':
  674. selected.value = selected.y.value + '-' + selected.m.value + '-' + selected.d.value + ' ' + selected.h.value;
  675. selected.text = selected.y.text + '-' + selected.m.text + '-' + selected.d.text + ' ' + selected.h.text;
  676. break;
  677. }
  678. return selected;
  679. },
  680. setSelectedValue: function(value) {
  681. var self = this;
  682. var ui = self.ui;
  683. var parsedValue = self._parseValue(value);
  684. //TODO 嵌套过多,因为picker的change时间是异步(考虑到性能)的,所以为了保证change之后再setSelected,目前使用回调处理
  685. ui.y.picker.setSelectedValue(parsedValue.y, 0, function() {
  686. ui.m.picker.setSelectedValue(parsedValue.m, 0, function() {
  687. ui.d.picker.setSelectedValue(parsedValue.d, 0, function() {
  688. ui.h.picker.setSelectedValue(parsedValue.h, 0, function() {
  689. ui.i.picker.setSelectedValue(parsedValue.i, 0);
  690. });
  691. });
  692. });
  693. });
  694. },
  695. isLeapYear: function(year) {
  696. return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
  697. },
  698. _inArray: function(array, item) {
  699. for (var index in array) {
  700. var _item = array[index];
  701. if (_item === item) return true;
  702. }
  703. return false;
  704. },
  705. getDayNum: function(year, month) {
  706. var self = this;
  707. if (self._inArray([1, 3, 5, 7, 8, 10, 12], month)) {
  708. return 31;
  709. } else if (self._inArray([4, 6, 9, 11], month)) {
  710. return 30;
  711. } else if (self.isLeapYear(year)) {
  712. return 29;
  713. } else {
  714. return 28;
  715. }
  716. },
  717. _fill: function(num) {
  718. num = num.toString();
  719. if (num.length < 2) {
  720. num = 0 + num;
  721. }
  722. return num;
  723. },
  724. _isBeginYear: function() {
  725. return this.options.beginYear === parseInt(this.ui.y.picker.getSelectedValue());
  726. },
  727. _isBeginMonth: function() {
  728. return this.options.beginMonth && this._isBeginYear() && this.options.beginMonth === parseInt(this.ui.m.picker.getSelectedValue());
  729. },
  730. _isBeginDay: function() {
  731. return this._isBeginMonth() && this.options.beginDay === parseInt(this.ui.d.picker.getSelectedValue());
  732. },
  733. _isBeginHours: function() {
  734. return this._isBeginDay() && this.options.beginHours === parseInt(this.ui.h.picker.getSelectedValue());
  735. },
  736. _isEndYear: function() {
  737. return this.options.endYear === parseInt(this.ui.y.picker.getSelectedValue());
  738. },
  739. _isEndMonth: function() {
  740. return this.options.endMonth && this._isEndYear() && this.options.endMonth === parseInt(this.ui.m.picker.getSelectedValue());
  741. },
  742. _isEndDay: function() {
  743. return this._isEndMonth() && this.options.endDay === parseInt(this.ui.d.picker.getSelectedValue());
  744. },
  745. _isEndHours: function() {
  746. return this._isEndDay() && this.options.endHours === parseInt(this.ui.h.picker.getSelectedValue());
  747. },
  748. _createYear: function(current) {
  749. var self = this;
  750. var options = self.options;
  751. var ui = self.ui;
  752. //生成年列表
  753. var yArray = [];
  754. if (options.customData.y) {
  755. yArray = options.customData.y;
  756. } else {
  757. var yBegin = options.beginYear;
  758. var yEnd = options.endYear;
  759. for (var y = yBegin; y <= yEnd; y++) {
  760. yArray.push({
  761. text: y + '',
  762. value: y
  763. });
  764. }
  765. }
  766. ui.y.picker.setItems(yArray);
  767. //ui.y.picker.setSelectedValue(current);
  768. },
  769. _createMonth: function(current) {
  770. var self = this;
  771. var options = self.options;
  772. var ui = self.ui;
  773. //生成月列表
  774. var mArray = [];
  775. if (options.customData.m) {
  776. mArray = options.customData.m;
  777. } else {
  778. var m = options.beginMonth && self._isBeginYear() ? options.beginMonth : 1;
  779. var maxMonth = options.endMonth && self._isEndYear() ? options.endMonth : 12;
  780. for (; m <= maxMonth; m++) {
  781. var val = self._fill(m);
  782. mArray.push({
  783. text: val,
  784. value: val
  785. });
  786. }
  787. }
  788. ui.m.picker.setItems(mArray);
  789. //ui.m.picker.setSelectedValue(current);
  790. },
  791. _createDay: function(current) {
  792. var self = this;
  793. var options = self.options;
  794. var ui = self.ui;
  795. //生成日列表
  796. var dArray = [];
  797. if (options.customData.d) {
  798. dArray = options.customData.d;
  799. } else {
  800. var d = self._isBeginMonth() ? options.beginDay : 1;
  801. var maxDay = self._isEndMonth() ? options.endDay : self.getDayNum(parseInt(this.ui.y.picker.getSelectedValue()), parseInt(this.ui.m.picker.getSelectedValue()));
  802. for (; d <= maxDay; d++) {
  803. var val = self._fill(d);
  804. dArray.push({
  805. text: val,
  806. value: val
  807. });
  808. }
  809. }
  810. ui.d.picker.setItems(dArray);
  811. current = current || ui.d.picker.getSelectedValue();
  812. //ui.d.picker.setSelectedValue(current);
  813. },
  814. _createHours: function(current) {
  815. var self = this;
  816. var options = self.options;
  817. var ui = self.ui;
  818. //生成时列表
  819. var hArray = [];
  820. if (options.customData.h) {
  821. hArray = options.customData.h;
  822. } else {
  823. var h = self._isBeginDay() ? options.beginHours : 0;
  824. var maxHours = self._isEndDay() ? options.endHours : 23;
  825. for (; h <= maxHours; h++) {
  826. var val = self._fill(h);
  827. hArray.push({
  828. text: val,
  829. value: val
  830. });
  831. }
  832. }
  833. ui.h.picker.setItems(hArray);
  834. //ui.h.picker.setSelectedValue(current);
  835. },
  836. _createMinutes: function(current) {
  837. var self = this;
  838. var options = self.options;
  839. var ui = self.ui;
  840. //生成分列表
  841. var iArray = [];
  842. if (options.customData.i) {
  843. iArray = options.customData.i;
  844. } else {
  845. var i = self._isBeginHours() ? options.beginMinutes : 0;
  846. var maxMinutes = self._isEndHours() ? options.endMinutes : 59;
  847. for (; i <= maxMinutes; i++) {
  848. var val = self._fill(i);
  849. iArray.push({
  850. text: val,
  851. value: val
  852. });
  853. }
  854. }
  855. ui.i.picker.setItems(iArray);
  856. //ui.i.picker.setSelectedValue(current);
  857. },
  858. _setLabels: function() {
  859. var self = this;
  860. var options = self.options;
  861. var ui = self.ui;
  862. ui.labels.each(function(i, label) {
  863. label.innerText = options.labels[i];
  864. });
  865. },
  866. _setButtons: function() {
  867. var self = this;
  868. var options = self.options;
  869. var ui = self.ui;
  870. ui.cancel.innerText = options.buttons[0];
  871. ui.ok.innerText = options.buttons[1];
  872. },
  873. _parseValue: function(value) {
  874. var self = this;
  875. var rs = {};
  876. if (value) {
  877. var parts = value.replace(":", "-").replace(" ", "-").split("-");
  878. rs.y = parts[0];
  879. rs.m = parts[1];
  880. rs.d = parts[2];
  881. rs.h = parts[3];
  882. rs.i = parts[4];
  883. } else {
  884. var now = new Date();
  885. rs.y = now.getFullYear();
  886. rs.m = now.getMonth() + 1;
  887. rs.d = now.getDate();
  888. rs.h = now.getHours();
  889. rs.i = now.getMinutes();
  890. }
  891. return rs;
  892. },
  893. _create: function(options) {
  894. var self = this;
  895. options = options || {};
  896. options.labels = options.labels || ['年', '月', '日', '时', '分'];
  897. options.buttons = options.buttons || ['取消', '确定'];
  898. options.type = options.type || 'datetime';
  899. options.customData = options.customData || {};
  900. self.options = options;
  901. var now = new Date();
  902. var beginDate = options.beginDate;
  903. if (beginDate instanceof Date && !isNaN(beginDate.valueOf())) { //设定了开始日期
  904. options.beginYear = beginDate.getFullYear();
  905. options.beginMonth = beginDate.getMonth() + 1;
  906. options.beginDay = beginDate.getDate();
  907. options.beginHours = beginDate.getHours();
  908. options.beginMinutes = beginDate.getMinutes();
  909. }
  910. var endDate = options.endDate;
  911. if (endDate instanceof Date && !isNaN(endDate.valueOf())) { //设定了结束日期
  912. options.endYear = endDate.getFullYear();
  913. options.endMonth = endDate.getMonth() + 1;
  914. options.endDay = endDate.getDate();
  915. options.endHours = endDate.getHours();
  916. options.endMinutes = endDate.getMinutes();
  917. }
  918. options.beginYear = options.beginYear || (now.getFullYear() - 5);
  919. options.endYear = options.endYear || (now.getFullYear() + 5);
  920. var ui = self.ui;
  921. //设定label
  922. self._setLabels();
  923. self._setButtons();
  924. //设定类型
  925. ui.picker.setAttribute('data-type', options.type);
  926. //生成
  927. self._createYear();
  928. self._createMonth();
  929. self._createDay();
  930. self._createHours();
  931. self._createMinutes();
  932. //设定默认值
  933. self.setSelectedValue(options.value);
  934. },
  935. //显示
  936. show: function(callback) {
  937. var self = this;
  938. var ui = self.ui;
  939. self.callback = callback || $.noop;
  940. ui.mask.show();
  941. document.body.classList.add($.className('dtpicker-active-for-page'));
  942. ui.picker.classList.add($.className('active'));
  943. //处理物理返回键
  944. self.__back = $.back;
  945. $.back = function() {
  946. self.hide();
  947. };
  948. },
  949. hide: function() {
  950. var self = this;
  951. if (self.disposed) return;
  952. var ui = self.ui;
  953. ui.picker.classList.remove($.className('active'));
  954. ui.mask.close();
  955. document.body.classList.remove($.className('dtpicker-active-for-page'));
  956. //处理物理返回键
  957. $.back = self.__back;
  958. },
  959. dispose: function() {
  960. var self = this;
  961. self.hide();
  962. setTimeout(function() {
  963. self.ui.picker.parentNode.removeChild(self.ui.picker);
  964. for (var name in self) {
  965. self[name] = null;
  966. delete self[name];
  967. };
  968. self.disposed = true;
  969. }, 300);
  970. }
  971. });
  972. })(mui, document);