u-count-down.vue 4.6 KB

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