推广小程序前端代码
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.

168 lines
4.7 KiB

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