├── .vscode
└── extensions.json
├── Vue3NumberScroll.gif
├── tsconfig.json
├── src
├── index.ts
├── requestAnimationFrame.js
└── Vue3NumberScroll.vue
├── .gitignore
├── tsconfig.node.json
├── index.html
├── package.json
├── tsconfig.app.json
├── vite.config.ts
├── .cz-config.js
├── public
└── vite.svg
└── README.md
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["Vue.volar"]
3 | }
4 |
--------------------------------------------------------------------------------
/Vue3NumberScroll.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LiCHUYA/vue3-number-scroll/HEAD/Vue3NumberScroll.gif
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": [],
3 | "references": [
4 | {
5 | "path": "./tsconfig.app.json"
6 | },
7 | {
8 | "path": "./tsconfig.node.json"
9 | }
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import { App } from 'vue';
2 | import Vue3NumberScroll from './Vue3NumberScroll.vue';
3 |
4 | const install: any = (app: App): void => {
5 | app.component('vue3-number-scroll', Vue3NumberScroll);
6 | app.component('Vue3NumberScroll', Vue3NumberScroll);
7 | };
8 |
9 | export default {install}
10 | export {
11 | Vue3NumberScroll
12 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
5 | "skipLibCheck": true,
6 | "module": "ESNext",
7 | "moduleResolution": "bundler",
8 | "allowSyntheticDefaultImports": true,
9 | "strict": true,
10 | "noEmit": true
11 | },
12 | "include": ["vite.config.ts"]
13 | }
14 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + Vue + TS
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue3-number-scroll",
3 | "version": "0.1.12",
4 | "type": "commonjs",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/LiCHUYA/vue3-scroll-number.git"
8 | },
9 | "main": "dist/vue3-number-scroll.js",
10 | "module": "dist/vue3-number-scroll.mjs",
11 | "types": "dist/index.d.ts",
12 | "scripts": {
13 | "dev": "vite",
14 | "build": "vue-tsc -b && vite build",
15 | "preview": "vite preview"
16 | },
17 | "dependencies": {
18 | "cz-customizable": "^6.3.0",
19 | "vue": "^3.4.29"
20 | },
21 | "devDependencies": {
22 | "@vitejs/plugin-vue": "^5.0.5",
23 | "typescript": "^5.2.2",
24 | "vite": "^5.3.3",
25 | "vite-plugin-dts": "^1.4.1",
26 | "vue-tsc": "^2.0.21"
27 | },
28 | "config": {
29 | "commitizen": {
30 | "path": "node_modules/cz-customizable"
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
5 | "target": "ES2020",
6 | "useDefineForClassFields": true,
7 | "module": "ESNext",
8 | "lib": ["ES2020", "DOM", "DOM.Iterable"],
9 | "skipLibCheck": true,
10 |
11 | "declaration": true,
12 | "declarationDir": "dist",
13 | "emitDeclarationOnly": true,
14 | "outDir": "dist",
15 | /* Bundler mode */
16 | "moduleResolution": "bundler",
17 | "allowImportingTsExtensions": true,
18 | "resolveJsonModule": true,
19 | "isolatedModules": true,
20 | "moduleDetection": "force",
21 | "jsx": "preserve",
22 |
23 | /* Linting */
24 | "strict": false,
25 | "noUnusedLocals": true,
26 | "noUnusedParameters": true,
27 | "noFallthroughCasesInSwitch": true
28 | },
29 | "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
30 | }
31 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import vue from '@vitejs/plugin-vue'
3 | import dts from "vite-plugin-dts";
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [vue(), dts({
7 | entryRoot: "./src",
8 | outputDir: ["dist"],
9 | //指定使用的tsconfig.json为我们整个项目根目录下,如果不配置,你也可以在components下新建tsconfig.json
10 | tsConfigFilePath: "./tsconfig.app.json",
11 | }),
12 | ],
13 | build: {
14 | //打包后文件目录
15 | outDir: "es",
16 | //压缩
17 | minify: false,
18 | rollupOptions: {
19 | //忽略打包vue文件
20 | external: ["vue"],
21 | //input: ["index.ts"],
22 | output: {
23 | globals: {
24 | vue: "Vue",
25 | },
26 | dir: "dist",
27 | },
28 | },
29 | lib: {
30 | entry: "./src/index.ts",
31 | name: "vue3-number-scroll",
32 | fileName: "vue3-number-scroll",
33 | formats: ["es", "umd", "cjs"],
34 | },
35 |
36 | },
37 | })
38 |
--------------------------------------------------------------------------------
/.cz-config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // 可选类型
3 | types: [
4 | { value: "feat", name: "feat: 新功能" },
5 | { value: "fix", name: "fix: 修复" },
6 | { value: "docs", name: "docs: 文档变更" },
7 | { value: "style", name: "style: 代码格式(不影响代码运行的变动)" },
8 | {
9 | value: "refactor",
10 | name: "refactor: 重构(既不是增加feature,也不是修复bug)"
11 | },
12 | { value: "merge", name: "merge: 合并分支" },
13 |
14 | { value: "perf", name: "perf: 性能优化" },
15 | { value: "test", name: "test: 增加测试" },
16 | { value: "chore", name: "chore: 构建过程或辅助工具的变动" },
17 | { value: "revert", name: "revert: 回退" },
18 | { value: "build", name: "build: 打包" }
19 | ],
20 | // 消息步骤
21 | messages: {
22 | type: "请选择提交类型:",
23 | customScope: "请输入修改范围(可选):",
24 | subject: "请简要描述提交(必填):",
25 | body: "请输入详细描述(可选):",
26 | footer: "请输入要关闭的issue(可选):",
27 | confirmCommit: "确认使用以上信息提交?(y/n/e/h)"
28 | },
29 | // 跳过问题
30 | skipQuestions: ["body", "footer"],
31 | // subject文字长度默认是72
32 | subjectLimit: 72
33 | }
34 |
--------------------------------------------------------------------------------
/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/requestAnimationFrame.js:
--------------------------------------------------------------------------------
1 | let lastTime = 0
2 | const prefixes = 'webkit moz ms o'.split(' ') // 各浏览器前缀
3 |
4 | let requestAnimationFrame
5 | let cancelAnimationFrame
6 |
7 | const isServer = typeof window === 'undefined'
8 | if (isServer) {
9 | requestAnimationFrame = function() {
10 | return
11 | }
12 | cancelAnimationFrame = function() {
13 | return
14 | }
15 | } else {
16 | requestAnimationFrame = window.requestAnimationFrame
17 | cancelAnimationFrame = window.cancelAnimationFrame
18 | let prefix
19 | // 通过遍历各浏览器前缀,来得到requestAnimationFrame和cancelAnimationFrame在当前浏览器的实现形式
20 | for (let i = 0; i < prefixes.length; i++) {
21 | if (requestAnimationFrame && cancelAnimationFrame) { break }
22 | prefix = prefixes[i]
23 | requestAnimationFrame = requestAnimationFrame || window[prefix + 'RequestAnimationFrame']
24 | cancelAnimationFrame = cancelAnimationFrame || window[prefix + 'CancelAnimationFrame'] || window[prefix + 'CancelRequestAnimationFrame']
25 | }
26 |
27 | // 如果当前浏览器不支持requestAnimationFrame和cancelAnimationFrame,则会退到setTimeout
28 | if (!requestAnimationFrame || !cancelAnimationFrame) {
29 | requestAnimationFrame = function(callback) {
30 | const currTime = new Date().getTime()
31 | // 为了使setTimteout的尽可能的接近每秒60帧的效果
32 | const timeToCall = Math.max(0, 16 - (currTime - lastTime))
33 | const id = window.setTimeout(() => {
34 | callback(currTime + timeToCall)
35 | }, timeToCall)
36 | lastTime = currTime + timeToCall
37 | return id
38 | }
39 |
40 | cancelAnimationFrame = function(id) {
41 | window.clearTimeout(id)
42 | }
43 | }
44 | }
45 |
46 | export { requestAnimationFrame, cancelAnimationFrame }
47 |
--------------------------------------------------------------------------------
/src/Vue3NumberScroll.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ displayValue }}
3 |
4 |
5 |
174 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## vue3-number-scroll使用指南
2 |
3 | **该组件用于创建具有动画效果的数字显示,可以配置起始值、结束值、动画持续时间等属性。**
4 | **它是基于 vue-count-to 升级改造,由于 [vue-count-to](https://panjiachen.github.io/countTo "原仓库地址") 不支持vue3,以及长时间没有更新的原因,我在项目中的大屏项目需要使用,所以顺便升级维护一下。**
5 |
6 | 
7 |
8 | **描述**
9 |
10 |
11 | | 新特性 | 支持 |
12 | | ------------------------------------------------------------------- | ------------------ |
13 | | 组件支持CamelCase和kebab-case命名方式引入(本文档采用大驼峰命名展示) | :white_check_mark: |
14 | | 重构为Vue3所支持的Composition Api | :white_check_mark: |
15 | | 良好的typescript支持 | :white_check_mark: |
16 | | 完善部分方法Api的语义化,新增一些新的属性 | :white_check_mark: |
17 |
18 | ### 开始使用
19 |
20 | ```js
21 | npm i vue3-number-scroll
22 | ```
23 |
24 | **局部引入**
25 |
26 | ```js
27 |
30 |
31 |
32 |
33 |
34 | ```
35 |
36 | **全局引入**
37 |
38 | ```js
39 | import { createApp } from 'vue'
40 | import App from './App.vue'
41 |
42 | import Vue3NumberScroll from 'vue3-number-scroll' //引入
43 |
44 | const app = createApp(App)
45 |
46 | app.use(Vue3NumberScroll) //全局注册
47 |
48 | app.mount('#app')
49 | ```
50 |
51 | ### 属性(Props)
52 |
53 |
54 | | **属性名** | **类型** | **默认值** | **说明** |
55 | | ----------------- | ------------ | ------------- | -------------------------------------------------------------------------------------------------------- |
56 | | `startVal` | **Number** | **0** | **动画的起始值** |
57 | | `endVal` | **Number** | **2000** | **动画的结束值** |
58 | | `duration` | **Number** | **3000** | **动画持续时间(毫秒)** |
59 | | `autoplay` | **Boolean** | **true** | **是否自动播放动画** |
60 | | `decimals` | **Number** | **0** | **小数位数,必须为非负整数** |
61 | | `decimal` | **String** | **'.'** | **小数点字符** |
62 | | `separator` | **String** | **','** | **千位分隔符** |
63 | | `prefix` | **String** | **''** | **数字前缀** |
64 | | `suffix` | **String** | **''** | **数字后缀** |
65 | | `useEasing` | **Boolean** | **true** | **是否使用缓动函数** |
66 | | `easingFn` | **Function** | **默认函数** | **缓动函数,默认使用一个缓动函数(公式:**`c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b`) |
67 | | `repeatAnimation` | **Number** | **undefined** | **重复动画的间隔时间(毫秒),如果未定义,则动画不会重复,传秒数,例如1000,代表1秒,动画则会在1秒执行一次** |
68 |
69 | **完整使用示例**
70 |
71 | ```js
72 |
73 |
75 | :end-val="10000"
76 | :duration="3000"
77 | :autoplay="true"
78 | :decimals="0"
79 | decimal="."
80 | separator=","
81 | prefix="¥"
82 | suffix=" 元"
83 | :useEasing="true"
84 | :easingFn="customEasingFn"
85 | :repeatAnimation="1000"
86 | @onFinish="handleFinish"
87 | @init="handleInit"
88 | />
89 |
90 | ```
91 |
92 | ### 事件(Events)
93 |
94 |
95 | | **事件名** | **参数** | **说明** |
96 | | ---------- | -------- | ------------------ |
97 | | `onFinish` | **-** | **动画完成时触发** |
98 | | `init` | - | **组件挂载时触发** |
99 |
100 | ### 方法(Methods)
101 |
102 | **组件暴露了一些控制动画的方法,可以使用通过实例来调用这些方法:**
103 |
104 | #### `start()`
105 |
106 | **开始动画。重置动画的开始时间,并重新计算显示值。**
107 |
108 | #### `pause()`
109 |
110 | **暂停动画。取消当前的**`requestAnimationFrame`。
111 |
112 | #### `resume()`
113 |
114 | **恢复动画。从暂停的时间点重新开始动画。**
115 |
116 | #### `pauseResume()`
117 |
118 | **切换动画的暂停和恢复状态。**
119 |
120 | #### `reset()`
121 |
122 | **重置动画。将显示值重置为起始值,并取消当前的**`requestAnimationFrame`。
123 |
124 | **方法完整使用示例**
125 |
126 | ```js
127 | //template
128 |
129 |
131 | :end-val="10000"
132 | ref="numberScrollRefBasic"
133 | />
134 |
135 |
136 | //script
137 | const numberScrollRefBasic = ref(null);
138 |
139 | 可以在特定时机触发实例上的方法,示例如下
140 | 开始
141 | 暂停
142 | 重置
143 |
144 | 可以通过实例来触发暴露出来的方法
145 | const startBasic = () => {
146 | numberScrollRefBasic.value.start();
147 | };
148 | const pauseBasic = () => {
149 | numberScrollRefBasic.value.pause();
150 | };
151 | const resumeBasic = () => {
152 | numberScrollRefBasic.value.resume();
153 | };
154 | ```
155 |
--------------------------------------------------------------------------------