├── .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 | 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 | ![这是图片](./Vue3NumberScroll.gif "Magic Gardens") 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 | 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 | --------------------------------------------------------------------------------