From b76c76d1838b14bf0907048cd3e4739cac22f65c Mon Sep 17 00:00:00 2001 From: lcy0620 Date: Wed, 7 May 2025 19:12:36 +0800 Subject: [PATCH] feat(number-animation): Add NumberAnimation component (#3301) * feat(number-animation): [number-animation] Add NumberAnimation component * feat(number-animation): [number-animation] Add NumberAnimation component * feat(number-animation): [number-animation] Add NumberAnimation component * feat(number-animation): [number-animation] Add NumberAnimation component * feat(number-animation): [number-animation] Add NumberAnimation component * feat(number-animation): [number-animation] Add NumberAnimation component --- examples/sites/demos/apis/number-animation.js | 104 ++++++++++++++++++ .../basic-usage-composition-api.vue | 16 +++ .../app/number-animation/basic-usage.spec.ts | 8 ++ .../pc/app/number-animation/basic-usage.vue | 26 +++++ .../finish-events-composition-api.vue | 20 ++++ .../number-animation/finish-events.spec.ts | 11 ++ .../pc/app/number-animation/finish-events.vue | 29 +++++ .../precision-composition-api.vue | 16 +++ .../pc/app/number-animation/precision.spec.ts | 9 ++ .../pc/app/number-animation/precision.vue | 26 +++++ .../separator-composition-api.vue | 17 +++ .../pc/app/number-animation/separator.spec.ts | 9 ++ .../pc/app/number-animation/separator.vue | 26 +++++ .../webdoc/number-animation.cn.md | 7 ++ .../webdoc/number-animation.en.md | 7 ++ .../webdoc/number-animation.js | 55 +++++++++ examples/sites/demos/pc/menus.js | 3 +- packages/modules.json | 13 +++ .../renderless/src/number-animation/index.ts | 55 +++++++++ .../renderless/src/number-animation/vue.ts | 26 +++++ .../theme/src/number-animation/index.less | 11 ++ packages/theme/src/number-animation/vars.less | 8 ++ packages/theme/src/table/index.less | 2 +- packages/theme/src/table/vars.less | 4 +- packages/vue/package.json | 1 + .../__tests__/number-animation.test.tsx | 3 + packages/vue/src/number-animation/index.ts | 30 +++++ .../vue/src/number-animation/package.json | 26 +++++ .../vue/src/number-animation/src/index.ts | 46 ++++++++ packages/vue/src/number-animation/src/pc.vue | 29 +++++ 30 files changed, 640 insertions(+), 3 deletions(-) create mode 100644 examples/sites/demos/apis/number-animation.js create mode 100644 examples/sites/demos/pc/app/number-animation/basic-usage-composition-api.vue create mode 100644 examples/sites/demos/pc/app/number-animation/basic-usage.spec.ts create mode 100644 examples/sites/demos/pc/app/number-animation/basic-usage.vue create mode 100644 examples/sites/demos/pc/app/number-animation/finish-events-composition-api.vue create mode 100644 examples/sites/demos/pc/app/number-animation/finish-events.spec.ts create mode 100644 examples/sites/demos/pc/app/number-animation/finish-events.vue create mode 100644 examples/sites/demos/pc/app/number-animation/precision-composition-api.vue create mode 100644 examples/sites/demos/pc/app/number-animation/precision.spec.ts create mode 100644 examples/sites/demos/pc/app/number-animation/precision.vue create mode 100644 examples/sites/demos/pc/app/number-animation/separator-composition-api.vue create mode 100644 examples/sites/demos/pc/app/number-animation/separator.spec.ts create mode 100644 examples/sites/demos/pc/app/number-animation/separator.vue create mode 100644 examples/sites/demos/pc/app/number-animation/webdoc/number-animation.cn.md create mode 100644 examples/sites/demos/pc/app/number-animation/webdoc/number-animation.en.md create mode 100644 examples/sites/demos/pc/app/number-animation/webdoc/number-animation.js create mode 100644 packages/renderless/src/number-animation/index.ts create mode 100644 packages/renderless/src/number-animation/vue.ts create mode 100644 packages/theme/src/number-animation/index.less create mode 100644 packages/theme/src/number-animation/vars.less create mode 100644 packages/vue/src/number-animation/__tests__/number-animation.test.tsx create mode 100644 packages/vue/src/number-animation/index.ts create mode 100644 packages/vue/src/number-animation/package.json create mode 100644 packages/vue/src/number-animation/src/index.ts create mode 100644 packages/vue/src/number-animation/src/pc.vue diff --git a/examples/sites/demos/apis/number-animation.js b/examples/sites/demos/apis/number-animation.js new file mode 100644 index 000000000..11f9069b5 --- /dev/null +++ b/examples/sites/demos/apis/number-animation.js @@ -0,0 +1,104 @@ +export default { + mode: ['pc'], + apis: [ + { + name: 'number-animation', + type: 'component', + props: [ + { + name: 'active', + type: 'boolean', + defaultValue: 'true', + desc: { + 'zh-CN': '是否开始动画', + 'en-US': 'Whether or not start animation' + }, + mode: ['pc'], + pcDemo: 'basic-usage' + }, + { + name: 'duration', + type: 'number', + defaultValue: '3000', + desc: { + 'zh-CN': '动画持续时间', + 'en-US': 'Animation duration' + }, + mode: ['pc'], + pcDemo: 'basic-usage' + }, + { + name: 'from', + type: 'number', + defaultValue: '0', + desc: { + 'zh-CN': '数值动画起始值', + 'en-US': 'Starting value of numerical animation' + }, + mode: ['pc'], + pcDemo: 'basic-usage' + }, + { + name: 'to', + type: 'number', + defaultValue: '', + desc: { + 'zh-CN': '目标值', + 'en-US': 'Target value' + }, + mode: ['pc'], + pcDemo: 'basic-usage' + }, + { + name: 'precision', + type: 'number', + defaultValue: '0', + desc: { + 'zh-CN': '精度,保留小数点后几位', + 'en-US': 'Precision, rounded to a few decimal places.' + }, + mode: ['pc'], + pcDemo: 'precision' + }, + { + name: 'separator', + type: 'string', + defaultValue: ',', + desc: { + 'zh-CN': '千分位分隔符', + 'en-US': 'Thousandth separator' + }, + mode: ['pc'], + pcDemo: 'separator' + } + ], + events: [ + { + name: 'finish', + type: '() => void', + defaultValue: '', + desc: { + 'zh-CN': '动画结束后的回调', + 'en-US': 'The callback after the animation ends.' + }, + mode: ['pc'], + pcDemo: 'finish-events' + } + ], + methods: [ + { + name: 'play', + type: '() => void', + defaultValue: '', + desc: { + 'zh-CN': '播放动画', + 'en-US': 'Play Animation' + }, + mode: ['pc'], + pcDemo: 'finish-events' + } + ], + slots: [] + } + ] +} diff --git a/examples/sites/demos/pc/app/number-animation/basic-usage-composition-api.vue b/examples/sites/demos/pc/app/number-animation/basic-usage-composition-api.vue new file mode 100644 index 000000000..e9d7e4017 --- /dev/null +++ b/examples/sites/demos/pc/app/number-animation/basic-usage-composition-api.vue @@ -0,0 +1,16 @@ + + + diff --git a/examples/sites/demos/pc/app/number-animation/basic-usage.spec.ts b/examples/sites/demos/pc/app/number-animation/basic-usage.spec.ts new file mode 100644 index 000000000..22c4e62d0 --- /dev/null +++ b/examples/sites/demos/pc/app/number-animation/basic-usage.spec.ts @@ -0,0 +1,8 @@ +import { test, expect } from '@playwright/test' + +test('基本用法', async ({ page }) => { + page.on('pageerror', (exception) => expect(exception).toBeNull()) // 断言页面上不出现错误 + await page.goto('number-animation#basic-usage') // 要测试的示例的相对地址 + await page.waitForTimeout(1000) + await page.locator('#basic-usage').getByText('12,039') +}) diff --git a/examples/sites/demos/pc/app/number-animation/basic-usage.vue b/examples/sites/demos/pc/app/number-animation/basic-usage.vue new file mode 100644 index 000000000..825c70cef --- /dev/null +++ b/examples/sites/demos/pc/app/number-animation/basic-usage.vue @@ -0,0 +1,26 @@ + + + diff --git a/examples/sites/demos/pc/app/number-animation/finish-events-composition-api.vue b/examples/sites/demos/pc/app/number-animation/finish-events-composition-api.vue new file mode 100644 index 000000000..fb23e0b76 --- /dev/null +++ b/examples/sites/demos/pc/app/number-animation/finish-events-composition-api.vue @@ -0,0 +1,20 @@ + + + diff --git a/examples/sites/demos/pc/app/number-animation/finish-events.spec.ts b/examples/sites/demos/pc/app/number-animation/finish-events.spec.ts new file mode 100644 index 000000000..a3db6c2c9 --- /dev/null +++ b/examples/sites/demos/pc/app/number-animation/finish-events.spec.ts @@ -0,0 +1,11 @@ +import { test, expect } from '@playwright/test' + +test('动画播放完成', async ({ page }) => { + page.on('pageerror', (exception) => expect(exception).toBeNull()) + await page.goto('number-animation#finish-events') + await page.getByRole('button', { name: '播放' }).click() + await page.waitForTimeout(1000) + await page.locator('#finish-events').getByText('900') + const messageLocator = page.locator('.tiny-modal__box').filter({ hasText: '动画结束了' }) + await expect(messageLocator).toBeVisible() +}) diff --git a/examples/sites/demos/pc/app/number-animation/finish-events.vue b/examples/sites/demos/pc/app/number-animation/finish-events.vue new file mode 100644 index 000000000..9a9248be8 --- /dev/null +++ b/examples/sites/demos/pc/app/number-animation/finish-events.vue @@ -0,0 +1,29 @@ + + + diff --git a/examples/sites/demos/pc/app/number-animation/precision-composition-api.vue b/examples/sites/demos/pc/app/number-animation/precision-composition-api.vue new file mode 100644 index 000000000..cfbe7b77e --- /dev/null +++ b/examples/sites/demos/pc/app/number-animation/precision-composition-api.vue @@ -0,0 +1,16 @@ + + + diff --git a/examples/sites/demos/pc/app/number-animation/precision.spec.ts b/examples/sites/demos/pc/app/number-animation/precision.spec.ts new file mode 100644 index 000000000..a03de4470 --- /dev/null +++ b/examples/sites/demos/pc/app/number-animation/precision.spec.ts @@ -0,0 +1,9 @@ +import { test, expect } from '@playwright/test' + +test('精度', async ({ page }) => { + page.on('pageerror', (exception) => expect(exception).toBeNull()) // 断言页面上不出现错误 + await page.goto('number-animation#precision') // 要测试的示例的相对地址 + await page.getByRole('button', { name: /播放/ }).click() + await page.waitForTimeout(1000) + await page.locator('#precision').getByText('24.0000') +}) diff --git a/examples/sites/demos/pc/app/number-animation/precision.vue b/examples/sites/demos/pc/app/number-animation/precision.vue new file mode 100644 index 000000000..7c964fe52 --- /dev/null +++ b/examples/sites/demos/pc/app/number-animation/precision.vue @@ -0,0 +1,26 @@ + + + diff --git a/examples/sites/demos/pc/app/number-animation/separator-composition-api.vue b/examples/sites/demos/pc/app/number-animation/separator-composition-api.vue new file mode 100644 index 000000000..d83a189d7 --- /dev/null +++ b/examples/sites/demos/pc/app/number-animation/separator-composition-api.vue @@ -0,0 +1,17 @@ + + + diff --git a/examples/sites/demos/pc/app/number-animation/separator.spec.ts b/examples/sites/demos/pc/app/number-animation/separator.spec.ts new file mode 100644 index 000000000..b00b67df0 --- /dev/null +++ b/examples/sites/demos/pc/app/number-animation/separator.spec.ts @@ -0,0 +1,9 @@ +import { test, expect } from '@playwright/test' + +test('分隔符', async ({ page }) => { + page.on('pageerror', (exception) => expect(exception).toBeNull()) // 断言页面上不出现错误 + await page.goto('number-animation#separator') // 要测试的示例的相对地址 + await page.getByRole('button', { name: '播放', exact: true }).click() + await page.waitForTimeout(1000) + await page.locator('#separator').getByText('100,000,000') +}) diff --git a/examples/sites/demos/pc/app/number-animation/separator.vue b/examples/sites/demos/pc/app/number-animation/separator.vue new file mode 100644 index 000000000..26d7b273f --- /dev/null +++ b/examples/sites/demos/pc/app/number-animation/separator.vue @@ -0,0 +1,26 @@ + + + diff --git a/examples/sites/demos/pc/app/number-animation/webdoc/number-animation.cn.md b/examples/sites/demos/pc/app/number-animation/webdoc/number-animation.cn.md new file mode 100644 index 000000000..8b4573530 --- /dev/null +++ b/examples/sites/demos/pc/app/number-animation/webdoc/number-animation.cn.md @@ -0,0 +1,7 @@ +--- +title: +--- + +# Number Animation 数值动画 + +
数值播放动画
diff --git a/examples/sites/demos/pc/app/number-animation/webdoc/number-animation.en.md b/examples/sites/demos/pc/app/number-animation/webdoc/number-animation.en.md new file mode 100644 index 000000000..774609a8a --- /dev/null +++ b/examples/sites/demos/pc/app/number-animation/webdoc/number-animation.en.md @@ -0,0 +1,7 @@ +--- +title: +--- + +# Number Animation 数值动画 + +
Numerical playback animation
diff --git a/examples/sites/demos/pc/app/number-animation/webdoc/number-animation.js b/examples/sites/demos/pc/app/number-animation/webdoc/number-animation.js new file mode 100644 index 000000000..94e741c37 --- /dev/null +++ b/examples/sites/demos/pc/app/number-animation/webdoc/number-animation.js @@ -0,0 +1,55 @@ +export default { + column: '1', + owner: '', + demos: [ + { + demoId: 'basic-usage', + name: { + 'zh-CN': '基本用法', + 'en-US': 'Basic Usage' + }, + desc: { + 'zh-CN': '通过 from 设置数值动画起始值;to设置目标值。', + 'en-US': 'Set the starting value of numerical animation throughfrom, to设置目标值.' + }, + codeFiles: ['basic-usage.vue'] + }, + { + demoId: 'precision', + name: { + 'zh-CN': '精度', + 'en-US': 'Precision Mode' + }, + desc: { + 'zh-CN': '通过 precision 设置 设定精度。', + 'en-US': 'Set precision throughprecision.' + }, + codeFiles: ['precision.vue'] + }, + { + demoId: 'separator', + name: { + 'zh-CN': '分隔符', + 'en-US': 'Separator Mode' + }, + desc: { + 'zh-CN': '通过 separator 设置分隔符。', + 'en-US': 'Set delimiter throughseparator.' + }, + codeFiles: ['separator.vue'] + }, + + { + demoId: 'finish-events', + name: { + 'zh-CN': '动画结束事件', + 'en-US': 'Finish Event' + }, + desc: { + 'zh-CN': '通过 finish 自定义动画结束后的事件', + 'en-US': 'Customize the events after the animation ends throughfinish.' + }, + codeFiles: ['finish-events.vue'] + } + ] +} diff --git a/examples/sites/demos/pc/menus.js b/examples/sites/demos/pc/menus.js index 9e015c0ad..3b0158016 100644 --- a/examples/sites/demos/pc/menus.js +++ b/examples/sites/demos/pc/menus.js @@ -249,7 +249,8 @@ export const cmpMenus = [ } }, { 'nameCn': '用户头像', 'name': 'UserHead', 'key': 'user-head' }, - { 'nameCn': '流程图', 'name': 'Wizard', 'key': 'wizard' } + { 'nameCn': '流程图', 'name': 'Wizard', 'key': 'wizard' }, + { 'nameCn': '数值动画', 'name': 'NumberAnimation', key: 'number-animation' } ] }, { diff --git a/packages/modules.json b/packages/modules.json index 32e14e0e2..8077ac1b2 100644 --- a/packages/modules.json +++ b/packages/modules.json @@ -1708,6 +1708,19 @@ "type": "template", "exclude": false }, + "NumberAnimation": { + "path": "vue/src/number-animation/index.ts", + "type": "component", + "exclude": false, + "mode": [ + "pc" + ] + }, + "NumberAnimationPc": { + "path": "vue/src/number-animation/src/pc.vue", + "type": "template", + "exclude": false + }, "Option": { "path": "vue/src/option/index.ts", "type": "component", diff --git a/packages/renderless/src/number-animation/index.ts b/packages/renderless/src/number-animation/index.ts new file mode 100644 index 000000000..8f808ece3 --- /dev/null +++ b/packages/renderless/src/number-animation/index.ts @@ -0,0 +1,55 @@ +export const onFinish = + ({ emit, props, state }) => + () => { + state.value = props.to + state.animating = false + emit('finish') + } + +const easeOut = (t: number): number => 1 - (1 - t) ** 5 + +export const play = + ({ props, state, api }) => + () => { + animate(state, props, api) + } +export const animate = (state, props, api) => { + state.animating = true + state.value = props.from + if (props.from !== props.to) { + const startTime = performance.now() + + const tick = () => { + const current = performance.now() + const elapsedTime = Math.min(current - startTime, props.duration) + const currentValue = props.from + (props.to - props.from) * easeOut(elapsedTime / props.duration) + if (elapsedTime === props.duration) { + api.onFinish() + return + } + state.value = currentValue + requestAnimationFrame(tick) + } + tick() + } +} + +export const formattedValue = + ({ state, props }) => + () => { + // 类型检查 + if (typeof state.value !== 'number' && typeof state.value !== 'string') return + if (typeof props.precision !== 'number') return + const numValue = Number(state.value) + if (isNaN(numValue) || !isFinite(numValue)) return + if (numValue === 0) { + return numValue.toFixed(props.precision) + } + let formatValue = numValue.toFixed(props.precision) + if (typeof props.separator === 'string' && props.separator !== '') { + const [integerPart, decimalPart] = formatValue.split('.') + formatValue = + integerPart.replace(/(\d)(?=(\d{3})+$)/g, '$1' + props.separator) + (decimalPart ? '.' + decimalPart : '') + } + return formatValue + } diff --git a/packages/renderless/src/number-animation/vue.ts b/packages/renderless/src/number-animation/vue.ts new file mode 100644 index 000000000..9e0f990b9 --- /dev/null +++ b/packages/renderless/src/number-animation/vue.ts @@ -0,0 +1,26 @@ +import { play, formattedValue, onFinish } from './index' + +export const api = ['state', 'play', 'formattedValue', 'onFinish'] +export const renderless = (props, { onMounted, computed, reactive }, { emit }) => { + const api = {} + + const state = reactive({ + animating: true, + value: props.from, + showValue: computed(() => api.formattedValue(state, props)) + }) + + onMounted(() => { + if (props.active) { + api.play(props, state) + } + }) + Object.assign(api, { + state, + play: play({ props, state, api }), + formattedValue: formattedValue({ state, props }), + onFinish: onFinish({ emit, props, state }) + }) + + return api +} diff --git a/packages/theme/src/number-animation/index.less b/packages/theme/src/number-animation/index.less new file mode 100644 index 000000000..1ab06975c --- /dev/null +++ b/packages/theme/src/number-animation/index.less @@ -0,0 +1,11 @@ +@import '../custom.less'; +@import './vars.less'; + +@number-animation-item-prefix-cls: ~'@{css-prefix}number-animation'; + +.@{number-animation-item-prefix-cls} { + .inject-NumberAnimation-vars(); + font-size: var(--tv-NumberAnimation-font-size); + font-weight: var(--tv-NumberAnimation-font-weight); + margin-bottom: var(--tv-NumberAnimation-margin-bottom); +} diff --git a/packages/theme/src/number-animation/vars.less b/packages/theme/src/number-animation/vars.less new file mode 100644 index 000000000..8d459188f --- /dev/null +++ b/packages/theme/src/number-animation/vars.less @@ -0,0 +1,8 @@ +.inject-NumberAnimation-vars() { + // 数字内容下间距 + --tv-NumberAnimation-margin-bottom: 20px; + // 数字内容字体粗细 + --tv-NumberAnimation-font-weight: var(--tv-font-weight-regular); + // 数字内容字体 + --tv-NumberAnimation-font-size: var(--tv-font-size-heading-lg); + } \ No newline at end of file diff --git a/packages/theme/src/table/index.less b/packages/theme/src/table/index.less index bc97332f5..c6dd1d3e1 100644 --- a/packages/theme/src/table/index.less +++ b/packages/theme/src/table/index.less @@ -118,7 +118,7 @@ font-size: var(--tv-Table-icon-font-size); border-radius: var(--tv-Table-check-icon-border-radius); & path:last-child{ - fill: var(--tv-Table-border-color); + fill: var(--tv-Table-icon-border-color); } & path:first-child { diff --git a/packages/theme/src/table/vars.less b/packages/theme/src/table/vars.less index fd1c64693..866a291d5 100644 --- a/packages/theme/src/table/vars.less +++ b/packages/theme/src/table/vars.less @@ -28,7 +28,9 @@ // 表格单元格字体大小 --tv-Table-td-font-size: var(--tv-font-size-default, 14px); // 表格边框颜色 - --tv-Table-border-color: var(--tv-color-border-divider, #f0f0f0); + --tv-Table-border-color: var(--tv-color-border-divider); + // 表格复选框边框颜色 + --tv-Table-icon-border-color: var(--tv-color-border); // 表头背景颜色 --tv-Table-thead-bg-color: var(--tv-color-bg-header, #f5f5f5); // 表格图标字体大小 diff --git a/packages/vue/package.json b/packages/vue/package.json index 1f43158bc..f1f2f7577 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -137,6 +137,7 @@ "@opentiny/vue-month-table": "workspace:~", "@opentiny/vue-nav-menu": "workspace:~", "@opentiny/vue-notify": "workspace:~", + "@opentiny/vue-number-animation": "workspace:~", "@opentiny/vue-numeric": "workspace:~", "@opentiny/vue-option": "workspace:~", "@opentiny/vue-option-group": "workspace:~", diff --git a/packages/vue/src/number-animation/__tests__/number-animation.test.tsx b/packages/vue/src/number-animation/__tests__/number-animation.test.tsx new file mode 100644 index 000000000..b526946df --- /dev/null +++ b/packages/vue/src/number-animation/__tests__/number-animation.test.tsx @@ -0,0 +1,3 @@ +import { describe } from 'vitest' + +describe('PC Mode', () => {}) diff --git a/packages/vue/src/number-animation/index.ts b/packages/vue/src/number-animation/index.ts new file mode 100644 index 000000000..5a00936e7 --- /dev/null +++ b/packages/vue/src/number-animation/index.ts @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2022 - present TinyVue Authors. + * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd. + * + * Use of this source code is governed by an MIT-style license. + * + * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, + * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR + * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS. + * + */ +import NumberAnimation from './src/index' +import '@opentiny/vue-theme/number-animation/index.less' +import { version } from './package.json' + +/* istanbul ignore next */ +NumberAnimation.install = function (Vue) { + Vue.component(NumberAnimation.name, NumberAnimation) +} + +NumberAnimation.version = version + +/* istanbul ignore next */ +if (process.env.BUILD_TARGET === 'runtime') { + if (typeof window !== 'undefined' && window.Vue) { + NumberAnimation.install(window.Vue) + } +} + +export default NumberAnimation diff --git a/packages/vue/src/number-animation/package.json b/packages/vue/src/number-animation/package.json new file mode 100644 index 000000000..a32ed5b4c --- /dev/null +++ b/packages/vue/src/number-animation/package.json @@ -0,0 +1,26 @@ +{ + "name": "@opentiny/vue-number-animation", + "type": "module", + "version": "3.20.0", + "description": "", + "license": "MIT", + "sideEffects": false, + "main": "lib/index.js", + "module": "index.ts", + "scripts": { + "build": "pnpm -w build:ui $npm_package_name", + "//postversion": "pnpm build" + }, + "dependencies": { + "@opentiny/vue-button": "workspace:~", + "@opentiny/vue-common": "workspace:~", + "@opentiny/vue-modal": "workspace:~", + "@opentiny/vue-renderless": "workspace:~", + "@opentiny/vue-statistic": "workspace:~", + "@opentiny/vue-theme": "workspace:~" + }, + "devDependencies": { + "@opentiny-internal/vue-test-utils": "workspace:*", + "vitest": "catalog:" + } +} \ No newline at end of file diff --git a/packages/vue/src/number-animation/src/index.ts b/packages/vue/src/number-animation/src/index.ts new file mode 100644 index 000000000..eb1a20181 --- /dev/null +++ b/packages/vue/src/number-animation/src/index.ts @@ -0,0 +1,46 @@ +import { $props, $prefix, $setup, defineComponent } from '@opentiny/vue-common' +import template from 'virtual-template?pc' + +export const $constants = { + PREFIX: 'tiny-number-animation' +} + +export const numberAnimationProps = { + ...$props, + _constants: { + type: Object, + default: () => $constants + }, + to: { + type: Number, + default: 0 + }, + precision: { + type: Number, + default: 0 + }, + separator: { + type: String, + default: ',' + }, + from: { + type: Number, + default: 0 + }, + active: { + type: Boolean, + default: true + }, + duration: { + type: Number, + default: 2000 + } +} + +export default defineComponent({ + name: $prefix + 'NumberAnimation', + props: numberAnimationProps, + setup(props, context) { + return $setup({ props, context, template }) + } +}) diff --git a/packages/vue/src/number-animation/src/pc.vue b/packages/vue/src/number-animation/src/pc.vue new file mode 100644 index 000000000..79518877b --- /dev/null +++ b/packages/vue/src/number-animation/src/pc.vue @@ -0,0 +1,29 @@ + + + +