tn-count-down.vue 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. <template>
  2. <view class="tn-countdown-class tn-countdown">
  3. <view
  4. v-if="showDays && (hideZeroDay || (!hideZeroDay && d != '00'))"
  5. class="tn-countdown__item"
  6. :class="[backgroundColorClass]"
  7. :style="[itemStyle]"
  8. >
  9. <view class="tn-countdown__item__time" :class="[fontColorClass]" :style="[letterStyle]">
  10. {{ d }}
  11. </view>
  12. </view>
  13. <view
  14. v-if="showHours && (hideZeroDay || (!hideZeroDay && d != '00'))"
  15. class="tn-countdown__separator"
  16. :style="{
  17. fontSize: separatorSize + 'rpx',
  18. color: separatorColor,
  19. paddingBottom: separator === 'en' ? '4rpx' : 0
  20. }"
  21. >
  22. {{ separator === 'en' ? ':' : '天'}}
  23. </view>
  24. <view
  25. v-if="showHours"
  26. class="tn-countdown__item"
  27. :class="[backgroundColorClass]"
  28. :style="[itemStyle]"
  29. >
  30. <view class="tn-countdown__item__time" :class="[fontColorClass]" :style="[letterStyle]">
  31. {{ h }}
  32. </view>
  33. </view>
  34. <view
  35. v-if="showMinutes"
  36. class="tn-countdown__separator"
  37. :style="{
  38. fontSize: separatorSize + 'rpx',
  39. color: separatorColor,
  40. paddingBottom: separator === 'en' ? '4rpx' : 0
  41. }"
  42. >
  43. {{ separator === 'en' ? ':' : '时'}}
  44. </view>
  45. <view
  46. v-if="showMinutes"
  47. class="tn-countdown__item"
  48. :class="[backgroundColorClass]"
  49. :style="[itemStyle]"
  50. >
  51. <view class="tn-countdown__item__time" :class="[fontColorClass]" :style="[letterStyle]">
  52. {{ m }}
  53. </view>
  54. </view>
  55. <view
  56. v-if="showSeconds"
  57. class="tn-countdown__separator"
  58. :style="{
  59. fontSize: separatorSize + 'rpx',
  60. color: separatorColor,
  61. paddingBottom: separator === 'en' ? '4rpx' : 0
  62. }"
  63. >
  64. {{ separator === 'en' ? ':' : '分'}}
  65. </view>
  66. <view
  67. v-if="showSeconds"
  68. class="tn-countdown__item"
  69. :class="[backgroundColorClass]"
  70. :style="[itemStyle]"
  71. >
  72. <view class="tn-countdown__item__time" :class="[fontColorClass]" :style="[letterStyle]">
  73. {{ s }}
  74. </view>
  75. </view>
  76. <view
  77. v-if="showSeconds && separator === 'cn'"
  78. class="tn-countdown__separator"
  79. :style="{
  80. fontSize: separatorSize + 'rpx',
  81. color: separatorColor,
  82. paddingBottom: separator === 'en' ? '4rpx' : 0
  83. }"
  84. >
  85. </view>
  86. </view>
  87. </template>
  88. <script>
  89. import componentsColorMixin from '../../libs/mixin/components_color.js'
  90. export default {
  91. name: 'tn-count-down',
  92. mixins: [componentsColorMixin],
  93. props: {
  94. // 倒计时时间,秒作为单位
  95. timestamp: {
  96. type: Number,
  97. default: 0
  98. },
  99. // 是否自动开始
  100. autoplay: {
  101. type: Boolean,
  102. default: true
  103. },
  104. // 数字框高度
  105. height: {
  106. type: [String, Number],
  107. default: 'auto'
  108. },
  109. // 分隔符类型
  110. // en -> 使用英文的冒号 cn -> 使用中文进行分割
  111. separator: {
  112. type: String,
  113. default: 'en'
  114. },
  115. // 分割符大小
  116. separatorSize: {
  117. type: Number,
  118. default: 30
  119. },
  120. // 分隔符颜色
  121. separatorColor: {
  122. type: String,
  123. default: '#080808'
  124. },
  125. // 是否显示边框
  126. showBorder: {
  127. type: Boolean,
  128. default: false
  129. },
  130. // 边框颜色
  131. borderColor: {
  132. type: String,
  133. default: '#080808'
  134. },
  135. // 是否显示秒
  136. showSeconds: {
  137. type: Boolean,
  138. default: true
  139. },
  140. // 是否显示分
  141. showMinutes: {
  142. type: Boolean,
  143. default: true
  144. },
  145. // 是否显示时
  146. showHours: {
  147. type: Boolean,
  148. default: true
  149. },
  150. // 是否显示天
  151. showDays: {
  152. type: Boolean,
  153. default: true
  154. },
  155. // 如果当天的部分为0时,是否隐藏不显示
  156. hideZeroDay: {
  157. type: Boolean,
  158. default: false
  159. }
  160. },
  161. computed: {
  162. // 倒计时item的样式
  163. itemStyle() {
  164. let style = {}
  165. if (this.height) {
  166. style.height = this.$t.string.getLengthUnitValue(this.height)
  167. style.width = style.height
  168. }
  169. if (this.showBorder) {
  170. style.borderStyle = 'solid'
  171. style.borderColor = this.borderColor
  172. style.borderWidth = '1rpx'
  173. }
  174. style.backgroundColor = this.backgroundColorStyle || '#FFFFFF'
  175. return style
  176. },
  177. // 倒计时数字样式
  178. letterStyle() {
  179. let style = {}
  180. style.fontSize = this.fontSizeStyle || '30rpx'
  181. style.color = this.fontColorStyle || '#080808'
  182. return style
  183. }
  184. },
  185. data() {
  186. return {
  187. d: '00',
  188. h: '00',
  189. m: '00',
  190. s: '00',
  191. // 定时器
  192. timer: null,
  193. // 记录倒计过程中变化的秒数
  194. seconds: 0
  195. }
  196. },
  197. watch: {
  198. // 监听时间戳变化
  199. timestamp(value) {
  200. this.clearTimer()
  201. this.start()
  202. }
  203. },
  204. mounted() {
  205. // 如果时自动倒计时,加载完成开始计时
  206. this.autoplay && this.timestamp && this.start()
  207. },
  208. beforeDestroy() {
  209. this.clearTimer()
  210. },
  211. methods: {
  212. // 开始倒计时
  213. start() {
  214. // 避免可能出现的倒计时重叠情况
  215. this.clearTimer()
  216. if (this.timestamp <= 0) return
  217. this.seconds = Number(this.timestamp)
  218. this.formatTime(this.seconds)
  219. this.timer = setInterval(() => {
  220. this.seconds--
  221. // 发出change事件
  222. this.$emit('change', this.seconds)
  223. if (this.seconds < 0) {
  224. return this.end()
  225. }
  226. this.formatTime(this.seconds)
  227. }, 1000)
  228. },
  229. // 格式化时间
  230. formatTime(seconds) {
  231. // 小于等于0的话,结束倒计时
  232. seconds <= 0 && this.end()
  233. let [day, hour, minute, second] = [0, 0, 0, 0]
  234. day = Math.floor(seconds / (60 * 60 * 24))
  235. // 如果不显示天,则将天对应的小时计入到小时中
  236. // 先把当前的hour计算出来供分和秒使用
  237. hour = Math.floor(seconds / (60 * 60)) - (day * 24)
  238. let showHour = null
  239. if (this.showDays) {
  240. showHour = hour
  241. } else {
  242. // 将天数对应的小时加入到时中进行显示
  243. showHour = Math.floor(seconds / (60 * 60))
  244. }
  245. minute = Math.floor(seconds / 60) - (hour * 60) - (day * 24 * 60)
  246. second = Math.floor(seconds) - (minute * 60) - (hour * 60 * 60) - (day * 24 * 60 * 60)
  247. // 如果小于0在前面进行补0操作
  248. showHour = this.$t.number.formatNumberAddZero(showHour)
  249. minute = this.$t.number.formatNumberAddZero(minute)
  250. second = this.$t.number.formatNumberAddZero(second)
  251. day = this.$t.number.formatNumberAddZero(day)
  252. this.d = day
  253. this.h = showHour
  254. this.m = minute
  255. this.s = second
  256. },
  257. // 倒计时结束
  258. end() {
  259. this.clearTimer()
  260. this.$emit('end')
  261. },
  262. // 清除倒计时
  263. clearTimer() {
  264. if (this.timer !== null) {
  265. clearInterval(this.timer)
  266. this.timer = null
  267. }
  268. }
  269. }
  270. }
  271. </script>
  272. <style lang="scss" scoped>
  273. .tn-countdown {
  274. /* #ifndef APP-NVUE */
  275. display: inline-flex;
  276. /* #endif */
  277. align-items: center;
  278. &__item {
  279. box-sizing: content-box;
  280. display: flex;
  281. flex-direction: row;
  282. align-items: center;
  283. justify-content: center;
  284. padding: 2rpx;
  285. border-radius: 6rpx;
  286. white-space: nowrap;
  287. transform: translateZ(0);
  288. &__time {
  289. margin: 0;
  290. padding: 0;
  291. line-height: 1;
  292. }
  293. }
  294. &__separator {
  295. display: flex;
  296. flex-direction: row;
  297. align-items: center;
  298. justify-content: center;
  299. padding: 0 5rpx;
  300. line-height: 1;
  301. }
  302. }
  303. </style>