7857c03f09512862be2f85ff4cf39804edb1af73bf77f3f1e22d52bfcde7c0140b5a44f9fdeff70ab25aa199048327a708409d5ae7a8cac1d85284a847c379 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. <template>
  2. <span>
  3. {{displayValue}}
  4. </span>
  5. </template>
  6. <script>
  7. import { requestAnimationFrame, cancelAnimationFrame } from './requestAnimationFrame.js'
  8. export default {
  9. props: {
  10. startVal: {
  11. type: Number,
  12. required: false,
  13. default: 0
  14. },
  15. endVal: {
  16. type: Number,
  17. required: false,
  18. default: 2017
  19. },
  20. duration: {
  21. type: Number,
  22. required: false,
  23. default: 3000
  24. },
  25. autoplay: {
  26. type: Boolean,
  27. required: false,
  28. default: true
  29. },
  30. decimals: {
  31. type: Number,
  32. required: false,
  33. default: 0,
  34. validator(value) {
  35. return value >= 0
  36. }
  37. },
  38. decimal: {
  39. type: String,
  40. required: false,
  41. default: '.'
  42. },
  43. separator: {
  44. type: String,
  45. required: false,
  46. default: ','
  47. },
  48. prefix: {
  49. type: String,
  50. required: false,
  51. default: ''
  52. },
  53. suffix: {
  54. type: String,
  55. required: false,
  56. default: ''
  57. },
  58. useEasing: {
  59. type: Boolean,
  60. required: false,
  61. default: true
  62. },
  63. easingFn: {
  64. type: Function,
  65. default(t, b, c, d) {
  66. return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
  67. }
  68. }
  69. },
  70. data() {
  71. return {
  72. localStartVal: this.startVal,
  73. displayValue: this.formatNumber(this.startVal),
  74. printVal: null,
  75. paused: false,
  76. localDuration: this.duration,
  77. startTime: null,
  78. timestamp: null,
  79. remaining: null,
  80. rAF: null
  81. };
  82. },
  83. computed: {
  84. countDown() {
  85. return this.startVal > this.endVal
  86. }
  87. },
  88. watch: {
  89. startVal() {
  90. if (this.autoplay) {
  91. this.start();
  92. }
  93. },
  94. endVal() {
  95. if (this.autoplay) {
  96. this.start();
  97. }
  98. }
  99. },
  100. mounted() {
  101. if (this.autoplay) {
  102. this.start();
  103. }
  104. this.$emit('mountedCallback')
  105. },
  106. methods: {
  107. start() {
  108. this.localStartVal = this.startVal;
  109. this.startTime = null;
  110. this.localDuration = this.duration;
  111. this.paused = false;
  112. this.rAF = requestAnimationFrame(this.count);
  113. },
  114. pauseResume() {
  115. if (this.paused) {
  116. this.resume();
  117. this.paused = false;
  118. } else {
  119. this.pause();
  120. this.paused = true;
  121. }
  122. },
  123. pause() {
  124. cancelAnimationFrame(this.rAF);
  125. },
  126. resume() {
  127. this.startTime = null;
  128. this.localDuration = +this.remaining;
  129. this.localStartVal = +this.printVal;
  130. requestAnimationFrame(this.count);
  131. },
  132. reset() {
  133. this.startTime = null;
  134. cancelAnimationFrame(this.rAF);
  135. this.displayValue = this.formatNumber(this.startVal);
  136. },
  137. count(timestamp) {
  138. if (!this.startTime) this.startTime = timestamp;
  139. this.timestamp = timestamp;
  140. const progress = timestamp - this.startTime;
  141. this.remaining = this.localDuration - progress;
  142. if (this.useEasing) {
  143. if (this.countDown) {
  144. this.printVal = this.localStartVal - this.easingFn(progress, 0, this.localStartVal - this.endVal, this.localDuration)
  145. } else {
  146. this.printVal = this.easingFn(progress, this.localStartVal, this.endVal - this.localStartVal, this.localDuration);
  147. }
  148. } else {
  149. if (this.countDown) {
  150. this.printVal = this.localStartVal - ((this.localStartVal - this.endVal) * (progress / this.localDuration));
  151. } else {
  152. this.printVal = this.localStartVal + (this.endVal - this.localStartVal) * (progress / this.localDuration);
  153. }
  154. }
  155. if (this.countDown) {
  156. this.printVal = this.printVal < this.endVal ? this.endVal : this.printVal;
  157. } else {
  158. this.printVal = this.printVal > this.endVal ? this.endVal : this.printVal;
  159. }
  160. this.displayValue = this.formatNumber(this.printVal)
  161. if (progress < this.localDuration) {
  162. this.rAF = requestAnimationFrame(this.count);
  163. } else {
  164. this.$emit('callback');
  165. }
  166. },
  167. isNumber(val) {
  168. return !isNaN(parseFloat(val))
  169. },
  170. formatNumber(num) {
  171. num = num.toFixed(this.decimals);
  172. num += '';
  173. const x = num.split('.');
  174. let x1 = x[0];
  175. const x2 = x.length > 1 ? this.decimal + x[1] : '';
  176. const rgx = /(\d+)(\d{3})/;
  177. if (this.separator && !this.isNumber(this.separator)) {
  178. while (rgx.test(x1)) {
  179. x1 = x1.replace(rgx, '$1' + this.separator + '$2');
  180. }
  181. }
  182. return this.prefix + x1 + x2 + this.suffix;
  183. }
  184. },
  185. destroyed() {
  186. cancelAnimationFrame(this.rAF)
  187. }
  188. };
  189. </script>