xianniu-ui 0.8.58 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xianniu-ui",
3
- "version": "0.8.58",
3
+ "version": "0.9.0",
4
4
  "private": false,
5
5
  "main": "lib/xianniu-ui.umd.min.js",
6
6
  "scripts": {
@@ -0,0 +1,222 @@
1
+
2
+ const root = typeof window !== 'undefined' ? window : global
3
+
4
+ /* istanbul ignore file */
5
+ const Animate = (global => {
6
+ /* istanbul ignore next */
7
+ const time =
8
+ Date.now ||
9
+ (() => {
10
+ return +new Date()
11
+ })
12
+ const desiredFrames = 60
13
+ const millisecondsPerSecond = 1000
14
+
15
+ let running = {}
16
+ let counter = 1
17
+
18
+ return {
19
+ /**
20
+ * A requestAnimationFrame wrapper / polyfill.
21
+ *
22
+ * @param callback {Function} The callback to be invoked before the next repaint.
23
+ * @param root {HTMLElement} The root element for the repaint
24
+ */
25
+ requestAnimationFrame: (() => {
26
+ // Check for request animation Frame support
27
+ const requestFrame =
28
+ global.requestAnimationFrame ||
29
+ global.webkitRequestAnimationFrame ||
30
+ global.mozRequestAnimationFrame ||
31
+ global.oRequestAnimationFrame
32
+ let isNative = !!requestFrame
33
+
34
+ if (requestFrame && !/requestAnimationFrame\(\)\s*\{\s*\[native code\]\s*\}/i.test(requestFrame.toString())) {
35
+ isNative = false
36
+ }
37
+
38
+ if (isNative) {
39
+ return (callback, root) => {
40
+ requestFrame(callback, root)
41
+ }
42
+ }
43
+
44
+ const TARGET_FPS = 60
45
+ let requests = {}
46
+ // eslint-disable-next-line no-unused-vars
47
+ let requestCount = 0
48
+ let rafHandle = 1
49
+ let intervalHandle = null
50
+ let lastActive = +new Date()
51
+
52
+ return callback => {
53
+ const callbackHandle = rafHandle++
54
+
55
+ // Store callback
56
+ requests[callbackHandle] = callback
57
+ requestCount++
58
+
59
+ // Create timeout at first request
60
+ if (intervalHandle === null) {
61
+ intervalHandle = setInterval(() => {
62
+ const time = +new Date()
63
+ const currentRequests = requests
64
+
65
+ // Reset data structure before executing callbacks
66
+ requests = {}
67
+ requestCount = 0
68
+
69
+ for (const key in currentRequests) {
70
+ if (Object.prototype.hasOwnProperty.call(currentRequests, key)) {
71
+ currentRequests[key](time)
72
+ lastActive = time
73
+ }
74
+ }
75
+
76
+ // Disable the timeout when nothing happens for a certain
77
+ // period of time
78
+ if (time - lastActive > 2500) {
79
+ clearInterval(intervalHandle)
80
+ intervalHandle = null
81
+ }
82
+ }, 1000 / TARGET_FPS)
83
+ }
84
+
85
+ return callbackHandle
86
+ }
87
+ })(),
88
+
89
+ /**
90
+ * Stops the given animation.
91
+ *
92
+ * @param id {Integer} Unique animation ID
93
+ * @return {Boolean} Whether the animation was stopped (aka, was running before)
94
+ */
95
+ stop(id) {
96
+ const cleared = running[id] != null
97
+ cleared && (running[id] = null)
98
+ return cleared
99
+ },
100
+
101
+ /**
102
+ * Whether the given animation is still running.
103
+ *
104
+ * @param id {Integer} Unique animation ID
105
+ * @return {Boolean} Whether the animation is still running
106
+ */
107
+ isRunning(id) {
108
+ return running[id] != null
109
+ },
110
+
111
+ /**
112
+ * Start the animation.
113
+ *
114
+ * @param stepCallback {Function} Pointer to function which is executed on every step.
115
+ * Signature of the method should be `function(percent, now, virtual) { return continueWithAnimation; }`
116
+ * @param verifyCallback {Function} Executed before every animation step.
117
+ * Signature of the method should be `function() { return continueWithAnimation; }`
118
+ * @param completedCallback {Function}
119
+ * Signature of the method should be `function(droppedFrames, finishedAnimation) {}`
120
+ * @param duration {Integer} Milliseconds to run the animation
121
+ * @param easingMethod {Function} Pointer to easing function
122
+ * Signature of the method should be `function(percent) { return modifiedValue; }`
123
+ * @param root {Element ? document.body} Render root, when available. Used for internal
124
+ * usage of requestAnimationFrame.
125
+ * @return {Integer} Identifier of animation. Can be used to stop it any time.
126
+ */
127
+ start(stepCallback, verifyCallback, completedCallback, duration, easingMethod, root) {
128
+ const start = time()
129
+ let lastFrame = start
130
+ let percent = 0
131
+ let dropCounter = 0
132
+ const id = counter++
133
+
134
+ if (!root) {
135
+ root = document.body
136
+ }
137
+
138
+ // Compacting running db automatically every few new animations
139
+ if (id % 20 === 0) {
140
+ const newRunning = {}
141
+ for (const usedId in running) {
142
+ newRunning[usedId] = true
143
+ }
144
+ running = newRunning
145
+ }
146
+
147
+ // This is the internal step method which is called every few milliseconds
148
+ const step = virtual => {
149
+ // Normalize virtual value
150
+ const render = virtual !== true
151
+
152
+ // Get current time
153
+ const now = time()
154
+
155
+ // Verification is executed before next animation step
156
+ if (!running[id] || (verifyCallback && !verifyCallback(id))) {
157
+ running[id] = null
158
+ completedCallback &&
159
+ completedCallback(desiredFrames - dropCounter / ((now - start) / millisecondsPerSecond), id, false)
160
+ return
161
+ }
162
+
163
+ // For the current rendering to apply let's update omitted steps in memory.
164
+ // This is important to bring internal state variables up-to-date with progress in time.
165
+ if (render) {
166
+ const droppedFrames = Math.round((now - lastFrame) / (millisecondsPerSecond / desiredFrames)) - 1
167
+ for (let j = 0; j < Math.min(droppedFrames, 4); j++) {
168
+ step(true)
169
+ dropCounter++
170
+ }
171
+ }
172
+
173
+ // Compute percent value
174
+ if (duration) {
175
+ percent = (now - start) / duration
176
+ if (percent > 1) {
177
+ percent = 1
178
+ }
179
+ }
180
+
181
+ // Execute step callback, then...
182
+ let value = easingMethod ? easingMethod(percent) : percent
183
+ value = isNaN(value) ? 0 : value
184
+ if ((stepCallback(value, now, render) === false || percent === 1) && render) {
185
+ running[id] = null
186
+ completedCallback &&
187
+ completedCallback(
188
+ desiredFrames - dropCounter / ((now - start) / millisecondsPerSecond),
189
+ id,
190
+ percent === 1 || duration == null,
191
+ )
192
+ } else if (render) {
193
+ lastFrame = now
194
+ this.requestAnimationFrame(step, root)
195
+ }
196
+ }
197
+
198
+ // Mark as running
199
+ running[id] = true
200
+
201
+ // Init first step
202
+ this.requestAnimationFrame(step, root)
203
+
204
+ // Return unique animation ID
205
+ return id
206
+ },
207
+ }
208
+ })(root)
209
+
210
+ export const easeOutCubic = pos => {
211
+ return Math.pow(pos - 1, 3) + 1
212
+ }
213
+
214
+ export const easeInOutCubic = pos => {
215
+ if ((pos /= 0.5) < 1) {
216
+ return 0.5 * Math.pow(pos, 3)
217
+ }
218
+
219
+ return 0.5 * (Math.pow(pos - 2, 3) + 2)
220
+ }
221
+
222
+ export default Animate
@@ -0,0 +1,79 @@
1
+ // 根据间隔规则格式化值
2
+ export function formatValueByGapRule(gapRule, value, gap = ' ', range, isAdd = 1) {
3
+ const arr = value ? value.split('') : [] // 将值转换为字符数组
4
+ let showValue = '' // 格式化后的值
5
+ const rule = [] // 间隔规则数组
6
+ gapRule.split('|').some((n, j) => {
7
+ rule[j] = +n + (rule[j - 1] ? +rule[j - 1] : 0) // 计算间隔位置
8
+ })
9
+ let j = 0
10
+ arr.some((n, i) => {
11
+ // 移除多余部分
12
+ if (i > rule[rule.length - 1] - 1) {
13
+ return
14
+ }
15
+ if (i > 0 && i === rule[j]) {
16
+ showValue = showValue + gap + n // 添加间隔符
17
+ j++
18
+ } else {
19
+ showValue = showValue + '' + n
20
+ }
21
+ })
22
+ let adapt = 0
23
+ rule.some((n, j) => {
24
+ if (range === +n + 1 + j) {
25
+ adapt = 1 * isAdd // 调整光标位置
26
+ }
27
+ })
28
+ range = typeof range !== 'undefined' ? (range === 0 ? 0 : range + adapt) : showValue.length
29
+ return { value: showValue, range: range } // 返回格式化后的值和光标位置
30
+ }
31
+
32
+ // 根据步长格式化值
33
+ export function formatValueByGapStep(step, value, gap = ' ', direction = 'right', range, isAdd = 1, oldValue = '') {
34
+ if (value.length === 0) {
35
+ return { value, range }
36
+ }
37
+
38
+ const arr = value && value.split('')
39
+ let _range = range
40
+ let showValue = ''
41
+
42
+ if (direction === 'right') {
43
+ for (let j = arr.length - 1, k = 0; j >= 0; j--, k++) {
44
+ const m = arr[j]
45
+ showValue = k > 0 && k % step === 0 ? m + gap + showValue : m + '' + showValue // 从右向左添加间隔符
46
+ }
47
+ if (isAdd === 1) {
48
+ // 在添加的情况下,如果添加前字符串的长度减去新的字符串的长度为2,说明多了一个间隔符,需要调整range
49
+ if (oldValue.length - showValue.length === -2) {
50
+ _range = range + 1
51
+ }
52
+ } else {
53
+ // 在删除情况下,如果删除前字符串的长度减去新的字符串的长度为2,说明少了一个间隔符,需要调整range
54
+ if (oldValue.length - showValue.length === 2) {
55
+ _range = range - 1
56
+ }
57
+ // 删除到最开始,range 保持 0
58
+ if (_range <= 0) {
59
+ _range = 0
60
+ }
61
+ }
62
+ } else {
63
+ arr.some((n, i) => {
64
+ showValue = i > 0 && i % step === 0 ? showValue + gap + n : showValue + '' + n // 从左向右添加间隔符
65
+ })
66
+ const adapt = range % (step + 1) === 0 ? 1 * isAdd : 0
67
+ _range = typeof range !== 'undefined' ? (range === 0 ? 0 : range + adapt) : showValue.length
68
+ }
69
+
70
+ return { value: showValue, range: _range } // 返回格式化后的值和光标位置
71
+ }
72
+
73
+ // 去除值中的间隔符
74
+ export function trimValue(value, gap = ' ') {
75
+ value = typeof value === 'undefined' ? '' : value
76
+ const reg = new RegExp(gap, 'g')
77
+ value = value.toString().replace(reg, '') // 去除所有间隔符
78
+ return value
79
+ }
@@ -0,0 +1,7 @@
1
+ import XnAmount from './main.vue'
2
+
3
+ XnAmount.install = function (Vue) {
4
+ Vue.component(XnAmount.name, XnAmount)
5
+ }
6
+
7
+ export default XnAmount
@@ -0,0 +1,164 @@
1
+ <template>
2
+ <span class="xn-amount" :class="{ numerical: !isCapital }">
3
+ <template v-if="!isCapital">
4
+ <i class="xn-amount-prefix" :style="prefixStyle">{{ prefix }}</i>{{ formatValue | doPrecision(legalPrecision, isRoundUp) | doFormat(hasSeparator, separator) }}
5
+ </template>
6
+ <template v-else>
7
+ {{ formatValue | doPrecision(4, isRoundUp) | doCapital }}
8
+ </template>
9
+ </span>
10
+ </template>
11
+
12
+ <script>
13
+ import { formatValueByGapStep } from "./formate-value.js";
14
+ import numberCapital from "./number-capital.js";
15
+ import { noop } from "./noop.js";
16
+ import Animate from "./animate.js";
17
+
18
+ export default {
19
+ name: "XnAmount",
20
+ inheritAttrs: false,
21
+ props: {
22
+ value: {
23
+ type: Number,
24
+ default: 0,
25
+ },
26
+ precision: {
27
+ type: Number,
28
+ default: 2,
29
+ },
30
+ isRoundUp: {
31
+ type: Boolean,
32
+ default: true,
33
+ },
34
+ hasSeparator: {
35
+ type: Boolean,
36
+ default: true,
37
+ },
38
+ separator: {
39
+ type: String,
40
+ default: ",",
41
+ },
42
+ isAnimated: {
43
+ type: Boolean,
44
+ default: false,
45
+ },
46
+ transition: {
47
+ type: Boolean,
48
+ default: false,
49
+ },
50
+ isCapital: {
51
+ type: Boolean,
52
+ default: false,
53
+ },
54
+ duration: {
55
+ type: Number,
56
+ default: 1000,
57
+ },
58
+ prefix: {
59
+ type: String,
60
+ default: "¥",
61
+ },
62
+ prefixStyle: {
63
+ type: Object,
64
+ default: () => ({}),
65
+ },
66
+ },
67
+ filters: {
68
+ doPrecision(value, precision, isRoundUp) {
69
+ const exponentialForm = Number(`${value}e${precision}`);
70
+ const rounded = isRoundUp
71
+ ? Math.round(exponentialForm)
72
+ : Math.floor(exponentialForm);
73
+ return Number(`${rounded}e-${precision}`).toFixed(precision);
74
+ },
75
+ doFormat(value, hasSeparator, separator) {
76
+ if (!hasSeparator) {
77
+ return value;
78
+ }
79
+
80
+ const numberParts = value.split(".");
81
+ let integerValue = numberParts[0];
82
+ const decimalValue = numberParts[1] || "";
83
+
84
+ let sign = "";
85
+ if (integerValue.startsWith("-")) {
86
+ integerValue = integerValue.substring(1);
87
+ sign = "-";
88
+ }
89
+
90
+ const formateValue = formatValueByGapStep(
91
+ 3,
92
+ integerValue,
93
+ separator,
94
+ "right",
95
+ 0,
96
+ 1
97
+ );
98
+ return decimalValue
99
+ ? `${sign}${formateValue.value}.${decimalValue}`
100
+ : `${sign}${formateValue.value}`;
101
+ },
102
+ doCapital(value) {
103
+ return numberCapital(value);
104
+ },
105
+ },
106
+ watch: {
107
+ value: {
108
+ handler(val, oldVal) {
109
+ /* istanbul ignore if */
110
+ if (!this.isMounted) {
111
+ this.formatValue = val;
112
+ return;
113
+ }
114
+ if (this.isAnimated || this.transition) {
115
+ this.$_doAnimateDisplay(oldVal, val);
116
+ } else {
117
+ this.formatValue = val;
118
+ }
119
+ },
120
+ immediate: true,
121
+ },
122
+ },
123
+ computed: {
124
+ legalPrecision() {
125
+ return this.precision > 0 ? this.precision : 0;
126
+ },
127
+ },
128
+ data() {
129
+ return {
130
+ formatValue: 0,
131
+ isMounted: false,
132
+ };
133
+ },
134
+ mounted() {
135
+ this.isMounted = true;
136
+ },
137
+ methods: {
138
+ // MARK: private methods
139
+ $_doAnimateDisplay(fromValue = 0, toValue = 0) {
140
+ /* istanbul ignore next */
141
+ const step = (percent) => {
142
+ if (percent === 1) {
143
+ this.formatValue = toValue;
144
+ return;
145
+ }
146
+ this.formatValue = fromValue + (toValue - fromValue) * percent;
147
+ };
148
+
149
+ /* istanbul ignore next */
150
+ const verify = (id) => id;
151
+ Animate.start(step, verify, noop, this.duration);
152
+ },
153
+ },
154
+ };
155
+ </script>
156
+
157
+ <style lang="scss" scoped>
158
+ .xn-amount{
159
+ &-prefix{
160
+ font-style: normal;
161
+ font-size: inherit;
162
+ }
163
+ }
164
+ </style>
@@ -0,0 +1 @@
1
+ export function noop() {}
@@ -0,0 +1,114 @@
1
+ // 中文数字
2
+ const cnNums = ['\u96f6', '\u58f9', '\u8d30', '\u53c1', '\u8086', '\u4f0d', '\u9646', '\u67d2', '\u634c', '\u7396']
3
+
4
+ // 整数部分的单位
5
+ const cnIntRadice = ['', '\u62fe', '\u4f70', '\u4edf']
6
+
7
+ // 整数部分的进位单位
8
+ const cnIntUnits = ['', '\u4e07', '\u4ebf', '兆']
9
+
10
+ // 小数部分的单位
11
+ const cnDecUnits = ['\u89d2', '\u5206', '\u5398', '\u6beb']
12
+
13
+ // 整数部分的结尾字符
14
+ const cnInteger = '\u6574' // 整
15
+
16
+ // 整数部分的货币单位
17
+ const cnIntLast = '\u5143' // 元
18
+
19
+ // 负数的符号
20
+ const cnNegative = '\u8d1f' // 负
21
+
22
+ // 最大处理的数字
23
+ const maxNum = 999999999999999.9999
24
+
25
+ // 将数字转换为中文大写金额的函数
26
+ export default function(number) {
27
+ let negative // 负数标志
28
+ let integerNum // 整数部分
29
+ let decimalNum // 小数部分
30
+ let capitalStr = '' // 中文大写金额字符串
31
+
32
+ let parts // 数字的整数和小数部分
33
+
34
+ /* istanbul ignore if */
35
+ if (number === '') {
36
+ return ''
37
+ }
38
+
39
+ number = parseFloat(number) // 将输入转换为浮点数
40
+
41
+ if (number < 0) {
42
+ negative = true // 如果是负数,设置负数标志
43
+ number = Math.abs(number) // 取绝对值
44
+ }
45
+
46
+ /* istanbul ignore if */
47
+ if (number >= maxNum) {
48
+ return ''
49
+ }
50
+
51
+ /* istanbul ignore if */
52
+ if (number === 0) {
53
+ capitalStr = cnNums[0] + cnIntLast + cnInteger // 如果数字为0,直接返回“零元整”
54
+ return capitalStr
55
+ }
56
+
57
+ // 将数字转换为字符串
58
+ number += ''
59
+
60
+ if (number.indexOf('.') === -1) {
61
+ integerNum = number // 如果没有小数点,整数部分为整个数字
62
+ decimalNum = '' // 小数部分为空
63
+ } else {
64
+ parts = number.split('.') // 分割整数和小数部分
65
+ integerNum = parts[0]
66
+ decimalNum = parts[1].substr(0, 4) // 取小数部分的前四位
67
+ }
68
+
69
+ // 转换整数部分
70
+ if (parseInt(integerNum, 10) > 0) {
71
+ let zeroCount = 0 // 连续零的计数器
72
+ for (let i = 0, IntLen = integerNum.length; i < IntLen; i++) {
73
+ const n = integerNum.substr(i, 1) // 当前位的数字
74
+ const p = IntLen - i - 1 // 当前位的权重
75
+ const q = p / 4 // 当前位的进位单位
76
+ const m = p % 4 // 当前位的单位
77
+ if (n === '0') {
78
+ zeroCount++ // 如果当前位是零,增加零计数器
79
+ } else {
80
+ if (zeroCount > 0) {
81
+ capitalStr += cnNums[0] // 如果有连续的零,添加一个零
82
+ }
83
+ zeroCount = 0 // 重置零计数器
84
+ capitalStr += cnNums[parseInt(n)] + cnIntRadice[m] // 添加当前位的中文数字和单位
85
+ }
86
+ if (m === 0 && zeroCount < 4) {
87
+ capitalStr += cnIntUnits[q] // 添加进位单位
88
+ }
89
+ }
90
+ capitalStr += cnIntLast // 添加货币单位
91
+ }
92
+
93
+ // 转换小数部分
94
+ if (decimalNum !== '') {
95
+ for (let i = 0, decLen = decimalNum.length; i < decLen; i++) {
96
+ const n = decimalNum.substr(i, 1) // 当前位的小数
97
+ if (n !== '0') {
98
+ capitalStr += cnNums[Number(n)] + cnDecUnits[i] // 添加当前位的小数的中文数字和单位
99
+ }
100
+ }
101
+ }
102
+
103
+ /* istanbul ignore if */
104
+ if (capitalStr === '') {
105
+ capitalStr += cnNums[0] + cnIntLast + cnInteger // 如果没有任何转换结果,返回“零元整”
106
+ } else if (decimalNum === '') {
107
+ capitalStr += cnInteger // 如果没有小数部分,添加“整”
108
+ }
109
+
110
+ if (negative) {
111
+ capitalStr = `${cnNegative}${capitalStr}` // 如果是负数,添加负号
112
+ }
113
+ return capitalStr // 返回中文大写金额字符串
114
+ }