time-picker.vue 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031
  1. <template>
  2. <view class="uni-datetime-picker">
  3. <view @click="initTimePicker">
  4. <slot>
  5. <view
  6. class="uni-datetime-picker-timebox-pointer"
  7. :class="{
  8. 'uni-datetime-picker-disabled': disabled,
  9. 'uni-datetime-picker-timebox': border
  10. }"
  11. >
  12. <text class="uni-datetime-picker-text">{{ time }}</text>
  13. <view v-if="!time" class="uni-datetime-picker-time">
  14. <text class="uni-datetime-picker-text">{{ selectTimeText }}</text>
  15. </view>
  16. </view>
  17. </slot>
  18. </view>
  19. <view
  20. v-if="visible"
  21. id="mask"
  22. class="uni-datetime-picker-mask"
  23. @click="tiggerTimePicker"
  24. ></view>
  25. <view
  26. v-if="visible"
  27. class="uni-datetime-picker-popup"
  28. :class="[dateShow && timeShow ? '' : 'fix-nvue-height']"
  29. :style="fixNvueBug"
  30. >
  31. <view class="uni-title">
  32. <text class="uni-datetime-picker-text">{{ selectTimeText }}</text>
  33. </view>
  34. <view v-if="dateShow" class="uni-datetime-picker__container-box">
  35. <picker-view
  36. class="uni-datetime-picker-view"
  37. :indicator-style="indicatorStyle"
  38. :value="ymd"
  39. @change="bindDateChange"
  40. >
  41. <picker-view-column>
  42. <view
  43. class="uni-datetime-picker-item"
  44. v-for="(item, index) in years"
  45. :key="index"
  46. >
  47. <text class="uni-datetime-picker-item">{{
  48. lessThanTen(item)
  49. }}</text>
  50. </view>
  51. </picker-view-column>
  52. <picker-view-column>
  53. <view
  54. class="uni-datetime-picker-item"
  55. v-for="(item, index) in months"
  56. :key="index"
  57. >
  58. <text class="uni-datetime-picker-item">{{
  59. lessThanTen(item)
  60. }}</text>
  61. </view>
  62. </picker-view-column>
  63. <picker-view-column>
  64. <view
  65. class="uni-datetime-picker-item"
  66. v-for="(item, index) in days"
  67. :key="index"
  68. >
  69. <text class="uni-datetime-picker-item">{{
  70. lessThanTen(item)
  71. }}</text>
  72. </view>
  73. </picker-view-column>
  74. </picker-view>
  75. <!-- 兼容 nvue 不支持伪类 -->
  76. <text class="uni-datetime-picker-sign sign-left">-</text>
  77. <text class="uni-datetime-picker-sign sign-right">-</text>
  78. </view>
  79. <view v-if="timeShow" class="uni-datetime-picker__container-box">
  80. <picker-view
  81. class="uni-datetime-picker-view"
  82. :class="[hideSecond ? 'time-hide-second' : '']"
  83. :indicator-style="indicatorStyle"
  84. :value="hms"
  85. @change="bindTimeChange"
  86. >
  87. <picker-view-column>
  88. <view
  89. class="uni-datetime-picker-item"
  90. v-for="(item, index) in hours"
  91. :key="index"
  92. >
  93. <text class="uni-datetime-picker-item">{{
  94. lessThanTen(item)
  95. }}</text>
  96. </view>
  97. </picker-view-column>
  98. <picker-view-column>
  99. <view
  100. class="uni-datetime-picker-item"
  101. v-for="(item, index) in minutes"
  102. :key="index"
  103. >
  104. <text class="uni-datetime-picker-item">{{
  105. lessThanTen(item)
  106. }}</text>
  107. </view>
  108. </picker-view-column>
  109. <picker-view-column v-if="!hideSecond">
  110. <view
  111. class="uni-datetime-picker-item"
  112. v-for="(item, index) in seconds"
  113. :key="index"
  114. >
  115. <text class="uni-datetime-picker-item">{{
  116. lessThanTen(item)
  117. }}</text>
  118. </view>
  119. </picker-view-column>
  120. </picker-view>
  121. <!-- 兼容 nvue 不支持伪类 -->
  122. <text
  123. class="uni-datetime-picker-sign"
  124. :class="[hideSecond ? 'sign-center' : 'sign-left']"
  125. >:</text
  126. >
  127. <text v-if="!hideSecond" class="uni-datetime-picker-sign sign-right"
  128. >:</text
  129. >
  130. </view>
  131. <view class="uni-datetime-picker-btn">
  132. <view @click="clearTime">
  133. <text class="uni-datetime-picker-btn-text">{{ clearText }}</text>
  134. </view>
  135. <view class="uni-datetime-picker-btn-group">
  136. <view class="uni-datetime-picker-cancel" @click="tiggerTimePicker">
  137. <text class="uni-datetime-picker-btn-text">{{ cancelText }}</text>
  138. </view>
  139. <view @click="setTime">
  140. <text class="uni-datetime-picker-btn-text">{{ okText }}</text>
  141. </view>
  142. </view>
  143. </view>
  144. </view>
  145. <!-- #ifdef H5 -->
  146. <!-- <keypress v-if="visible" @esc="tiggerTimePicker" @enter="setTime" /> -->
  147. <!-- #endif -->
  148. </view>
  149. </template>
  150. <script>
  151. // #ifdef H5
  152. import keypress from './keypress'
  153. // #endif
  154. import { initVueI18n } from '@dcloudio/uni-i18n'
  155. import messages from './i18n/index.js'
  156. const { t } = initVueI18n(messages)
  157. /**
  158. * DatetimePicker 时间选择器
  159. * @description 可以同时选择日期和时间的选择器
  160. * @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
  161. * @property {String} type = [datetime | date | time] 显示模式
  162. * @property {Boolean} multiple = [true|false] 是否多选
  163. * @property {String|Number} value 默认值
  164. * @property {String|Number} start 起始日期或时间
  165. * @property {String|Number} end 起始日期或时间
  166. * @property {String} return-type = [timestamp | string]
  167. * @event {Function} change 选中发生变化触发
  168. */
  169. export default {
  170. name: 'UniDatetimePicker',
  171. components: {
  172. // #ifdef H5
  173. keypress
  174. // #endif
  175. },
  176. data () {
  177. return {
  178. indicatorStyle: `height: 50px;`,
  179. visible: false,
  180. fixNvueBug: {},
  181. dateShow: true,
  182. timeShow: true,
  183. title: '日期和时间',
  184. // 输入框当前时间
  185. time: '',
  186. // 当前的年月日时分秒
  187. year: 1920,
  188. month: 0,
  189. day: 0,
  190. hour: 0,
  191. minute: 0,
  192. second: 0,
  193. // 起始时间
  194. startYear: 1920,
  195. startMonth: 1,
  196. startDay: 1,
  197. startHour: 0,
  198. startMinute: 0,
  199. startSecond: 0,
  200. // 结束时间
  201. endYear: 2120,
  202. endMonth: 12,
  203. endDay: 31,
  204. endHour: 23,
  205. endMinute: 59,
  206. endSecond: 59
  207. }
  208. },
  209. props: {
  210. type: {
  211. type: String,
  212. default: 'datetime'
  213. },
  214. value: {
  215. type: [String, Number],
  216. default: ''
  217. },
  218. modelValue: {
  219. type: [String, Number],
  220. default: ''
  221. },
  222. start: {
  223. type: [Number, String],
  224. default: ''
  225. },
  226. end: {
  227. type: [Number, String],
  228. default: ''
  229. },
  230. returnType: {
  231. type: String,
  232. default: 'string'
  233. },
  234. disabled: {
  235. type: [Boolean, String],
  236. default: false
  237. },
  238. border: {
  239. type: [Boolean, String],
  240. default: true
  241. },
  242. hideSecond: {
  243. type: [Boolean, String],
  244. default: false
  245. }
  246. },
  247. watch: {
  248. value: {
  249. handler (newVal, oldVal) {
  250. if (newVal) {
  251. this.parseValue(this.fixIosDateFormat(newVal)) //兼容 iOS、safari 日期格式
  252. this.initTime(false)
  253. } else {
  254. this.time = ''
  255. this.parseValue(Date.now())
  256. }
  257. },
  258. immediate: true
  259. },
  260. type: {
  261. handler (newValue) {
  262. if (newValue === 'date') {
  263. this.dateShow = true
  264. this.timeShow = false
  265. this.title = '日期'
  266. } else if (newValue === 'time') {
  267. this.dateShow = false
  268. this.timeShow = true
  269. this.title = '时间'
  270. } else {
  271. this.dateShow = true
  272. this.timeShow = true
  273. this.title = '日期和时间'
  274. }
  275. },
  276. immediate: true
  277. },
  278. start: {
  279. handler (newVal) {
  280. this.parseDatetimeRange(this.fixIosDateFormat(newVal), 'start') //兼容 iOS、safari 日期格式
  281. },
  282. immediate: true
  283. },
  284. end: {
  285. handler (newVal) {
  286. this.parseDatetimeRange(this.fixIosDateFormat(newVal), 'end') //兼容 iOS、safari 日期格式
  287. },
  288. immediate: true
  289. },
  290. // 月、日、时、分、秒可选范围变化后,检查当前值是否在范围内,不在则当前值重置为可选范围第一项
  291. months (newVal) {
  292. this.checkValue('month', this.month, newVal)
  293. },
  294. days (newVal) {
  295. this.checkValue('day', this.day, newVal)
  296. },
  297. hours (newVal) {
  298. this.checkValue('hour', this.hour, newVal)
  299. },
  300. minutes (newVal) {
  301. this.checkValue('minute', this.minute, newVal)
  302. },
  303. seconds (newVal) {
  304. this.checkValue('second', this.second, newVal)
  305. }
  306. },
  307. computed: {
  308. // 当前年、月、日、时、分、秒选择范围
  309. years () {
  310. return this.getCurrentRange('year')
  311. },
  312. months () {
  313. return this.getCurrentRange('month')
  314. },
  315. days () {
  316. return this.getCurrentRange('day')
  317. },
  318. hours () {
  319. return this.getCurrentRange('hour')
  320. },
  321. minutes () {
  322. return this.getCurrentRange('minute')
  323. },
  324. seconds () {
  325. return this.getCurrentRange('second')
  326. },
  327. // picker 当前值数组
  328. ymd () {
  329. return [
  330. this.year - this.minYear,
  331. this.month - this.minMonth,
  332. this.day - this.minDay
  333. ]
  334. },
  335. hms () {
  336. return [
  337. this.hour - this.minHour,
  338. this.minute - this.minMinute,
  339. this.second - this.minSecond
  340. ]
  341. },
  342. // 当前 date 是 start
  343. currentDateIsStart () {
  344. return (
  345. this.year === this.startYear &&
  346. this.month === this.startMonth &&
  347. this.day === this.startDay
  348. )
  349. },
  350. // 当前 date 是 end
  351. currentDateIsEnd () {
  352. return (
  353. this.year === this.endYear &&
  354. this.month === this.endMonth &&
  355. this.day === this.endDay
  356. )
  357. },
  358. // 当前年、月、日、时、分、秒的最小值和最大值
  359. minYear () {
  360. return this.startYear
  361. },
  362. maxYear () {
  363. return this.endYear
  364. },
  365. minMonth () {
  366. if (this.year === this.startYear) {
  367. return this.startMonth
  368. } else {
  369. return 1
  370. }
  371. },
  372. maxMonth () {
  373. if (this.year === this.endYear) {
  374. return this.endMonth
  375. } else {
  376. return 12
  377. }
  378. },
  379. minDay () {
  380. if (this.year === this.startYear && this.month === this.startMonth) {
  381. return this.startDay
  382. } else {
  383. return 1
  384. }
  385. },
  386. maxDay () {
  387. if (this.year === this.endYear && this.month === this.endMonth) {
  388. return this.endDay
  389. } else {
  390. return this.daysInMonth(this.year, this.month)
  391. }
  392. },
  393. minHour () {
  394. if (this.type === 'datetime') {
  395. if (this.currentDateIsStart) {
  396. return this.startHour
  397. } else {
  398. return 0
  399. }
  400. }
  401. if (this.type === 'time') {
  402. return this.startHour
  403. }
  404. },
  405. maxHour () {
  406. if (this.type === 'datetime') {
  407. if (this.currentDateIsEnd) {
  408. return this.endHour
  409. } else {
  410. return 23
  411. }
  412. }
  413. if (this.type === 'time') {
  414. return this.endHour
  415. }
  416. },
  417. minMinute () {
  418. if (this.type === 'datetime') {
  419. if (this.currentDateIsStart && this.hour === this.startHour) {
  420. return this.startMinute
  421. } else {
  422. return 0
  423. }
  424. }
  425. if (this.type === 'time') {
  426. if (this.hour === this.startHour) {
  427. return this.startMinute
  428. } else {
  429. return 0
  430. }
  431. }
  432. },
  433. maxMinute () {
  434. if (this.type === 'datetime') {
  435. if (this.currentDateIsEnd && this.hour === this.endHour) {
  436. return this.endMinute
  437. } else {
  438. return 59
  439. }
  440. }
  441. if (this.type === 'time') {
  442. if (this.hour === this.endHour) {
  443. return this.endMinute
  444. } else {
  445. return 59
  446. }
  447. }
  448. },
  449. minSecond () {
  450. if (this.type === 'datetime') {
  451. if (
  452. this.currentDateIsStart &&
  453. this.hour === this.startHour &&
  454. this.minute === this.startMinute
  455. ) {
  456. return this.startSecond
  457. } else {
  458. return 0
  459. }
  460. }
  461. if (this.type === 'time') {
  462. if (this.hour === this.startHour && this.minute === this.startMinute) {
  463. return this.startSecond
  464. } else {
  465. return 0
  466. }
  467. }
  468. },
  469. maxSecond () {
  470. if (this.type === 'datetime') {
  471. if (
  472. this.currentDateIsEnd &&
  473. this.hour === this.endHour &&
  474. this.minute === this.endMinute
  475. ) {
  476. return this.endSecond
  477. } else {
  478. return 59
  479. }
  480. }
  481. if (this.type === 'time') {
  482. if (this.hour === this.endHour && this.minute === this.endMinute) {
  483. return this.endSecond
  484. } else {
  485. return 59
  486. }
  487. }
  488. },
  489. /**
  490. * for i18n
  491. */
  492. selectTimeText () {
  493. return t('uni-datetime-picker.selectTime')
  494. },
  495. okText () {
  496. return t('uni-datetime-picker.ok')
  497. },
  498. clearText () {
  499. return t('uni-datetime-picker.clear')
  500. },
  501. cancelText () {
  502. return t('uni-datetime-picker.cancel')
  503. }
  504. },
  505. mounted () {
  506. // #ifdef APP-NVUE
  507. const res = uni.getSystemInfoSync()
  508. this.fixNvueBug = {
  509. top: res.windowHeight / 2,
  510. left: res.windowWidth / 2
  511. }
  512. // #endif
  513. },
  514. methods: {
  515. /**
  516. * @param {Object} item
  517. * 小于 10 在前面加个 0
  518. */
  519. lessThanTen (item) {
  520. return item < 10 ? '0' + item : item
  521. },
  522. /**
  523. * 解析时分秒字符串,例如:00:00:00
  524. * @param {String} timeString
  525. */
  526. parseTimeType (timeString) {
  527. if (timeString) {
  528. let timeArr = timeString.split(':')
  529. this.hour = Number(timeArr[0])
  530. this.minute = Number(timeArr[1])
  531. this.second = Number(timeArr[2])
  532. }
  533. },
  534. /**
  535. * 解析选择器初始值,类型可以是字符串、时间戳,例如:2000-10-02、'08:30:00'、 1610695109000
  536. * @param {String | Number} datetime
  537. */
  538. initPickerValue (datetime) {
  539. let defaultValue = null
  540. if (datetime) {
  541. defaultValue = this.compareValueWithStartAndEnd(
  542. datetime,
  543. this.start,
  544. this.end
  545. )
  546. } else {
  547. defaultValue = Date.now()
  548. defaultValue = this.compareValueWithStartAndEnd(
  549. defaultValue,
  550. this.start,
  551. this.end
  552. )
  553. }
  554. this.parseValue(defaultValue)
  555. },
  556. /**
  557. * 初始值规则:
  558. * - 用户设置初始值 value
  559. * - 设置了起始时间 start、终止时间 end,并 start < value < end,初始值为 value, 否则初始值为 start
  560. * - 只设置了起始时间 start,并 start < value,初始值为 value,否则初始值为 start
  561. * - 只设置了终止时间 end,并 value < end,初始值为 value,否则初始值为 end
  562. * - 无起始终止时间,则初始值为 value
  563. * - 无初始值 value,则初始值为当前本地时间 Date.now()
  564. * @param {Object} value
  565. * @param {Object} dateBase
  566. */
  567. compareValueWithStartAndEnd (value, start, end) {
  568. let winner = null
  569. value = this.superTimeStamp(value)
  570. start = this.superTimeStamp(start)
  571. end = this.superTimeStamp(end)
  572. if (start && end) {
  573. if (value < start) {
  574. winner = new Date(start)
  575. } else if (value > end) {
  576. winner = new Date(end)
  577. } else {
  578. winner = new Date(value)
  579. }
  580. } else if (start && !end) {
  581. winner = start <= value ? new Date(value) : new Date(start)
  582. } else if (!start && end) {
  583. winner = value <= end ? new Date(value) : new Date(end)
  584. } else {
  585. winner = new Date(value)
  586. }
  587. return winner
  588. },
  589. /**
  590. * 转换为可比较的时间戳,接受日期、时分秒、时间戳
  591. * @param {Object} value
  592. */
  593. superTimeStamp (value) {
  594. let dateBase = ''
  595. if (this.type === 'time' && value && typeof value === 'string') {
  596. const now = new Date()
  597. const year = now.getFullYear()
  598. const month = now.getMonth() + 1
  599. const day = now.getDate()
  600. dateBase = year + '/' + month + '/' + day + ' '
  601. }
  602. if (Number(value) && typeof value !== NaN) {
  603. value = parseInt(value)
  604. dateBase = 0
  605. }
  606. return this.createTimeStamp(dateBase + value)
  607. },
  608. /**
  609. * 解析默认值 value,字符串、时间戳
  610. * @param {Object} defaultTime
  611. */
  612. parseValue (value) {
  613. if (!value) {
  614. return
  615. }
  616. if (this.type === 'time' && typeof value === 'string') {
  617. this.parseTimeType(value)
  618. } else {
  619. let defaultDate = null
  620. defaultDate = new Date(value)
  621. if (this.type !== 'time') {
  622. this.year = defaultDate.getFullYear()
  623. this.month = defaultDate.getMonth() + 1
  624. this.day = defaultDate.getDate()
  625. }
  626. if (this.type !== 'date') {
  627. this.hour = defaultDate.getHours()
  628. this.minute = defaultDate.getMinutes()
  629. this.second = defaultDate.getSeconds()
  630. }
  631. }
  632. if (this.hideSecond) {
  633. this.second = 0
  634. }
  635. },
  636. /**
  637. * 解析可选择时间范围 start、end,年月日字符串、时间戳
  638. * @param {Object} defaultTime
  639. */
  640. parseDatetimeRange (point, pointType) {
  641. // 时间为空,则重置为初始值
  642. if (!point) {
  643. if (pointType === 'start') {
  644. this.startYear = 1920
  645. this.startMonth = 1
  646. this.startDay = 1
  647. this.startHour = 0
  648. this.startMinute = 0
  649. this.startSecond = 0
  650. }
  651. if (pointType === 'end') {
  652. this.endYear = 2120
  653. this.endMonth = 12
  654. this.endDay = 31
  655. this.endHour = 23
  656. this.endMinute = 59
  657. this.endSecond = 59
  658. }
  659. return
  660. }
  661. if (this.type === 'time') {
  662. const pointArr = point.split(':')
  663. this[pointType + 'Hour'] = Number(pointArr[0])
  664. this[pointType + 'Minute'] = Number(pointArr[1])
  665. this[pointType + 'Second'] = Number(pointArr[2])
  666. } else {
  667. if (!point) {
  668. pointType === 'start'
  669. ? (this.startYear = this.year - 60)
  670. : (this.endYear = this.year + 60)
  671. return
  672. }
  673. if (Number(point) && Number(point) !== NaN) {
  674. point = parseInt(point)
  675. }
  676. // datetime 的 end 没有时分秒, 则不限制
  677. const hasTime = /[0-9]:[0-9]/
  678. if (
  679. this.type === 'datetime' &&
  680. pointType === 'end' &&
  681. typeof point === 'string' &&
  682. !hasTime.test(point)
  683. ) {
  684. point = point + ' 23:59:59'
  685. }
  686. const pointDate = new Date(point)
  687. this[pointType + 'Year'] = pointDate.getFullYear()
  688. this[pointType + 'Month'] = pointDate.getMonth() + 1
  689. this[pointType + 'Day'] = pointDate.getDate()
  690. if (this.type === 'datetime') {
  691. this[pointType + 'Hour'] = pointDate.getHours()
  692. this[pointType + 'Minute'] = pointDate.getMinutes()
  693. this[pointType + 'Second'] = pointDate.getSeconds()
  694. }
  695. }
  696. },
  697. // 获取 年、月、日、时、分、秒 当前可选范围
  698. getCurrentRange (value) {
  699. const range = []
  700. for (
  701. let i = this['min' + this.capitalize(value)];
  702. i <= this['max' + this.capitalize(value)];
  703. i++
  704. ) {
  705. range.push(i)
  706. }
  707. return range
  708. },
  709. // 字符串首字母大写
  710. capitalize (str) {
  711. return str.charAt(0).toUpperCase() + str.slice(1)
  712. },
  713. // 检查当前值是否在范围内,不在则当前值重置为可选范围第一项
  714. checkValue (name, value, values) {
  715. if (values.indexOf(value) === -1) {
  716. this[name] = values[0]
  717. }
  718. },
  719. // 每个月的实际天数
  720. daysInMonth (year, month) {
  721. // Use 1 for January, 2 for February, etc.
  722. return new Date(year, month, 0).getDate()
  723. },
  724. //兼容 iOS、safari 日期格式
  725. fixIosDateFormat (value) {
  726. if (typeof value === 'string') {
  727. value = value.replace(/-/g, '/')
  728. }
  729. return value
  730. },
  731. /**
  732. * 生成时间戳
  733. * @param {Object} time
  734. */
  735. createTimeStamp (time) {
  736. if (!time) return
  737. if (typeof time === 'number') {
  738. return time
  739. } else {
  740. time = time.replace(/-/g, '/')
  741. if (this.type === 'date') {
  742. time = time + ' ' + '00:00:00'
  743. }
  744. return Date.parse(time)
  745. }
  746. },
  747. /**
  748. * 生成日期或时间的字符串
  749. */
  750. createDomSting () {
  751. const yymmdd =
  752. this.year +
  753. '-' +
  754. this.lessThanTen(this.month) +
  755. '-' +
  756. this.lessThanTen(this.day)
  757. let hhmmss =
  758. this.lessThanTen(this.hour) + ':' + this.lessThanTen(this.minute)
  759. if (!this.hideSecond) {
  760. hhmmss = hhmmss + ':' + this.lessThanTen(this.second)
  761. }
  762. if (this.type === 'date') {
  763. return yymmdd
  764. } else if (this.type === 'time') {
  765. return hhmmss
  766. } else {
  767. return yymmdd + ' ' + hhmmss
  768. }
  769. },
  770. /**
  771. * 初始化返回值,并抛出 change 事件
  772. */
  773. initTime (emit = true) {
  774. this.time = this.createDomSting()
  775. if (!emit) return
  776. if (this.returnType === 'timestamp' && this.type !== 'time') {
  777. this.$emit('change', this.createTimeStamp(this.time))
  778. this.$emit('input', this.createTimeStamp(this.time))
  779. this.$emit('update:modelValue', this.createTimeStamp(this.time))
  780. } else {
  781. this.$emit('change', this.time)
  782. this.$emit('input', this.time)
  783. this.$emit('update:modelValue', this.time)
  784. }
  785. },
  786. /**
  787. * 用户选择日期或时间更新 data
  788. * @param {Object} e
  789. */
  790. bindDateChange (e) {
  791. const val = e.detail.value
  792. this.year = this.years[val[0]]
  793. this.month = this.months[val[1]]
  794. this.day = this.days[val[2]]
  795. },
  796. bindTimeChange (e) {
  797. const val = e.detail.value
  798. this.hour = this.hours[val[0]]
  799. this.minute = this.minutes[val[1]]
  800. this.second = this.seconds[val[2]]
  801. },
  802. /**
  803. * 初始化弹出层
  804. */
  805. initTimePicker () {
  806. if (this.disabled) return
  807. const value = this.fixIosDateFormat(this.value)
  808. this.initPickerValue(value)
  809. this.visible = !this.visible
  810. },
  811. /**
  812. * 触发或关闭弹框
  813. */
  814. tiggerTimePicker (e) {
  815. this.visible = !this.visible
  816. },
  817. /**
  818. * 用户点击“清空”按钮,清空当前值
  819. */
  820. clearTime () {
  821. this.time = ''
  822. this.$emit('change', this.time)
  823. this.$emit('input', this.time)
  824. this.$emit('update:modelValue', this.time)
  825. this.tiggerTimePicker()
  826. },
  827. /**
  828. * 用户点击“确定”按钮
  829. */
  830. setTime () {
  831. this.initTime()
  832. this.tiggerTimePicker()
  833. }
  834. }
  835. }
  836. </script>
  837. <style>
  838. .uni-datetime-picker {
  839. /* #ifndef APP-NVUE */
  840. /* width: 100%; */
  841. /* #endif */
  842. }
  843. .uni-datetime-picker-view {
  844. height: 130px;
  845. width: 270px;
  846. /* #ifndef APP-NVUE */
  847. cursor: pointer;
  848. /* #endif */
  849. }
  850. .uni-datetime-picker-item {
  851. height: 50px;
  852. line-height: 50px;
  853. text-align: center;
  854. font-size: 32rpx;
  855. }
  856. .uni-datetime-picker-btn {
  857. margin-top: 60px;
  858. /* #ifndef APP-NVUE */
  859. display: flex;
  860. cursor: pointer;
  861. /* #endif */
  862. flex-direction: row;
  863. justify-content: space-between;
  864. }
  865. .uni-datetime-picker-btn-text {
  866. font-size: 32rpx;
  867. color: #007aff;
  868. }
  869. .uni-datetime-picker-btn-group {
  870. /* #ifndef APP-NVUE */
  871. display: flex;
  872. /* #endif */
  873. flex-direction: row;
  874. }
  875. .uni-datetime-picker-cancel {
  876. margin-right: 30px;
  877. }
  878. .uni-datetime-picker-mask {
  879. position: fixed;
  880. bottom: 0px;
  881. top: 0px;
  882. left: 0px;
  883. right: 0px;
  884. background-color: rgba(0, 0, 0, 0.4);
  885. transition-duration: 0.3s;
  886. z-index: 998;
  887. }
  888. .uni-datetime-picker-popup {
  889. border-radius: 8px;
  890. padding: 30px;
  891. width: 270px;
  892. /* #ifdef APP-NVUE */
  893. height: 500px;
  894. /* #endif */
  895. /* #ifdef APP-NVUE */
  896. width: 330px;
  897. /* #endif */
  898. background-color: #fff;
  899. position: fixed;
  900. top: 50%;
  901. left: 50%;
  902. transform: translate(-50%, -50%);
  903. transition-duration: 0.3s;
  904. z-index: 999;
  905. }
  906. .fix-nvue-height {
  907. /* #ifdef APP-NVUE */
  908. height: 330px;
  909. /* #endif */
  910. }
  911. .uni-datetime-picker-time {
  912. color: grey;
  913. }
  914. .uni-datetime-picker-column {
  915. height: 50px;
  916. }
  917. .uni-datetime-picker-timebox {
  918. border: 1px solid #e5e5e5;
  919. border-radius: 5px;
  920. padding: 7px 10px;
  921. /* #ifndef APP-NVUE */
  922. box-sizing: border-box;
  923. cursor: pointer;
  924. /* #endif */
  925. }
  926. .uni-datetime-picker-timebox-pointer {
  927. /* #ifndef APP-NVUE */
  928. cursor: pointer;
  929. /* #endif */
  930. }
  931. .uni-datetime-picker-disabled {
  932. opacity: 0.4;
  933. /* #ifdef H5 */
  934. cursor: not-allowed !important;
  935. /* #endif */
  936. }
  937. .uni-datetime-picker-text {
  938. font-size: 32rpx;
  939. }
  940. .uni-datetime-picker-sign {
  941. position: absolute;
  942. top: 53px;
  943. /* 减掉 10px 的元素高度,兼容nvue */
  944. color: #999;
  945. /* #ifdef APP-NVUE */
  946. font-size: 16px;
  947. /* #endif */
  948. }
  949. .sign-left {
  950. left: 86px;
  951. }
  952. .sign-right {
  953. right: 86px;
  954. }
  955. .sign-center {
  956. left: 135px;
  957. }
  958. .uni-datetime-picker__container-box {
  959. position: relative;
  960. display: flex;
  961. align-items: center;
  962. justify-content: center;
  963. margin-top: 40px;
  964. }
  965. .time-hide-second {
  966. width: 180px;
  967. }
  968. </style>