countdown.vue 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <template>
  2. <span class="nut-cd-timer">
  3. <template v-if="showPlainText">
  4. <span class="nut-cd-block">{{plainText}}</span>
  5. </template>
  6. <template v-else>
  7. <template v-if="resttime.d >= 0 && showDays">
  8. <span class="nut-cd-block">{{resttime.d}}</span>
  9. <span class="nut-cd-dot">天</span>
  10. </template>
  11. <span class="nut-cd-block">{{resttime.h}}</span><span class="nut-cd-dot">:</span><span class="nut-cd-block">{{resttime.m}}</span><span class="nut-cd-dot">:</span><span class="nut-cd-block">{{resttime.s}}</span>
  12. </template>
  13. </span>
  14. </template>
  15. <script>
  16. function fill2(v) {
  17. v += '';
  18. while(v.length < 2) {
  19. v = '0' + v;
  20. }
  21. return v;
  22. }
  23. function restTime(t) {
  24. const ts = t;
  25. let rest = {
  26. d: '-',
  27. h: '--',
  28. m: '--',
  29. s: '--'
  30. };
  31. if(ts === 0) {
  32. rest = {
  33. d: '0',
  34. h: '00',
  35. m: '00',
  36. s: '00'
  37. };
  38. }
  39. if(ts) {
  40. const ds = 24 * 60 * 60 * 1000;
  41. const hs = 60 * 60 * 1000;
  42. const ms = 60 * 1000;
  43. const d = ts >= ds? parseInt(ts / ds): 0;
  44. const h = ts - d*ds >= hs? parseInt((ts - d*ds) / hs): 0;
  45. const m = ts - d*ds - h*hs >= ms? parseInt((ts - d*ds - h*hs) / ms): 0;
  46. const s = Math.round((ts - d*ds - h*hs - m*ms) / 1000);
  47. if(d >= 0) rest.d = d + '';
  48. if(h >= 0) rest.h = fill2(h);
  49. if(m >= 0) rest.m = fill2(m);
  50. if(s >= 0) rest.s = fill2(s);
  51. }
  52. return rest;
  53. };
  54. const countdownTimer = {
  55. name: 'nut-countdown',
  56. data() {
  57. return {
  58. restTime: 0,
  59. p: 0,
  60. _curr: 0
  61. }
  62. },
  63. props: {
  64. paused: {
  65. default: false,
  66. type: Boolean
  67. },
  68. showDays: {
  69. default: false,
  70. type: Boolean
  71. },
  72. showPlainText: {
  73. default: false,
  74. type: Boolean
  75. },
  76. startTime: {
  77. // 可以是服务器当前时间
  78. type: [Number, String],
  79. validator(v) {
  80. const dateStr = (new Date(v)).toString().toLowerCase();
  81. return dateStr !== 'invalid date';
  82. }
  83. },
  84. endTime: {
  85. type: [Number, String],
  86. validator(v) {
  87. const dateStr = (new Date(v)).toString().toLowerCase();
  88. return dateStr !== 'invalid date';
  89. }
  90. }
  91. },
  92. computed: {
  93. resttime() {
  94. const rest = restTime(this.restTime);
  95. const {d, h, m, s} = rest;
  96. if(!this.showDays && d > 0) {
  97. rest.h = fill2(Number(rest.h) + d * 24);
  98. rest.d = 0;
  99. }
  100. return rest;
  101. },
  102. plainText() {
  103. const {d, h, m, s} = this.resttime;
  104. return `${d > 0 && this.showDays? d + '天' + h: h}小时${m}分${s}秒`;
  105. }
  106. },
  107. watch: {
  108. paused(v, ov) {
  109. if(!ov) {
  110. this._curr = this.getTimeStamp();
  111. this.$emit('on-paused', this.restTime);
  112. }else{
  113. this.p += (this.getTimeStamp() - this._curr);
  114. this.$emit('on-restart', this.restTime);
  115. }
  116. },
  117. endTime() {
  118. this.initTimer();
  119. },
  120. startTime() {
  121. this.initTimer();
  122. }
  123. },
  124. methods: {
  125. getTimeStamp(timeStr) {
  126. if(!timeStr) return Date.now();
  127. let t = timeStr;
  128. t = t > 0? +t: t.toString().replace(/\-/g, '/');
  129. return new Date(t).getTime();
  130. },
  131. initTimer() {
  132. const delay = 1000;
  133. const curr = Date.now();
  134. const start = this.getTimeStamp(this.startTime || curr);
  135. const end = this.getTimeStamp(this.endTime || curr);
  136. const diffTime = curr - start;
  137. this.restTime = end - (start + diffTime);
  138. this.timer = setInterval(() => {
  139. if(!this.paused) {
  140. let restTime = end - (Date.now() - this.p + diffTime);
  141. this.restTime = restTime;
  142. if(restTime < delay) {
  143. this.restTime = 0;
  144. this.$emit('on-end');
  145. clearInterval(this.timer);
  146. }
  147. }else{
  148. // 暂停
  149. }
  150. }, delay);
  151. }
  152. },
  153. created() {
  154. this.initTimer();
  155. },
  156. destroyed() {
  157. this.timer && clearInterval(this.timer);
  158. }
  159. }
  160. countdownTimer.restTime = restTime;
  161. // export fill2 for test
  162. export {restTime, fill2};
  163. export default countdownTimer;
  164. </script>