index.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. import baseComponent from '../helpers/baseComponent'
  2. import classNames from '../helpers/classNames'
  3. const defaults = {
  4. prefixCls: 'wux-calendar',
  5. monthNames: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
  6. monthNamesShort: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
  7. dayNames: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
  8. dayNamesShort: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'],
  9. firstDay: 1, // First day of the week, Monday
  10. weekendDays: [0, 6], // Sunday and Saturday
  11. multiple: false,
  12. dateFormat: 'yyyy-mm-dd',
  13. direction: 'horizontal', // or 'vertical'
  14. minDate: null,
  15. maxDate: null,
  16. touchMove: true,
  17. animate: true,
  18. closeOnSelect: true,
  19. weekHeader: true,
  20. toolbar: true,
  21. value: [],
  22. onMonthAdd() {},
  23. onChange() {},
  24. onOpen() {},
  25. onClose() {},
  26. onDayClick() {},
  27. onMonthYearChangeStart() {},
  28. onMonthYearChangeEnd() {},
  29. }
  30. // 获取手指触摸点坐标
  31. const getTouchPosition = (e) => {
  32. const touches = e.touches[0] || e.changedTouches[0]
  33. return {
  34. x: touches.pageX,
  35. y: touches.pageY,
  36. }
  37. }
  38. // 获取元素旋转属性
  39. const getTransform = (translate, isH) => `transform: translate3d(${isH ? translate : 0}%, ${isH ? 0 : translate}%, 0)`
  40. // 判断两个日期是否在同一天
  41. const isSameDate = (a, b) => {
  42. const prev = new Date(a)
  43. const next = new Date(b)
  44. return prev.getFullYear() === next.getFullYear() && prev.getMonth() === next.getMonth() && prev.getDate() === next.getDate()
  45. }
  46. baseComponent({
  47. useFunc: true,
  48. data: defaults,
  49. computed: {
  50. classes() {
  51. const { prefixCls, direction } = this.data
  52. const wrap = classNames(prefixCls, {
  53. [`${prefixCls}--${direction}`]: direction,
  54. })
  55. const content = `${prefixCls}__content`
  56. const hd = `${prefixCls}__hd`
  57. const toolbar = `${prefixCls}__toolbar`
  58. const picker = `${prefixCls}__picker`
  59. const link = `${prefixCls}__link`
  60. const prev = classNames(`${prefixCls}__icon`, {
  61. [`${prefixCls}__icon--prev`]: true,
  62. })
  63. const next = classNames(`${prefixCls}__icon`, {
  64. [`${prefixCls}__icon--next`]: true,
  65. })
  66. const value = `${prefixCls}__value`
  67. const bd = `${prefixCls}__bd`
  68. const weekdays = `${prefixCls}__weekdays`
  69. const weekday = `${prefixCls}__weekday`
  70. const months = `${prefixCls}__months`
  71. const monthsContent = `${prefixCls}__months-content`
  72. const month = `${prefixCls}__month`
  73. const days = `${prefixCls}__days`
  74. const day = `${prefixCls}__day`
  75. const text = `${prefixCls}__text`
  76. return {
  77. wrap,
  78. content,
  79. hd,
  80. toolbar,
  81. picker,
  82. link,
  83. prev,
  84. next,
  85. value,
  86. bd,
  87. weekdays,
  88. weekday,
  89. months,
  90. monthsContent,
  91. month,
  92. days,
  93. day,
  94. text,
  95. }
  96. },
  97. },
  98. methods: {
  99. /**
  100. * 打开日历
  101. * @param {Object} opts
  102. */
  103. open(opts = {}) {
  104. const options = this.$$mergeOptionsAndBindMethods(Object.assign({}, defaults, opts))
  105. this.monthsTranslate = 0
  106. this.isH = options.direction === 'horizontal'
  107. this.$$setData({ in: true, ...options }).then(() => this.init())
  108. this.setValue(options.value)
  109. if (typeof this.fns.onOpen === 'function') {
  110. this.fns.onOpen.call(this)
  111. }
  112. },
  113. /**
  114. * 关闭日历
  115. */
  116. close() {
  117. this.$$setData({ in: false })
  118. if (typeof this.fns.onClose === 'function') {
  119. this.fns.onClose.call(this)
  120. }
  121. },
  122. /**
  123. * 初始化
  124. */
  125. init() {
  126. const weeks = this.setWeekHeader()
  127. const months = this.setMonthsHTML()
  128. const monthsTranslate = this.setMonthsTranslate()
  129. if (typeof this.fns.onMonthAdd === 'function') {
  130. months.forEach((month) => this.fns.onMonthAdd.call(this, month))
  131. }
  132. return this.$$setData({ weeks, months, monthsTranslate, wrapperTranslate: '' }).then(() => this.$$setData({...this.updateCurrentMonthYear() }))
  133. },
  134. /**
  135. * 设置月份的位置信息
  136. * @param {Number} translate
  137. */
  138. setMonthsTranslate(translate = this.monthsTranslate) {
  139. const prevMonthTranslate = -(translate + 1) * 100
  140. const currentMonthTranslate = -translate * 100
  141. const nextMonthTranslate = -(translate - 1) * 100
  142. return [
  143. getTransform(prevMonthTranslate, this.isH),
  144. getTransform(currentMonthTranslate, this.isH),
  145. getTransform(nextMonthTranslate, this.isH),
  146. ]
  147. },
  148. /**
  149. * 更新当前年月
  150. * @param {String} dir 方向
  151. */
  152. updateCurrentMonthYear(dir) {
  153. const { months, monthNames } = this.data
  154. if (typeof dir === 'undefined') {
  155. const currentMonth = parseInt(months[1].month, 10)
  156. const currentYear = parseInt(months[1].year, 10)
  157. const currentMonthName = monthNames[currentMonth]
  158. return {
  159. currentMonth,
  160. currentYear,
  161. currentMonthName,
  162. }
  163. }
  164. const currentMonth = parseInt(months[dir === 'next' ? (months.length - 1) : 0].month, 10)
  165. const currentYear = parseInt(months[dir === 'next' ? (months.length - 1) : 0].year, 10)
  166. const currentMonthName = monthNames[currentMonth]
  167. return {
  168. currentMonth,
  169. currentYear,
  170. currentMonthName,
  171. }
  172. },
  173. /**
  174. * 手指触摸动作开始
  175. * @param {Object} e 事件对象
  176. */
  177. onTouchStart(e) {
  178. if (!this.data.touchMove || this.isMoved || this.isRendered) {
  179. return false
  180. }
  181. this.start = getTouchPosition(e)
  182. this.move = {}
  183. this.touchesDiff = 0
  184. this.allowItemClick = true
  185. this.isMoved = false
  186. },
  187. /**
  188. * 手指触摸后移动
  189. * @param {Object} e 事件对象
  190. */
  191. onTouchMove(e) {
  192. if (!this.data.touchMove || this.isRendered) {
  193. return false
  194. }
  195. this.allowItemClick = false
  196. if (!this.isMoved) {
  197. this.isMoved = true
  198. }
  199. const { prefixCls } = this.data
  200. const query = wx.createSelectorQuery().in(this)
  201. query.select(`.${prefixCls}__months-content`).boundingClientRect((rect) => {
  202. // 由于 boundingClientRect 为异步方法,某些情况下其回调函数在 onTouchEnd 之后触发,导致 wrapperTranslate 计算错误
  203. // 所以判断 this.isMoved = false 时阻止回调函数的执行
  204. if (!rect || !this.isMoved) {
  205. return false
  206. }
  207. this.move = getTouchPosition(e)
  208. this.touchesDiff = this.isH ? this.move.x - this.start.x : this.move.y - this.start.y
  209. const { width, height } = rect
  210. const percentage = this.touchesDiff / (this.isH ? width : height)
  211. const currentTranslate = (this.monthsTranslate + percentage) * 100
  212. const transform = getTransform(currentTranslate, this.isH)
  213. this.$$setData({
  214. wrapperTranslate: `transition-duration: 0s; ${transform}`,
  215. })
  216. })
  217. query.exec()
  218. },
  219. /**
  220. * 手指触摸动作结束
  221. */
  222. onTouchEnd() {
  223. if (!this.data.touchMove || !this.isMoved || this.isRendered) {
  224. return false
  225. }
  226. this.isMoved = false
  227. if (Math.abs(this.touchesDiff) < 30) {
  228. this.resetMonth()
  229. } else if (this.touchesDiff >= 30) {
  230. this.prevMonth()
  231. } else {
  232. this.nextMonth()
  233. }
  234. // Allow click
  235. setTimeout(() => (this.allowItemClick = true), 100)
  236. },
  237. /**
  238. * 日期的点击事件
  239. * @param {Object} e 事件对象
  240. */
  241. onDayClick(e) {
  242. if (this.allowItemClick) {
  243. const dataset = e.currentTarget.dataset
  244. const dateYear = dataset.year
  245. const dateMonth = dataset.month
  246. const dateDay = dataset.day
  247. const dateType = dataset.type
  248. if (dateType.selected && !this.data.multiple) return false
  249. if (dateType.disabled) return false
  250. if (dateType.next) this.nextMonth()
  251. if (dateType.prev) this.prevMonth()
  252. if (typeof this.fns.onDayClick === 'function') {
  253. this.fns.onDayClick.call(this, dateYear, dateMonth, dateDay)
  254. }
  255. this.addValue(new Date(dateYear, dateMonth, dateDay).getTime())
  256. if (this.data.closeOnSelect && !this.data.multiple) {
  257. this.close()
  258. }
  259. }
  260. },
  261. /**
  262. * 重置月份的位置信息
  263. */
  264. resetMonth() {
  265. const translate = this.monthsTranslate * 100
  266. const transform = getTransform(translate, this.isH)
  267. this.$$setData({
  268. wrapperTranslate: `transition-duration: 0s; ${transform}`,
  269. })
  270. },
  271. /**
  272. * 设置年月
  273. * @param {String} year 年份
  274. * @param {String} month 月份
  275. */
  276. setYearMonth(year = this.data.currentYear, month = this.data.currentMonth) {
  277. const { months, monthsTranslate, maxDate, minDate, currentYear, currentMonth } = this.data
  278. const targetDate = year < currentYear ? new Date(year, month + 1, -1).getTime() : new Date(year, month).getTime()
  279. // 判断是否存在最大日期
  280. if (maxDate && targetDate > new Date(maxDate).getTime()) {
  281. return false
  282. }
  283. // 判断是否存在最小日期
  284. if (minDate && targetDate < new Date(minDate).getTime()) {
  285. return false
  286. }
  287. const currentDate = new Date(currentYear, currentMonth).getTime()
  288. const dir = targetDate > currentDate ? 'next' : 'prev'
  289. const newMonthHTML = this.monthHTML(new Date(year, month))
  290. const prevTranslate = this.monthsTranslate = this.monthsTranslate || 0
  291. if (targetDate > currentDate) {
  292. this.monthsTranslate = this.monthsTranslate - 1
  293. const translate = -(prevTranslate - 1) * 100
  294. const nextMonthTranslate = getTransform(translate, this.isH)
  295. this.$$setData({
  296. months: [months[1], months[2], newMonthHTML],
  297. monthsTranslate: [monthsTranslate[1], monthsTranslate[2], nextMonthTranslate],
  298. })
  299. } else {
  300. this.monthsTranslate = this.monthsTranslate + 1
  301. const translate = -(prevTranslate + 1) * 100
  302. const prevMonthTranslate = getTransform(translate, this.isH)
  303. this.$$setData({
  304. months: [newMonthHTML, months[0], months[1]],
  305. monthsTranslate: [prevMonthTranslate, monthsTranslate[0], monthsTranslate[1]],
  306. })
  307. }
  308. this.onMonthChangeStart(dir)
  309. const transform = getTransform(this.monthsTranslate * 100, this.isH)
  310. const duration = this.data.animate ? .3 : 0
  311. const wrapperTranslate = `transition-duration: ${duration}s; ${transform}`
  312. this.$$setData({
  313. wrapperTranslate,
  314. })
  315. setTimeout(() => this.onMonthChangeEnd(dir, true), duration)
  316. },
  317. /**
  318. * 下一年
  319. */
  320. nextYear() {
  321. this.setYearMonth(this.data.currentYear + 1)
  322. },
  323. /**
  324. * 上一年
  325. */
  326. prevYear() {
  327. this.setYearMonth(this.data.currentYear - 1)
  328. },
  329. /**
  330. * 下一月
  331. */
  332. nextMonth() {
  333. const { months, monthsTranslate, maxDate, currentMonth } = this.data
  334. const nextMonth = parseInt(months[months.length - 1].month, 10)
  335. const nextYear = parseInt(months[months.length - 1].year, 10)
  336. const nextDate = new Date(nextYear, nextMonth)
  337. const nextDateTime = nextDate.getTime()
  338. // 判断是否存在最大日期
  339. if (maxDate && nextDateTime > new Date(maxDate).getTime()) {
  340. return this.resetMonth()
  341. }
  342. this.monthsTranslate = this.monthsTranslate - 1
  343. if (nextMonth === currentMonth) {
  344. const translate = -(this.monthsTranslate) * 100
  345. const nextMonthHTML = this.monthHTML(nextDateTime, 'next')
  346. const nextMonthTranslate = getTransform(translate, this.isH)
  347. const months = [this.data.months[1], this.data.months[2], nextMonthHTML]
  348. this.$$setData({
  349. months,
  350. monthsTranslate: [monthsTranslate[1], monthsTranslate[2], nextMonthTranslate],
  351. })
  352. if (typeof this.fns.onMonthAdd === 'function') {
  353. this.fns.onMonthAdd.call(this, months[months.length - 1])
  354. }
  355. }
  356. this.onMonthChangeStart('next')
  357. const transform = getTransform(this.monthsTranslate * 100, this.isH)
  358. const duration = this.data.animate ? .3 : 0
  359. const wrapperTranslate = `transition-duration: ${duration}s; ${transform}`
  360. this.$$setData({
  361. wrapperTranslate,
  362. })
  363. setTimeout(() => this.onMonthChangeEnd('next'), duration)
  364. },
  365. /**
  366. * 上一月
  367. */
  368. prevMonth() {
  369. const { months, monthsTranslate, minDate, currentMonth } = this.data
  370. const prevMonth = parseInt(months[0].month, 10)
  371. const prevYear = parseInt(months[0].year, 10)
  372. const prevDate = new Date(prevYear, prevMonth + 1, -1)
  373. const prevDateTime = prevDate.getTime()
  374. // 判断是否存在最小日期
  375. if (minDate && prevDateTime < new Date(minDate).getTime()) {
  376. return this.resetMonth()
  377. }
  378. this.monthsTranslate = this.monthsTranslate + 1
  379. if (prevMonth === currentMonth) {
  380. const translate = -(this.monthsTranslate) * 100
  381. const prevMonthHTML = this.monthHTML(prevDateTime, 'prev')
  382. const prevMonthTranslate = getTransform(translate, this.isH)
  383. const months = [prevMonthHTML, this.data.months[0], this.data.months[1]]
  384. this.$$setData({
  385. months,
  386. monthsTranslate: [prevMonthTranslate, monthsTranslate[0], monthsTranslate[1]],
  387. })
  388. if (typeof this.fns.onMonthAdd === 'function') {
  389. this.fns.onMonthAdd.call(this, months[0])
  390. }
  391. }
  392. this.onMonthChangeStart('prev')
  393. const transform = getTransform(this.monthsTranslate * 100, this.isH)
  394. const duration = this.data.animate ? .3 : 0
  395. const wrapperTranslate = `transition-duration: ${duration}s; ${transform}`
  396. this.$$setData({
  397. wrapperTranslate,
  398. })
  399. setTimeout(() => this.onMonthChangeEnd('prev'), duration)
  400. },
  401. /**
  402. * 月份变化开始时的回调函数
  403. * @param {String} dir 方向
  404. */
  405. onMonthChangeStart(dir) {
  406. const params = this.updateCurrentMonthYear(dir)
  407. this.$$setData(params)
  408. if (typeof this.fns.onMonthYearChangeStart === 'function') {
  409. this.fns.onMonthYearChangeStart.call(this, params.currentYear, params.currentMonth)
  410. }
  411. },
  412. /**
  413. * 月份变化完成时的回调函数
  414. * @param {String} dir 方向
  415. * @param {Boolean} rebuildBoth 重置
  416. */
  417. onMonthChangeEnd(dir = 'next', rebuildBoth = false) {
  418. const { currentYear, currentMonth } = this.data
  419. let nextMonthHTML, prevMonthHTML, newMonthHTML, months = [...this.data.months]
  420. if (!rebuildBoth) {
  421. newMonthHTML = this.monthHTML(new Date(currentYear, currentMonth), dir)
  422. if (dir === 'next') {
  423. months = [months[1], months[2], newMonthHTML]
  424. } else if (dir === 'prev') {
  425. months = [newMonthHTML, months[0], months[1]]
  426. }
  427. } else {
  428. prevMonthHTML = this.monthHTML(new Date(currentYear, currentMonth), 'prev')
  429. nextMonthHTML = this.monthHTML(new Date(currentYear, currentMonth), 'next')
  430. months = [prevMonthHTML, months[dir === 'next' ? months.length - 1 : 0], nextMonthHTML]
  431. }
  432. const monthsTranslate = this.setMonthsTranslate(this.monthsTranslate)
  433. this.isRendered = true
  434. this.$$setData({ months, monthsTranslate }).then(() => (this.isRendered = false))
  435. if (typeof this.fns.onMonthAdd === 'function') {
  436. this.fns.onMonthAdd.call(this, dir === 'next' ? months[months.length - 1] : months[0])
  437. }
  438. if (typeof this.fns.onMonthYearChangeEnd === 'function') {
  439. this.fns.onMonthYearChangeEnd.call(this, currentYear, currentMonth)
  440. }
  441. },
  442. /**
  443. * 设置星期
  444. */
  445. setWeekHeader() {
  446. const { weekHeader, firstDay, dayNamesShort, weekendDays } = this.data
  447. const weeks = []
  448. if (weekHeader) {
  449. for (let i = 0; i < 7; i++) {
  450. const weekDayIndex = (i + firstDay > 6) ? (i - 7 + firstDay) : (i + firstDay)
  451. const dayName = dayNamesShort[weekDayIndex]
  452. const weekend = weekendDays.indexOf(weekDayIndex) >= 0
  453. weeks.push({
  454. weekend,
  455. dayName,
  456. })
  457. }
  458. }
  459. return weeks
  460. },
  461. /**
  462. * 判断日期是否存在
  463. */
  464. daysInMonth(date) {
  465. const d = new Date(date)
  466. return new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate()
  467. },
  468. /**
  469. * 设置月份数据
  470. */
  471. monthHTML(date, offset) {
  472. date = new Date(date)
  473. let year = date.getFullYear(),
  474. month = date.getMonth(),
  475. time = date.getTime()
  476. const monthHTML = {
  477. year,
  478. month,
  479. time,
  480. items: [],
  481. }
  482. if (offset === `next`) {
  483. if (month === 11) date = new Date(year + 1, 0)
  484. else date = new Date(year, month + 1, 1)
  485. }
  486. if (offset === `prev`) {
  487. if (month === 0) date = new Date(year - 1, 11)
  488. else date = new Date(year, month - 1, 1)
  489. }
  490. if (offset === `next` || offset === `prev`) {
  491. month = date.getMonth()
  492. year = date.getFullYear()
  493. time = date.getTime()
  494. }
  495. let daysInPrevMonth = this.daysInMonth(new Date(date.getFullYear(), date.getMonth()).getTime() - 10 * 24 * 60 * 60 * 1000),
  496. daysInMonth = this.daysInMonth(date),
  497. firstDayOfMonthIndex = new Date(date.getFullYear(), date.getMonth()).getDay()
  498. if (firstDayOfMonthIndex === 0) firstDayOfMonthIndex = 7
  499. let dayDate, currentValues = [],
  500. i, j,
  501. rows = 6,
  502. cols = 7,
  503. dayIndex = 0 + (this.data.firstDay - 1),
  504. today = new Date().setHours(0, 0, 0, 0),
  505. minDate = this.data.minDate ? new Date(this.data.minDate).getTime() : null,
  506. maxDate = this.data.maxDate ? new Date(this.data.maxDate).getTime() : null
  507. if (this.data.value && this.data.value.length) {
  508. for (let i = 0; i < this.data.value.length; i++) {
  509. currentValues.push(new Date(this.data.value[i]).setHours(0, 0, 0, 0))
  510. }
  511. }
  512. for (let i = 1; i <= rows; i++) {
  513. let rowHTML = []
  514. let row = i
  515. for (let j = 1; j <= cols; j++) {
  516. let col = j
  517. dayIndex++
  518. let dayNumber = dayIndex - firstDayOfMonthIndex
  519. let type = {}
  520. if (dayNumber < 0) {
  521. dayNumber = daysInPrevMonth + dayNumber + 1
  522. type.prev = true
  523. dayDate = new Date(month - 1 < 0 ? year - 1 : year, month - 1 < 0 ? 11 : month - 1, dayNumber).getTime()
  524. } else {
  525. dayNumber = dayNumber + 1
  526. if (dayNumber > daysInMonth) {
  527. dayNumber = dayNumber - daysInMonth
  528. type.next = true
  529. dayDate = new Date(month + 1 > 11 ? year + 1 : year, month + 1 > 11 ? 0 : month + 1, dayNumber).getTime()
  530. } else {
  531. dayDate = new Date(year, month, dayNumber).getTime()
  532. }
  533. }
  534. // Today
  535. if (dayDate === today) type.today = true
  536. // Selected
  537. if (currentValues.indexOf(dayDate) >= 0) type.selected = true
  538. // Weekend
  539. if (this.data.weekendDays.indexOf(col - 1) >= 0) {
  540. type.weekend = true
  541. }
  542. // Disabled
  543. if ((minDate && dayDate < minDate) || (maxDate && dayDate > maxDate)) {
  544. type.disabled = true
  545. }
  546. dayDate = new Date(dayDate)
  547. const dayYear = dayDate.getFullYear()
  548. const dayMonth = dayDate.getMonth()
  549. rowHTML.push({
  550. type,
  551. year: dayYear,
  552. month: dayMonth,
  553. day: dayNumber,
  554. date: `${dayYear}-${dayMonth + 1}-${dayNumber}`,
  555. })
  556. }
  557. monthHTML.year = year
  558. monthHTML.month = month
  559. monthHTML.time = time
  560. monthHTML.items.push(rowHTML)
  561. }
  562. return monthHTML
  563. },
  564. /**
  565. * 设置月份
  566. */
  567. setMonthsHTML() {
  568. const layoutDate = this.data.value && this.data.value.length ? this.data.value[0] : new Date().setHours(0, 0, 0, 0)
  569. const prevMonthHTML = this.monthHTML(layoutDate, `prev`)
  570. const currentMonthHTML = this.monthHTML(layoutDate)
  571. const nextMonthHTML = this.monthHTML(layoutDate, `next`)
  572. return [prevMonthHTML, currentMonthHTML, nextMonthHTML]
  573. },
  574. /**
  575. * 格式化日期
  576. */
  577. formatDate(date) {
  578. date = new Date(date)
  579. const year = date.getFullYear()
  580. const month = date.getMonth()
  581. const month1 = month + 1
  582. const day = date.getDate()
  583. const weekDay = date.getDay()
  584. return this.data.dateFormat
  585. .replace(/yyyy/g, year)
  586. .replace(/yy/g, (year + '').substring(2))
  587. .replace(/mm/g, month1 < 10 ? '0' + month1 : month1)
  588. .replace(/m/g, month1)
  589. .replace(/MM/g, this.data.monthNames[month])
  590. .replace(/M/g, this.data.monthNamesShort[month])
  591. .replace(/dd/g, day < 10 ? '0' + day : day)
  592. .replace(/d/g, day)
  593. .replace(/DD/g, this.data.dayNames[weekDay])
  594. .replace(/D/g, this.data.dayNamesShort[weekDay])
  595. },
  596. /**
  597. * 添加选中值
  598. */
  599. addValue(value) {
  600. if (this.data.multiple) {
  601. let arrValues = this.data.value || []
  602. let inValuesIndex = -1
  603. for (let i = 0; i < arrValues.length; i++) {
  604. if (isSameDate(value, arrValues[i])) {
  605. inValuesIndex = i
  606. }
  607. }
  608. if (inValuesIndex === -1) {
  609. arrValues.push(value)
  610. } else {
  611. arrValues.splice(inValuesIndex, 1)
  612. }
  613. this.setValue(arrValues)
  614. } else {
  615. this.setValue([value])
  616. }
  617. },
  618. /**
  619. * 设置选择值
  620. */
  621. setValue(value) {
  622. this.$$setData({ value }).then(() => this.updateValue())
  623. },
  624. /**
  625. * 更新日历
  626. */
  627. updateValue() {
  628. const changedPath = {}
  629. this.data.months.forEach((n, i) => {
  630. n.items.forEach((v, k) => {
  631. v.forEach((p, j) => {
  632. if (p.type.selected) {
  633. changedPath[`months[${i}].items[${k}][${j}].type.selected`] = false
  634. }
  635. })
  636. })
  637. })
  638. for (let ii = 0; ii < this.data.value.length; ii++) {
  639. const valueDate = new Date(this.data.value[ii])
  640. const valueYear = valueDate.getFullYear()
  641. const valueMonth = valueDate.getMonth()
  642. const valueDay = valueDate.getDate()
  643. this.data.months.forEach((n, i) => {
  644. if (n.year === valueYear && n.month === valueMonth) {
  645. n.items.forEach((v, k) => {
  646. v.forEach((p, j) => {
  647. if (p.year === valueYear && p.month === valueMonth && p.day === valueDay) {
  648. changedPath[`months[${i}].items[${k}][${j}].type.selected`] = true
  649. }
  650. })
  651. })
  652. }
  653. })
  654. }
  655. this.$$setData(changedPath)
  656. if (typeof this.fns.onChange === 'function') {
  657. this.fns.onChange.call(this, this.data.value, this.data.value.map((n) => this.formatDate(n)))
  658. }
  659. },
  660. },
  661. })