yu-datetime-picker.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. <template>
  2. <view class="yu-datetime-picker">
  3. <view class="yu-datetime-mask" :class="{'show':showPicker}" @tap="maskClick" @touchmove.stop.prevent catchtouchmove="true"></view>
  4. <view class="yu-datetime-content" :class="{'show':showPicker}">
  5. <view class="yu-datetime-hd" @touchmove.stop.prevent catchtouchmove="true">
  6. <view class="yu-datetime-btn" @tap="pickerCancel">取消</view>
  7. <view class="yu-datetime-btn" :style="{color: color}" @tap="pickerConfirm">确定</view>
  8. </view>
  9. <view class="yu-datetime-view">
  10. <picker-view v-if="isAll" class="picker-view" :indicator-style="itemHeight" :value="values" @change="bindChange">
  11. <picker-view-column>
  12. <view class="yu-datetime-item" v-for="(item,index) in dateObj.years" :key="index">{{item}}年</view>
  13. </picker-view-column>
  14. <picker-view-column>
  15. <view class="yu-datetime-item" v-for="(item,index) in dateObj.months" :key="index">{{item}}月</view>
  16. </picker-view-column>
  17. <picker-view-column>
  18. <view class="yu-datetime-item" v-for="(item,index) in dateObj.days" :key="index">{{item}}日</view>
  19. </picker-view-column>
  20. <picker-view-column>
  21. <view class="yu-datetime-item" v-for="(item,index) in dateObj.hours" :key="index">{{item}}时</view>
  22. </picker-view-column>
  23. <picker-view-column>
  24. <view class="yu-datetime-item" v-for="(item,index) in dateObj.minutes" :key="index">{{item}}分</view>
  25. </picker-view-column>
  26. <picker-view-column>
  27. <view class="yu-datetime-item" v-for="(item,index) in dateObj.seconds" :key="index">{{item}}秒</view>
  28. </picker-view-column>
  29. </picker-view>
  30. <picker-view v-else class="picker-view" :indicator-style="itemHeight" :value="dateValues" @change="bindDateChange">
  31. <picker-view-column class="yu-picker-column">
  32. <view class="yu-datetime-item" v-for="(item,index) in dateObj.dates" :key="index">{{item}}</view>
  33. </picker-view-column>
  34. <picker-view-column>
  35. <view class="yu-datetime-item" v-for="(item,index) in dateObj.hours" :key="index">{{item}}时</view>
  36. </picker-view-column>
  37. <picker-view-column>
  38. <view class="yu-datetime-item" v-for="(item,index) in dateObj.minutes" :key="index">{{item}}分</view>
  39. </picker-view-column>
  40. <picker-view-column>
  41. <view class="yu-datetime-item" v-for="(item,index) in dateObj.seconds" :key="index">{{item}}秒</view>
  42. </picker-view-column>
  43. </picker-view>
  44. </view>
  45. </view>
  46. </view>
  47. </template>
  48. <script>
  49. export default {
  50. name: 'yuDatetimePicker',
  51. props: {
  52. isAll: {
  53. //全部日期有效可选
  54. type: Boolean,
  55. default() {
  56. return true
  57. }
  58. },
  59. current: {
  60. //默认显示当前日期时间
  61. type: Boolean,
  62. default() {
  63. return true
  64. }
  65. },
  66. color: {
  67. //颜色
  68. type: String,
  69. default() {
  70. return '#3279e4'
  71. }
  72. },
  73. startYear: {
  74. //开始年份
  75. type: [String, Number],
  76. default() {
  77. return new Date().getFullYear()
  78. }
  79. },
  80. endYear: {
  81. //结束年份
  82. type: [String, Number],
  83. default() {
  84. return '2050'
  85. }
  86. },
  87. value: {
  88. //设置默认日期时间,优先级高于current
  89. type: String,
  90. default() {
  91. return ''
  92. }
  93. }
  94. },
  95. data() {
  96. let date = new Date()
  97. let year = date.getFullYear()
  98. let month = date.getMonth() + 1
  99. let day = date.getDate()
  100. let hour = date.getHours()
  101. let minute = date.getMinutes()
  102. let second = date.getSeconds()
  103. let dates = []
  104. let months = []
  105. let years = []
  106. let days = []
  107. let hours = []
  108. let minutes = []
  109. let seconds = []
  110. for (let i = month; i <= month + 2; i++) {
  111. //获取包括当前月份在内的3个月内的日期
  112. let localMonth = i
  113. let localYear = year
  114. if (i == 13) {
  115. localYear += 1
  116. }
  117. if (i >= 13) {
  118. localMonth -= 12
  119. }
  120. let total = new Date(localYear, localMonth, 0).getDate()
  121. if (i == month) {
  122. for (let j = day; j <= total; j++) {
  123. let m = localMonth
  124. let d = j
  125. if (localMonth < 10) {
  126. m = '0' + m
  127. }
  128. if (j < 10) {
  129. d = '0' + d
  130. }
  131. let str = year + '-' + m + '-' + d
  132. dates.push(str)
  133. }
  134. } else {
  135. for (let j = 1; j <= total; j++) {
  136. let m = localMonth
  137. let d = j
  138. if (localMonth < 10) {
  139. m = '0' + m
  140. }
  141. if (j < 10) {
  142. d = '0' + d
  143. }
  144. let str = localYear + '-' + m + '-' + d
  145. dates.push(str)
  146. }
  147. }
  148. }
  149. for (let i = parseInt(this.startYear); i <= this.endYear; i++) {
  150. years.push(i)
  151. }
  152. for (let i = 1; i <= 12; i++) {
  153. let str = i
  154. if (i < 10) {
  155. str = '0' + str
  156. } else {
  157. str = '' + str
  158. }
  159. months.push(str)
  160. }
  161. if (this.value) {
  162. let valueArr = this.value.split(' ')
  163. let valueDateArr = valueArr[0].split('-')
  164. let totalCurrent = new Date(valueDateArr[0], valueDateArr[1], 0).getDate()
  165. for (let i = 1; i <= totalCurrent; i++) {
  166. let str = i
  167. if (i < 10) {
  168. str = '0' + str
  169. } else {
  170. str = '' + str
  171. }
  172. days.push(str)
  173. }
  174. } else {
  175. let totalCurrent = new Date(year, month, 0).getDate()
  176. for (let i = 1; i <= totalCurrent; i++) {
  177. let str = i
  178. if (i < 10) {
  179. str = '0' + str
  180. } else {
  181. str = '' + str
  182. }
  183. days.push(str)
  184. }
  185. }
  186. for (let i = 0; i < 24; i++) {
  187. let str = i
  188. if (i < 10) {
  189. str = '0' + str
  190. } else {
  191. str = '' + str
  192. }
  193. hours.push(str)
  194. }
  195. for (let i = 0; i < 60; i++) {
  196. let str = i
  197. if (i < 10) {
  198. str = '0' + str
  199. } else {
  200. str = '' + str
  201. }
  202. minutes.push(str)
  203. }
  204. for (let i = 0; i < 60; i++) {
  205. let str = i
  206. if (i < 10) {
  207. str = '0' + str
  208. } else {
  209. str = '' + str
  210. }
  211. seconds.push(str)
  212. }
  213. let dateObj = {
  214. dates,
  215. years,
  216. months,
  217. days,
  218. hours,
  219. minutes,
  220. seconds
  221. }
  222. return {
  223. year,
  224. month,
  225. day,
  226. hour,
  227. minute,
  228. second,
  229. dateObj,
  230. itemHeight: `height: ${uni.upx2px(88)}px;`,
  231. values: [0, 0, 0, 0, 0, 0],
  232. selectArr: [],
  233. selectRes: '',
  234. showPicker: false,
  235. dateValues: [0, 0, 0, 0]
  236. }
  237. },
  238. mounted() {
  239. this.initDate()
  240. if (!this.value && this.current) {
  241. this.showCurrent()
  242. }
  243. },
  244. methods: {
  245. initDate() {
  246. let _this = this
  247. //解析默认显示的日期时间
  248. if (_this.value) {
  249. let values = [0, 0, 0, 0, 0, 0]
  250. let dateValues = [0, 0, 0, 0]
  251. let valueStr = _this.value
  252. let valueArr = valueStr.split(' ')
  253. let valueDateArr = valueArr[0].split('-')
  254. let valueTimeArr = valueArr[1].split(':')
  255. if (_this.isAll) {
  256. values[0] =
  257. valueDateArr[0] - _this.startYear > 0
  258. ? valueDateArr[0] - _this.startYear
  259. : 0
  260. values[1] = parseInt(valueDateArr[1]) - 1
  261. values[2] = parseInt(valueDateArr[2]) - 1
  262. values[3] = parseInt(valueTimeArr[0])
  263. values[4] = parseInt(valueTimeArr[1])
  264. values[5] = parseInt(valueTimeArr[2])
  265. _this.$nextTick(() => {
  266. _this.values = values
  267. })
  268. if (valueDateArr[0] - _this.startYear >= 0) {
  269. _this.selectArr = [
  270. valueDateArr[0],
  271. valueDateArr[1],
  272. valueDateArr[2],
  273. valueTimeArr[0],
  274. valueTimeArr[1],
  275. valueTimeArr[2]
  276. ]
  277. _this.selectRes = _this.value
  278. } else {
  279. _this.selectArr = [
  280. _this.formatNum(_this.startYear),
  281. valueDateArr[1],
  282. valueDateArr[2],
  283. valueTimeArr[0],
  284. valueTimeArr[1],
  285. valueTimeArr[2]
  286. ]
  287. _this.selectRes = `${
  288. this.formatNum(_this.startYear) +
  289. '-' +
  290. valueDateArr[1] +
  291. '-' +
  292. valueDateArr[2] +
  293. ' ' +
  294. valueTimeArr[0] +
  295. ':' +
  296. valueTimeArr[1] +
  297. ':' +
  298. valueTimeArr[2]
  299. }`
  300. }
  301. } else {
  302. let str = valueDateArr.join('')
  303. let localStr =
  304. _this.formatNum(_this.year) +
  305. _this.formatNum(_this.month) +
  306. _this.formatNum(_this.day) +
  307. ''
  308. if (str < localStr) {
  309. dateValues[0] = 0
  310. _this.selectArr = [
  311. _this.formatNum(_this.year),
  312. _this.formatNum(_this.month),
  313. _this.formatNum(_this.day),
  314. valueTimeArr[0],
  315. valueTimeArr[1],
  316. valueTimeArr[2]
  317. ]
  318. _this.selectRes = `${
  319. _this.formatNum(_this.year) +
  320. '-' +
  321. _this.formatNum(_this.month) +
  322. '-' +
  323. _this.formatNum(_this.day) +
  324. ' ' +
  325. valueTimeArr[0] +
  326. ':' +
  327. valueTimeArr[1] +
  328. ':' +
  329. valueTimeArr[2]
  330. }`
  331. } else {
  332. let num = 0 //计算默认日期和当前日期相隔天数,计算下标
  333. let start =
  334. _this.formatNum(_this.year) +
  335. '-' +
  336. _this.formatNum(_this.month) +
  337. '-' +
  338. _this.formatNum(_this.day)
  339. let res = _this.getBetweenDateStr(start, valueArr[0])
  340. dateValues[0] = res.length - 1
  341. _this.selectArr = [
  342. valueDateArr[0],
  343. valueDateArr[1],
  344. valueDateArr[2],
  345. valueTimeArr[0],
  346. valueTimeArr[1],
  347. valueTimeArr[2]
  348. ]
  349. _this.selectRes = _this.value
  350. }
  351. dateValues[1] = parseInt(valueTimeArr[0])
  352. dateValues[2] = parseInt(valueTimeArr[1])
  353. dateValues[3] = parseInt(valueTimeArr[2])
  354. _this.$nextTick(() => {
  355. _this.dateValues = dateValues
  356. })
  357. }
  358. return
  359. }
  360. if (_this.isAll) {
  361. _this.selectArr = [_this.formatNum(_this.startYear), '01', '01', '00', '00', '00']
  362. _this.selectRes = `${_this.formatNum(_this.startYear) + '-01-01 00:00:00'}`
  363. } else {
  364. _this.selectArr = [
  365. _this.formatNum(_this.year),
  366. _this.formatNum(_this.month),
  367. '01',
  368. '00',
  369. '00',
  370. '00'
  371. ]
  372. _this.selectRes = `${
  373. _this.formatNum(_this.year) +
  374. '-' +
  375. _this.formatNum(_this.month) +
  376. '-01 00:00:00'
  377. }`
  378. }
  379. },
  380. showCurrent() {
  381. //显示当前的日期时间
  382. let arr = [0, 0, 0, 0, 0, 0]
  383. let dateArr = [0, 0, 0, 0]
  384. this.selectArr = [
  385. this.formatNum(this.year),
  386. this.formatNum(this.month),
  387. this.formatNum(this.day),
  388. this.formatNum(this.hour),
  389. this.formatNum(this.minute),
  390. this.formatNum(this.second)
  391. ]
  392. this.selectRes = `${
  393. this.formatNum(this.year) +
  394. '-' +
  395. this.formatNum(this.month) +
  396. '-' +
  397. this.formatNum(this.day) +
  398. ' ' +
  399. this.formatNum(this.hour) +
  400. ':' +
  401. this.formatNum(this.minute) +
  402. ':' +
  403. this.formatNum(this.second)
  404. }`
  405. if (this.isAll) {
  406. arr[0] = this.year - this.startYear
  407. arr[1] = this.month - 1
  408. arr[2] = this.day - 1
  409. arr[3] = this.hour
  410. arr[4] = this.minute
  411. arr[5] = this.second
  412. this.$nextTick(() => {
  413. this.values = arr
  414. })
  415. } else {
  416. dateArr[1] = this.hour
  417. dateArr[2] = this.minute
  418. dateArr[3] = this.second
  419. this.$nextTick(() => {
  420. this.dateValues = dateArr
  421. })
  422. }
  423. },
  424. initDayArr: (year, month) => {
  425. //初始化月份天数
  426. let totalDay = new Date(year, month, 0).getDate()
  427. let dayArr = []
  428. for (let i = 1; i <= totalDay; i++) {
  429. if (i < 10) {
  430. i = '0' + i
  431. } else {
  432. i = i + ''
  433. }
  434. dayArr.push(i)
  435. }
  436. return dayArr
  437. },
  438. formatNum(num) {
  439. //日期时间的初始化
  440. return num < 10 ? '0' + num : num + ''
  441. },
  442. maskClick() {
  443. //日期时间的遮罩
  444. this.showPicker = false
  445. },
  446. show() {
  447. //日期时间的显示
  448. this.showPicker = true
  449. },
  450. hide() {
  451. //日期时间的隐藏
  452. this.showPicker = false
  453. },
  454. pickerCancel() {
  455. //日期时间取消
  456. this.$emit('cancel', {
  457. selectArr: this.selectArr
  458. })
  459. this.showPicker = false
  460. },
  461. pickerConfirm(e) {
  462. //日期时间确定
  463. this.$emit('confirm', {
  464. selectArr: this.selectArr,
  465. selectRes: this.selectRes
  466. })
  467. this.showPicker = false
  468. },
  469. bindChange(e) {
  470. //默认滚动日期时间方法
  471. let valueArr = e.detail.value
  472. let year = '',
  473. month = '',
  474. day = '',
  475. hour = '',
  476. minute = '',
  477. second = ''
  478. let selectArr = this.selectArr
  479. let dayArr = []
  480. year = this.dateObj.years[valueArr[0]]
  481. month = this.dateObj.months[valueArr[1]]
  482. day = this.dateObj.days[valueArr[2]]
  483. hour = this.dateObj.hours[valueArr[3]]
  484. minute = this.dateObj.minutes[valueArr[4]]
  485. second = this.dateObj.seconds[valueArr[5]]
  486. if (year != selectArr[0]) {
  487. dayArr = this.initDayArr(year, month)
  488. this.dateObj.days = dayArr
  489. }
  490. if (month != selectArr[1]) {
  491. dayArr = this.initDayArr(year, month)
  492. this.dateObj.days = dayArr
  493. }
  494. this.selectArr = [year, month, day, hour, minute, second]
  495. this.selectRes = `${
  496. year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second
  497. }`
  498. this.$nextTick(() => {
  499. this.values = valueArr
  500. })
  501. },
  502. bindDateChange(e) {
  503. //有效日期的滚动日期时间方法
  504. let valueArr = e.detail.value
  505. let dateStr = '',
  506. dateArr = [],
  507. hour = '',
  508. minute = '',
  509. second = ''
  510. let selectArr = this.selectArr
  511. let dayArr = []
  512. dateStr = this.dateObj.dates[valueArr[0]]
  513. dateArr = dateStr.split('-')
  514. hour = this.dateObj.hours[valueArr[1]]
  515. minute = this.dateObj.minutes[valueArr[2]]
  516. second = this.dateObj.seconds[valueArr[3]]
  517. this.selectArr = [dateArr[0], dateArr[1], dateArr[2], hour, minute, second]
  518. this.selectRes = `${
  519. dateArr[0] +
  520. '-' +
  521. dateArr[1] +
  522. '-' +
  523. dateArr[2] +
  524. ' ' +
  525. hour +
  526. ':' +
  527. minute +
  528. ':' +
  529. second
  530. }`
  531. this.$nextTick(() => {
  532. this.dateValues = valueArr
  533. })
  534. },
  535. //遍历两个日期间的所有日期
  536. getBetweenDateStr(start, end) {
  537. let result = []
  538. let beginDay = start.split('-')
  539. let endDay = end.split('-')
  540. let diffDay = new Date()
  541. let dateList = new Array()
  542. let i = 0
  543. diffDay.setDate(beginDay[2])
  544. diffDay.setMonth(beginDay[1] - 1)
  545. diffDay.setFullYear(beginDay[0])
  546. result.push(start)
  547. while (i == 0) {
  548. let countDay = diffDay.getTime() + 24 * 60 * 60 * 1000
  549. diffDay.setTime(countDay)
  550. dateList[2] = diffDay.getDate()
  551. dateList[1] = diffDay.getMonth() + 1
  552. dateList[0] = diffDay.getFullYear()
  553. if (String(dateList[1]).length == 1) {
  554. dateList[1] = '0' + dateList[1]
  555. }
  556. if (String(dateList[2]).length == 1) {
  557. dateList[2] = '0' + dateList[2]
  558. }
  559. result.push(dateList[0] + '-' + dateList[1] + '-' + dateList[2])
  560. if (
  561. dateList[0] == endDay[0] &&
  562. dateList[1] == endDay[1] &&
  563. dateList[2] == endDay[2]
  564. ) {
  565. i = 1
  566. }
  567. }
  568. return result
  569. }
  570. }
  571. }
  572. </script>
  573. <style lang="scss" scoped>
  574. .yu-datetime-picker {
  575. position: relative;
  576. z-index: 888;
  577. }
  578. .yu-datetime-mask {
  579. position: fixed;
  580. z-index: 1000;
  581. top: 0;
  582. right: 0;
  583. left: 0;
  584. bottom: 0;
  585. background: rgba(0, 0, 0, 0.4);
  586. visibility: hidden;
  587. opacity: 0;
  588. transition: all 0.3s ease;
  589. }
  590. .yu-datetime-mask.show {
  591. visibility: visible;
  592. opacity: 1;
  593. }
  594. .yu-datetime-content {
  595. position: fixed;
  596. bottom: 0;
  597. left: 0;
  598. width: 100%;
  599. transition: all 0.3s ease;
  600. transform: translateY(100%);
  601. z-index: 3000;
  602. }
  603. .yu-datetime-content.show {
  604. transform: translateY(0);
  605. }
  606. .yu-datetime-hd {
  607. display: flex;
  608. align-items: center;
  609. padding: 0 30upx;
  610. height: 44px;
  611. background-color: #fff;
  612. position: relative;
  613. text-align: center;
  614. font-size: 15px;
  615. justify-content: space-between;
  616. }
  617. .yu-datetime-btn {
  618. font-size: 14px;
  619. }
  620. .yu-datetime-hd:after {
  621. content: ' ';
  622. position: absolute;
  623. left: 0;
  624. bottom: 0;
  625. right: 0;
  626. height: 1px;
  627. border-bottom: 1px solid #e5e5e5;
  628. color: #e5e5e5;
  629. transform-origin: 0 100%;
  630. transform: scaleY(0.5);
  631. }
  632. .yu-datetime-view {
  633. width: 100%;
  634. height: 200px;
  635. overflow: hidden;
  636. background-color: rgba(255, 255, 255, 1);
  637. z-index: 666;
  638. }
  639. .yu-datetime-view .picker-view {
  640. height: 100%;
  641. }
  642. .yu-picker-column {
  643. -webkit-flex: 2;
  644. -webkit-box-flex: 2;
  645. flex: 2;
  646. }
  647. .yu-datetime-item {
  648. text-align: center;
  649. width: 100%;
  650. height: 88upx;
  651. line-height: 88upx;
  652. text-overflow: ellipsis;
  653. white-space: nowrap;
  654. font-size: 30upx;
  655. }
  656. </style>