time-picker.vue 23 KB

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