SingleNumber.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import _extends from "@babel/runtime/helpers/esm/extends";
  2. import { createVNode as _createVNode } from "vue";
  3. import { computed, defineComponent, onUnmounted, reactive, ref, watch } from 'vue';
  4. import classNames from '../_util/classNames';
  5. function UnitNumber(_ref) {
  6. let {
  7. prefixCls,
  8. value,
  9. current,
  10. offset = 0
  11. } = _ref;
  12. let style;
  13. if (offset) {
  14. style = {
  15. position: 'absolute',
  16. top: `${offset}00%`,
  17. left: 0
  18. };
  19. }
  20. return _createVNode("p", {
  21. "style": style,
  22. "class": classNames(`${prefixCls}-only-unit`, {
  23. current
  24. })
  25. }, [value]);
  26. }
  27. function getOffset(start, end, unit) {
  28. let index = start;
  29. let offset = 0;
  30. while ((index + 10) % 10 !== end) {
  31. index += unit;
  32. offset += unit;
  33. }
  34. return offset;
  35. }
  36. export default defineComponent({
  37. compatConfig: {
  38. MODE: 3
  39. },
  40. name: 'SingleNumber',
  41. props: {
  42. prefixCls: String,
  43. value: String,
  44. count: Number
  45. },
  46. setup(props) {
  47. const originValue = computed(() => Number(props.value));
  48. const originCount = computed(() => Math.abs(props.count));
  49. const state = reactive({
  50. prevValue: originValue.value,
  51. prevCount: originCount.value
  52. });
  53. // ============================= Events =============================
  54. const onTransitionEnd = () => {
  55. state.prevValue = originValue.value;
  56. state.prevCount = originCount.value;
  57. };
  58. const timeout = ref();
  59. // Fallback if transition event not support
  60. watch(originValue, () => {
  61. clearTimeout(timeout.value);
  62. timeout.value = setTimeout(() => {
  63. onTransitionEnd();
  64. }, 1000);
  65. }, {
  66. flush: 'post'
  67. });
  68. onUnmounted(() => {
  69. clearTimeout(timeout.value);
  70. });
  71. return () => {
  72. let unitNodes;
  73. let offsetStyle = {};
  74. const value = originValue.value;
  75. if (state.prevValue === value || Number.isNaN(value) || Number.isNaN(state.prevValue)) {
  76. // Nothing to change
  77. unitNodes = [UnitNumber(_extends(_extends({}, props), {
  78. current: true
  79. }))];
  80. offsetStyle = {
  81. transition: 'none'
  82. };
  83. } else {
  84. unitNodes = [];
  85. // Fill basic number units
  86. const end = value + 10;
  87. const unitNumberList = [];
  88. for (let index = value; index <= end; index += 1) {
  89. unitNumberList.push(index);
  90. }
  91. // Fill with number unit nodes
  92. const prevIndex = unitNumberList.findIndex(n => n % 10 === state.prevValue);
  93. unitNodes = unitNumberList.map((n, index) => {
  94. const singleUnit = n % 10;
  95. return UnitNumber(_extends(_extends({}, props), {
  96. value: singleUnit,
  97. offset: index - prevIndex,
  98. current: index === prevIndex
  99. }));
  100. });
  101. // Calculate container offset value
  102. const unit = state.prevCount < originCount.value ? 1 : -1;
  103. offsetStyle = {
  104. transform: `translateY(${-getOffset(state.prevValue, value, unit)}00%)`
  105. };
  106. }
  107. return _createVNode("span", {
  108. "class": `${props.prefixCls}-only`,
  109. "style": offsetStyle,
  110. "onTransitionend": () => onTransitionEnd()
  111. }, [unitNodes]);
  112. };
  113. }
  114. });