You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
4.4 KiB

8 months ago
  1. <template>
  2. <view class="u-count-down">
  3. <slot>
  4. <text class="u-count-down__text">{{ formattedTime }}</text>
  5. </slot>
  6. </view>
  7. </template>
  8. <script>
  9. import props from './props.js';
  10. import {
  11. isSameSecond,
  12. parseFormat,
  13. parseTimeData
  14. } from './utils';
  15. /**
  16. * u-count-down 倒计时
  17. * @description 该组件一般使用于某个活动的截止时间上通过数字的变化给用户明确的时间感受提示用户进行某一个行为操作
  18. * @tutorial https://uviewui.com/components/countDown.html
  19. * @property {String | Number} time 倒计时时长单位ms 默认 0
  20. * @property {String} format 时间格式DD-HH-mm-ss-SSS-毫秒 默认 'HH:mm:ss'
  21. * @property {Boolean} autoStart 是否自动开始倒计时 默认 true
  22. * @property {Boolean} millisecond 是否展示毫秒倒计时 默认 false
  23. * @event {Function} finish 倒计时结束时触发
  24. * @event {Function} change 倒计时变化时触发
  25. * @event {Function} start 开始倒计时
  26. * @event {Function} pause 暂停倒计时
  27. * @event {Function} reset 重设倒计时 auto-start true重设后会自动开始倒计时
  28. * @example <u-count-down :time="time"></u-count-down>
  29. */
  30. export default {
  31. name: 'u-count-down',
  32. mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
  33. data() {
  34. return {
  35. timer: null,
  36. // 各单位(天,时,分等)剩余时间
  37. timeData: parseTimeData(0),
  38. // 格式化后的时间,如"03:23:21"
  39. formattedTime: '0',
  40. // 倒计时是否正在进行中
  41. runing: false,
  42. endTime: 0, // 结束的毫秒时间戳
  43. remainTime: 0, // 剩余的毫秒时间
  44. }
  45. },
  46. watch: {
  47. time(n) {
  48. this.reset()
  49. }
  50. },
  51. mounted() {
  52. this.init()
  53. },
  54. methods: {
  55. init() {
  56. this.reset()
  57. },
  58. // 开始倒计时
  59. start() {
  60. if (this.runing) return
  61. // 标识为进行中
  62. this.runing = true
  63. // 结束时间戳 = 此刻时间戳 + 剩余的时间
  64. this.endTime = Date.now() + this.remainTime
  65. this.toTick()
  66. },
  67. // 根据是否展示毫秒,执行不同操作函数
  68. toTick() {
  69. if (this.millisecond) {
  70. this.microTick()
  71. } else {
  72. this.macroTick()
  73. }
  74. },
  75. macroTick() {
  76. this.clearTimeout()
  77. // 每隔一定时间,更新一遍定时器的值
  78. // 同时此定时器的作用也能带来毫秒级的更新
  79. this.timer = setTimeout(() => {
  80. // 获取剩余时间
  81. const remain = this.getRemainTime()
  82. // 重设剩余时间
  83. if (!isSameSecond(remain, this.remainTime) || remain === 0) {
  84. this.setRemainTime(remain)
  85. }
  86. // 如果剩余时间不为0,则继续检查更新倒计时
  87. if (this.remainTime !== 0) {
  88. this.macroTick()
  89. }
  90. }, 30)
  91. },
  92. microTick() {
  93. this.clearTimeout()
  94. this.timer = setTimeout(() => {
  95. this.setRemainTime(this.getRemainTime())
  96. if (this.remainTime !== 0) {
  97. this.microTick()
  98. }
  99. }, 50)
  100. },
  101. // 获取剩余的时间
  102. getRemainTime() {
  103. // 取最大值,防止出现小于0的剩余时间值
  104. return Math.max(this.endTime - Date.now(), 0)
  105. },
  106. // 设置剩余的时间
  107. setRemainTime(remain) {
  108. this.remainTime = remain
  109. // 根据剩余的毫秒时间,得出该有天,小时,分钟等的值,返回一个对象
  110. const timeData = parseTimeData(remain)
  111. this.$emit('change', timeData)
  112. // 得出格式化后的时间
  113. this.formattedTime = parseFormat(this.format, timeData)
  114. // 如果时间已到,停止倒计时
  115. if (remain <= 0) {
  116. this.pause()
  117. this.$emit('finish')
  118. }
  119. },
  120. // 重置倒计时
  121. reset() {
  122. this.pause()
  123. this.remainTime = this.time
  124. this.setRemainTime(this.remainTime)
  125. if (this.autoStart) {
  126. this.start()
  127. }
  128. },
  129. // 暂停倒计时
  130. pause() {
  131. this.runing = false;
  132. this.clearTimeout()
  133. },
  134. // 清空定时器
  135. clearTimeout() {
  136. clearTimeout(this.timer)
  137. this.timer = null
  138. }
  139. },
  140. beforeDestroy() {
  141. this.clearTimeout()
  142. }
  143. }
  144. </script>
  145. <style
  146. lang="scss"
  147. scoped
  148. >
  149. @import "../../libs/css/components.scss";
  150. $u-count-down-text-color:$u-content-color !default;
  151. $u-count-down-text-font-size:15px !default;
  152. $u-count-down-text-line-height:22px !default;
  153. .u-count-down {
  154. &__text {
  155. color: $u-count-down-text-color;
  156. font-size: $u-count-down-text-font-size;
  157. line-height: $u-count-down-text-line-height;
  158. }
  159. }
  160. </style>