├── .browserslistrc
├── .github
├── FUNDING.yml
└── workflows
│ ├── release.yml
│ ├── deploy-demo.yml
│ └── ci.yml
├── .stylelintignore
├── src
├── components
│ ├── index.ts
│ └── CountTo
│ │ ├── index.ts
│ │ ├── types.ts
│ │ └── index.vue
├── constant.ts
├── index.ts
└── types.ts
├── CONTRIBUTING.md
├── pnpm-workspace.yaml
├── readme
└── xiaohe-vue-count-to.gif
├── .npmrc
├── test
└── index.test.ts
├── examples
└── demo
│ ├── src
│ ├── main.ts
│ ├── style.scss
│ ├── types.ts
│ └── App.vue
│ ├── uno.config.ts
│ ├── vite.config.ts
│ ├── package.json
│ ├── index.html
│ └── public
│ └── vite.svg
├── .vscode
├── extensions.json
└── settings.json
├── tsconfig.node.json
├── .gitignore
├── .editorconfig
├── tsconfig.json
├── vite.config.ts
├── LICENSE
├── stylelint.config.js
├── eslint.config.js
├── package.json
└── README.md
/.browserslistrc:
--------------------------------------------------------------------------------
1 | >0.3%, defaults
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [xiaohe0601]
--------------------------------------------------------------------------------
/.stylelintignore:
--------------------------------------------------------------------------------
1 | dist
2 | node_modules
3 | public
--------------------------------------------------------------------------------
/src/components/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./CountTo/index.ts";
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Please refer to https://github.com/antfu/contribute
--------------------------------------------------------------------------------
/src/constant.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * class前缀
3 | */
4 | export const CLASS_PREFIX: string = "xh";
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./constant.ts";
2 | export * from "./components/index.ts";
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - playground
3 | - docs
4 | - packages/*
5 | - examples/*
--------------------------------------------------------------------------------
/readme/xiaohe-vue-count-to.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaohe0601/xiaohe-vue-count-to/HEAD/readme/xiaohe-vue-count-to.gif
--------------------------------------------------------------------------------
/src/components/CountTo/index.ts:
--------------------------------------------------------------------------------
1 | import CountTo from "./index.vue";
2 |
3 | export * from "./types.ts";
4 |
5 | export { CountTo };
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | strict-peer-dependencies=false
2 | auto-install-peers=true
3 | shamefully-hoist=true
4 | ignore-workspace-root-check=true
5 | shell-emulator=true
--------------------------------------------------------------------------------
/test/index.test.ts:
--------------------------------------------------------------------------------
1 | import { describe, expect, it } from "vitest";
2 |
3 | describe("should", () => {
4 | it("exported", () => {
5 | expect(1).toEqual(1);
6 | });
7 | });
--------------------------------------------------------------------------------
/examples/demo/src/main.ts:
--------------------------------------------------------------------------------
1 | import "ress";
2 | import "virtual:uno.css";
3 | import { createApp } from "vue";
4 | import App from "./App.vue";
5 |
6 | const app = createApp(App);
7 |
8 | app.mount("#app");
--------------------------------------------------------------------------------
/examples/demo/uno.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig, presetUno, transformerDirectives } from "unocss";
2 |
3 | export default defineConfig({
4 | presets: [
5 | presetUno()
6 | ],
7 | transformers: [
8 | transformerDirectives()
9 | ]
10 | });
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "vue.volar",
4 | "vue.vscode-typescript-vue-plugin",
5 | "dbaeumer.vscode-eslint",
6 | "stylelint.vscode-stylelint",
7 | "editorConfig.editorConfig",
8 | "antfu.vite"
9 | ]
10 | }
--------------------------------------------------------------------------------
/examples/demo/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vite";
2 | import VuePlugin from "@vitejs/plugin-vue";
3 | import UnoCSS from "unocss/vite";
4 |
5 | export default defineConfig({
6 | plugins: [
7 | VuePlugin(),
8 | UnoCSS()
9 | ]
10 | });
--------------------------------------------------------------------------------
/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "composite": true,
5 | "module": "ESNext",
6 | "moduleResolution": "Bundler",
7 | "skipLibCheck": true
8 | },
9 | "include": ["vite.config.ts"]
10 | }
--------------------------------------------------------------------------------
/examples/demo/src/style.scss:
--------------------------------------------------------------------------------
1 | html {
2 | font-family: MiSans, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Segoe UI, Arial, Roboto, "PingFang SC", "miui", "Hiragino Sans GB", "Microsoft Yahei", sans-serif;
3 | }
4 |
5 | html, body, #app {
6 | --at-apply: w-full h-full;
7 | }
8 |
9 | #app {
10 | --at-apply: relative text-14px text-black;
11 | }
12 |
13 | .app-container {
14 | --at-apply: w-980px mx-a;
15 | }
--------------------------------------------------------------------------------
/examples/demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "demo",
3 | "type": "module",
4 | "version": "1.0.0",
5 | "private": true,
6 | "scripts": {
7 | "serve": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "ress": "^5.0.2",
13 | "xiaohe-vue-count-to": "workspace:^"
14 | },
15 | "devDependencies": {
16 | "naive-ui": "^2.37.3",
17 | "unocss": "^0.58.3"
18 | }
19 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # 其他包管理器LOCK文件
2 | package-lock.json
3 | yarn.lock
4 |
5 | # 本地文件
6 | .env.local
7 | .env.*.local
8 | *.local
9 |
10 | # 日志文件
11 | logs
12 | *.log
13 | npm-debug.log*
14 | yarn-debug.log*
15 | yarn-error.log*
16 | pnpm-debug.log*
17 | lerna-debug.log*
18 |
19 | # 制品文件
20 | node_modules
21 | dist
22 | dist-ssr
23 |
24 | # IDE文件
25 | .vscode/*
26 | !.vscode/extensions.json
27 | !.vscode/settings.json
28 | .project
29 | .idea
30 | .hbuilderx
31 | .DS_Store
32 | *.suo
33 | *.ntvs*
34 | *.njsproj
35 | *.sln
36 | *.sw?
--------------------------------------------------------------------------------
/examples/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | xiaohe-vue-count-to
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # [EditorConfig](https://editorconfig.org)
2 | # [配置项](https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties)
3 |
4 | root = true
5 |
6 | [*]
7 | # 字符编码
8 | charset = utf-8
9 | # 结尾换行符 (lf, cr, crlf)
10 | end_of_line = lf
11 | # 去除行尾空格
12 | trim_trailing_whitespace = true
13 | # 在文件结尾插入新行
14 | insert_final_newline = false
15 | # 单行最大长度
16 | max_line_length = off
17 |
18 | [*.{js,jsx,ts,tsx,vue,json}]
19 | # 缩进风格 (space, tab)
20 | indent_style = space
21 | # 缩进大小
22 | indent_size = 2
23 | # 单个tab大小
24 | tab_width = 2
--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------
1 | export type OptionalObject = T | undefined;
2 | export type OptionalNumber = OptionalObject;
3 | export type OptionalString = OptionalObject;
4 | export type OptionalBoolean = OptionalObject;
5 |
6 | export type NullableObject = T | null;
7 | export type NullableNumber = NullableObject;
8 | export type NullableString = NullableObject;
9 | export type NullableBoolean = NullableObject;
10 |
11 | export type NumberLike = number | `${number}`;
12 |
13 | export type Arrayable = T | T[];
--------------------------------------------------------------------------------
/examples/demo/src/types.ts:
--------------------------------------------------------------------------------
1 | export type OptionalObject = T | undefined;
2 | export type OptionalNumber = OptionalObject;
3 | export type OptionalString = OptionalObject;
4 | export type OptionalBoolean = OptionalObject;
5 |
6 | export type NullableObject = T | null;
7 | export type NullableNumber = NullableObject;
8 | export type NullableString = NullableObject;
9 | export type NullableBoolean = NullableObject;
10 |
11 | export type NumberLike = number | `${number}`;
12 |
13 | export type Arrayable = T | T[];
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | permissions:
4 | contents: write
5 |
6 | on:
7 | push:
8 | tags:
9 | - "v*"
10 |
11 | jobs:
12 | release:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v3
16 | with:
17 | fetch-depth: 0
18 |
19 | - name: Install pnpm
20 | uses: pnpm/action-setup@v2
21 |
22 | - name: Set node
23 | uses: actions/setup-node@v3
24 | with:
25 | node-version: lts/*
26 |
27 | - run: npx changelogithub
28 | env:
29 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowImportingTsExtensions": true,
4 | "isolatedModules": true,
5 | "jsx": "preserve",
6 | "lib": ["ESNext", "DOM"],
7 | "module": "ESNext",
8 | "moduleResolution": "Bundler",
9 | "noFallthroughCasesInSwitch": true,
10 | "noUnusedLocals": true,
11 | "noUnusedParameters": true,
12 | "resolveJsonModule": true,
13 | "skipLibCheck": true,
14 | "strict": true,
15 | "target": "ESNext",
16 | "useDefineForClassFields": true
17 | },
18 | "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"],
19 | "references": [{ "path": "./tsconfig.node.json" }]
20 | }
--------------------------------------------------------------------------------
/.github/workflows/deploy-demo.yml:
--------------------------------------------------------------------------------
1 | name: Deploy demo
2 |
3 | permissions:
4 | contents: write
5 |
6 | on:
7 | push:
8 | branches:
9 | - main
10 |
11 | jobs:
12 | deploy:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v3
16 | with:
17 | fetch-depth: 0
18 |
19 | - name: Install pnpm
20 | uses: pnpm/action-setup@v2
21 |
22 | - name: Set node
23 | uses: actions/setup-node@v3
24 | with:
25 | node-version: lts/*
26 |
27 | - name: Setup
28 | run: npm i -g @antfu/ni
29 |
30 | - name: Install
31 | run: |
32 | cd examples/demo
33 | nci
34 |
35 | - name: Build
36 | run: |
37 | nr build
38 | nr build:demo
39 | > examples/demo/dist/.nojekyll
40 |
41 | - name: Deploy
42 | uses: JamesIves/github-pages-deploy-action@v4
43 | with:
44 | branch: demo/gh-pages
45 | folder: examples/demo/dist
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import path from "node:path";
2 | import { defineConfig } from "vite";
3 | import VuePlugin from "@vitejs/plugin-vue";
4 | import DtsPlugin from "vite-plugin-dts";
5 | import Autoprefixer from "autoprefixer";
6 |
7 | function resolve(...paths: string[]): string {
8 | return path.resolve(__dirname, ...paths);
9 | }
10 |
11 | export default defineConfig({
12 | build: {
13 | lib: {
14 | entry: resolve("src", "index.ts"),
15 | name: "XhCountTo",
16 | formats: ["es", "cjs", "umd"],
17 | fileName: "index"
18 | },
19 | rollupOptions: {
20 | external: ["vue", "vue-demi", "xiaohe-transition"],
21 | output: {
22 | globals: {
23 | "vue": "Vue",
24 | "vue-demi": "VueDemi",
25 | "xiaohe-transition": "XhTransition"
26 | }
27 | }
28 | }
29 | },
30 | optimizeDeps: {
31 | exclude: ["vue-demi"]
32 | },
33 | plugins: [
34 | VuePlugin(),
35 | DtsPlugin({
36 | rollupTypes: true
37 | })
38 | ],
39 | css: {
40 | postcss: {
41 | plugins: [Autoprefixer()]
42 | }
43 | }
44 | });
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 xiaohe0601
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | // Enable the ESlint flat config support
3 | "eslint.experimental.useFlatConfig": true,
4 |
5 | // Disable the default formatter, use eslint instead
6 | "prettier.enable": false,
7 | "editor.formatOnSave": false,
8 |
9 | // Auto fix
10 | "editor.codeActionsOnSave": {
11 | "source.fixAll.eslint": "explicit",
12 | "source.organizeImports": "never"
13 | },
14 |
15 | // Silent the stylistic rules in you IDE, but still auto fix them
16 | "eslint.rules.customizations": [
17 | { "rule": "style/*", "severity": "off" },
18 | { "rule": "*-indent", "severity": "off" },
19 | { "rule": "*-spacing", "severity": "off" },
20 | { "rule": "*-spaces", "severity": "off" },
21 | { "rule": "*-order", "severity": "off" },
22 | { "rule": "*-dangle", "severity": "off" },
23 | { "rule": "*-newline", "severity": "off" },
24 | { "rule": "*quotes", "severity": "off" },
25 | { "rule": "*semi", "severity": "off" }
26 | ],
27 |
28 | // Enable eslint for all supported languages
29 | "eslint.validate": [
30 | "javascript",
31 | "javascriptreact",
32 | "typescript",
33 | "typescriptreact",
34 | "vue",
35 | "html",
36 | "markdown",
37 | "json",
38 | "jsonc",
39 | "yaml"
40 | ]
41 | }
--------------------------------------------------------------------------------
/examples/demo/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | pull_request:
9 | branches:
10 | - main
11 |
12 | jobs:
13 | lint:
14 | runs-on: ubuntu-latest
15 | steps:
16 | - uses: actions/checkout@v3
17 |
18 | - name: Install pnpm
19 | uses: pnpm/action-setup@v2
20 |
21 | - name: Set node
22 | uses: actions/setup-node@v3
23 | with:
24 | node-version: lts/*
25 |
26 | - name: Setup
27 | run: npm i -g @antfu/ni
28 |
29 | - name: Install
30 | run: nci
31 |
32 | - name: Lint code
33 | run: nr lint
34 |
35 | - name: Lint type
36 | run: nr lint:type
37 |
38 | - name: Lint style
39 | run: nr style
40 |
41 | test:
42 | runs-on: ${{ matrix.os }}
43 |
44 | strategy:
45 | matrix:
46 | node: [lts/*]
47 | os: [ubuntu-latest, windows-latest, macos-latest]
48 | fail-fast: false
49 |
50 | steps:
51 | - uses: actions/checkout@v3
52 |
53 | - name: Install pnpm
54 | uses: pnpm/action-setup@v2
55 |
56 | - name: Set node ${{ matrix.node }}
57 | uses: actions/setup-node@v3
58 | with:
59 | node-version: ${{ matrix.node }}
60 |
61 | - name: Setup
62 | run: npm i -g @antfu/ni
63 |
64 | - name: Install
65 | run: nci
66 |
67 | - name: Build
68 | run: nr build
69 |
70 | - name: Test
71 | run: nr test
--------------------------------------------------------------------------------
/stylelint.config.js:
--------------------------------------------------------------------------------
1 | // 配置参考
2 | // https://stylelint.io/user-guide/rules
3 | // https://github.com/stylelint-scss/stylelint-scss#list-of-rules
4 |
5 | /** @type {import("stylelint").Config} */
6 | export default {
7 | defaultSeverity: "error",
8 | extends: [
9 | "stylelint-config-standard",
10 | "stylelint-config-standard-scss",
11 | "stylelint-config-recommended",
12 | "stylelint-config-recommended-vue",
13 | "stylelint-config-html",
14 | "stylelint-config-recess-order"
15 | ],
16 | plugins: [
17 | "stylelint-order"
18 | ],
19 | rules: {
20 | "unit-no-unknown": null,
21 | "no-empty-source": null,
22 | "color-hex-length": ["long", {
23 | message: "16进制颜色需要使用长符号(#ffffff)风格"
24 | }],
25 | "at-rule-no-unknown": null,
26 | "value-keyword-case": null,
27 | "length-zero-no-unit": [true, {
28 | ignore: ["custom-properties"],
29 | ignoreFunctions: ["/^--/", "var", "calc"]
30 | }],
31 | "alpha-value-notation": ["number"],
32 | "no-duplicate-selectors": null,
33 | "selector-class-pattern": ["^([#a-z][$#{}a-z0-9]*)((-{1,2}|_{2})[$#{}a-z0-9]+)*$", {
34 | message: "class命名需要符合BEM风格(block-element[__element][--modifier])"
35 | }],
36 | "color-function-notation": ["legacy", {
37 | ignore: ["with-var-inside"]
38 | }],
39 | "font-family-name-quotes": null,
40 | "no-descending-specificity": null,
41 | "selector-type-no-unknown": [true, {
42 | ignore: ["custom-elements", "default-namespace"],
43 | ignoreTypes: ["page", "rich-text", "scroll-view"]
44 | }],
45 | "selector-pseudo-class-no-unknown": [true, {
46 | ignorePseudoClasses: ["deep"]
47 | }],
48 | "custom-property-empty-line-before": null,
49 | "font-family-no-missing-generic-family-keyword": null,
50 | "declaration-block-no-redundant-longhand-properties": [true, {
51 | ignoreShorthands: ["inset"]
52 | }],
53 | "scss/at-import-partial-extension": ["always"],
54 | "scss/at-extend-no-missing-placeholder": null
55 | }
56 | };
--------------------------------------------------------------------------------
/src/components/CountTo/types.ts:
--------------------------------------------------------------------------------
1 | import type { BezierCurve, BezierCurvePreset, Transition } from "xiaohe-transition";
2 | import type { NumberLike } from "../../types.ts";
3 |
4 | export type BezierCurvePresetLike = BezierCurvePreset | "linear" | "ease" | "ease-in" | "ease-out" | "ease-in-out";
5 |
6 | export interface CountToProps {
7 | /**
8 | * 数值
9 | */
10 | value?: NumberLike;
11 | /**
12 | * 小数位数
13 | */
14 | decimals?: NumberLike;
15 | /**
16 | * 动画时长(单位: ms)
17 | */
18 | duration?: NumberLike;
19 | /**
20 | * 预设曲线
21 | */
22 | preset?: BezierCurvePresetLike;
23 | /**
24 | * 自定义曲线(优先级高于preset)
25 | */
26 | bezier?: BezierCurve;
27 | /**
28 | * 延迟开始时间(单位: ms)
29 | */
30 | delay?: NumberLike;
31 | /**
32 | * 帧率(即每秒回调多少次,若小于或等于0则使用requestAnimationFrame自动处理)
33 | */
34 | fps?: NumberLike;
35 | /**
36 | * 小数点
37 | *
38 | * @since 0.3.0
39 | */
40 | decimal?: string;
41 | /**
42 | * 是否启用数值分组(示例:10000000.00 -> 10,000,000.00)
43 | *
44 | * @since 0.3.0
45 | */
46 | useGroupValue?: boolean;
47 | /**
48 | * 是否使用印度风格数值分组(示例:10000000.00 -> 1,00,00,000.00)
49 | *
50 | * @since 0.3.0
51 | */
52 | useIndianStyleGroup?: boolean;
53 | /**
54 | * 分隔符
55 | *
56 | * @since 0.3.0
57 | */
58 | separator?: string;
59 | /**
60 | * 自定义数字
61 | *
62 | * @since 0.3.0
63 | */
64 | numerals?: string[];
65 | }
66 |
67 | export interface CountToEmits {
68 | /**
69 | * transition初始化完成
70 | */
71 | (e: "inited", instance: Transition): void;
72 |
73 | /**
74 | * 数值变化
75 | */
76 | (e: "change", value: string, instance: Transition): void;
77 |
78 | /**
79 | * 动画开始
80 | */
81 | (e: "started", instance: Transition): void;
82 |
83 | /**
84 | * 动画暂停
85 | */
86 | (e: "paused", instance: Transition): void;
87 |
88 | /**
89 | * 动画继续
90 | */
91 | (e: "resumed", instance: Transition): void;
92 |
93 | /**
94 | * 动画停止
95 | */
96 | (e: "stopped", instance: Transition): void;
97 |
98 | /**
99 | * 动画完成
100 | */
101 | (e: "completed", instance: Transition): void;
102 | }
103 |
104 | export interface CountToSlots {
105 | default(props: { value: string; }): any;
106 | }
107 |
108 | export interface CountToInst {
109 | transition: Transition;
110 | }
111 |
112 | export {};
--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------
1 | import defineConfig from "@antfu/eslint-config";
2 |
3 | // 配置参考
4 | // https://github.com/antfu/eslint-config
5 | // https://github.com/antfu/eslint-flat-config-viewer
6 | export default defineConfig({
7 | stylistic: {
8 | indent: 2,
9 | quotes: "double"
10 | },
11 | ignores: []
12 | }, {
13 | rules: {
14 | "curly": ["error", "all"],
15 | "no-console": ["warn", {
16 | allow: [
17 | "warn",
18 | "error"
19 | ]
20 | }],
21 | "dot-notation": ["off"],
22 | "symbol-description": ["off"],
23 | "no-extra-boolean-cast": ["off"],
24 | "prefer-promise-reject-errors": ["off"],
25 | "style/semi": ["error", "always"],
26 | "style/eol-last": ["error", "never"],
27 | "style/brace-style": ["error", "1tbs"],
28 | "style/quote-props": ["off"],
29 | "style/comma-dangle": ["error", "never"],
30 | "style/arrow-parens": ["error", "always"],
31 | "style/padded-blocks": ["error", {
32 | blocks: "never",
33 | classes: "always",
34 | switches: "never"
35 | }],
36 | "style/operator-linebreak": ["error", "before", {
37 | overrides: {
38 | "=": "after"
39 | }
40 | }],
41 | "style/no-multiple-empty-lines": ["error", {
42 | max: 2,
43 | maxBOF: 0,
44 | maxEOF: 0
45 | }],
46 | "style/member-delimiter-style": ["error", {
47 | singleline: {
48 | delimiter: "semi",
49 | requireLast: true
50 | },
51 | multiline: {
52 | delimiter: "semi",
53 | requireLast: true
54 | },
55 | multilineDetection: "brackets"
56 | }],
57 | "ts/ban-ts-comment": ["off"],
58 | "ts/prefer-ts-expect-error": ["off"],
59 | "import/no-self-import": ["off"],
60 | "import/newline-after-import": ["error", {
61 | count: 1,
62 | considerComments: false
63 | }],
64 | "vue/quote-props": ["off"],
65 | "vue/block-order": ["error", {
66 | order: ["template", "script:not([setup])", "script[setup]", "style:not([scoped])", "style[scoped]"]
67 | }],
68 | "vue/html-self-closing": ["error", {
69 | html: {
70 | void: "any",
71 | normal: "never",
72 | component: "never"
73 | },
74 | svg: "never",
75 | math: "never"
76 | }],
77 | "vue/custom-event-name-casing": ["error", "kebab-case"],
78 | "vue/first-attribute-linebreak": ["error", {
79 | singleline: "beside",
80 | multiline: "beside"
81 | }],
82 | "vue/html-closing-bracket-newline": ["error", {
83 | singleline: "never",
84 | multiline: "never"
85 | }],
86 | "vue/component-name-in-template-casing": ["error", "kebab-case"],
87 | "vue/singleline-html-element-content-newline": ["off"],
88 | "vue/multiline-html-element-content-newline": ["off"],
89 | "node/prefer-global/process": ["error", "always"],
90 | "antfu/consistent-list-newline": ["off"]
91 | }
92 | });
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "xiaohe-vue-count-to",
3 | "type": "module",
4 | "version": "0.3.2",
5 | "packageManager": "pnpm@8.14.0",
6 | "description": "⏱️ 一个实现数字平滑变化的Vue小组件",
7 | "author": "xiaohe0601 ",
8 | "license": "MIT",
9 | "funding": "https://github.com/sponsors/xiaohe0601",
10 | "homepage": "https://count-to.netlify.app",
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/xiaohe0601/xiaohe-vue-count-to.git"
14 | },
15 | "bugs": "https://github.com/xiaohe0601/xiaohe-vue-count-to/issues",
16 | "keywords": [
17 | "xiaohe",
18 | "count-to",
19 | "bezier",
20 | "transition",
21 | "animation"
22 | ],
23 | "sideEffects": false,
24 | "exports": {
25 | ".": {
26 | "types": "./dist/index.d.ts",
27 | "import": "./dist/index.js",
28 | "require": "./dist/index.umd.cjs"
29 | }
30 | },
31 | "main": "./dist/index.umd.cjs",
32 | "module": "./dist/index.js",
33 | "types": "./dist/index.d.ts",
34 | "typesVersions": {
35 | "*": {
36 | "*": [
37 | "./dist/*",
38 | "./dist/index.d.ts"
39 | ]
40 | }
41 | },
42 | "files": [
43 | "dist"
44 | ],
45 | "scripts": {
46 | "serve": "vite",
47 | "serve:demo": "nr --dir examples/demo serve",
48 | "build": "vite build",
49 | "build:demo": "nr --dir examples/demo build",
50 | "preview": "vite preview",
51 | "preview:demo": "nr --dir examples/demo preview",
52 | "release": "nr build && bumpp && npm publish",
53 | "test": "vitest",
54 | "test:ui": "vitest --ui",
55 | "test:coverage": "vitest run --coverage",
56 | "lint": "eslint src",
57 | "lint:fix": "eslint src --fix",
58 | "lint:type": "vue-tsc --noEmit",
59 | "style": "stylelint src/**/*.{css,scss,vue,html} --aei",
60 | "style:fix": "stylelint src/**/*.{css,scss,vue,html} --aei --fix",
61 | "prepare": "simple-git-hooks"
62 | },
63 | "dependencies": {
64 | "vue": "^3.4.14",
65 | "vue-demi": "^0.14.6",
66 | "xiaohe-transition": "^1.1.0"
67 | },
68 | "peerDependencies": {
69 | "vue": ">=2.5.0 || >=3.0.0"
70 | },
71 | "devDependencies": {
72 | "@antfu/eslint-config": "^2.6.2",
73 | "@antfu/ni": "^0.21.12",
74 | "@antfu/utils": "^0.7.7",
75 | "@types/node": "^20.11.3",
76 | "@vitejs/plugin-vue": "^5.0.3",
77 | "autoprefixer": "^10.4.16",
78 | "bumpp": "^9.2.1",
79 | "eslint": "^8.56.0",
80 | "esno": "^4.0.0",
81 | "lint-staged": "^15.2.0",
82 | "rimraf": "^5.0.5",
83 | "sass": "^1.69.7",
84 | "simple-git-hooks": "^2.9.0",
85 | "stylelint": "^16.1.0",
86 | "stylelint-config-html": "^1.1.0",
87 | "stylelint-config-recess-order": "^4.4.0",
88 | "stylelint-config-recommended": "^14.0.0",
89 | "stylelint-config-recommended-vue": "^1.5.0",
90 | "stylelint-config-standard": "^36.0.0",
91 | "stylelint-config-standard-scss": "^12.0.0",
92 | "stylelint-order": "^6.0.4",
93 | "typescript": "^5.3.3",
94 | "vite": "^5.0.11",
95 | "vite-plugin-dts": "^3.7.1",
96 | "vitest": "^1.2.0",
97 | "vue-tsc": "^1.8.27"
98 | },
99 | "simple-git-hooks": {
100 | "pre-commit": "pnpm lint-staged"
101 | },
102 | "lint-staged": {
103 | "*.{js,jsx,ts,tsx,vue}": "eslint --fix",
104 | "*.{css,scss,vue,html}": "stylelint --aei --fix"
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/components/CountTo/index.vue:
--------------------------------------------------------------------------------
1 |
176 |
177 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
xiaohe-vue-count-to
3 | ⏱️ 一个实现数字平滑变化的Vue小组件
4 |
5 |
6 |
7 |
8 | [![github stars][github-stars-src]][github-stars-href]
9 | [![npm version][npm-version-src]][npm-version-href]
10 | [![npm downloads][npm-downloads-src]][npm-downloads-href]
11 | [![bundle][bundle-src]][bundle-href]
12 | [![JSDocs][jsdocs-src]][jsdocs-href]
13 | [![License][license-src]][license-href]
14 |
15 | 小何 / [github@xiaohe0601](https://github.com/xiaohe0601) / [gitee@xiaohe0601](https://gitee.com/xiaohe0601)
16 |
17 | ### 🎉 特性
18 |
19 | - 🍜 支持非线性动画
20 | - 🍟 支持中途打断动画
21 | - 🐼 支持Vue 2/3
22 | - 🧀 支持TypeScript
23 | - 🍳 支持免费商用
24 | - 🥗 更多特性等你发掘...
25 |
26 | ### 🎮 示例
27 |
28 |
29 |

30 |
31 |
32 | > 还可以[试一试](https://count-to.netlify.app)在线DEMO
33 |
34 | ### 🚁 安装
35 |
36 | #### PNPM
37 |
38 | ``` shell
39 | pnpm add xiaohe-vue-count-to
40 | ```
41 |
42 | #### YARN
43 |
44 | ``` shell
45 | yarn add xiaohe-vue-count-to
46 | ```
47 |
48 | #### NPM
49 |
50 | ``` shell
51 | npm install xiaohe-vue-count-to
52 | ```
53 |
54 | #### 另外
55 |
56 | > 如果 `Vue` 版本小于 `2.7`,还需要安装 `@vue/composition-api`
57 |
58 | ``` shell
59 | pnpm add @vue/composition-api
60 | ```
61 |
62 | ### 🛹 使用
63 |
64 | #### 简单使用
65 |
66 | ``` vue
67 |
68 |
69 |
70 | {{ value }}
71 |
72 |
73 |
74 |
75 |
87 | ```
88 |
89 | #### 控制动画
90 |
91 | - 仅 `Vue 3` 可直接通过 `ref` 获取到 `xiaohe-transition` 实例用于控制动画
92 |
93 | ``` vue
94 |
95 |
96 |
97 | {{ value }}
98 |
99 |
100 |
101 |
102 |
125 | ```
126 |
127 | - `Vue 2/3` 均可通过 `inited` 事件获取到 `xiaohe-transition` 实例用于控制动画
128 |
129 | ``` vue
130 |
131 |
132 |
133 | {{ value }}
134 |
135 |
136 |
137 |
138 |
170 | ```
171 |
172 | #### 属性(Props)
173 |
174 | |参数|说明|类型|可选值|默认值|
175 | |---|---|---|---|---|
176 | |value|数值|`NumberLike`|-|0|
177 | |decimals|小数位数|`NumberLike`|-|0|
178 | |duration|动画时长(单位: ms)|`NumberLike`|-|2000|
179 | |preset|预设曲线|`BezierCurvePresetLike`|linear/ease/ease-in/ease-out/ease-in-out|linear|
180 | |bezier|自定义曲线(优先级高于preset)|`BezierCurve`|-|-|
181 | |delay|延迟开始时间(单位: ms)|`NumberLike`|-|0|
182 | |fps|帧率|`NumberLike`|-|-1|
183 | |decimal `0.3.0`|小数点|`string`|-|.|
184 | |use-group-value `0.3.0`|是否启用数值分组(示例:10000000.00 -> 10,000,000.00)|`boolean`|-|false|
185 | |use-indian-style-group `0.3.0`|是否使用印度风格数值分组(示例:10000000.00 -> 1,00,00,000.00)|`boolean`|-|false|
186 | |separator `0.3.0`|分隔符|`string`|-|,|
187 | |numerals `0.3.0`|自定义数字|`string[]`|-|-|
188 |
189 | #### 事件(Events)
190 |
191 | |事件|说明|回调参数|
192 | |---|---|---|
193 | |inited|`transition` 初始化完成|(instance: `Transition`)|
194 | |change|数值变化|(value: `string`, instance: `Transition`)|
195 | |started|动画开始|(instance: `Transition`)|
196 | |paused|动画暂停|(instance: `Transition`)|
197 | |resumed|动画继续|(instance: `Transition`)|
198 | |stopped|动画停止|(instance: `Transition`)|
199 | |completed|动画完成|(instance: `Transition`)|
200 |
201 | #### 插槽(Slots)
202 |
203 | |名称|说明|类型|
204 | |---|---|---|
205 | |default|默认内容|{ value: `string` }|
206 |
207 | #### 实例(Inst)
208 |
209 | |属性|说明|类型|
210 | |---|---|---|
211 | |transition|`xiaohe-transition` 实例|`Transition`|
212 |
213 | #### 类型定义
214 |
215 | > 请查看 [jsdocs.io](https://www.jsdocs.io/package/xiaohe-vue-count-to)
216 |
217 | ### 🛸 链接
218 |
219 | - [xiaohe-transition](https://github.com/xiaohe0601/xiaohe-transition) 🏀 一个简单易用的贝塞尔曲线过渡动画工具
220 |
221 | ### 🐶 讨论交流
222 |
223 | - ❓:若有疑问或BUG反馈,可提交[issues](https://github.com/xiaohe0601/xiaohe-vue-count-to/issues)
224 | - 📫:[xiaohe0601@outlook.com](mailto:xiaohe0601@outlook.com)
225 | - 🐧:暂未开通
226 |
227 | ### 🏆 开源协议
228 |
229 | - MIT [LICENSE](./LICENSE)
230 |
231 |
232 |
233 | [github-stars-src]: https://img.shields.io/github/stars/xiaohe0601/xiaohe-vue-count-to?style=flat&colorA=080f12&colorB=1fa669&logo=GitHub
234 | [github-stars-href]: https://github.com/xiaohe0601/xiaohe-vue-count-to
235 | [npm-version-src]: https://img.shields.io/npm/v/xiaohe-vue-count-to?style=flat&colorA=080f12&colorB=1fa669
236 | [npm-version-href]: https://npmjs.com/package/xiaohe-vue-count-to
237 | [npm-downloads-src]: https://img.shields.io/npm/dm/xiaohe-vue-count-to?style=flat&colorA=080f12&colorB=1fa669
238 | [npm-downloads-href]: https://npmjs.com/package/xiaohe-vue-count-to
239 | [bundle-src]: https://img.shields.io/bundlephobia/minzip/xiaohe-vue-count-to?style=flat&colorA=080f12&colorB=1fa669&label=minzip
240 | [bundle-href]: https://bundlephobia.com/result?p=xiaohe-vue-count-to
241 | [jsdocs-src]: https://img.shields.io/badge/jsdocs-reference-080f12?style=flat&colorA=080f12&colorB=1fa669
242 | [jsdocs-href]: https://www.jsdocs.io/package/xiaohe-vue-count-to
243 | [license-src]: https://img.shields.io/github/license/xiaohe0601/xiaohe-vue-count-to.svg?style=flat&colorA=080f12&colorB=1fa669
244 | [license-href]: https://github.com/xiaohe0601/xiaohe-vue-count-to/blob/main/LICENSE
--------------------------------------------------------------------------------
/examples/demo/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | xiaohe-vue-count-to
7 | ⏱️ 一个实现数字平滑变化的Vue小组件
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
47 |
48 | {{ value }}
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | 毫秒
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | 启用
77 | 禁用
78 |
79 |
80 | 印度风格
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 | 毫秒
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | 暂停
105 | 继续
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
160 |
161 |
--------------------------------------------------------------------------------