mui.dtpicker.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. /**
  2. * 日期时间插件
  3. * varstion 1.0.5
  4. * by Houfeng
  5. * Houfeng@DCloud.io
  6. */
  7. (function($, document) {
  8. //创建 DOM
  9. $.dom = function(str) {
  10. if (typeof(str) !== 'string') {
  11. if ((str instanceof Array) || (str[0] && str.length)) {
  12. return [].slice.call(str);
  13. } else {
  14. return [str];
  15. }
  16. }
  17. if (!$.__create_dom_div__) {
  18. $.__create_dom_div__ = document.createElement('div');
  19. }
  20. $.__create_dom_div__.innerHTML = str;
  21. return [].slice.call($.__create_dom_div__.childNodes);
  22. };
  23. var domBuffer = '<div class="mui-dtpicker" data-type="datetime">\
  24. <div class="mui-dtpicker-header">\
  25. <button data-id="btn-cancel" class="mui-btn">取消</button>\
  26. <button data-id="btn-ok" class="mui-btn mui-btn-blue">确定</button>\
  27. </div>\
  28. <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>\
  29. <div class="mui-dtpicker-body">\
  30. <div data-id="picker-y" class="mui-picker">\
  31. <div class="mui-picker-inner">\
  32. <div class="mui-pciker-rule mui-pciker-rule-ft"></div>\
  33. <ul class="mui-pciker-list">\
  34. </ul>\
  35. <div class="mui-pciker-rule mui-pciker-rule-bg"></div>\
  36. </div>\
  37. </div>\
  38. <div data-id="picker-m" class="mui-picker">\
  39. <div class="mui-picker-inner">\
  40. <div class="mui-pciker-rule mui-pciker-rule-ft"></div>\
  41. <ul class="mui-pciker-list">\
  42. </ul>\
  43. <div class="mui-pciker-rule mui-pciker-rule-bg"></div>\
  44. </div>\
  45. </div>\
  46. <div data-id="picker-d" class="mui-picker">\
  47. <div class="mui-picker-inner">\
  48. <div class="mui-pciker-rule mui-pciker-rule-ft"></div>\
  49. <ul class="mui-pciker-list">\
  50. </ul>\
  51. <div class="mui-pciker-rule mui-pciker-rule-bg"></div>\
  52. </div>\
  53. </div>\
  54. <div data-id="picker-h" class="mui-picker">\
  55. <div class="mui-picker-inner">\
  56. <div class="mui-pciker-rule mui-pciker-rule-ft"></div>\
  57. <ul class="mui-pciker-list">\
  58. </ul>\
  59. <div class="mui-pciker-rule mui-pciker-rule-bg"></div>\
  60. </div>\
  61. </div>\
  62. <div data-id="picker-i" class="mui-picker">\
  63. <div class="mui-picker-inner">\
  64. <div class="mui-pciker-rule mui-pciker-rule-ft"></div>\
  65. <ul class="mui-pciker-list">\
  66. </ul>\
  67. <div class="mui-pciker-rule mui-pciker-rule-bg"></div>\
  68. </div>\
  69. </div>\
  70. </div>\
  71. </div>';
  72. //plugin
  73. var DtPicker = $.DtPicker = $.Class.extend({
  74. init: function(options) {
  75. var self = this;
  76. var _picker = $.dom(domBuffer)[0];
  77. document.body.appendChild(_picker);
  78. $('[data-id*="picker"]', _picker).picker();
  79. var ui = self.ui = {
  80. picker: _picker,
  81. mask: $.createMask(),
  82. ok: $('[data-id="btn-ok"]', _picker)[0],
  83. cancel: $('[data-id="btn-cancel"]', _picker)[0],
  84. y: $('[data-id="picker-y"]', _picker)[0],
  85. m: $('[data-id="picker-m"]', _picker)[0],
  86. d: $('[data-id="picker-d"]', _picker)[0],
  87. h: $('[data-id="picker-h"]', _picker)[0],
  88. i: $('[data-id="picker-i"]', _picker)[0],
  89. labels: $('[data-id*="title-"]', _picker),
  90. };
  91. ui.cancel.addEventListener('tap', function() {
  92. self.hide();
  93. }, false);
  94. ui.ok.addEventListener('tap', function() {
  95. var rs = self.callback(self.getSelected());
  96. if (rs !== false) {
  97. self.hide();
  98. }
  99. }, false);
  100. ui.y.addEventListener('change', function(e) { //目前的change事件容易导致级联触发
  101. if (self.options.beginMonth || self.options.endMonth) {
  102. self._createMonth();
  103. } else {
  104. self._createDay();
  105. }
  106. }, false);
  107. ui.m.addEventListener('change', function(e) {
  108. self._createDay();
  109. }, false);
  110. ui.d.addEventListener('change', function(e) {
  111. if (self.options.beginMonth || self.options.endMonth) { //仅提供了beginDate时,触发day,hours,minutes的change
  112. self._createHours();
  113. }
  114. }, false);
  115. ui.h.addEventListener('change', function(e) {
  116. if (self.options.beginMonth || self.options.endMonth) {
  117. self._createMinutes();
  118. }
  119. }, false);
  120. ui.mask[0].addEventListener('tap', function() {
  121. self.hide();
  122. }, false);
  123. self._create(options);
  124. //防止滚动穿透
  125. self.ui.picker.addEventListener($.EVENT_START, function(event) {
  126. event.preventDefault();
  127. }, false);
  128. self.ui.picker.addEventListener($.EVENT_MOVE, function(event) {
  129. event.preventDefault();
  130. }, false);
  131. },
  132. getSelected: function() {
  133. var self = this;
  134. var ui = self.ui;
  135. var type = self.options.type;
  136. var selected = {
  137. type: type,
  138. y: ui.y.picker.getSelectedItem(),
  139. m: ui.m.picker.getSelectedItem(),
  140. d: ui.d.picker.getSelectedItem(),
  141. h: ui.h.picker.getSelectedItem(),
  142. i: ui.i.picker.getSelectedItem(),
  143. toString: function() {
  144. return this.value;
  145. }
  146. };
  147. switch (type) {
  148. case 'datetime':
  149. selected.value = selected.y.value + '-' + selected.m.value + '-' + selected.d.value + ' ' + selected.h.value + ':' + selected.i.value;
  150. selected.text = selected.y.text + '-' + selected.m.text + '-' + selected.d.text + ' ' + selected.h.text + ':' + selected.i.text;
  151. break;
  152. case 'date':
  153. selected.value = selected.y.value + '-' + selected.m.value + '-' + selected.d.value;
  154. selected.text = selected.y.text + '-' + selected.m.text + '-' + selected.d.text;
  155. break;
  156. case 'time':
  157. selected.value = selected.h.value + ':' + selected.i.value;
  158. selected.text = selected.h.text + ':' + selected.i.text;
  159. break;
  160. case 'month':
  161. selected.value = selected.y.value + '-' + selected.m.value;
  162. selected.text = selected.y.text + '-' + selected.m.text;
  163. break;
  164. case 'hour':
  165. selected.value = selected.y.value + '-' + selected.m.value + '-' + selected.d.value + ' ' + selected.h.value;
  166. selected.text = selected.y.text + '-' + selected.m.text + '-' + selected.d.text + ' ' + selected.h.text;
  167. break;
  168. }
  169. return selected;
  170. },
  171. setSelectedValue: function(value) {
  172. var self = this;
  173. var ui = self.ui;
  174. var parsedValue = self._parseValue(value);
  175. //TODO 嵌套过多,因为picker的change时间是异步(考虑到性能)的,所以为了保证change之后再setSelected,目前使用回调处理
  176. ui.y.picker.setSelectedValue(parsedValue.y, 0, function() {
  177. ui.m.picker.setSelectedValue(parsedValue.m, 0, function() {
  178. ui.d.picker.setSelectedValue(parsedValue.d, 0, function() {
  179. ui.h.picker.setSelectedValue(parsedValue.h, 0, function() {
  180. ui.i.picker.setSelectedValue(parsedValue.i, 0);
  181. });
  182. });
  183. });
  184. });
  185. },
  186. isLeapYear: function(year) {
  187. return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
  188. },
  189. _inArray: function(array, item) {
  190. for (var index in array) {
  191. var _item = array[index];
  192. if (_item === item) return true;
  193. }
  194. return false;
  195. },
  196. getDayNum: function(year, month) {
  197. var self = this;
  198. if (self._inArray([1, 3, 5, 7, 8, 10, 12], month)) {
  199. return 31;
  200. } else if (self._inArray([4, 6, 9, 11], month)) {
  201. return 30;
  202. } else if (self.isLeapYear(year)) {
  203. return 29;
  204. } else {
  205. return 28;
  206. }
  207. },
  208. _fill: function(num) {
  209. num = num.toString();
  210. if (num.length < 2) {
  211. num = 0 + num;
  212. }
  213. return num;
  214. },
  215. _isBeginYear: function() {
  216. return this.options.beginYear === parseInt(this.ui.y.picker.getSelectedValue());
  217. },
  218. _isBeginMonth: function() {
  219. return this.options.beginMonth && this._isBeginYear() && this.options.beginMonth === parseInt(this.ui.m.picker.getSelectedValue());
  220. },
  221. _isBeginDay: function() {
  222. return this._isBeginMonth() && this.options.beginDay === parseInt(this.ui.d.picker.getSelectedValue());
  223. },
  224. _isBeginHours: function() {
  225. return this._isBeginDay() && this.options.beginHours === parseInt(this.ui.h.picker.getSelectedValue());
  226. },
  227. _isEndYear: function() {
  228. return this.options.endYear === parseInt(this.ui.y.picker.getSelectedValue());
  229. },
  230. _isEndMonth: function() {
  231. return this.options.endMonth && this._isEndYear() && this.options.endMonth === parseInt(this.ui.m.picker.getSelectedValue());
  232. },
  233. _isEndDay: function() {
  234. return this._isEndMonth() && this.options.endDay === parseInt(this.ui.d.picker.getSelectedValue());
  235. },
  236. _isEndHours: function() {
  237. return this._isEndDay() && this.options.endHours === parseInt(this.ui.h.picker.getSelectedValue());
  238. },
  239. _createYear: function(current) {
  240. var self = this;
  241. var options = self.options;
  242. var ui = self.ui;
  243. //生成年列表
  244. var yArray = [];
  245. if (options.customData.y) {
  246. yArray = options.customData.y;
  247. } else {
  248. var yBegin = options.beginYear;
  249. var yEnd = options.endYear;
  250. for (var y = yBegin; y <= yEnd; y++) {
  251. yArray.push({
  252. text: y + '',
  253. value: y
  254. });
  255. }
  256. }
  257. ui.y.picker.setItems(yArray);
  258. //ui.y.picker.setSelectedValue(current);
  259. },
  260. _createMonth: function(current) {
  261. var self = this;
  262. var options = self.options;
  263. var ui = self.ui;
  264. //生成月列表
  265. var mArray = [];
  266. if (options.customData.m) {
  267. mArray = options.customData.m;
  268. } else {
  269. var m = options.beginMonth && self._isBeginYear() ? options.beginMonth : 1;
  270. var maxMonth = options.endMonth && self._isEndYear() ? options.endMonth : 12;
  271. for (; m <= maxMonth; m++) {
  272. var val = self._fill(m);
  273. mArray.push({
  274. text: val,
  275. value: val
  276. });
  277. }
  278. }
  279. ui.m.picker.setItems(mArray);
  280. //ui.m.picker.setSelectedValue(current);
  281. },
  282. _createDay: function(current) {
  283. var self = this;
  284. var options = self.options;
  285. var ui = self.ui;
  286. //生成日列表
  287. var dArray = [];
  288. if (options.customData.d) {
  289. dArray = options.customData.d;
  290. } else {
  291. var d = self._isBeginMonth() ? options.beginDay : 1;
  292. var maxDay = self._isEndMonth() ? options.endDay : self.getDayNum(parseInt(this.ui.y.picker.getSelectedValue()), parseInt(this.ui.m.picker.getSelectedValue()));
  293. for (; d <= maxDay; d++) {
  294. var val = self._fill(d);
  295. dArray.push({
  296. text: val,
  297. value: val
  298. });
  299. }
  300. }
  301. ui.d.picker.setItems(dArray);
  302. current = current || ui.d.picker.getSelectedValue();
  303. //ui.d.picker.setSelectedValue(current);
  304. },
  305. _createHours: function(current) {
  306. var self = this;
  307. var options = self.options;
  308. var ui = self.ui;
  309. //生成时列表
  310. var hArray = [];
  311. if (options.customData.h) {
  312. hArray = options.customData.h;
  313. } else {
  314. var h = self._isBeginDay() ? options.beginHours : 0;
  315. var maxHours = self._isEndDay() ? options.endHours : 23;
  316. for (; h <= maxHours; h++) {
  317. var val = self._fill(h);
  318. hArray.push({
  319. text: val,
  320. value: val
  321. });
  322. }
  323. }
  324. ui.h.picker.setItems(hArray);
  325. //ui.h.picker.setSelectedValue(current);
  326. },
  327. _createMinutes: function(current) {
  328. var self = this;
  329. var options = self.options;
  330. var ui = self.ui;
  331. //生成分列表
  332. var iArray = [];
  333. if (options.customData.i) {
  334. iArray = options.customData.i;
  335. } else {
  336. var i = self._isBeginHours() ? options.beginMinutes : 0;
  337. var maxMinutes = self._isEndHours() ? options.endMinutes : 59;
  338. for (; i <= maxMinutes; i++) {
  339. var val = self._fill(i);
  340. iArray.push({
  341. text: val,
  342. value: val
  343. });
  344. }
  345. }
  346. ui.i.picker.setItems(iArray);
  347. //ui.i.picker.setSelectedValue(current);
  348. },
  349. _setLabels: function() {
  350. var self = this;
  351. var options = self.options;
  352. var ui = self.ui;
  353. ui.labels.each(function(i, label) {
  354. label.innerText = options.labels[i];
  355. });
  356. },
  357. _setButtons: function() {
  358. var self = this;
  359. var options = self.options;
  360. var ui = self.ui;
  361. ui.cancel.innerText = options.buttons[0];
  362. ui.ok.innerText = options.buttons[1];
  363. },
  364. _parseValue: function(value) {
  365. var self = this;
  366. var rs = {};
  367. if (value) {
  368. var parts = value.replace(":", "-").replace(" ", "-").split("-");
  369. rs.y = parts[0];
  370. rs.m = parts[1];
  371. rs.d = parts[2];
  372. rs.h = parts[3];
  373. rs.i = parts[4];
  374. } else {
  375. var now = new Date();
  376. rs.y = now.getFullYear();
  377. rs.m = now.getMonth() + 1;
  378. rs.d = now.getDate();
  379. rs.h = now.getHours();
  380. rs.i = now.getMinutes();
  381. }
  382. return rs;
  383. },
  384. _create: function(options) {
  385. var self = this;
  386. options = options || {};
  387. options.labels = options.labels || ['年', '月', '日', '时', '分'];
  388. options.buttons = options.buttons || ['取消', '确定'];
  389. options.type = options.type || 'datetime';
  390. options.customData = options.customData || {};
  391. self.options = options;
  392. var now = new Date();
  393. var beginDate = options.beginDate;
  394. if (beginDate instanceof Date && !isNaN(beginDate.valueOf())) { //设定了开始日期
  395. options.beginYear = beginDate.getFullYear();
  396. options.beginMonth = beginDate.getMonth() + 1;
  397. options.beginDay = beginDate.getDate();
  398. options.beginHours = beginDate.getHours();
  399. options.beginMinutes = beginDate.getMinutes();
  400. }
  401. var endDate = options.endDate;
  402. if (endDate instanceof Date && !isNaN(endDate.valueOf())) { //设定了结束日期
  403. options.endYear = endDate.getFullYear();
  404. options.endMonth = endDate.getMonth() + 1;
  405. options.endDay = endDate.getDate();
  406. options.endHours = endDate.getHours();
  407. options.endMinutes = endDate.getMinutes();
  408. }
  409. options.beginYear = options.beginYear || (now.getFullYear() - 5);
  410. options.endYear = options.endYear || (now.getFullYear() + 5);
  411. var ui = self.ui;
  412. //设定label
  413. self._setLabels();
  414. self._setButtons();
  415. //设定类型
  416. ui.picker.setAttribute('data-type', options.type);
  417. //生成
  418. self._createYear();
  419. self._createMonth();
  420. self._createDay();
  421. self._createHours();
  422. self._createMinutes();
  423. //设定默认值
  424. self.setSelectedValue(options.value);
  425. },
  426. //显示
  427. show: function(callback) {
  428. var self = this;
  429. var ui = self.ui;
  430. self.callback = callback || $.noop;
  431. ui.mask.show();
  432. document.body.classList.add($.className('dtpicker-active-for-page'));
  433. ui.picker.classList.add($.className('active'));
  434. //处理物理返回键
  435. self.__back = $.back;
  436. $.back = function() {
  437. self.hide();
  438. };
  439. },
  440. hide: function() {
  441. var self = this;
  442. if (self.disposed) return;
  443. var ui = self.ui;
  444. ui.picker.classList.remove($.className('active'));
  445. ui.mask.close();
  446. document.body.classList.remove($.className('dtpicker-active-for-page'));
  447. //处理物理返回键
  448. $.back = self.__back;
  449. },
  450. dispose: function() {
  451. var self = this;
  452. self.hide();
  453. setTimeout(function() {
  454. self.ui.picker.parentNode.removeChild(self.ui.picker);
  455. for (var name in self) {
  456. self[name] = null;
  457. delete self[name];
  458. };
  459. self.disposed = true;
  460. }, 300);
  461. }
  462. });
  463. })(mui, document);