index.vue 11.3 KB
<template>
  <span class="zui-amount" :class="{numerical: !isCapital}">
    <slot v-if="$slots.prefix" name="prefix"></slot>
    <template v-else-if="prefix">{{ prefix }}</template>
    <template v-if="!isCapital">{{ formatValue | doPrecision(legalPrecision, isRoundUp) | doFormat(hasSeparator, separator) }}</template>
    <template v-else> {{ formatValue | doPrecision(4, isRoundUp) | doCapital }} </template>
  </span>
</template>

<script>
var noop = function() {};
var inBrowser = true;
var root = window;
var easeOutCubic = function(pos) {
  return Math.pow(pos - 1, 3) + 1
}
var easeInOutCubic = function(pos) {
  if ((pos /= 0.5) < 1) {
    return 0.5 * Math.pow(pos, 3);
  }
  return 0.5 * (Math.pow(pos - 2, 3) + 2);
}
/* istanbul ignore file */
var Animate = (function(global) {
  /* istanbul ignore next */
  var time =
    Date.now ||
    (function() {
      return +new Date()
    })
  var desiredFrames = 60
  var millisecondsPerSecond = 1000

  var running = {}
  var counter = 1

  return {
    requestAnimationFrame: (function() {
      var requestFrame =
        global.requestAnimationFrame ||
        global.webkitRequestAnimationFrame ||
        global.mozRequestAnimationFrame ||
        global.oRequestAnimationFrame;
      var isNative = !!requestFrame;
      var regPass = /requestAnimationFrame\(\)\s*\{\s*\[native code\]\s*\}/i.test(requestFrame.toString());
      if (requestFrame && !regPass) {
        isNative = false;
      }
      if (isNative) {
        return function(callback, root) {
          requestFrame(callback, root);
        }
      }
      var TARGET_FPS = 60;
      var requests = {};
      var requestCount = 0;
      var rafHandle = 1;
      var intervalHandle = null;
      var lastActive = +new Date();
      return function(callback) {
        var callbackHandle = rafHandle++;
        requests[callbackHandle] = callback;
        requestCount++;
        if (intervalHandle == null) {
          intervalHandle = setInterval(function() {
            var time = +new Date();
            var currentRequests = requests;
            requests = {};
            requestCount = 0;
            for (var key in currentRequests) {
              if (currentRequests.hasOwnProperty(key)) {
                currentRequests[key](time);
                lastActive = time;
              }
            }
            if (time - lastActive > 2500) {
              clearInterval(intervalHandle);
              intervalHandle = null;
            }
          }, 1000 / TARGET_FPS);
        }
        return callbackHandle;
      }
    })(),
    stop: function(id) {
      var cleared = running[id] != null;
      cleared && (running[id] = null);
      return cleared;
    },
    isRunning: function(id) {
      return running[id] != null;
    },
    start: function(stepCallback, verifyCallback, completedCallback, duration, easingMethod, root) {
      var start = time();
      var lastFrame = start;
      var percent = 0;
      var dropCounter = 0;
      var id = counter++;
      if (!root) {
        root = document.body;
      }
      if (id % 20 == 0) {
        var newRunning = {};
        for (var usedId in running) {
          newRunning[usedId] = true;
        }
        running = newRunning;
      }
      var self = this;
      var step = function(virtual) {
        var render = virtual !== true;
        var now = time();
        if (!running[id] || (verifyCallback && !verifyCallback(id))) {
          running[id] = null;
          completedCallback &&
            completedCallback(desiredFrames - dropCounter / ((now - start) / millisecondsPerSecond), id, false);
          return;
        }
        if (render) {
          var droppedFrames = Math.round((now - lastFrame) / (millisecondsPerSecond / desiredFrames)) - 1;
          for (var j = 0; j < Math.min(droppedFrames, 4); j++) {
            step(true);
            dropCounter++;
          }
        }
        if (duration) {
          percent = (now - start) / duration;
          if (percent > 1) {
            percent = 1;
          }
        }
        var value = easingMethod ? easingMethod(percent) : percent;
        value = isNaN(value) ? 0 : value;
        if ((stepCallback(value, now, render) == false || percent == 1) && render) {
          running[id] = null;
          completedCallback &&
            completedCallback(
              desiredFrames - dropCounter / ((now - start) / millisecondsPerSecond),
              id,
              percent == 1 || duration == null,
            );
        } else if (render) {
          lastFrame = now;
          self.requestAnimationFrame(step, root);
        }
      }
      running[id] = true;
      this.requestAnimationFrame(step, root);
      return id;
    },
  }
})(root);
var formatValueByGapStep = function(step, value, gap = ' ', direction = 'right', range, isAdd = 1, oldValue = '') {
  if (value.length == 0) {
    return {value, range};
  }
  var arr = value && value.split('');
  var _range = range;
  var showValue = '';
  if (direction == 'right') {
    for (var j = arr.length - 1, k = 0; j >= 0; j--, k++) {
      var m = arr[j];
      showValue = k > 0 && k % step == 0 ? m + gap + showValue : m + '' + showValue;
    }
    if (isAdd == 1) {
      // 在添加的情况下,如果添加前字符串的长度减去新的字符串的长度为2,说明多了一个间隔符,需要调整range
      if (oldValue.length - showValue.length == -2) {
        _range = range + 1;
      }
    } else {
      // 在删除情况下,如果删除前字符串的长度减去新的字符串的长度为2,说明少了一个间隔符,需要调整range
      if (oldValue.length - showValue.length == 2) {
        _range = range - 1;
      }
      // 删除到最开始,range 保持 0
      if (_range <= 0) {
        _range = 0;
      }
    }
  } else {
    arr.some(function(n, i) {
      showValue = i > 0 && i % step == 0 ? showValue + gap + n : showValue + '' + n;
    })
    var adapt = range % (step + 1) == 0 ? 1 * isAdd : 0;
    _range = typeof range !== 'undefined' ? (range == 0 ? 0 : range + adapt) : showValue.length;
  }
  return {value: showValue, range: _range};
}
var numberCapital = function(number) {
  var cnNums = ['\u96f6', '\u58f9', '\u8d30', '\u53c1', '\u8086', '\u4f0d', '\u9646', '\u67d2', '\u634c', '\u7396'];
  // 拾 \u62fe 佰 \u4f70 仟 \u4edf
  var cnIntRadice = ['', '\u62fe', '\u4f70', '\u4edf'];
  // 万 \u4e07 亿 \u4ebf 兆 \u5146
  var cnIntUnits = ['', '\u4e07', '\u4ebf', '兆'];
  // 角 \u89d2 分 \u5206 毫 \u6beb 厘 \u5398
  var cnDecUnits = ['\u89d2', '\u5206', '\u6beb', '\u5398'];
  var cnInteger = '\u6574'; // 整 \u6574
  var cnIntLast = '\u5143'; // 元 \u5143
  var cnNegative = '\u8d1f'; // 负
  // Maximum number
  var maxNum = 999999999999999.9999;
  var negative;
  // Integral part
  var integerNum;
  // Decimal part
  var decimalNum;
  // Capital number
  var capitalStr = '';
  var parts;
  /* istanbul ignore if  */
  if (number == '') {
    return '';
  }
  number = parseFloat(number);
  if (number < 0) {
    negative = true;
    number = Math.abs(number);
  }
  /* istanbul ignore if  */
  if (number >= maxNum) {
    return '';
  }
  /* istanbul ignore if  */
  if (number == 0) {
    capitalStr = cnNums[0] + cnIntLast + cnInteger;
    return capitalStr;
  }
  // Convert to String
  number += '';
  if (number.indexOf('.') == -1) {
    integerNum = number;
    decimalNum = '';
  } else {
    parts = number.split('.');
    integerNum = parts[0];
    decimalNum = parts[1].substr(0, 4);
  }
  // Convert integer part
  if (parseInt(integerNum, 10) > 0) {
    var zeroCount = 0;
    for (var i = 0, IntLen = integerNum.length; i < IntLen; i++) {
      var n = integerNum.substr(i, 1);
      var p = IntLen - i - 1;
      var q = p / 4;
      var m = p % 4;
      if (n == '0') {
        zeroCount++;
      } else {
        if (zeroCount > 0) {
          capitalStr += cnNums[0];
        }
        zeroCount = 0;
        capitalStr += cnNums[parseInt(n)] + cnIntRadice[m];
      }
      if (m == 0 && zeroCount < 4) {
        capitalStr += cnIntUnits[q];
      }
    }
    capitalStr += cnIntLast;
  }
  // Convert decimal part
  if (decimalNum !== '') {
    for (var i = 0, decLen = decimalNum.length; i < decLen; i++) {
      var n = decimalNum.substr(i, 1);
      if (n !== '0') {
        capitalStr += cnNums[Number(n)] + cnDecUnits[i];
      }
    }
  }
  /* istanbul ignore if  */
  if (capitalStr == '') {
    capitalStr += cnNums[0] + cnIntLast + cnInteger;
  } else if (decimalNum == '') {
    capitalStr += cnInteger;
  }
  if (negative) {
    capitalStr = '' + cnNegative + capitalStr;
  }
  return capitalStr;
};
export default {
  name: 'Amount',
  filters: {
    doPrecision: function(value, precision, isRoundUp) {
      var exponentialForm = Number(value + 'e' + precision);
      var rounded = isRoundUp ? Math.round(exponentialForm) : Math.floor(exponentialForm);
      return Number(rounded + 'e-' + precision).toFixed(precision);
    },
    doFormat: function(value, hasSeparator, separator) {
      if (!hasSeparator) {
        return value;
      }
      var numberParts = value.split('.');
      var integerValue = numberParts[0];
      var decimalValue = numberParts[1] || '';
      var sign = '';
      if (integerValue.startsWith('-')) {
        integerValue = integerValue.substring(1);
        sign = '-';
      }
      var formateValue = formatValueByGapStep(3, integerValue, separator, 'right', 0, 1);
      return decimalValue ? '' + sign + formateValue.value + '.' + decimalValue : '' + sign + formateValue.value;
    },
    doCapital: function(value) {
      return numberCapital(value);
    },
  },
  props: {
    value: {
      type: Number,
      default: 0,
    },
    precision: {
      type: Number,
      default: 2,
    },
    isRoundUp: {
      type: Boolean,
      default: true,
    },
    hasSeparator: {
      type: Boolean,
      default: false,
    },
    separator: {
      type: String,
      default: ',',
    },
    isAnimated: {
      type: Boolean,
      default: false,
    },
    transition: {
      type: Boolean,
      default: false,
    },
    isCapital: {
      type: Boolean,
      default: false,
    },
    duration: {
      type: Number,
      default: 1000,
    },
    prefix: String,
  },
  data: function() {
    return {
      formatValue: 0,
      isMounted: false,
    }
  },
  watch: {
    value: {
      handler: function(val, oldVal) {
        /* istanbul ignore if  */
        if (!inBrowser && !this.isMounted) {
          this.formatValue = val;
          return;
        }
        if (this.isAnimated || this.transition) {
          this.$_doAnimateDisplay(oldVal, val);
        } else {
          this.formatValue = val;
        }
      },
      immediate: true,
    },
  },
  computed: {
    legalPrecision: function() {
      return this.precision > 0 ? this.precision : 0;
    },
  },
  mounted: function() {
    this.isMounted = true;
  },
  methods: {
    // MARK: private methods
    $_doAnimateDisplay: function(fromValue = 0, toValue = 0) {
      /* istanbul ignore next  */
      var self = this;
      var step = function(percent) {
        if (percent == 1) {
          self.formatValue = toValue;
          return;
        }
        self.formatValue = fromValue + (toValue - fromValue) * percent;
      }
      /* istanbul ignore next  */
      var verify = function(id) { return id };
      Animate.start(step, verify, noop, this.duration);
    },
  },
}
</script>

<style>
@import "./index.css";
</style>