├── .github └── workflows │ └── npm-publish-github-packages.yml ├── .gitignore ├── .hintrc ├── .npmrc ├── .prettierrc ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── buildSpecial.mjs ├── docs ├── .vitepress │ ├── cache │ │ └── deps │ │ │ ├── _metadata.json │ │ │ ├── chunk-P6MQ6B53.js │ │ │ ├── chunk-P6MQ6B53.js.map │ │ │ ├── chunk-XVMVVWGL.js │ │ │ ├── chunk-XVMVVWGL.js.map │ │ │ ├── package.json │ │ │ ├── vitepress___@vue_devtools-api.js │ │ │ ├── vitepress___@vue_devtools-api.js.map │ │ │ ├── vitepress___@vueuse_core.js │ │ │ ├── vitepress___@vueuse_core.js.map │ │ │ ├── vitepress___@vueuse_integrations_useFocusTrap.js │ │ │ ├── vitepress___@vueuse_integrations_useFocusTrap.js.map │ │ │ ├── vitepress___mark__js_src_vanilla__js.js │ │ │ ├── vitepress___mark__js_src_vanilla__js.js.map │ │ │ ├── vitepress___minisearch.js │ │ │ ├── vitepress___minisearch.js.map │ │ │ ├── vue.js │ │ │ └── vue.js.map │ ├── config.mts │ └── theme │ │ └── index.ts └── src │ ├── commitInfo.js │ ├── components │ ├── PhoneModel.vue │ └── Preview.vue │ ├── contribution │ ├── index.md │ ├── log.md │ ├── more.md │ └── moreDetails │ │ ├── CH.md │ │ └── EN.md │ ├── index.md │ ├── layout │ ├── nav.ts │ └── sidebar.ts │ ├── public │ ├── image │ │ ├── atom-logo.jpg │ │ ├── contribution-really.png │ │ ├── contribution.png │ │ ├── creator.jpg │ │ ├── log-image.png │ │ ├── logo.png │ │ └── logo_2.png │ └── style │ │ └── theme.css │ ├── template │ ├── native │ │ └── customAjax.md │ ├── root │ │ ├── native.md │ │ ├── vue.md │ │ └── wxChat.md │ ├── vue │ │ └── customAxios.md │ └── wxChat │ │ └── customKeyboard.md │ └── utils │ ├── guide │ ├── directory.md │ ├── guide.md │ └── use.md │ ├── public │ ├── Array │ │ ├── arraySortByKey.md │ │ ├── fuzzyMatchByProperty.md │ │ └── uniqueByProperty.md │ ├── Browser │ │ ├── browseRownership.md │ │ ├── clearAllCookie.md │ │ ├── copyText.md │ │ ├── exitFullScreen.md │ │ ├── getUrlParams.md │ │ ├── log.md │ │ ├── preventRightKey.md │ │ ├── randomHexColor.md │ │ ├── removeElementMark.md │ │ ├── rgbGray.md │ │ └── toFullScreen.md │ ├── File │ │ ├── canvasToFile.md │ │ ├── convertQualityToBit.md │ │ ├── createFileFromBlob.md │ │ ├── dataURLToImage.md │ │ ├── fileToDataURL.md │ │ ├── formatFileSize.md │ │ ├── getFileExtension.md │ │ ├── readFileAsText.md │ │ └── saveFile.md │ ├── FormatDate │ │ ├── constant.md │ │ ├── formatDate.md │ │ ├── formatDateWeekCN.md │ │ ├── getDayOfYear.md │ │ ├── getTwoDaysApart.md │ │ ├── isLeapYear.md │ │ └── toDate.md │ ├── HighOrderFunction │ │ ├── KeepLoop.md │ │ ├── cloneDeep.md │ │ ├── debounce.md │ │ ├── sington.md │ │ ├── sleep.md │ │ └── throttle.md │ ├── Number │ │ ├── fillZero.md │ │ ├── getRandomNumber.md │ │ └── keepDecimal.md │ ├── Object │ │ └── pick.md │ ├── String │ │ ├── getRandomString.md │ │ ├── maskString.md │ │ ├── toLower.md │ │ └── toUpper.md │ └── TypeCheck │ │ ├── constant.md │ │ ├── is.md │ │ ├── isEmpty.md │ │ └── optional.md │ └── special │ ├── Vue │ ├── setupDirectivePlugins │ │ ├── before.md │ │ ├── vCopy.md │ │ ├── vDebounce.md │ │ ├── vDraggable.md │ │ ├── vHighlight.md │ │ ├── vObserveVisibility.md │ │ ├── vOutsideClick.md │ │ ├── vResize.md │ │ ├── vWaterMarker.md │ │ └── vZoom.md │ └── utils │ │ └── debounceRef.md │ └── WeChat │ ├── createQRcode.md │ └── uploadFile.md ├── extract-commit.mjs ├── index.d.ts ├── index.html ├── lib ├── public │ ├── Array │ │ └── index.ts │ ├── Browser │ │ └── index.ts │ ├── File │ │ └── index.ts │ ├── FormatDate │ │ ├── constant.ts │ │ └── index.ts │ ├── HighOrderFunction │ │ ├── KeepLoop.ts │ │ └── index.ts │ ├── Number │ │ └── index.ts │ ├── Object │ │ └── index.ts │ ├── PrettyLog │ │ └── index.ts │ ├── String │ │ └── index.ts │ ├── TypeCheck │ │ └── index.ts │ ├── main.ts │ └── types │ │ ├── global.d.ts │ │ └── index.d.ts └── special │ ├── Vue │ ├── Directive │ │ ├── index.ts │ │ ├── vCopy.ts │ │ ├── vDebounce.ts │ │ ├── vDraggable.ts │ │ ├── vHighlight.ts │ │ ├── vObserveVisibility.ts │ │ ├── vOutsideClick.ts │ │ ├── vResize.ts │ │ ├── vWaterMarker.ts │ │ └── vZoom.ts │ ├── main.ts │ ├── types │ │ ├── global.d.ts │ │ └── index.d.ts │ └── utils │ │ ├── debounceRef │ │ └── index.ts │ │ └── index.ts │ └── WeChat │ ├── CreateQRCode │ └── index.ts │ ├── UploadFile │ └── index.ts │ ├── main.ts │ └── types │ ├── global.d.ts │ └── index.d.ts ├── package-lock.json ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── public └── vite.svg ├── src ├── App.tsx ├── components │ ├── HelloWorld.tsx │ └── Test.vue ├── main.ts ├── style.css ├── typescript.svg └── vite-env.d.ts ├── tailwind.config.js ├── tsconfig.json └── vite.config.ts /.github/workflows/npm-publish-github-packages.yml: -------------------------------------------------------------------------------- 1 | name: Publish Package to npmjs 2 | 3 | on: 4 | push: 5 | tags: 6 | - v* 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: 🔄 Checkout 13 | uses: actions/checkout@v4 14 | - name: 🚀 Setup Node 15 | uses: actions/setup-node@v3 16 | with: 17 | node-version: 18 18 | - name: 📦 Install pnpm 19 | run: npm install -g pnpm 20 | - name: 📚 Cache dependencies 21 | uses: actions/cache@v2 22 | with: 23 | path: ~/.pnpm-store 24 | key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} 25 | restore-keys: | 26 | ${{ runner.os }}-pnpm- 27 | 28 | publish-gpr: 29 | needs: build 30 | runs-on: ubuntu-latest 31 | permissions: 32 | contents: read 33 | packages: write 34 | steps: 35 | - name: 📦 Install pnpm 36 | run: npm install -g pnpm 37 | - name: Set up Git 38 | run: | 39 | git config --global user.email "${GITHUB_ACTOR}@users.noreply.github.com" 40 | git config --global user.name "${GITHUB_ACTOR}" 41 | - name: 🔄 Checkout 42 | uses: actions/checkout@v4 43 | - name: 🚀 Setup Node 44 | uses: actions/setup-node@v3 45 | with: 46 | node-version: 18 47 | registry-url: https://npm.pkg.github.com/ 48 | - name: 📚 Cache dependencies 49 | uses: actions/cache@v2 50 | with: 51 | path: ~/.pnpm-store 52 | key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} 53 | restore-keys: | 54 | ${{ runner.os }}-pnpm- 55 | - name: 🛠️ Configure npm authentication 56 | run: echo "//npm.pkg.github.com/:_authToken=${{ secrets.ATOM_NPM_TOKEN }}" > ~/.npmrc 57 | 58 | - name: 🛡️ Check for uncommitted changes 59 | run: | 60 | git status --porcelain 61 | git diff --exit-code 62 | 63 | - name: 🛠️ Authenticate with npm 64 | run: npm adduser 65 | - name: 🌼 Set package version 66 | run: npm version --no-git-tag-version ${GITHUB_REF#refs/tags/v} 67 | - name: 🏗️ Install package 68 | run: pnpm install 69 | - name: 🚀 Build package 70 | run: pnpm run build 71 | - name: 🛠️ Commit changes 72 | run: | 73 | git add . 74 | git commit -m "Publish version ${GITHUB_REF#refs/tags/v}" 75 | - name: 🚀 Publish package to npm 76 | run: pnpm publish --no-git-checks 77 | env: 78 | NODE_AUTH_TOKEN: ${{ secrets.ATOM_NPM_TOKEN }} 79 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.hintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "development" 4 | ] 5 | } -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist = true 2 | 3 | @LinHanLove:registry=https://npm.pkg.github.com 4 | 5 | //npm.pkg.github.com/:_authToken=ATOM_NPM_TOKEN -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": false, 3 | "tabWidth": 2, 4 | "printWidth": 100, 5 | "singleQuote": true, 6 | "trailingComma": "none", 7 | "bracketSpacing": true, 8 | "semi": false, 9 | "endOfLine": "lf" 10 | } 11 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # 贡献指南 2 | 3 | 感谢您对 **AtomTools** 的兴趣和想要为其做出贡献的愿望!以下是参与贡献的步骤和指南。 4 | 5 | ## 报告问题 6 | 7 | 如果您发现了错误或有新功能的想法,请通过 [GitHub Issues](https://github.com/LinHanlove/atom-tools/issues) 提交。 8 | 9 | ## 贡献流程 10 | 11 | 1. **Fork 仓库**:点击项目的 GitHub 仓库主页上的 "Fork" 按钮。 12 | 2. **克隆您的仓库**:将您 Fork 的仓库克隆到本地。 13 | 14 | ```bash 15 | git clone https://github.com/your-github-username/atom-tools.git 16 | ``` 17 | 18 | 3. **创建分支**:创建一个新分支以进行更改。 19 | 20 | ```bash 21 | git checkout -b your-branch-name 22 | ``` 23 | 24 | 4. **进行更改**:在 `lib/` 目录下进行您的更改。 25 | 5. **提交更改**:将更改提交到您的分支。 26 | 27 | ```bash 28 | git commit -am "Add some feature or fix a bug" 29 | ``` 30 | 31 | 6. **推送到 GitHub**:将您的更改推送到 GitHub 上的分支 32 | 7. **发起 Pull Request**:在 GitHub 上,提交一个新的 Pull Request。 33 | 34 | ## 联系我们 35 | 36 | 如果您有任何问题或建议,欢迎随时通过以下方式联系我们: 37 | 38 | - 邮箱:2188817393@qq.com 39 | - 电话:15097255355 40 | - GitHub:[讨论](https://github.com/LinHanlove/atom-tools/discussions) 41 | - 稀土掘金:https://juejin.cn/post/7362370608346677283 42 | - 微信:添加微信号 "linhan_0119" 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 LinHan 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## 注意⚠️: 3 | 4 | - 自从 2024-12-05 开始,本库将进行整体模块迁移,将所有工具函数按功能模块划分,并逐步迁移至 新的 `atom-tools` 👉[atom-tools](https://github.com/LinHanlove/atom-tools) 库中。版本号将升级至01.0.0大版本,并逐步迭代更新。 5 | - 迁移后,本库将暂不更新,请及时迁移至新版本。本库后续将更名为 `atom-module-tools`。用于按主流前端框架(vue,react,微信小程序),新增工具,并逐步完善。 6 | - 后续会在我的掘金统一通知 7 | 8 | 寻找志同道合的朋友一起参与 AtomTools 的开发。如果你对 TypeScript、JavaScript 工具库开发充满热情,欢迎加入我们,共同打造一个更加强大、易用的编程工具集。 9 | 10 | 11 | **AtomTools** 致力于成为一个全方位的前端开发工具库,帮助开发者提升生产力,实现更优雅的编程体验。加入我们,一起构建未来! 12 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /buildSpecial.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * vite目前并不能构建多个特殊库,但是可以通过配置多个lib来解决 3 | * github并没有找到解决办法,但是目前这种方式或许是最优的解决方式 4 | */ 5 | 6 | import { build } from 'vite' 7 | import { resolve } from 'path' 8 | import { fileURLToPath } from 'url' 9 | 10 | /** 11 | * 在 ES 模块中,__dirname 不是一个全局变量,因为它是 CommonJS 模块的一部分。 12 | */ 13 | const __dirname = fileURLToPath(new URL('.', import.meta.url)) 14 | 15 | /** 16 | * @Array 特殊构建库的根路径 17 | * 规定:必须由大写组成文件夹,其文件夹内必须统一由main.ts导出具体的模块['Vue', 'WeChat'] 18 | */ 19 | const libMap = [ 20 | { 21 | entry: resolve(__dirname, `./lib/special/Vue/main.ts`), 22 | name: `AtomToolsVue`, 23 | filename: 'index', 24 | format: 'umd' 25 | }, 26 | { 27 | entry: resolve(__dirname, `./lib/special/WeChat/main.ts`), 28 | name: `AtomToolsWeChat`, 29 | filename: 'index', 30 | format: 'cjs' 31 | } 32 | ] 33 | 34 | libMap.forEach(async (lib) => { 35 | const config = { 36 | configFile: false, 37 | base: './', 38 | resolve: { 39 | alias: { 40 | '@': resolve(__dirname, 'lib') 41 | } 42 | }, 43 | build: { 44 | // 必须要逐个指定 lib 配置,否则会出现部分配置不生效的情况 45 | lib: { 46 | entry: lib.entry, 47 | name: lib.name, 48 | fileName: lib.filename // 使用模板字符串 49 | }, 50 | rollupOptions: { 51 | output: { 52 | // 确保格式是 cjs 53 | format: lib.format, 54 | name: lib.name, 55 | // 指定输出目录 56 | dir: resolve(__dirname, `dist/${lib.name}`) 57 | } 58 | } 59 | } 60 | } 61 | 62 | try { 63 | console.log('Built...') 64 | await build(config) 65 | console.log(`Built library: ${lib.name}`) 66 | } catch (error) { 67 | console.error(`Error building library: ${lib.name}`, error) 68 | } 69 | }) 70 | -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/_metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "hash": "722ad9d8", 3 | "configHash": "dc8ed8b7", 4 | "lockfileHash": "68c33f29", 5 | "browserHash": "adf3aba0", 6 | "optimized": { 7 | "vue": { 8 | "src": "../../../../node_modules/.pnpm/vue@3.4.26_typescript@5.4.5/node_modules/vue/dist/vue.runtime.esm-bundler.js", 9 | "file": "vue.js", 10 | "fileHash": "90e6cd40", 11 | "needsInterop": false 12 | }, 13 | "vitepress > @vue/devtools-api": { 14 | "src": "../../../../node_modules/.pnpm/@vue+devtools-api@7.1.3_vue@3.4.26_typescript@5.4.5_/node_modules/@vue/devtools-api/dist/index.js", 15 | "file": "vitepress___@vue_devtools-api.js", 16 | "fileHash": "c906417c", 17 | "needsInterop": false 18 | }, 19 | "vitepress > @vueuse/core": { 20 | "src": "../../../../node_modules/.pnpm/@vueuse+core@10.9.0_vue@3.4.26_typescript@5.4.5_/node_modules/@vueuse/core/index.mjs", 21 | "file": "vitepress___@vueuse_core.js", 22 | "fileHash": "76c6264f", 23 | "needsInterop": false 24 | }, 25 | "vitepress > @vueuse/integrations/useFocusTrap": { 26 | "src": "../../../../node_modules/.pnpm/@vueuse+integrations@10.9.0_focus-trap@7.5.4_qrcode@1.5.3_vue@3.4.26_typescript@5.4.5_/node_modules/@vueuse/integrations/useFocusTrap.mjs", 27 | "file": "vitepress___@vueuse_integrations_useFocusTrap.js", 28 | "fileHash": "cb5f84b6", 29 | "needsInterop": false 30 | }, 31 | "vitepress > mark.js/src/vanilla.js": { 32 | "src": "../../../../node_modules/.pnpm/mark.js@8.11.1/node_modules/mark.js/src/vanilla.js", 33 | "file": "vitepress___mark__js_src_vanilla__js.js", 34 | "fileHash": "47a0542d", 35 | "needsInterop": false 36 | }, 37 | "vitepress > minisearch": { 38 | "src": "../../../../node_modules/.pnpm/minisearch@6.3.0/node_modules/minisearch/dist/es/index.js", 39 | "file": "vitepress___minisearch.js", 40 | "fileHash": "6a85b53b", 41 | "needsInterop": false 42 | } 43 | }, 44 | "chunks": { 45 | "chunk-P6MQ6B53": { 46 | "file": "chunk-P6MQ6B53.js" 47 | }, 48 | "chunk-XVMVVWGL": { 49 | "file": "chunk-XVMVVWGL.js" 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } 4 | -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/vitepress___@vueuse_core.js: -------------------------------------------------------------------------------- 1 | import { 2 | DefaultMagicKeysAliasMap, 3 | StorageSerializers, 4 | TransitionPresets, 5 | assert, 6 | breakpointsAntDesign, 7 | breakpointsBootstrapV5, 8 | breakpointsMasterCss, 9 | breakpointsPrimeFlex, 10 | breakpointsQuasar, 11 | breakpointsSematic, 12 | breakpointsTailwind, 13 | breakpointsVuetify, 14 | breakpointsVuetifyV2, 15 | breakpointsVuetifyV3, 16 | bypassFilter, 17 | camelize, 18 | clamp, 19 | cloneFnJSON, 20 | computedAsync, 21 | computedEager, 22 | computedInject, 23 | computedWithControl, 24 | containsProp, 25 | controlledRef, 26 | createEventHook, 27 | createFetch, 28 | createFilterWrapper, 29 | createGlobalState, 30 | createInjectionState, 31 | createReusableTemplate, 32 | createSharedComposable, 33 | createSingletonPromise, 34 | createTemplatePromise, 35 | createUnrefFn, 36 | customStorageEventName, 37 | debounceFilter, 38 | defaultDocument, 39 | defaultLocation, 40 | defaultNavigator, 41 | defaultWindow, 42 | directiveHooks, 43 | executeTransition, 44 | extendRef, 45 | formatDate, 46 | formatTimeAgo, 47 | get, 48 | getLifeCycleTarget, 49 | getSSRHandler, 50 | hasOwn, 51 | hyphenate, 52 | identity, 53 | increaseWithUnit, 54 | injectLocal, 55 | invoke, 56 | isClient, 57 | isDef, 58 | isDefined, 59 | isIOS, 60 | isObject, 61 | isWorker, 62 | makeDestructurable, 63 | mapGamepadToXbox360Controller, 64 | noop, 65 | normalizeDate, 66 | notNullish, 67 | now, 68 | objectEntries, 69 | objectOmit, 70 | objectPick, 71 | onClickOutside, 72 | onKeyDown, 73 | onKeyPressed, 74 | onKeyStroke, 75 | onKeyUp, 76 | onLongPress, 77 | onStartTyping, 78 | pausableFilter, 79 | promiseTimeout, 80 | provideLocal, 81 | rand, 82 | reactify, 83 | reactifyObject, 84 | reactiveComputed, 85 | reactiveOmit, 86 | reactivePick, 87 | refAutoReset, 88 | refDebounced, 89 | refDefault, 90 | refThrottled, 91 | refWithControl, 92 | resolveRef, 93 | resolveUnref, 94 | set, 95 | setSSRHandler, 96 | syncRef, 97 | syncRefs, 98 | templateRef, 99 | throttleFilter, 100 | timestamp, 101 | toReactive, 102 | toRef, 103 | toRefs, 104 | toValue, 105 | tryOnBeforeMount, 106 | tryOnBeforeUnmount, 107 | tryOnMounted, 108 | tryOnScopeDispose, 109 | tryOnUnmounted, 110 | unrefElement, 111 | until, 112 | useActiveElement, 113 | useAnimate, 114 | useArrayDifference, 115 | useArrayEvery, 116 | useArrayFilter, 117 | useArrayFind, 118 | useArrayFindIndex, 119 | useArrayFindLast, 120 | useArrayIncludes, 121 | useArrayJoin, 122 | useArrayMap, 123 | useArrayReduce, 124 | useArraySome, 125 | useArrayUnique, 126 | useAsyncQueue, 127 | useAsyncState, 128 | useBase64, 129 | useBattery, 130 | useBluetooth, 131 | useBreakpoints, 132 | useBroadcastChannel, 133 | useBrowserLocation, 134 | useCached, 135 | useClipboard, 136 | useClipboardItems, 137 | useCloned, 138 | useColorMode, 139 | useConfirmDialog, 140 | useCounter, 141 | useCssVar, 142 | useCurrentElement, 143 | useCycleList, 144 | useDark, 145 | useDateFormat, 146 | useDebounceFn, 147 | useDebouncedRefHistory, 148 | useDeviceMotion, 149 | useDeviceOrientation, 150 | useDevicePixelRatio, 151 | useDevicesList, 152 | useDisplayMedia, 153 | useDocumentVisibility, 154 | useDraggable, 155 | useDropZone, 156 | useElementBounding, 157 | useElementByPoint, 158 | useElementHover, 159 | useElementSize, 160 | useElementVisibility, 161 | useEventBus, 162 | useEventListener, 163 | useEventSource, 164 | useEyeDropper, 165 | useFavicon, 166 | useFetch, 167 | useFileDialog, 168 | useFileSystemAccess, 169 | useFocus, 170 | useFocusWithin, 171 | useFps, 172 | useFullscreen, 173 | useGamepad, 174 | useGeolocation, 175 | useIdle, 176 | useImage, 177 | useInfiniteScroll, 178 | useIntersectionObserver, 179 | useInterval, 180 | useIntervalFn, 181 | useKeyModifier, 182 | useLastChanged, 183 | useLocalStorage, 184 | useMagicKeys, 185 | useManualRefHistory, 186 | useMediaControls, 187 | useMediaQuery, 188 | useMemoize, 189 | useMemory, 190 | useMounted, 191 | useMouse, 192 | useMouseInElement, 193 | useMousePressed, 194 | useMutationObserver, 195 | useNavigatorLanguage, 196 | useNetwork, 197 | useNow, 198 | useObjectUrl, 199 | useOffsetPagination, 200 | useOnline, 201 | usePageLeave, 202 | useParallax, 203 | useParentElement, 204 | usePerformanceObserver, 205 | usePermission, 206 | usePointer, 207 | usePointerLock, 208 | usePointerSwipe, 209 | usePreferredColorScheme, 210 | usePreferredContrast, 211 | usePreferredDark, 212 | usePreferredLanguages, 213 | usePreferredReducedMotion, 214 | usePrevious, 215 | useRafFn, 216 | useRefHistory, 217 | useResizeObserver, 218 | useScreenOrientation, 219 | useScreenSafeArea, 220 | useScriptTag, 221 | useScroll, 222 | useScrollLock, 223 | useSessionStorage, 224 | useShare, 225 | useSorted, 226 | useSpeechRecognition, 227 | useSpeechSynthesis, 228 | useStepper, 229 | useStorage, 230 | useStorageAsync, 231 | useStyleTag, 232 | useSupported, 233 | useSwipe, 234 | useTemplateRefsList, 235 | useTextDirection, 236 | useTextSelection, 237 | useTextareaAutosize, 238 | useThrottleFn, 239 | useThrottledRefHistory, 240 | useTimeAgo, 241 | useTimeout, 242 | useTimeoutFn, 243 | useTimeoutPoll, 244 | useTimestamp, 245 | useTitle, 246 | useToNumber, 247 | useToString, 248 | useToggle, 249 | useTransition, 250 | useUrlSearchParams, 251 | useUserMedia, 252 | useVModel, 253 | useVModels, 254 | useVibrate, 255 | useVirtualList, 256 | useWakeLock, 257 | useWebNotification, 258 | useWebSocket, 259 | useWebWorker, 260 | useWebWorkerFn, 261 | useWindowFocus, 262 | useWindowScroll, 263 | useWindowSize, 264 | watchArray, 265 | watchAtMost, 266 | watchDebounced, 267 | watchDeep, 268 | watchIgnorable, 269 | watchImmediate, 270 | watchOnce, 271 | watchPausable, 272 | watchThrottled, 273 | watchTriggerable, 274 | watchWithFilter, 275 | whenever 276 | } from "./chunk-P6MQ6B53.js"; 277 | import "./chunk-XVMVVWGL.js"; 278 | export { 279 | DefaultMagicKeysAliasMap, 280 | StorageSerializers, 281 | TransitionPresets, 282 | assert, 283 | computedAsync as asyncComputed, 284 | refAutoReset as autoResetRef, 285 | breakpointsAntDesign, 286 | breakpointsBootstrapV5, 287 | breakpointsMasterCss, 288 | breakpointsPrimeFlex, 289 | breakpointsQuasar, 290 | breakpointsSematic, 291 | breakpointsTailwind, 292 | breakpointsVuetify, 293 | breakpointsVuetifyV2, 294 | breakpointsVuetifyV3, 295 | bypassFilter, 296 | camelize, 297 | clamp, 298 | cloneFnJSON, 299 | computedAsync, 300 | computedEager, 301 | computedInject, 302 | computedWithControl, 303 | containsProp, 304 | computedWithControl as controlledComputed, 305 | controlledRef, 306 | createEventHook, 307 | createFetch, 308 | createFilterWrapper, 309 | createGlobalState, 310 | createInjectionState, 311 | reactify as createReactiveFn, 312 | createReusableTemplate, 313 | createSharedComposable, 314 | createSingletonPromise, 315 | createTemplatePromise, 316 | createUnrefFn, 317 | customStorageEventName, 318 | debounceFilter, 319 | refDebounced as debouncedRef, 320 | watchDebounced as debouncedWatch, 321 | defaultDocument, 322 | defaultLocation, 323 | defaultNavigator, 324 | defaultWindow, 325 | directiveHooks, 326 | computedEager as eagerComputed, 327 | executeTransition, 328 | extendRef, 329 | formatDate, 330 | formatTimeAgo, 331 | get, 332 | getLifeCycleTarget, 333 | getSSRHandler, 334 | hasOwn, 335 | hyphenate, 336 | identity, 337 | watchIgnorable as ignorableWatch, 338 | increaseWithUnit, 339 | injectLocal, 340 | invoke, 341 | isClient, 342 | isDef, 343 | isDefined, 344 | isIOS, 345 | isObject, 346 | isWorker, 347 | makeDestructurable, 348 | mapGamepadToXbox360Controller, 349 | noop, 350 | normalizeDate, 351 | notNullish, 352 | now, 353 | objectEntries, 354 | objectOmit, 355 | objectPick, 356 | onClickOutside, 357 | onKeyDown, 358 | onKeyPressed, 359 | onKeyStroke, 360 | onKeyUp, 361 | onLongPress, 362 | onStartTyping, 363 | pausableFilter, 364 | watchPausable as pausableWatch, 365 | promiseTimeout, 366 | provideLocal, 367 | rand, 368 | reactify, 369 | reactifyObject, 370 | reactiveComputed, 371 | reactiveOmit, 372 | reactivePick, 373 | refAutoReset, 374 | refDebounced, 375 | refDefault, 376 | refThrottled, 377 | refWithControl, 378 | resolveRef, 379 | resolveUnref, 380 | set, 381 | setSSRHandler, 382 | syncRef, 383 | syncRefs, 384 | templateRef, 385 | throttleFilter, 386 | refThrottled as throttledRef, 387 | watchThrottled as throttledWatch, 388 | timestamp, 389 | toReactive, 390 | toRef, 391 | toRefs, 392 | toValue, 393 | tryOnBeforeMount, 394 | tryOnBeforeUnmount, 395 | tryOnMounted, 396 | tryOnScopeDispose, 397 | tryOnUnmounted, 398 | unrefElement, 399 | until, 400 | useActiveElement, 401 | useAnimate, 402 | useArrayDifference, 403 | useArrayEvery, 404 | useArrayFilter, 405 | useArrayFind, 406 | useArrayFindIndex, 407 | useArrayFindLast, 408 | useArrayIncludes, 409 | useArrayJoin, 410 | useArrayMap, 411 | useArrayReduce, 412 | useArraySome, 413 | useArrayUnique, 414 | useAsyncQueue, 415 | useAsyncState, 416 | useBase64, 417 | useBattery, 418 | useBluetooth, 419 | useBreakpoints, 420 | useBroadcastChannel, 421 | useBrowserLocation, 422 | useCached, 423 | useClipboard, 424 | useClipboardItems, 425 | useCloned, 426 | useColorMode, 427 | useConfirmDialog, 428 | useCounter, 429 | useCssVar, 430 | useCurrentElement, 431 | useCycleList, 432 | useDark, 433 | useDateFormat, 434 | refDebounced as useDebounce, 435 | useDebounceFn, 436 | useDebouncedRefHistory, 437 | useDeviceMotion, 438 | useDeviceOrientation, 439 | useDevicePixelRatio, 440 | useDevicesList, 441 | useDisplayMedia, 442 | useDocumentVisibility, 443 | useDraggable, 444 | useDropZone, 445 | useElementBounding, 446 | useElementByPoint, 447 | useElementHover, 448 | useElementSize, 449 | useElementVisibility, 450 | useEventBus, 451 | useEventListener, 452 | useEventSource, 453 | useEyeDropper, 454 | useFavicon, 455 | useFetch, 456 | useFileDialog, 457 | useFileSystemAccess, 458 | useFocus, 459 | useFocusWithin, 460 | useFps, 461 | useFullscreen, 462 | useGamepad, 463 | useGeolocation, 464 | useIdle, 465 | useImage, 466 | useInfiniteScroll, 467 | useIntersectionObserver, 468 | useInterval, 469 | useIntervalFn, 470 | useKeyModifier, 471 | useLastChanged, 472 | useLocalStorage, 473 | useMagicKeys, 474 | useManualRefHistory, 475 | useMediaControls, 476 | useMediaQuery, 477 | useMemoize, 478 | useMemory, 479 | useMounted, 480 | useMouse, 481 | useMouseInElement, 482 | useMousePressed, 483 | useMutationObserver, 484 | useNavigatorLanguage, 485 | useNetwork, 486 | useNow, 487 | useObjectUrl, 488 | useOffsetPagination, 489 | useOnline, 490 | usePageLeave, 491 | useParallax, 492 | useParentElement, 493 | usePerformanceObserver, 494 | usePermission, 495 | usePointer, 496 | usePointerLock, 497 | usePointerSwipe, 498 | usePreferredColorScheme, 499 | usePreferredContrast, 500 | usePreferredDark, 501 | usePreferredLanguages, 502 | usePreferredReducedMotion, 503 | usePrevious, 504 | useRafFn, 505 | useRefHistory, 506 | useResizeObserver, 507 | useScreenOrientation, 508 | useScreenSafeArea, 509 | useScriptTag, 510 | useScroll, 511 | useScrollLock, 512 | useSessionStorage, 513 | useShare, 514 | useSorted, 515 | useSpeechRecognition, 516 | useSpeechSynthesis, 517 | useStepper, 518 | useStorage, 519 | useStorageAsync, 520 | useStyleTag, 521 | useSupported, 522 | useSwipe, 523 | useTemplateRefsList, 524 | useTextDirection, 525 | useTextSelection, 526 | useTextareaAutosize, 527 | refThrottled as useThrottle, 528 | useThrottleFn, 529 | useThrottledRefHistory, 530 | useTimeAgo, 531 | useTimeout, 532 | useTimeoutFn, 533 | useTimeoutPoll, 534 | useTimestamp, 535 | useTitle, 536 | useToNumber, 537 | useToString, 538 | useToggle, 539 | useTransition, 540 | useUrlSearchParams, 541 | useUserMedia, 542 | useVModel, 543 | useVModels, 544 | useVibrate, 545 | useVirtualList, 546 | useWakeLock, 547 | useWebNotification, 548 | useWebSocket, 549 | useWebWorker, 550 | useWebWorkerFn, 551 | useWindowFocus, 552 | useWindowScroll, 553 | useWindowSize, 554 | watchArray, 555 | watchAtMost, 556 | watchDebounced, 557 | watchDeep, 558 | watchIgnorable, 559 | watchImmediate, 560 | watchOnce, 561 | watchPausable, 562 | watchThrottled, 563 | watchTriggerable, 564 | watchWithFilter, 565 | whenever 566 | }; 567 | //# sourceMappingURL=vitepress___@vueuse_core.js.map 568 | -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "sources": [], 4 | "sourcesContent": [], 5 | "mappings": "", 6 | "names": [] 7 | } 8 | -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/vue.js: -------------------------------------------------------------------------------- 1 | import { 2 | BaseTransition, 3 | BaseTransitionPropsValidators, 4 | Comment, 5 | DeprecationTypes, 6 | EffectScope, 7 | ErrorCodes, 8 | ErrorTypeStrings, 9 | Fragment, 10 | KeepAlive, 11 | ReactiveEffect, 12 | Static, 13 | Suspense, 14 | Teleport, 15 | Text, 16 | TrackOpTypes, 17 | Transition, 18 | TransitionGroup, 19 | TriggerOpTypes, 20 | VueElement, 21 | assertNumber, 22 | callWithAsyncErrorHandling, 23 | callWithErrorHandling, 24 | camelize, 25 | capitalize, 26 | cloneVNode, 27 | compatUtils, 28 | compile, 29 | computed, 30 | createApp, 31 | createBaseVNode, 32 | createBlock, 33 | createCommentVNode, 34 | createElementBlock, 35 | createHydrationRenderer, 36 | createPropsRestProxy, 37 | createRenderer, 38 | createSSRApp, 39 | createSlots, 40 | createStaticVNode, 41 | createTextVNode, 42 | createVNode, 43 | customRef, 44 | defineAsyncComponent, 45 | defineComponent, 46 | defineCustomElement, 47 | defineEmits, 48 | defineExpose, 49 | defineModel, 50 | defineOptions, 51 | defineProps, 52 | defineSSRCustomElement, 53 | defineSlots, 54 | devtools, 55 | effect, 56 | effectScope, 57 | getCurrentInstance, 58 | getCurrentScope, 59 | getTransitionRawChildren, 60 | guardReactiveProps, 61 | h, 62 | handleError, 63 | hasInjectionContext, 64 | hydrate, 65 | initCustomFormatter, 66 | initDirectivesForSSR, 67 | inject, 68 | isMemoSame, 69 | isProxy, 70 | isReactive, 71 | isReadonly, 72 | isRef, 73 | isRuntimeOnly, 74 | isShallow, 75 | isVNode, 76 | markRaw, 77 | mergeDefaults, 78 | mergeModels, 79 | mergeProps, 80 | nextTick, 81 | normalizeClass, 82 | normalizeProps, 83 | normalizeStyle, 84 | onActivated, 85 | onBeforeMount, 86 | onBeforeUnmount, 87 | onBeforeUpdate, 88 | onDeactivated, 89 | onErrorCaptured, 90 | onMounted, 91 | onRenderTracked, 92 | onRenderTriggered, 93 | onScopeDispose, 94 | onServerPrefetch, 95 | onUnmounted, 96 | onUpdated, 97 | openBlock, 98 | popScopeId, 99 | provide, 100 | proxyRefs, 101 | pushScopeId, 102 | queuePostFlushCb, 103 | reactive, 104 | readonly, 105 | ref, 106 | registerRuntimeCompiler, 107 | render, 108 | renderList, 109 | renderSlot, 110 | resolveComponent, 111 | resolveDirective, 112 | resolveDynamicComponent, 113 | resolveFilter, 114 | resolveTransitionHooks, 115 | setBlockTracking, 116 | setDevtoolsHook, 117 | setTransitionHooks, 118 | shallowReactive, 119 | shallowReadonly, 120 | shallowRef, 121 | ssrContextKey, 122 | ssrUtils, 123 | stop, 124 | toDisplayString, 125 | toHandlerKey, 126 | toHandlers, 127 | toRaw, 128 | toRef, 129 | toRefs, 130 | toValue, 131 | transformVNodeArgs, 132 | triggerRef, 133 | unref, 134 | useAttrs, 135 | useCssModule, 136 | useCssVars, 137 | useModel, 138 | useSSRContext, 139 | useSlots, 140 | useTransitionState, 141 | vModelCheckbox, 142 | vModelDynamic, 143 | vModelRadio, 144 | vModelSelect, 145 | vModelText, 146 | vShow, 147 | version, 148 | warn, 149 | watch, 150 | watchEffect, 151 | watchPostEffect, 152 | watchSyncEffect, 153 | withAsyncContext, 154 | withCtx, 155 | withDefaults, 156 | withDirectives, 157 | withKeys, 158 | withMemo, 159 | withModifiers, 160 | withScopeId 161 | } from "./chunk-XVMVVWGL.js"; 162 | export { 163 | BaseTransition, 164 | BaseTransitionPropsValidators, 165 | Comment, 166 | DeprecationTypes, 167 | EffectScope, 168 | ErrorCodes, 169 | ErrorTypeStrings, 170 | Fragment, 171 | KeepAlive, 172 | ReactiveEffect, 173 | Static, 174 | Suspense, 175 | Teleport, 176 | Text, 177 | TrackOpTypes, 178 | Transition, 179 | TransitionGroup, 180 | TriggerOpTypes, 181 | VueElement, 182 | assertNumber, 183 | callWithAsyncErrorHandling, 184 | callWithErrorHandling, 185 | camelize, 186 | capitalize, 187 | cloneVNode, 188 | compatUtils, 189 | compile, 190 | computed, 191 | createApp, 192 | createBlock, 193 | createCommentVNode, 194 | createElementBlock, 195 | createBaseVNode as createElementVNode, 196 | createHydrationRenderer, 197 | createPropsRestProxy, 198 | createRenderer, 199 | createSSRApp, 200 | createSlots, 201 | createStaticVNode, 202 | createTextVNode, 203 | createVNode, 204 | customRef, 205 | defineAsyncComponent, 206 | defineComponent, 207 | defineCustomElement, 208 | defineEmits, 209 | defineExpose, 210 | defineModel, 211 | defineOptions, 212 | defineProps, 213 | defineSSRCustomElement, 214 | defineSlots, 215 | devtools, 216 | effect, 217 | effectScope, 218 | getCurrentInstance, 219 | getCurrentScope, 220 | getTransitionRawChildren, 221 | guardReactiveProps, 222 | h, 223 | handleError, 224 | hasInjectionContext, 225 | hydrate, 226 | initCustomFormatter, 227 | initDirectivesForSSR, 228 | inject, 229 | isMemoSame, 230 | isProxy, 231 | isReactive, 232 | isReadonly, 233 | isRef, 234 | isRuntimeOnly, 235 | isShallow, 236 | isVNode, 237 | markRaw, 238 | mergeDefaults, 239 | mergeModels, 240 | mergeProps, 241 | nextTick, 242 | normalizeClass, 243 | normalizeProps, 244 | normalizeStyle, 245 | onActivated, 246 | onBeforeMount, 247 | onBeforeUnmount, 248 | onBeforeUpdate, 249 | onDeactivated, 250 | onErrorCaptured, 251 | onMounted, 252 | onRenderTracked, 253 | onRenderTriggered, 254 | onScopeDispose, 255 | onServerPrefetch, 256 | onUnmounted, 257 | onUpdated, 258 | openBlock, 259 | popScopeId, 260 | provide, 261 | proxyRefs, 262 | pushScopeId, 263 | queuePostFlushCb, 264 | reactive, 265 | readonly, 266 | ref, 267 | registerRuntimeCompiler, 268 | render, 269 | renderList, 270 | renderSlot, 271 | resolveComponent, 272 | resolveDirective, 273 | resolveDynamicComponent, 274 | resolveFilter, 275 | resolveTransitionHooks, 276 | setBlockTracking, 277 | setDevtoolsHook, 278 | setTransitionHooks, 279 | shallowReactive, 280 | shallowReadonly, 281 | shallowRef, 282 | ssrContextKey, 283 | ssrUtils, 284 | stop, 285 | toDisplayString, 286 | toHandlerKey, 287 | toHandlers, 288 | toRaw, 289 | toRef, 290 | toRefs, 291 | toValue, 292 | transformVNodeArgs, 293 | triggerRef, 294 | unref, 295 | useAttrs, 296 | useCssModule, 297 | useCssVars, 298 | useModel, 299 | useSSRContext, 300 | useSlots, 301 | useTransitionState, 302 | vModelCheckbox, 303 | vModelDynamic, 304 | vModelRadio, 305 | vModelSelect, 306 | vModelText, 307 | vShow, 308 | version, 309 | warn, 310 | watch, 311 | watchEffect, 312 | watchPostEffect, 313 | watchSyncEffect, 314 | withAsyncContext, 315 | withCtx, 316 | withDefaults, 317 | withDirectives, 318 | withKeys, 319 | withMemo, 320 | withModifiers, 321 | withScopeId 322 | }; 323 | //# sourceMappingURL=vue.js.map 324 | -------------------------------------------------------------------------------- /docs/.vitepress/cache/deps/vue.js.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "sources": [], 4 | "sourcesContent": [], 5 | "mappings": "", 6 | "names": [] 7 | } 8 | -------------------------------------------------------------------------------- /docs/.vitepress/config.mts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress' 2 | import nav from '../src/layout/nav' 3 | import sidebar from '../src/layout/sidebar' 4 | 5 | // https://vitepress.dev/reference/site-config 6 | export default defineConfig({ 7 | title: 'atom-tools', 8 | description: 'atom-tools', 9 | srcDir: 'src', 10 | head: [['link', { rel: 'icon', href: '/image/atom-logo.jpg' }]], 11 | themeConfig: { 12 | logo: '/image/logo.png', 13 | // https://vitepress.dev/reference/default-theme-config 14 | nav: nav, 15 | sidebar: sidebar, 16 | socialLinks: [{ icon: 'github', link: 'https://github.com/LinHanlove/atom-tools' }], 17 | search: { 18 | provider: 'local' 19 | }, 20 | lastUpdated: { 21 | text: 'Updated at', 22 | formatOptions: { 23 | dateStyle: 'full', 24 | timeStyle: 'medium' 25 | } 26 | } 27 | } 28 | }) 29 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | // .vitepress/theme/index.js 2 | import DefaultTheme from 'vitepress/theme' 3 | import '../../src/public/style/theme.css' 4 | 5 | export default DefaultTheme -------------------------------------------------------------------------------- /docs/src/components/PhoneModel.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 21 | 22 | 68 | -------------------------------------------------------------------------------- /docs/src/components/Preview.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | -------------------------------------------------------------------------------- /docs/src/contribution/index.md: -------------------------------------------------------------------------------- 1 | # 贡献指南 2 | 3 | 感谢您对 **AtomTools** 的兴趣和想要为其做出贡献的愿望!以下是参与贡献的步骤和指南。 4 | 5 | ## 报告问题 6 | 7 | 如果您发现了错误或有新功能的想法,请通过 [GitHub Issues](https://github.com/LinHanlove/atom-tools/issues) 提交。 8 | 9 | ## 贡献流程 10 | 11 | 1. **Fork 仓库**:点击项目的 GitHub 仓库主页上的 "Fork" 按钮。 12 | 2. **克隆您的仓库**:将您 Fork 的仓库克隆到本地。 13 | 14 | ```bash 15 | git clone https://github.com/your-github-username/atom-tools.git 16 | ``` 17 | 18 | 3. **创建分支**:创建一个新分支以进行更改。 19 | 20 | ```bash 21 | git checkout -b feature-name // 分支名请以feature-开头 22 | ``` 23 | 24 | 4. **进行更改**:在 `lib/` 目录下进行您的更改。 25 | 26 | 5. **测试功能**:请在`src/`目录下测试,确保您的更改符合预期,并运行测试以确保代码质量。 27 | 28 | 6. **提交更改**:将更改提交到您的分支。 29 | 30 | ```bash 31 | git commit -am "Add some feature or fix a bug" 32 | ``` 33 | 34 | 7. **推送到 GitHub**:将您的更改推送到 GitHub 上的分支 35 | 36 | 8. **发起 Pull Request**:在 GitHub 上,提交一个新的 Pull Request。 37 | 38 | 9. 拉取请求流程如下图 39 | 40 | [gitHub标准规范](https://github.com/lean-soft/devopshub-docs-g4e/blob/master/basic/07-pull-request/index.md) 41 | 42 | #### 注意点: 43 | 44 | ![拉取请求流程](../public/image/contribution.png) 45 | 46 | #### 示范: 47 | 48 | ![示范](../public/image/contribution-really.png) 49 | 50 | ## 联系我们 51 | 52 | 如果您有任何问题或建议,欢迎随时通过以下方式联系我们: 53 | 54 | - 邮箱:2188817393@qq.com 55 | - 电话:15097255355 56 | - GitHub:[讨论](https://github.com/LinHanlove/atom-tools/discussions) 57 | - 稀土掘金:https://juejin.cn/post/7362370608346677283 58 | - 微信:添加微信号 "linhan_0119" 59 | 60 |
61 | 62 | # 我们的团队 63 | 64 | 向我们优秀的团队问好 65 | 66 | 67 | 68 | 82 | -------------------------------------------------------------------------------- /docs/src/contribution/log.md: -------------------------------------------------------------------------------- 1 | 16 | 17 |
18 | 历史提交记录 19 |
20 | 21 | ::: danger 22 | 23 |
24 |

下面是关于 atom-tools 的历史提交记录,其中包含 hash 提交记录的哈希值,提交记录的描述信息,以及提交时间,点击可查看具体的提交

25 |
26 | ::: 27 |
28 |
29 | 30 |
31 |
32 | {{item.hash}} 33 | hash 34 |
35 |
36 | 37 |
38 |
39 | {{item.message}} 40 |
41 | 42 |
43 | {{item.commitTime}} 44 |
45 |
46 | 47 |
48 | 49 |
50 | 51 | 56 | -------------------------------------------------------------------------------- /docs/src/contribution/more.md: -------------------------------------------------------------------------------- 1 | --- 2 | title 3 | --- 4 | 5 | 17 | 18 |
19 | 25 | 31 | 32 |
33 |
34 | 35 |
36 |
37 | 38 |
39 | -------------------------------------------------------------------------------- /docs/src/contribution/moreDetails/CH.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 加入我们的atom工具开发之旅 3 | --- 4 | 5 | ## 探索开源,共创未来 6 | 7 | 亲爱的技术爱好者们,您好!🌟 8 | 9 | 在这个快速变化的技术世界中,我有幸投身于一个激动人心的项目——**atom工具**的开发。🛠️ 10 | 11 | ### 一个共同成长的机遇 12 | 13 | 我坚信,通过集思广益和协作,我们能够将atom工具打造成为一个不仅对我个人,而且对整个开发者社区都极具价值的开源项目。🌐 14 | 15 | **现在,我正式向您发出邀请**,加入我们的团队,一起在这个充满挑战与机遇的旅程中成长。🏗️ 16 | 17 | ### 您将获得: 18 | 19 | - **深入项目核心**:与atom工具的每一个功能亲密接触,了解其背后的奥秘。 20 | - **技能提升**:在实战中锤炼您的技术,与资深开发者并肩作战。 21 | - **社区贡献**:您的每一份努力都将直接造福广大用户,推动技术进步。 22 | - **开放协作**:在一个开放、互助的环境中,与志同道合的伙伴们一起工作。 23 | 24 | ### 我们期待这样的您: 25 | 26 | - 对技术充满热情,愿意不断学习和探索。 27 | - 拥有团队精神,相信协作的力量。 28 | - 愿意为开源事业贡献自己的力量。 29 | 30 | ### 行动起来! 31 | 32 | 如果您对此感到兴奋,请不要犹豫,立即与我们联系。📢 33 | 34 | 我们张开双臂欢迎您的加入,一起在开源的世界里留下您的足迹。👣 35 | 36 | --- 37 | 38 | 加入我们,让atom工具成为连接你我、共创辉煌的桥梁。🖌️✨ 39 | 40 | 让我们携手,为技术社区注入更多的活力和创新!🤝💡 41 | -------------------------------------------------------------------------------- /docs/src/contribution/moreDetails/EN.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Join Our Journey in Developing the Atom Tool 3 | --- 4 | 5 | ## Exploring Open Source, Shaping the Future 6 | 7 | Hello, dear tech enthusiasts! 🌟 8 | 9 | In this rapidly evolving world of technology, I have had the privilege to immerse myself in the development of an exciting project – the **Atom Tool**. 🛠️ 10 | 11 | ### An Opportunity for Mutual Growth 12 | 13 | I firmly believe that by pooling our ideas and working together, we can transform the Atom Tool into an open-source project that is valuable not only to me but to the entire developer community as well. 🌐 14 | 15 | **Now, I am extending an invitation to you** to join our team and grow together on this journey filled with challenges and opportunities. 🏗️ 16 | 17 | ### What You Will Gain: 18 | 19 | - **Dive into the Core**: Engage intimately with every feature of the Atom Tool and uncover the secrets behind them. 20 | - **Skill Enhancement**: Hone your skills in a practical setting, side by side with seasoned developers. 21 | - **Community Contribution**: Every effort you put in will directly benefit a broad audience and propel technological advancement. 22 | - **Open Collaboration**: Work in an open, supportive environment with like-minded peers. 23 | 24 | ### We Are Looking for Someone Like You: 25 | 26 | - Passionate about technology and eager to learn and explore. 27 | - Possessing a team spirit and believing in the power of collaboration. 28 | - Willing to contribute to the open-source cause. 29 | 30 | ### Take Action! 31 | 32 | If this excites you, please do not hesitate to get in touch. 📢 33 | 34 | We warmly welcome your participation and look forward to leaving your mark together in the world of open source. 👣 35 | 36 | --- 37 | 38 | Join us and let the Atom Tool become a bridge that connects us and achieves greatness. 🖌️✨ 39 | 40 | Let's work together to infuse more vitality and innovation into the tech community! 🤝💡 41 | -------------------------------------------------------------------------------- /docs/src/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # https://vitepress.dev/reference/default-theme-home-page 3 | layout: home 4 | 5 | hero: 6 | name: 'atom-tools' 7 | text: '全量的快捷工具库' 8 | tagline: A fast, powerful, and out of the box TypeScript tool library 9 | image: /image/logo.png 10 | actions: 11 | - theme: brand 12 | text: 快速开始 13 | link: /utils/guide/guide 14 | - theme: alt 15 | text: 示例 16 | link: /utils/guide/use 17 | 18 | features: 19 | - title: 🚀 Simplicity First 20 | details: Minimal setup with TypeScript project structure helps you focus on use 21 | - title: 🍃 tools 22 | details: Enjoy the dev experience of tools, use tools components in project 23 | - title: ⚡️ more 24 | details: more good,more convenient,more utils 25 | 26 | footer: MIT Licensed | Copyright © atom-to 27 | --- 28 | -------------------------------------------------------------------------------- /docs/src/layout/nav.ts: -------------------------------------------------------------------------------- 1 | export default [ 2 | { text: '贡献指南', link: '/contribution/index' }, 3 | { text: '使用', link: '/utils/guide/use' }, 4 | // { 5 | // text: '代码片段', 6 | // items: [ 7 | // { 8 | // items: [ 9 | // { text: '原生', link: '/template/root/native.md' }, 10 | // { text: 'vue', link: '/template/root/vue.md' }, 11 | // { text: '微信小程序', link: '/template/root/wxChat.md' }, 12 | // ] 13 | // } 14 | // ] 15 | // }, 16 | { 17 | text: '其他工具', 18 | items: [ 19 | { 20 | items: [ 21 | { 22 | text: 'atom-honeycomb', 23 | link: 'https://chromewebstore.google.com/detail/atom-honeycomb/fmhijekdellfaaphjifjadpdfdaffddd?hl=zh-CN&utm_source=ext_sidebar' 24 | } 25 | ] 26 | }, 27 | { 28 | items: [{ text: 'atom-draw', link: 'https://draw.atomnotion.com' }] 29 | } 30 | ] 31 | }, 32 | { text: '开放', link: '/contribution/more' } 33 | // { text: '提交记录', link: '/contribution/log' } 34 | ] 35 | -------------------------------------------------------------------------------- /docs/src/layout/sidebar.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs' 2 | import * as path from 'path' 3 | 4 | /** 5 | * 定义菜单项类型,包含是否折叠的属性 6 | */ 7 | type IMenuItem = { 8 | text: string 9 | link?: string 10 | items?: IMenuItem[] 11 | collapsed?: boolean 12 | } 13 | 14 | // 排除的文件夹名称列表 15 | const excludedFolders = ['node_modules', '.git','WeChat']; 16 | 17 | /** 18 | * 获取文件和文件夹的映射关系,并设置默认折叠状态 19 | * @param src 目录路径 20 | * @returns 菜单项数组 21 | */ 22 | const getFilesItem = (src: string): IMenuItem[] => { 23 | try { 24 | const dirent = fs.readdirSync(path.join(__dirname, src), { withFileTypes: true }); 25 | if (!dirent) { 26 | return []; // 如果无法读取目录,返回空数组 27 | } 28 | return dirent 29 | .filter((dirent) => dirent.name[0] !== '.' && !excludedFolders.includes(dirent.name)) 30 | .map((dirent) => { 31 | const itemPath = path.join(src, dirent.name); 32 | const menuItem: IMenuItem = { 33 | text: dirent.name.split('.')[0], 34 | collapsed: true, 35 | }; 36 | 37 | if (dirent.isDirectory()) { 38 | menuItem.items = getFilesItem(itemPath); // 递归获取子菜单 39 | } else { 40 | menuItem.link = `/${itemPath}`; 41 | } 42 | 43 | return menuItem; 44 | }); 45 | } catch (error) { 46 | console.error(`无法读取目录 ${src}: ${error}`); 47 | return []; // 如果发生错误,返回空数组 48 | } 49 | }; 50 | 51 | export default { 52 | // 使用递归获取的菜单项填充侧边栏结构 53 | '/utils/': [ 54 | { 55 | text: 'Guide', 56 | items: [ 57 | { 58 | text: '指南', 59 | link: '/utils/guide/guide.md' 60 | }, 61 | { 62 | text: '快速上手', 63 | link: '/utils/guide/use.md' 64 | }, 65 | { 66 | text: '目录结构', 67 | link: '/utils/guide/directory.md' 68 | } 69 | ] 70 | }, 71 | { 72 | text: 'Public', 73 | items: getFilesItem('../utils/public/') 74 | }, 75 | { 76 | text: 'Special', 77 | items: getFilesItem('../utils/special/') 78 | } 79 | ], 80 | '/template/root/vue': [ 81 | { 82 | text: 'template', 83 | items: getFilesItem('../template/vue/') 84 | } 85 | ], 86 | '/template/vue': [ 87 | { 88 | text: 'template', 89 | items: getFilesItem('../template/vue/') 90 | } 91 | ], 92 | '/template/root/wxChat': [ 93 | { 94 | text: 'template', 95 | items: getFilesItem('../template/wxChat/') 96 | } 97 | ], 98 | '/template/wxChat/': [ 99 | { 100 | text: 'template', 101 | items: getFilesItem('../template/wxChat/') 102 | }, 103 | ], 104 | '/template/root/native': [ 105 | { 106 | text: 'template', 107 | items: getFilesItem('../template/native/') 108 | } 109 | ], 110 | '/template/native/': [ 111 | { 112 | text: 'template', 113 | items: getFilesItem('../template/native/') 114 | } 115 | ] 116 | } 117 | -------------------------------------------------------------------------------- /docs/src/public/image/atom-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinHanlove/atom-module-tools/34306a90311ee64144ad897281ab511883b7fc88/docs/src/public/image/atom-logo.jpg -------------------------------------------------------------------------------- /docs/src/public/image/contribution-really.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinHanlove/atom-module-tools/34306a90311ee64144ad897281ab511883b7fc88/docs/src/public/image/contribution-really.png -------------------------------------------------------------------------------- /docs/src/public/image/contribution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinHanlove/atom-module-tools/34306a90311ee64144ad897281ab511883b7fc88/docs/src/public/image/contribution.png -------------------------------------------------------------------------------- /docs/src/public/image/creator.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinHanlove/atom-module-tools/34306a90311ee64144ad897281ab511883b7fc88/docs/src/public/image/creator.jpg -------------------------------------------------------------------------------- /docs/src/public/image/log-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinHanlove/atom-module-tools/34306a90311ee64144ad897281ab511883b7fc88/docs/src/public/image/log-image.png -------------------------------------------------------------------------------- /docs/src/public/image/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinHanlove/atom-module-tools/34306a90311ee64144ad897281ab511883b7fc88/docs/src/public/image/logo.png -------------------------------------------------------------------------------- /docs/src/public/image/logo_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinHanlove/atom-module-tools/34306a90311ee64144ad897281ab511883b7fc88/docs/src/public/image/logo_2.png -------------------------------------------------------------------------------- /docs/src/public/style/theme.css: -------------------------------------------------------------------------------- 1 | /* 该文件配置网站的文字 图标 等等 一系列dom元素的样式文件 */ 2 | @tailwind base; 3 | @tailwind components; 4 | @tailwind utilities; 5 | 6 | :root { 7 | --base-color: #008080; 8 | 9 | /* 通过配置 自定义颜色 */ 10 | --vp-home-hero-name-color: transparent; 11 | /* 主页标题文字的颜色 */ 12 | --vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe 30%, var(--base-color)); 13 | /* 主页左侧背景添加渐变光圈 */ 14 | --vp-home-hero-image-background-image: linear-gradient(25deg, #8765ba, #888bc6, #83afd1, #77d4dc); 15 | --vp-home-hero-image-filter: blur(100px); 16 | 17 | /* 主题基色 */ 18 | --vp-c-brand: #008080; 19 | /* 白色模式 主题基色 */ 20 | --vp-c-brand-light: #008080; 21 | /* 黑色模式 主题基色 */ 22 | --vp-c-brand-dark: #008080; 23 | /* 侧边栏 */ 24 | --vp-sidebar-width: 270px; 25 | /* 内容区 */ 26 | --lh-content-width: calc(100vw - 270px); 27 | 28 | /* 按钮背景颜色 */ 29 | .image-src { 30 | width: 300px; 31 | height: 300px; 32 | } 33 | 34 | ::-webkit-scrollbar { 35 | background-color: rgba(73, 177, 245, 0.2); 36 | width: 4px; 37 | height: 6px; 38 | } 39 | ::-webkit-scrollbar-thumb { 40 | background-color: var(--vp-c-brand-1); 41 | background-image: linear-gradient( 42 | 45deg, 43 | hsla(0, 0%, 100%, 0.4) 25%, 44 | transparent 0, 45 | transparent 50%, 46 | hsla(0, 0%, 100%, 0.4) 0, 47 | hsla(0, 0%, 100%, 0.4) 75%, 48 | transparent 0, 49 | transparent 50 | ); 51 | border-radius: 1em; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /docs/src/template/native/customAjax.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 封装 AJAX 请求 3 | --- 4 | 5 | # 封装 AJAX 请求 6 | 7 | ## ajaxService 8 | 9 | ## 函数式封装 10 | 11 | #### 说明 12 | `ajaxService` 函数是一个通用的 AJAX 请求封装,支持 Promise 以及可选的成功和失败回调。它简化了 AJAX 请求的创建和处理流程。 13 | 14 | #### 参数 15 | | 参数名 | 类型 | 默认值 | 说明 | 16 | | -------- | ------- | ------ | ------------------------------------ | 17 | | options | Object | {} | AJAX 请求的配置项。 | 18 | 19 | #### 返回值 20 | 无 21 | 22 | ## 代码演示 23 | 24 | ```javascript 25 | /** 26 | * 创建一个公共 AJAX 函数,支持 Promise 以及可选的成功和失败回调 27 | * @param {Object} options - AJAX 请求的配置项 28 | * @returns {Promise} - 包含请求结果的 Promise 对象 29 | */ 30 | const ajaxService = (options = {}) => { 31 | // 参数校验 32 | if (!options.url) { 33 | throw new Error('URL is required for ajax call'); 34 | } 35 | 36 | // 默认配置 37 | const defaults = { 38 | type: 'GET', 39 | dataType: 'json', 40 | async: true, 41 | data: null, // 默认没有数据 42 | success: null, // 默认没有成功回调 43 | error: null, // 默认没有失败回调 44 | }; 45 | 46 | // 合并用户配置和默认配置 47 | const settings = { ...defaults, ...options }; 48 | 49 | // 创建 XMLHttpRequest 实例 50 | const xhr = new XMLHttpRequest(); 51 | 52 | // 返回 Promise 对象 53 | return new Promise((resolve, reject) => { 54 | // 设置请求状态改变的回调函数 55 | xhr.onreadystatechange = () => { 56 | if (xhr.readyState === 4) { 57 | const { status } = xhr; 58 | if (status >= 200 && status < 300) { 59 | // 请求成功 60 | try { 61 | // 尝试解析响应数据为 JSON 62 | const data = settings.dataType === 'json' ? JSON.parse(xhr.responseText) : xhr.responseText; 63 | // 如果提供了 success 回调,执行它 64 | if (typeof settings.success === 'function') { 65 | settings.success(data); 66 | } 67 | resolve(data); 68 | } catch (err) { 69 | // 解析错误时,执行 error 回调 70 | if (typeof settings.error === 'function') { 71 | settings.error(err); 72 | } 73 | reject(new Error('Error parsing response data')); 74 | } 75 | } else { 76 | // 请求失败 77 | const error = new Error(`Request failed with status ${status}`); 78 | // 如果提供了 error 回调,执行它 79 | if (typeof settings.error === 'function') { 80 | settings.error(error); 81 | } 82 | reject(error); 83 | } 84 | } 85 | }; 86 | 87 | // 初始化请求 88 | xhr.open(settings.type.toUpperCase(), settings.url, settings.async); 89 | 90 | // 设置 Content-Type 请求头 91 | if (settings.type.toUpperCase() === 'POST' && settings.data) { 92 | xhr.setRequestHeader('Content-Type', 'application/json'); 93 | } 94 | 95 | // 发送请求 96 | xhr.send(settings.data ? JSON.stringify(settings.data) : null); 97 | }); 98 | } 99 | ``` 100 | 101 | ## 使用示例 102 | ```js 103 | ajax({ 104 | url: 'https://api.example.com/data', 105 | type: 'GET', 106 | success: (data) => { 107 | console.log('请求成功:', data); 108 | }, 109 | error: (error) => { 110 | console.error('请求失败:', error); 111 | } 112 | }); 113 | ``` 114 | 115 | ## 类方法式封装 116 | 117 | 118 | ## 代码演示 119 | ```js 120 | class AjaxService { 121 | /** 122 | * 创建 AjaxService 类的实例 123 | * @param {Object} [defaults={}] - 默认配置选项 124 | */ 125 | constructor(defaults = {}) { 126 | this.defaults = defaults; 127 | } 128 | 129 | /** 130 | * 发起 AJAX 请求 131 | * @param {Object} options - 请求配置项 132 | * @returns {Promise} - 包含请求结果的 Promise 对象 133 | */ 134 | request(options = {}) { 135 | // 参数校验 136 | if (!options.url) { 137 | throw new Error('URL is required for ajax call'); 138 | } 139 | 140 | // 合并默认配置和用户配置 141 | const settings = { ...this.defaults, ...options }; 142 | 143 | // 创建 XMLHttpRequest 实例 144 | const xhr = new XMLHttpRequest(); 145 | 146 | // 返回 Promise 对象 147 | return new Promise((resolve, reject) => { 148 | // 设置请求状态改变的回调函数 149 | xhr.onreadystatechange = () => { 150 | if (xhr.readyState === 4) { 151 | const { status } = xhr; 152 | if (status >= 200 && status < 300) { 153 | // 请求成功 154 | try { 155 | // 尝试解析响应数据为 JSON 156 | const data = settings.dataType === 'json' ? JSON.parse(xhr.responseText) : xhr.responseText; 157 | // 如果提供了 success 回调,执行它 158 | if (typeof settings.success === 'function') { 159 | settings.success(data); 160 | } 161 | resolve(data); 162 | } catch (err) { 163 | // 解析错误时,执行 error 回调 164 | if (typeof settings.error === 'function') { 165 | settings.error(err); 166 | } 167 | reject(new Error('Error parsing response data')); 168 | } 169 | } else { 170 | // 请求失败 171 | const error = new Error(`Request failed with status ${status}`); 172 | // 如果提供了 error 回调,执行它 173 | if (typeof settings.error === 'function') { 174 | settings.error(error); 175 | } 176 | reject(error); 177 | } 178 | } 179 | }; 180 | 181 | // 初始化请求 182 | xhr.open(settings.type.toUpperCase(), settings.url, settings.async); 183 | 184 | // 设置 Content-Type 请求头 185 | if (settings.type.toUpperCase() === 'POST' && settings.data) { 186 | xhr.setRequestHeader('Content-Type', 'application/json'); 187 | } 188 | 189 | // 发送请求 190 | xhr.send(settings.data ? JSON.stringify(settings.data) : null); 191 | }); 192 | } 193 | } 194 | 195 | ``` 196 | 197 | ## 使用示例 198 | ```js 199 | const ajaxService = new AjaxService({ 200 | type: 'GET', 201 | dataType: 'json', 202 | async: true, 203 | }); 204 | 205 | ajaxService.request({ 206 | url: 'https://api.example.com/data', 207 | success: (data) => { 208 | console.log('请求成功:', data); 209 | }, 210 | error: (error) => { 211 | console.error('请求失败:', error); 212 | } 213 | }) 214 | .then(response => { 215 | // 处理响应 216 | }) 217 | .catch(error => { 218 | // 处理错误 219 | }); 220 | ``` 221 | 222 | 注意:本章节内容仅供参考,实际开发中请根据具体项目需求和上下文环境进行适配和调整。 -------------------------------------------------------------------------------- /docs/src/template/root/native.md: -------------------------------------------------------------------------------- 1 | # 关于本章 2 | :::warning 3 | :tada: 原生 JavaScript 代码封装指南 4 | 5 | 在本章节中,我们汇集了一系列原生 JavaScript 开发中常用的代码封装思路,特别是针对 AJAX 请求、DOM 操作、事件处理等常见功能。这些封装旨在帮助开发者提高代码复用性、增强代码的可维护性,并简化日常开发任务。 6 | 7 | ::: 8 | 9 | ## 实现思路 10 | 在封装原生 JavaScript 代码时,我们不仅关注功能的实现,还注重代码的可读性和可扩展性。通过将通用逻辑抽象成函数或模块,我们能够减少代码冗余,提高开发效率。 11 | 12 | ## 快速定位与复用 13 | 每个封装函数都配有清晰的注释和使用说明,使得开发者能够快速理解其用途和工作机制,并在需要时快速复用。 14 | 15 | 注意:本章节内容仅供参考,实际开发中请根据具体项目需求和上下文环境进行适配和调整。 -------------------------------------------------------------------------------- /docs/src/template/root/vue.md: -------------------------------------------------------------------------------- 1 | # 关于本章 2 | 3 | :::warning 4 | :tada: Vue组件开发指南 5 | 6 | 在本章节中,我们汇集了一系列Vue.js开发中常用的组件、函数和方法的封装思路。这些代码片段专为解决日常开发中遇到的常见问题而设计,旨在帮助开发者快速定位问题、解决问题,甚至直接复用代码以提升开发效率。 7 | 8 | ::: 9 | 10 | ## 组件封装 11 | 12 | 我们提供了多种Vue组件的封装示例,涵盖了从表单输入到高级列表展示等各种场景。这些封装不仅注重功能性,还兼顾了代码的可读性和可维护性。 13 | 14 | ## 函数与方法 15 | 16 | 针对状态管理、API交互、DOM操作等关键开发环节,我们精选了一些实用的函数和方法。这些代码片段能够帮助开发者在面对类似问题时,迅速找到解决方案。 17 | 18 | ## 实现思路 19 | 20 | 除了具体的代码实现,我们还分享了解决问题的思路和策略。理解这些思路有助于开发者在遇到新问题时,能够灵活运用已有知识,创造性地解决问题。 21 | 22 | ## 快速定位与复用 23 | 24 | 每个代码片段都配有详细的说明和适用场景描述,使得开发者能够快速定位到所需的功能代码,并实现代码的快速复制和复用。 25 | 26 | 注意:本章节内容仅供参考,实际开发中请根据具体项目需求和上下文环境进行适配和调整。 27 | -------------------------------------------------------------------------------- /docs/src/template/root/wxChat.md: -------------------------------------------------------------------------------- 1 | # 关于本章 2 | 3 | :::danger 4 | :tada: 实用代码片段集锦 5 | 6 | 在本章节中,我们精心整理了一系列在日常微信小程序开发中常用的组件、函数和方法的封装思路。这些代码片段是针对常见需求设计的,旨在帮助开发者快速定位问题、解决问题,甚至直接复用代码以提高开发效率。 7 | 8 | ::: 9 | 10 | ## 组件封装 11 | 12 | 我们提供了多种组件的封装示例,包括但不限于自定义键盘和标签页切换组件。这些封装不仅关注功能性,还注重代码的可读性和可维护性。 13 | 14 | ## 函数与方法 15 | 16 | 针对数据处理、网络请求、用户界面交互等关键环节,我们总结了一些实用的函数和方法。这些代码片段能够帮助开发者在面对类似问题时,迅速找到解决方案。 17 | 18 | ## 实现思路 19 | 20 | 除了具体的代码实现,我们还分享了解决问题的思路和策略。理解这些思路有助于开发者在遇到新问题时,能够灵活运用已有知识,创造性地解决问题。 21 | 22 | ## 快速定位与复用 23 | 24 | 每个代码片段都配有清晰的说明和使用场景描述,使得开发者能够快速定位到所需的功能代码,实现代码的快速复制和复用。 25 | 26 | > **注意**:本章节内容仅供参考,实际开发中请根据具体项目需求和上下文环境进行适配和调整。 27 | -------------------------------------------------------------------------------- /docs/src/template/vue/customAxios.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinHanlove/atom-module-tools/34306a90311ee64144ad897281ab511883b7fc88/docs/src/template/vue/customAxios.md -------------------------------------------------------------------------------- /docs/src/template/wxChat/customKeyboard.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinHanlove/atom-module-tools/34306a90311ee64144ad897281ab511883b7fc88/docs/src/template/wxChat/customKeyboard.md -------------------------------------------------------------------------------- /docs/src/utils/guide/directory.md: -------------------------------------------------------------------------------- 1 | > [!WARNING] 2 | > 该目录适用于0.5.6版本及之前的版本,后续迭代会陆陆续续完善添加其余功能,具体请以实际为准。 3 | 4 | ## 目录结构 5 | 6 | ``` 7 | atom-tools 8 | 9 | ├──Guide // 文档指南 10 | ├──Public // 公共工具函数 11 | │ ├──Array // 数组 12 | │ ├──Browser // web浏览器 13 | │ ├──FormatDate // 格式化日期 14 | │ ├──HighOrderFunction // 高阶函数 15 | │ ├──Number // 数字 16 | │ ├──Object // 对象 17 | │ ├──String // 字符串 18 | │ ├──TypeCheck // 类型校验 19 | └──Special // 特殊模块 20 | ├──vue // 针对vue 21 | └──WeChat // 针对微信小程序 22 | 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/src/utils/guide/guide.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | atom-tools logo 4 | 5 |

6 |
7 |

8 | npm package 9 |

10 |
11 | 12 | # AtomTools 13 | 14 | ## 极速、强大、开箱即用的 TypeScript 工具库 15 | 16 | ### 简介 17 | 18 | 🌟 **AtomTools** 是一个现代、基于 TypeScript 的 JavaScript 工具库,旨在提供项目开发中不可或缺的实用工具函数。通过简单的导入语句,您可以快速地将这些工具函数集成到您的项目中,无需任何复杂配置。 19 | 20 | ### 选择 AtomTools 的理由 21 | 22 | 在传统的业务项目开发中,开发者经常面临编写大量重复的函数、类型定义和常量的需求。这些代码往往需要在不同项目间移植和重用,导致效率低下。 23 | 24 | **AtomTools** 的设计初衷是提供一个高效、便捷的解决方案,帮助开发人员轻松管理和使用这些常用的编程元素。使用 AtomTools,您将能够简化开发流程,更专注于核心业务逻辑的实现。 25 | 26 | ### 特性亮点 27 | 28 | - 🌈 **全面兼容**:完美兼容任何使用 JavaScript 或 TypeScript 开发的项目,包括微信小程序。 29 | - 🚀 **极速体验**:提升开发速度,让编程更快捷、更高效。 30 | - 📠 **类型安全**:完全采用 TypeScript 编写,提供精确的类型提示,增强代码健壮性。 31 | - 🍃 **轻量设计**:注重性能和实用性,无冗余依赖,保持库的轻量化。 32 | - 📦 **即装即用**:安装后即可立即投入使用,无需复杂配置。 33 | 34 | ## 开发者社区 35 | 36 | 寻找志同道合的朋友一起参与 **AtomTools** 的开发。如果你对 TypeScript、JavaScript 工具库开发充满热情,欢迎加入我们,共同打造一个更加强大、易用的编程工具集。 37 | 38 | ## 未来规划 39 | 40 | - Vue 自定义指令:提供众多开箱即用的 Vue 自定义指令,简化 Vue 应用开发。 41 | - 组件封装:计划添加更多常用组件的封装,提升开发效率和用户体验。 42 | - 代码片段集合:集成一系列常用代码片段,帮助开发者快速解决特定问题。 43 | 44 | **AtomTools** 致力于成为一个全方位的前端开发工具库,帮助开发者提升生产力,实现更优雅的编程体验。加入我们,一起构建未来! 45 | -------------------------------------------------------------------------------- /docs/src/utils/guide/use.md: -------------------------------------------------------------------------------- 1 | > [!WARNING] 2 | > 使用前须知: 3 | > 使用atom-tools之前,请确保你已熟练使用TypeScript( **以下简称ts**), 并且了解 **ts** 中的 **type**, **interface**, **enum**, **class**, **namespace**, **module**, **import**, **export** 等关键字。 4 | 5 | ## 快速上手 6 | 7 | ## 安装 8 | 9 | ### 安装 10 | 11 | 通过 NPM、YARN 或 PNPM 安装 **atom-tools**。 12 | 13 | ::: code-group 14 | 15 | ```js [npm] 16 | npm install atom-tools 17 | ``` 18 | 19 | ```js [pnpm] 20 | pnpm add atom-tools 21 | 22 | ``` 23 | 24 | ```js [yarn] 25 | yarn add atom-tools 26 | 27 | ``` 28 | 29 | ::: 30 | 31 | ## 示例 32 | 33 | 推荐按需导入使用 atom-tools。 34 | 35 | --- 36 | 37 | ::: code-group 38 | 39 | ```ts [工具] 40 | import { pick } from 'atom-tools' 41 | 42 | interface Person { 43 | name: string 44 | age: number 45 | email: string 46 | } 47 | 48 | const person = { 49 | name: 'John Doe', 50 | age: 30, 51 | email: 'john.doe@example.com' 52 | } 53 | 54 | // 使用 pick 函数筛选出 'name' 和 'age' 属性 55 | const selectedFields = pick(person, ['name', 'age']) 56 | console.log(selectedFields) // 输出:{ name: 'John Doe', age: 30 } 57 | ``` 58 | 59 | ```vue [vue自定义指令] 60 | 63 | 64 | 78 | ``` 79 | 80 | ::: 81 | -------------------------------------------------------------------------------- /docs/src/utils/public/Array/arraySortByKey.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 数组对象排序 3 | --- 4 | 5 | # 数组对象排序 6 | 7 | ### arraySortByKey 8 | 9 | ## 说明 10 | 11 | `arraySortByKey` 函数接受一个对象数组和一个键名,然后根据该键名对应的属性值对数组进行排序。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ------ | ---------------------- | ----------------- | ------ | 17 | | params | 包含数组和键的参数对象 | `IArraySortByKey` | --- | 18 | 19 | ## 参数类型 20 | 21 | ```ts 22 | interface IArraySortByKey { 23 | /** 需要排序的数组,其中每个元素都是一个对象 */ 24 | array: object[] 25 | /** 用于排序的数组元素的键 */ 26 | key: string 27 | } 28 | ``` 29 | 30 | ## 返回值 31 | 32 | `排序后的数组` 33 | 34 | ## 代码演示 35 | 36 | ### 基础用法 37 | 38 | ```ts 39 | import { arraySortByKey } from '@/utils/Array' 40 | 41 | const list = [ 42 | { name: '张三', age: 18 }, 43 | { name: '李四', age: 22 }, 44 | { name: '王五', age: 15 } 45 | ] 46 | 47 | const result = arraySortByKey({ 48 | array: list, 49 | key: age 50 | }) 51 | 52 | console.log(result) 53 | // 输出:[ 54 | // { name: '王五', age: 15 }, 55 | // { name: '张三', age: 18 }, 56 | // { name: '李四', age: 22 }, 57 | // ] 58 | ``` 59 | -------------------------------------------------------------------------------- /docs/src/utils/public/Array/fuzzyMatchByProperty.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 模糊匹配 3 | --- 4 | 5 | # 模糊匹配 6 | 7 | ### fuzzyMatchByProperty 8 | 9 | ## 说明 10 | 11 | `fuzzyMatchByProperty` 函数用于在给定的对象数组中,根据指定属性进行模糊匹配。它将返回与搜索关键词最匹配的对象。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ------ | ------------------ | ----------------------- | ------ | 17 | | params | 包含搜索参数的对象 | `IFuzzyMatchByProperty` | --- | 18 | 19 | ## 参数类型 20 | 21 | ```ts 22 | interface IFuzzyMatchByProperty { 23 | /** 要进行模糊匹配的对象数组 */ 24 | array: object[] 25 | /** 要匹配的属性名 */ 26 | prop: string 27 | /** 用户输入的搜索关键词 */ 28 | key: string 29 | /** (可选)匹配成功后的回调函数 */ 30 | callback?: () => void 31 | } 32 | ``` 33 | 34 | ## 返回值 35 | 36 | `匹配到的对象` 37 | 38 | ## 代码演示 39 | 40 | ### 基础用法 41 | 42 | ```ts 43 | import { fuzzyMatchByProperty } from '@/utils/Array' 44 | 45 | const params = { 46 | prop: 'name', 47 | key: '张三', 48 | list: [ 49 | { name: '张三', age: 18 }, 50 | { name: '李四', age: 20 }, 51 | { name: '王五', age: 22 } 52 | ] 53 | } 54 | 55 | const result = fuzzyMatchByProperty(params) 56 | 57 | console.log(result) // 输出:{ name: '张三', age: 18 } 58 | ``` 59 | -------------------------------------------------------------------------------- /docs/src/utils/public/Array/uniqueByProperty.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 根据指定属性去重数组 3 | --- 4 | 5 | # 根据指定属性去重数组 6 | 7 | ### uniqueByProperty 8 | 9 | ## 说明 10 | 11 | `uniqueByProperty` 函数接收一个数组和一个属性键,然后根据该属性键的值对数组进行去重处理,返回一个新的去重后的数组。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ------ | ------------------ | ------------------- | ------ | 17 | | option | 包含去重参数的对象 | `IUniqueByProperty` | --- | 18 | 19 | ## 参数类型 20 | 21 | ```ts 22 | interface IUniqueByProperty { 23 | /** 需要去重的数组,其中每个元素都是一个对象 */ 24 | array: object[] 25 | /** 用于去重的数组元素的键 */ 26 | key: string 27 | /** (可选)去重完成后的回调函数 */ 28 | callback?: (uniqueArray: object[]) => void 29 | } 30 | ``` 31 | 32 | ## 返回值 33 | 34 | `去重后的数组` 35 | 36 | ## 代码演示 37 | 38 | ### 基础用法 39 | 40 | ```ts 41 | import { uniqueByProperty } from 'atom-tools' 42 | 43 | const list = [ 44 | { id: 1, name: '张三' }, 45 | { id: 2, name: '李四' }, 46 | { id: 1, name: '张三' }, 47 | { id: 3, name: '王五' } 48 | ] 49 | 50 | const result = uniqueByProperty({ 51 | prop: 'id', 52 | list 53 | }) 54 | 55 | console.log(result) 56 | // 输出:[ 57 | // { id: 1, name: '张三' }, 58 | // { id: 2, name: '李四' }, 59 | // { id: 3, name: '王五' }, 60 | // ] 61 | ``` 62 | -------------------------------------------------------------------------------- /docs/src/utils/public/Browser/browseRownership.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 浏览器归属 3 | --- 4 | 5 | # 浏览器归属 6 | 7 | ## 说明 8 | 9 | 以下是一些用于判断当前浏览器类型的常用函数,返回布尔值 10 | 11 | 12 | ## 函数列表 13 | 14 | | 名称 | 说明 | 返回值 | 15 | | ------------------ | -------------------------------------- | -------- | 16 | | isWxBrowser | 判断当前浏览器是否为微信浏览器 | `boolean`| 17 | | isAliBrowser | 判断当前浏览器是否为支付宝浏览器 | `boolean`| 18 | | isDouyinBrowser | 判断当前浏览器是否为抖音客户端浏览器 | `boolean`| 19 | | isDouyinLiteBrowser| 判断当前浏览器是否为抖音极速版客户端浏览器 | `boolean`| 20 | | isQqBrowser | 判断当前浏览器是否为QQ浏览器 | `boolean`| 21 | | isBaiduBrowser | 判断当前浏览器是否为百度浏览器 | `boolean`| 22 | | isSafariBrowser | 判断当前浏览器是否为Safari浏览器 | `boolean`| 23 | | isUcBrowser | 判断当前浏览器是否为UC浏览器 | `boolean`| 24 | | is360Browser | 判断当前浏览器是否为360浏览器 | `boolean`| 25 | | isSogouBrowser | 判断当前浏览器是否为搜狗浏览器 | `boolean`| 26 | 27 | ## 示例代码 28 | 29 | ### 判断是否为微信浏览器 30 | 31 | ```javascript 32 | import { isWxBrowser } from 'atom-tools'; 33 | 34 | if (isWxBrowser()) { 35 | console.log('当前是微信浏览器'); 36 | } else { 37 | console.log('当前不是微信浏览器'); 38 | } 39 | ``` -------------------------------------------------------------------------------- /docs/src/utils/public/Browser/clearAllCookie.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 清除所有Cookie 3 | --- 4 | 5 | # 清除所有Cookie 6 | 7 | ### clearAllCookie 8 | 9 | ## 说明 10 | 11 | `clearAllCookie` 函数用于清除当前浏览器中的 cookie。如果提供了参数,它将只清除指定名称的 cookie;如果没有提供参数,它将清除当前域名下的所有 cookie。 12 | 13 | ## 参数 14 | 15 | | 参数名 | 类型 | 默认值 | 说明 | 16 | | ------ | -------- | ----------- | ---------------------------- | 17 | | name | `string` | `undefined` | 可选。要清除的 cookie 名称。 | 18 | 19 | ## 返回值 20 | 21 | `无` 22 | 23 | ## 代码演示 24 | 25 | ### 清除特定 cookie 26 | 27 | ```javascript 28 | import { clearAllCookie } from 'atom-tools' 29 | 30 | // 清除名为 'myCookie' 的 cookie 31 | clearAllCookie('myCookie') 32 | ``` 33 | 34 | ### 清除当前域名下的所有 cookie 35 | 36 | ```javascript 37 | import { clearAllCookie } from 'atom-tools' 38 | 39 | // 清除当前域名下的所有 cookie 40 | clearAllCookie() 41 | ``` 42 | 43 | ` 44 | -------------------------------------------------------------------------------- /docs/src/utils/public/Browser/copyText.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 一键复制到剪切板 3 | --- 4 | 5 | # 一键复制到剪切板 6 | 7 | ### copyText 8 | 9 | ## 说明 10 | 11 | `copyText` 函数用于将指定的文本内容复制到剪切板,方便用户粘贴使用。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ----- | ---------------- | -------- | ------ | 17 | | value | 要复制的文本内容 | `string` | --- | 18 | 19 | ## 返回值 20 | 21 | `string` 22 | 23 | ## 代码演示 24 | 25 | ### 基础用法 26 | 27 | ```ts 28 | import { copyText } from 'atom-tools' 29 | 30 | // 按钮点击事件 31 | const clickBtn = () => { 32 | copyText('这是一段文字') 33 | } 34 | ``` 35 | 36 | ### 复制成功提示 37 | 38 | ```ts 39 | import { copyText } from 'atom-tools' 40 | 41 | // 按钮点击事件 42 | const clickBtn = () => { 43 | copyText('这是一段文字').then((res) => { 44 | console.log(res) 45 | }) 46 | } 47 | ``` 48 | -------------------------------------------------------------------------------- /docs/src/utils/public/Browser/exitFullScreen.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 退出浏览器全屏 3 | --- 4 | 5 | # 退出浏览器全屏 6 | 7 | ### exitFullScreen 8 | 9 | ## 说明 10 | 11 | `exitFullScreen` 函数提供了一个统一的接口来退出浏览器的全屏模式,它自动适配各种浏览器的全屏API,使得退出全屏操作在不同浏览器上能够保持一致。 12 | 13 | ## 返回值 14 | 15 | `void` 16 | 17 | ## 代码演示 18 | 19 | ### 基础用法 20 | 21 | ```ts 22 | import { exitFullScreen } from 'atom-tools' 23 | 24 | const clickExitFullScreen = () => { 25 | return exitFullScreen() 26 | } 27 | ``` 28 | -------------------------------------------------------------------------------- /docs/src/utils/public/Browser/getUrlParams.md: -------------------------------------------------------------------------------- 1 | # 解析 URL 地址参数 2 | 3 | ### getUrlParams 4 | 5 | ## 说明 6 | 7 | `getUrlParams` 函数用于解析 URL 地址中的查询参数,并将它们转换为一个键值对对象。 8 | 9 | ## 参数 10 | 11 | | 参数 | 说明 | 类型 | 默认值 | 12 | | ---- | ------------------- | -------- | ------ | 13 | | url | 需要解析的 URL 地址 | `string` | --- | 14 | 15 | ## 返回值 16 | 17 | `object` - 一个对象,其属性为 URL 查询参数的名称和对应的值。 18 | 19 | ## 代码演示 20 | 21 | ### 基础用法 22 | 23 | ```ts 24 | import { getUrlParams } from 'atom-tools' 25 | 26 | // url地址 27 | const url = 'https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=49055317_48_hao_pg&wd=atom-tools' 28 | 29 | // 传入url地址 30 | const result = getUrlParams(url) 31 | 32 | console.log(result) 33 | // 输出:{ 34 | // ie: 'utf-8', 35 | // f: '8', 36 | // rsv_bp: '1', 37 | // tn: '49055317_48_hao_pg', 38 | // wd: 'atom-tools' 39 | // } 40 | ``` 41 | -------------------------------------------------------------------------------- /docs/src/utils/public/Browser/log.md: -------------------------------------------------------------------------------- 1 | # prettyLog 日志工具库 2 | 3 | `prettyLog` 提供了一种简洁的方式来打印不同级别的日志信息,包括信息、错误、警告和成功。每种日志级别都有其对应的颜色和标题,以便在控制台中快速区分。 4 | 5 | ## 功能列表 6 | 7 | - **info**: 打印信息类型的日志。 8 | - **error**: 打印错误类型的日志。 9 | - **warning**: 打印警告类型的日志。 10 | - **success**: 打印成功类型的日志。 11 | 12 | ## 使用方法 13 | 14 | ### 导入 prettyLog 15 | 16 | ```javascript 17 | import { log } from 'atom-tools' 18 | ``` 19 | 20 | ### 调用日志方法 21 | 22 | ```javascript 23 | log.info('这是一条信息日志') 24 | log.error('这是一条错误日志') 25 | log.warning('这是一条警告日志') 26 | log.success('这是一条成功日志') 27 | ``` 28 | 29 | ### 打印带有多个参数的日志 30 | 31 | ```javascript 32 | // 打印带有多个参数的日志 33 | log.info('打印信息', 'atom', 'tools') 34 | log.error('打印错误', 'atom', 'tools') 35 | log.warning('打印警告', 'atom', 'tools') 36 | log.success('打印成功', 'atom', 'tools') 37 | ``` 38 | 39 | `prettyLog` 支持打印带有多个参数的日志。当传入的参数中包含`引用类型`时,`prettyLog` 将自动输出一个带主题颜色的`标题`,`指示参数类型`,并详细列出`参数内容`。 40 | 41 | ```javascript 42 | // 打印带有多个含有引用类型参数的日志 43 | log.success('打印成功', e, ['atom', 'tools']) 44 | log.success('打印成功', { 45 | name: 'atom', 46 | type: 'tools' 47 | }) 48 | log.success('打印成功', () => { 49 | console.log('123') 50 | }) 51 | ``` 52 | 53 | ## 示例快照 54 | 55 | ![快照](/image/log-image.png) 56 | -------------------------------------------------------------------------------- /docs/src/utils/public/Browser/preventRightKey.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 禁止右键 3 | --- 4 | 5 | # 禁止右键 6 | 7 | ### preventRightKey 8 | 9 | ## 说明 10 | 11 | `preventRightKey` 函数用于禁用浏览器中通过鼠标右键触发的所有事件,如打开上下文菜单、选择文本、复制等操作。 12 | 13 | ## 返回值 14 | 15 | `void` 16 | 17 | ## 代码演示 18 | 19 | ### 基础用法 20 | 21 | ```ts 22 | import { preventRightKey } from 'atom-tools' 23 | 24 | const prevent = () => { 25 | // 可以右键,5s后禁止右键 26 | setTimeout(() => { 27 | preventRightKey() 28 | }, 5000) 29 | } 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/src/utils/public/Browser/randomHexColor.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 随机 HEX 颜色 3 | --- 4 | 5 | # 随机 HEX 颜色 6 | 7 | ### randomHexColor 8 | 9 | ## 说明 10 | 11 | `randomHexColor` 函数用于生成一个随机的十六进制颜色值。 12 | 13 | ## 返回值 14 | 15 | `string` - 返回一个随机的十六进制颜色字符串,例如 `#ddf900`。 16 | 17 | ## 代码演示 18 | 19 | ### 基础用法 20 | 21 | ```ts 22 | import { randomHexColor } from 'atom-tools' 23 | 24 | const result = randomHexColor() 25 | 26 | console.log(result) // 输出随机HEX颜色 #ddf900 27 | ``` 28 | -------------------------------------------------------------------------------- /docs/src/utils/public/Browser/removeElementMark.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 去掉标签字符串中的元素标记 3 | --- 4 | 5 | # 去掉标签字符串中的元素标记 6 | 7 | ### removeElementMark 8 | 9 | ## 说明 10 | 11 | `removeElementMark` 函数用于移除传入的标签字符串中的所有HTML元素标记,只保留纯文本内容。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ---- | -------------------- | -------- | ------ | 17 | | str | 包含HTML标签的字符串 | `String` | --- | 18 | 19 | ## 返回值 20 | 21 | `string` - 返回去除HTML元素标记后的纯文本字符串。 22 | 23 | ## 代码演示 24 | 25 | ### 基础用法 26 | 27 | ```ts 28 | import { removeElementMark } from 'atom-tools' 29 | 30 | const str = '

hello world

' 31 | 32 | const result = removeElementMark(str) 33 | 34 | console.log(result) // 输出:hello world 35 | ``` 36 | -------------------------------------------------------------------------------- /docs/src/utils/public/Browser/rgbGray.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 颜色灰度化 3 | --- 4 | 5 | # 颜色灰度化 6 | 7 | ### rgbGray 8 | 9 | ## 说明 10 | 11 | `rgbGray` 函数根据光感加权平均值将 RGB 颜色转换为灰度值。该函数接受一个 RGB 颜色值,可以是字符串形式或数字数组形式,并返回一个介于 0-255 之间的数值,该数值可以用于创建一个灰度化的 RGB 颜色。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ---- | --------------------- | --------------------- | ------ | 17 | | rgb | 要灰度化的 RGB 颜色值 | `String` / `String[]` | --- | 18 | 19 | ## 返回值 20 | 21 | `number` - 返回一个表示灰度化颜色的数值。 22 | 23 | ## 代码演示 24 | 25 | ### 基础用法 26 | 27 | ```ts 28 | import { rgbGray } from 'atom-tools' 29 | 30 | // 传入字符串 31 | const result = rgbGray('96, 77, 77') // 输出:81.0394 32 | 33 | // 传入数组 34 | const result2 = rgbGray(['96', '96', '96']) // 输出:81.0394 35 | 36 | // 得到灰度化后的颜色 37 | const newRbgGray = rbg(result, result, result) // 输出:rbg(81.0394, 81.0394, 81.0394) 38 | ``` 39 | -------------------------------------------------------------------------------- /docs/src/utils/public/Browser/toFullScreen.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 浏览器全屏 3 | --- 4 | 5 | # 浏览器全屏 6 | 7 | ### toFullScreen 8 | 9 | ## 说明 10 | 11 | `toFullScreen` 函数提供了一个统一的接口来触发浏览器进入全屏模式。它自动适配各种浏览器的全屏API,使得全屏操作在不同浏览器上能够保持一致。 12 | 13 | ## 返回值 14 | 15 | `void` 16 | 17 | ## 代码演示 18 | 19 | ### 基础用法 20 | 21 | ```ts 22 | import { toFullScreen } from 'atom-tools' 23 | 24 | const clickFullScreen = () => { 25 | return toFullScreen() 26 | } 27 | ``` 28 | -------------------------------------------------------------------------------- /docs/src/utils/public/File/canvasToFile.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: canvasToFile 3 | --- 4 | 5 | # 画布转文件函数 6 | 7 | ### canvasToFile 8 | 9 | ## 说明 10 | 11 | `canvasToFile` 函数用于将画布元素转换为一个文件对象。它返回一个`Promise`对象,该对象在转换成功后解决(resolve)为文件对象。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ------ | ------------ | -------- | ----------- | 17 | | canvas | 画布元素 | `HTMLCanvasElement` | - | 18 | | type | 文件的MIME类型 | `string` | - | 19 | | quality | 文件质量(0-100) | `number` | - | 20 | 21 | ## 返回值 22 | 23 | `Promise` 24 | 25 | ## 代码演示 26 | 27 | ### 基础用法 28 | 29 | ```typescript 30 | import { canvasToFile } from 'atom-tools' 31 | 32 | async function convertCanvasToFile() { 33 | const canvas = document.getElementById('myCanvas') as HTMLCanvasElement 34 | const file = await canvasToFile(canvas, 'image/png', 90) 35 | console.log(file) 36 | } 37 | 38 | convertCanvasToFile() 39 | ``` -------------------------------------------------------------------------------- /docs/src/utils/public/File/convertQualityToBit.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: convertQualityToBit 3 | --- 4 | 5 | # 质量转比特率函数 6 | 7 | ### convertQualityToBit 8 | 9 | ## 说明 10 | 11 | `convertQualityToBit` 函数用于将质量值(0-100)转换为比特率(0-256)。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 16 | | ------ | -------- | -------- | 17 | | quality | 质量值(0-100) | `number` | 18 | 19 | ## 返回值 20 | 21 | `number` - 对应的比特率值(0-256)。 22 | 23 | ## 代码演示 24 | 25 | ### 基础用法 26 | 27 | ```typescript 28 | import { convertQualityToBit } from 'atom-tools' 29 | 30 | const bitRate = convertQualityToBit(90) 31 | console.log(bitRate) // 输出: 230 32 | ``` -------------------------------------------------------------------------------- /docs/src/utils/public/File/createFileFromBlob.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: createFileFromBlob 3 | --- 4 | 5 | # 从Blob创建文件函数 6 | 7 | ### createFileFromBlob 8 | 9 | ## 说明 10 | 11 | `createFileFromBlob` 函数用于从给定的Blob和文件名创建一个新的文件对象。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 16 | | ------ | -------- | -------- | 17 | | blob | Blob对象 | `Blob` | 18 | | filename | 文件名 | `string` | 19 | 20 | ## 返回值 21 | 22 | `File` - 新创建的文件对象。 23 | 24 | ## 代码演示 25 | 26 | ### 基础用法 27 | 28 | ```typescript 29 | import { createFileFromBlob } from 'atom-tools' 30 | 31 | const blob = new Blob(['Hello, world!'], { type: 'text/plain' }) 32 | const file = createFileFromBlob(blob, 'hello.txt') 33 | console.log(file) 34 | ``` -------------------------------------------------------------------------------- /docs/src/utils/public/File/dataURLToImage.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: dataURLToImage 3 | --- 4 | 5 | # 数据URL转图像函数 6 | 7 | ### dataURLToImage 8 | 9 | ## 说明 10 | 11 | `dataURLToImage` 函数用于将数据URL字符串转换为一个图像元素(`HTMLImageElement`)。它返回一个`Promise`对象,该对象在图像加载成功后解决(resolve)为图像元素。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 16 | | ------ | -------- | -------- | 17 | | dataURL | 数据URL字符串 | `string` | 18 | 19 | ## 返回值 20 | 21 | `Promise` 22 | 23 | ## 代码演示 24 | 25 | ### 基础用法 26 | 27 | ```typescript 28 | import { dataURLToImage } from 'atom-tools' 29 | 30 | async function convertDataURLToImage() { 31 | const dataURL = 'data:image/png;base64,...' // 假设这是你的数据URL 32 | const image = await dataURLToImage(dataURL) 33 | document.body.appendChild(image) 34 | } 35 | 36 | convertDataURLToImage() 37 | ``` -------------------------------------------------------------------------------- /docs/src/utils/public/File/fileToDataURL.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: fileToDataURL 3 | --- 4 | 5 | # 文件转DataURL函数 6 | 7 | ### fileToDataURL 8 | 9 | ## 说明 10 | 11 | `fileToDataURL` 函数用于将传入的文件对象转换为一个数据URL字符串。它返回一个`Promise`对象,该对象在文件读取成功后解决(resolve)为数据URL字符串。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 16 | | ---- | -------- | ------ | 17 | | file | 文件对象 | `File` | 18 | 19 | ## 返回值 20 | 21 | `Promise` 22 | 23 | ## 代码演示 24 | 25 | ### 基础用法 26 | 27 | ```typescript 28 | import { fileToDataURL } from 'atom-tools' 29 | 30 | async function convertFileToDataURL() { 31 | const file = await fileInput.files[0] 32 | const dataURL = await fileToDataURL(file) 33 | console.log(dataURL) 34 | } 35 | 36 | convertFileToDataURL() 37 | ``` -------------------------------------------------------------------------------- /docs/src/utils/public/File/formatFileSize.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: formatFileSize 3 | --- 4 | 5 | # 文件大小格式化函数 6 | 7 | ### formatFileSize 8 | 9 | ## 说明 10 | 11 | `formatFileSize` 函数用于将文件大小(以字节为单位)格式化为易读的字符串(B、KB、MB、GB)。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 16 | | ---- | -------- | -------- | 17 | | size | 文件大小 | `number` | 18 | 19 | ## 返回值 20 | 21 | `string` - 格式化后的文件大小字符串。 22 | 23 | ## 代码演示 24 | 25 | ### 基础用法 26 | 27 | ```typescript 28 | import { formatFileSize } from 'atom-tools' 29 | 30 | const formattedSize = formatFileSize(1024 * 1024 * 5) 31 | console.log(formattedSize) // 输出: 5.00MB 32 | ``` -------------------------------------------------------------------------------- /docs/src/utils/public/File/getFileExtension.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: getFileExtension 3 | --- 4 | 5 | # 获取文件扩展名函数 6 | 7 | ### getFileExtension 8 | 9 | ## 说明 10 | 11 | `getFileExtension` 函数用于获取文件的扩展名。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 16 | | ---- | -------- | ------ | 17 | | file | 文件对象 | `File` | 18 | 19 | ## 返回值 20 | 21 | `string` - 文件的扩展名。 22 | 23 | ## 代码演示 24 | 25 | ### 基础用法 26 | 27 | ```typescript 28 | import { getFileExtension } from 'atom-tools' 29 | 30 | const file = new File(['Hello, world!'], 'hello.txt', { type: 'text/plain' }) 31 | const extension = getFileExtension(file) 32 | console.log(extension) // 输出: txt 33 | ``` -------------------------------------------------------------------------------- /docs/src/utils/public/File/readFileAsText.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: readFileAsText 3 | --- 4 | 5 | # 读取文件为文本函数 6 | 7 | ### readFileAsText 8 | 9 | ## 说明 10 | 11 | `readFileAsText` 函数用于读取文件的内容作为文本。它返回一个`Promise`对象,该对象在文件读取成功后解决(resolve)为文本字符串。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 16 | | ---- | -------- | ------ | 17 | | file | 文件对象 | `File` | 18 | 19 | ## 返回值 20 | 21 | `Promise` 22 | 23 | ## 代码演示 24 | 25 | ### 基础用法 26 | 27 | ```typescript 28 | import { readFileAsText } from 'atom-tools' 29 | 30 | async function readFileContent() { 31 | const file = await fileInput.files[0] 32 | const content = await readFileAsText(file) 33 | console.log(content) 34 | } 35 | 36 | readFileContent() 37 | 38 | ``` -------------------------------------------------------------------------------- /docs/src/utils/public/File/saveFile.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: saveFile 3 | --- 4 | 5 | # 保存文件函数 6 | 7 | ### saveFile 8 | 9 | ## 说明 10 | 11 | `saveFile` 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 16 | | ------ | -------- | -------- | 17 | | blob | Blob对象 | `Blob` | 18 | | filename | 文件名 | `string` | 19 | 20 | ## 代码演示 21 | 22 | ### 基础用法 23 | 24 | ```typescript 25 | import { saveFile } from 'atom-tools' 26 | 27 | const blob = new Blob(['Hello, world!'], { type: 'text/plain' }) 28 | saveFile(blob, 'hello.txt') 29 | ``` -------------------------------------------------------------------------------- /docs/src/utils/public/FormatDate/constant.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 日期常量 3 | --- 4 | 5 | # 日期常量 6 | 7 | ### DATA_CONSTANT 8 | 9 | ## 说明 10 | 11 | 以下是一些常用的日期常量,统一封装在`DATA_CONSTANT`对象当中,使用时推荐解构。 12 | 13 | ## 时间戳 14 | 15 | | 名称 | 说明 | 类型 | 值 | 16 | | ---------- | -------------------------------------- | -------- | --- | 17 | | ONE_DAY | 一天的毫秒数 | `Number` | --- | 18 | | ONE_HOUR | 一小时的毫秒数 | `Number` | --- | 19 | | ONE_MINUTE | 一分钟的毫秒数 | `Number` | --- | 20 | | ONE_SECOND | 一秒的毫秒数 | `Number` | --- | 21 | | TODAY | 今天(当天00:00:00)的时间戳 | `Number` | --- | 22 | | TOMORROW | 明天(第二天00:00:00)的时间戳 | `Number` | --- | 23 | | YESTERDAY | 昨天(前一天00:00:00)的时间戳 | `Number` | --- | 24 | | THIS_WEEK | 本周的第一天(周一00:00:00)的时间戳 | `Number` | --- | 25 | | NEXT_WEEK | 下周的第一天(周一00:00:00)的时间戳 | `Number` | --- | 26 | | LAST_WEEK | 上周的最后一天(周日23:59:59)的时间戳 | `Number` | --- | 27 | | THIS_MONTH | 本月第一天(00:00:00)的时间戳 | `Number` | --- | 28 | | NEXT_MONTH | 下月第一天(00:00:00)的时间戳 | `Number` | --- | 29 | | LAST_MONTH | 上月最后一天(23:59:59)的时间戳 | `Number` | --- | 30 | -------------------------------------------------------------------------------- /docs/src/utils/public/FormatDate/formatDate.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 格式化日期函数 3 | --- 4 | 5 | # 格式化日期函数 6 | 7 | ### formatDate 8 | 9 | 10 | ## 描述 11 | `formatDate` 函数用于将传入的日期对象格式化为指定格式的字符串。支持多种预设格式,也可以通过函数自定义格式。 12 | 13 | ## 参数 14 | 15 | | 参数名 | 类型 | 默认值 | 说明 | 16 | |--------|------------------------------|--------|--------------------------------------------------------------| 17 | | date | `Date` / `Number` / `String` | -- | 需要格式化的日期对象、时间戳或日期字符串。 | 18 | | formatter | `string` 或 `Function` | -- | 日期的格式化描述或格式化函数。 | 19 | | isPad | `boolean` | `true` | 是否对日期时间的各个部分进行零填充。 | 20 | 21 | ## 返回 22 | 23 | `string` - 格式化后的日期字符串。 24 | 25 | ## 预设格式化关键字 26 | 27 | - `date`: `"yyyy-MM-dd"` 28 | - `dateTime`: `"yyyy-MM-dd HH:mm:ss"` 29 | - `time`: `"HH:mm:ss"` 30 | - `year`: `"yyyy"` 31 | - `monthDay`: `"MM-dd"` 32 | 33 | ## 代码演示 34 | 35 | ### 基础用法 36 | 37 | ```javascript 38 | import { formatDate } from 'atom-tools' 39 | 40 | // 传入 Date 对象 41 | console.log(formatDate(new Date(), 'date')) // 输出:当前日期的格式化字符串,例如 "2024-04-29" 42 | 43 | // 使用预设格式 44 | console.log(formatDate(new Date(), 'dateTime')) // 输出:当前日期时间的格式化字符串 45 | 46 | // 使用自定义格式 47 | console.log(formatDate(new Date(), 'yyyy-MM月mm日')) // 输出:自定义格式的字符串 48 | ``` 49 | ### 自定义格式化函数 50 | ```javascript 51 | // 自定义格式化函数 52 | const customFormatter = (dateInfo) => { 53 | return `${dateInfo.year}年${dateInfo.month}月${dateInfo.day}日`; 54 | }; 55 | 56 | // 使用自定义格式化函数 57 | console.log(formatDate(new Date(), customFormatter)); 58 | 59 | ``` 60 | 61 | ### 零填充控制 62 | ```javascript 63 | // 不使用零填充 64 | console.log(formatDate(new Date(), 'yyyy-MM-dd', false)); // 输出可能包含非零填充的字符串,例如 "2024-4-29" 65 | ``` 66 | ### 注意事项 67 | - 确保 date 参数是有效的 Date 对象。 68 | - 自定义 formatter 字符串时,确保使用正确的占位符,例如 yyyy, MM, dd, HH, mm, ss。 69 | - 当 isPad 为 false 时,数值将不会进行零填充,这可能会导致格式不一致。 -------------------------------------------------------------------------------- /docs/src/utils/public/FormatDate/formatDateWeekCN.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 格式化日期为中文星期 3 | --- 4 | 5 | # 格式化日期为中文星期 6 | 7 | ### transformDateWeekCN 8 | 9 | ## 说明 10 | 11 | `transformDateWeekCN` 函数将传入的日期对象转换为中文表示的星期。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ---- | ------------ | --------------- | ------ | 17 | | date | 要转换的日期 | `Date`/`Number` | --- | 18 | 19 | ## 返回值 20 | 21 | `string` - 返回中文表示的星期,如 "星期一"。 22 | 23 | ## 代码演示 24 | 25 | ### 基础用法 26 | 27 | ```ts 28 | import { formatDateWeekCN } from 'atom-tools' 29 | 30 | // 传入当前日期的 Date 对象 31 | console.log(formatDateWeekCN(new Date())) // 输出:当前日期对应的中文星期,例如 "星期一" 32 | 33 | // 传入特定日期的 Date 对象 34 | console.log(formatDateWeekCN(new Date('2022-01-01'))) // 输出:"星期五",假设 2022-01-01 是星期五 35 | 36 | console.log(formatDateWeekCN(1)) // 应该传入一个 Date 对象 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/src/utils/public/FormatDate/getDayOfYear.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: getDayOfYear 3 | --- 4 | 5 | # 获取某个日期是当年的第几天 6 | 7 | ### getDayOfYear 8 | 9 | ## 说明 10 | 11 | `getDayOfYear` 函数用于计算并返回给定日期在该年中是第几天。 12 | 13 | ## 参数 14 | 15 | | 参数名 | 类型 | 默认值 | 说明 | 16 | | ------ | ----------------- | ------ | ------------------------------ | 17 | | date | `Date` / `Number` | --- | 需要计算是哪一天的日期或时间戳 | 18 | 19 | ## 返回 20 | 21 | `number` - 返回给定日期在一年中的天数序号,范围从1到366。 22 | 23 | ## 代码演示 24 | 25 | ### 基础用法 26 | 27 | ```js 28 | import { getDayOfYear } from 'atom-tools' 29 | 30 | // 传入 Date 对象 31 | console.log(getDayOfYear(new Date())) // 输出:当前日期在一年中的天数序号,例如 120 32 | 33 | // 传入时间戳 34 | console.log(getDayOfYear(1714405699791)) // 输出:给定时间戳在一年中的天数序号,例如 120 35 | ``` 36 | -------------------------------------------------------------------------------- /docs/src/utils/public/FormatDate/getTwoDaysApart.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: getTwoDaysApart 3 | --- 4 | 5 | # 计算两个日期之间的天数差。 6 | 7 | ### getTwoDaysApart 8 | 9 | ## 说明 10 | 11 | `getTwoDaysApart` 函数用于计算传入的两个日期之间的天数差。它支持传入日期对象、时间戳或日期字符串。 12 | 13 | ## 参数 14 | 15 | | 参数名 | 类型 | 说明 | 16 | | -------- | ---------------------------- | -------- | 17 | | lastDate | `Date` / `Number` / `String` | 开始日期 | 18 | | nextDate | `Date` / `Number` / `String` | 结束日期 | 19 | 20 | ## 返回 21 | 22 | `number` - 两个日期之间的天数差。 23 | 24 | ## 代码演示 25 | 26 | ### 基础用法 27 | 28 | ```js 29 | import { getTwoDaysApart } from 'atom-tools' 30 | 31 | // 传入 Date 对象 32 | console.log(getTwoDaysApart(new Date('2024-04-01'), new Date('2024-04-03'))) // 输出:2 33 | 34 | // 传入时间戳 35 | console.log(getTwoDaysApart(1617427200000, 1617513600000)) // 输出:2 36 | 37 | // 传入字符串 38 | console.log(getTwoDaysApart('2024-04-01', '2024-04-03')) // 输出:2 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/src/utils/public/FormatDate/isLeapYear.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: isLeapYear 3 | --- 4 | 5 | # 判断是否为闰年 6 | 7 | ### isLeapYear 8 | 9 | ## 说明 10 | 11 | `isLeapYear` 函数用于判断给定的年份是否为闰年。 12 | 13 | ## 参数 14 | 15 | | 参数名 | 类型 | 默认值 | 说明 | 16 | | ------ | -------- | ------ | -------------- | 17 | | year | `Number` | --- | 需要检查的年份 | 18 | 19 | ## 返回 20 | 21 | `boolean` - 返回 `true` 如果给定的年份是闰年,否则返回 `false`。 22 | 23 | ## 代码演示 24 | 25 | ### 基础用法 26 | 27 | ```js 28 | import { isLeapYear } from 'atom-tools' 29 | 30 | // 检查特定年份是否为闰年 31 | console.log(isLeapYear(2024)) // 输出:true,因为2024年是闰年 32 | 33 | // 检查其他年份 34 | console.log(isLeapYear(1900)) // 输出:false,因为1900年不是闰年 35 | console.log(isLeapYear(2000)) // 输出:true,因为2000年是闰年 36 | ``` 37 | -------------------------------------------------------------------------------- /docs/src/utils/public/FormatDate/toDate.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 将值转换为日期对象 3 | --- 4 | 5 | # 将值转换为日期对象 6 | 7 | ### toDate 8 | 9 | ## 说明 10 | 11 | `toDate` 函数用于将传入的值转换为 `Date` 对象。如果输入值无法被识别为有效的日期,函数将抛出一个错误。 12 | 13 | ## 参数 14 | 15 | | 参数名 | 类型 | 默认值 | 说明 | 16 | | ------ | --------------------------------------------------- | ------ | ---------------- | 17 | | date | `string` / `number` / `Date` / `null` / `undefined` | --- | 需要转换的日期值 | 18 | 19 | ## 返回值 20 | 21 | `Date` - 如果转换成功,返回 `Date` 对象。 22 | 23 | ## 抛出错误 24 | 25 | - 如果 `date` 参数为 `null` 或 `undefined`,函数将抛出一个错误,指出“日期参数为空,无法转换为日期对象”。 26 | - 如果 `date` 参数为 `string` 或 `number` 但无法被转换为有效的日期对象,函数将抛出一个错误,指出“无法识别日期类型:Invalid date format” 或 “提供的数字不是一个有效的时间戳”。 27 | 28 | ## 代码演示 29 | 30 | ### 基础用法 31 | 32 | ```javascript 33 | import { toDate } from 'atom-tools' 34 | 35 | // 传入 Date 对象 36 | const dateFromObject = toDate(new Date()) 37 | 38 | // 传入时间戳 39 | const dateFromTimestamp = toDate(1617427200000) 40 | 41 | // 传入字符串 42 | const dateFromString = toDate('2024-04-29') 43 | 44 | try { 45 | // 尝试转换无效的日期字符串 46 | const invalidDate = toDate('not-a-date') 47 | } catch (error) { 48 | console.error(error.message) // 输出错误信息 49 | } 50 | ``` 51 | -------------------------------------------------------------------------------- /docs/src/utils/public/HighOrderFunction/KeepLoop.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: KeepLoop 定时轮询 3 | --- 4 | 5 | # KeepLoop 定时轮询 6 | 7 | ## 概述 8 | 9 | `KeepLoop` 类是一个强大的工具,用于实现定时轮询机制。它允许用户配置轮询的时间间隔、限制轮询的最大次数,并且定义一个自定义函数来在每次轮询时执行特定的操作。 10 | 11 | ## 构造函数 12 | 13 | ### 参数 14 | 15 | | 参数 | 描述 | 类型 | 默认值 | 16 | | ----------- | ---------------------------- | ---------------------- | --------- | 17 | | option | 包含轮询设置的配置对象 | `TYPE.IKeepLoopOption` | --- | 18 | 19 | ### 返回值 20 | 21 | - `TYPE.IReturnInfo`: 当前的轮询次数信息。 22 | 23 | ## 类型定义 24 | 25 | - `TYPE.IKeepLoopOption` 接口包括以下属性: 26 | - `run`: **必选**. 每次轮询调用的函数。 27 | - `interval`: **必选**. 轮询之间的时间间隔,单位为毫秒,默认1000。 28 | - `maxCount`: **可选**. 最大轮询次数;如果为0或未指定,则轮询无限进行,默认0。 29 | 30 | - `TYPE.IReturnInfo` 接口包括以下属性: 31 | - `currentCount`: 当前的轮询次数。 32 | 33 | ## 方法 34 | 35 | - `start()`: 开始轮询。 36 | - `stop()`: 停止轮询。 37 | - `pause()`: 暂停轮询。 38 | - `resume()`: 继续(恢复)轮询。 39 | 40 | ## 使用示例 41 | 42 | ### Vue 3 组件中使用 KeepLoop 43 | 44 | 以下是如何在 Vue 3 组件中使用 `KeepLoop` 类的示例,包括新增的暂停和继续功能: 45 | 46 | ```vue 47 | 55 | 56 | 96 | ``` 97 | 98 | ### 注意事项 99 | - 请确保在组件销毁时调用 stop 方法以停止轮询,防止内存泄漏。 100 | - 根据实际的业务逻辑,您可能需要对 loopFunc 函数返回的结果进行处理。 101 | - 使用 pause 和 resume 方法可以暂停和继续轮询,这对于节省资源或响应用户操作非常有用。 -------------------------------------------------------------------------------- /docs/src/utils/public/HighOrderFunction/cloneDeep.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: cloneDeep 3 | --- 4 | 5 | # 深度克隆 6 | 7 | ### cloneDeep 8 | 9 | ## 说明 10 | 11 | `cloneDeep` 函数用于深度克隆一个给定的值。它通过序列化值到 JSON 字符串,然后再解析回一个对象,从而实现深度克隆。 12 | 13 | 注意:此方法不能克隆函数、undefined、循环引用的对象等。 14 | 15 | ## 参数 16 | 17 | | 参数 | 说明 | 类型 | 18 | | ----- | ---------------- | ----- | 19 | | value | 需要深度克隆的值 | `any` | 20 | 21 | ## 返回值 22 | 23 | `any` - 返回深度克隆后的新值。 24 | 25 | ## 代码演示 26 | 27 | ### 基础用法 28 | 29 | ```ts 30 | import { cloneDeep } from 'atom-tools' 31 | 32 | const original = { 33 | number: 1, 34 | string: 'string', 35 | boolean: true, 36 | null: null, 37 | undefined: undefined, 38 | array: [1, 2, 3], 39 | object: { a: 1, b: 2 }, 40 | date: new Date() 41 | } 42 | 43 | const cloned = cloneDeep(original) 44 | 45 | console.log(cloned) // 输出克隆后的值,与 original 不同的引用 46 | ``` 47 | -------------------------------------------------------------------------------- /docs/src/utils/public/HighOrderFunction/debounce.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Debounce Function 3 | --- 4 | 5 | # 防抖函数 6 | 7 | ### debounce 8 | 9 | ## 说明 10 | 11 | `debounce` 函数用于控制传入函数的执行频率,确保函数在指定的时间间隔结束后才执行。如果在这个间隔时间内多次调用函数,则只有最后一次调用会执行。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | --------- | ---------------- | ---------- | ------- | 17 | | func | 需要防抖的函数 | `Function` | - | 18 | | wait | 等待时间(毫秒) | `number` | - | 19 | | immediate | 是否立即执行 | `boolean` | `false` | 20 | 21 | ## 返回值 22 | 23 | `Function` - 返回一个新的函数,这个函数根据提供的参数对原始函数进行防抖处理。 24 | 25 | ## 代码演示 26 | 27 | ### 基础用法 28 | 29 | #### 正确示范: 30 | 31 | `该示例为jsx[其他使用场景同理]` 32 | 33 | ```typescript 34 | import { debounce } from 'atom-tools' 35 | 36 | export default function HelloWorld() { 37 | 38 | const debounceFun = debounce(function(){ 39 | console.log('debounce'); 40 | }, 1000) 41 | 42 | const handleClick = () => debounceFun() 43 | 44 | return ( 45 |
46 |

Hello, world!

47 | 48 |
49 | ) 50 | } 51 | ``` 52 | 53 | #### 错误示范: 54 | 55 | `该示例为jsx[其他使用场景同理]` 56 | 57 | ```typescript 58 | import { debounce } from '@/public/main' 59 | 60 | export default function HelloWorld() { 61 | 62 | // 示例1: 63 | const handleClick = () => { 64 | const debounceFun = debounce(function(){ 65 | console.log('debounce'); 66 | }, 1000) 67 | return debounceFun() 68 | } 69 | 70 | // 示例2: 71 | const handleClick = () => { 72 | return debounce(function(){ 73 | console.log('debounce'); 74 | }, 1000) 75 | } 76 | 77 | return ( 78 |
79 |

Hello, world!

80 | 81 |
82 | ) 83 | } 84 | ``` 85 | 86 | #### 注意: 87 | 88 | 防抖函数和节流函数使用方法类似 89 | 90 | :::danger 91 | 92 | - 1.debounce 返回的是一个经过防抖处理的新函数,你需要使用这个返回的函数作为事件处理器。 93 | - 2.你不能直接在 debounce 调用后立即执行返回的函数,因为这样会立即执行一次被 debounce 包装的函数,违背了防抖的初衷。 94 | - 3.debounce 函数在每次点击时都会被重新创建,导致之前的定时器被新的定时器覆盖,而不是按照防抖逻辑去阻止多次执行。所以,你需要将 debounce 函数的创建移出事件处理器,以确保只创建一次。 95 | ::: 96 | 97 | ## 立即执行 98 | 99 | 如果 `immediate` 参数设置为 `true`,则函数会在第一次调用时立即执行,而不是等待等待时间结束后再执行。 100 | -------------------------------------------------------------------------------- /docs/src/utils/public/HighOrderFunction/sington.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Singleton Factory 3 | --- 4 | 5 | # 单例模式工厂 6 | 7 | ## 单例模式工厂 (Singleton Factory) 8 | 9 | ### 说明 10 | 11 | `singleton` 函数用于创建一个单例模式,确保某个类只有一个实例。它通过代理一个类的构造函数,确保无论多少次尝试创建实例,都只会存在一个实例。 12 | 13 | 注意:此方法不适用于需要多次实例化的类,且不支持异步构造函数。 14 | 15 | ### 参数 16 | 17 | | 参数 | 说明 | 类型 | 18 | |---------|--------------|----------------------------------------| 19 | | className | 需要单例化的类 | `new (...args: any[]) => any` | 20 | 21 | ### 返回值 22 | 23 | `InstanceType` - 返回单例类的实例。 24 | 25 | ### 代码演示 26 | 27 | 28 | ```typescript 29 | import { singleton } from 'atom-tools'; 30 | 31 | class MyClass { 32 | private static instance: MyClass | null = null; 33 | 34 | private constructor() { 35 | // 私有构造函数确保类不能被直接实例化 36 | } 37 | 38 | public static getInstance(): MyClass { 39 | return singleton(MyClass); 40 | } 41 | 42 | // 类的其他方法... 43 | } 44 | 45 | const instance1 = MyClass.getInstance(); 46 | const instance2 = MyClass.getInstance(); 47 | 48 | console.log(instance1 === instance2); // 输出 true,表示为同一个实例 49 | ``` 50 | ### 使用单例类 51 | ```typescript 52 | import { singleton } from 'path-to-singleton-factory'; 53 | 54 | class MyService { 55 | // 服务类的方法... 56 | } 57 | 58 | // 使用 singleton 工厂创建单例 59 | const myService = singleton(MyService); 60 | 61 | // 在应用的其他部分可以使用相同的单例 62 | const anotherService = singleton(MyService); 63 | 64 | console.log(myService === anotherService); // 输出 true,表示为同一个实例 65 | ``` -------------------------------------------------------------------------------- /docs/src/utils/public/HighOrderFunction/sleep.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: sleep 3 | --- 4 | 5 | # 睡眠函数 6 | 7 | ### sleep 8 | 9 | ## 说明 10 | 11 | `sleep` 函数用于模拟异步操作中的延迟时间。它接受一个以毫秒为单位的参数来指定延迟的时长,并返回一个 `Promise` 对象。当延迟时间过后,`Promise` 会被解决(resolve)。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | -------- | ------------ | -------- | ----------- | 17 | | duration | 延迟的毫秒数 | `number` | `undefined` | 18 | 19 | ## 返回值 20 | 21 | `Promise` - 在指定的延迟时间过后解决的 `Promise` 对象。 22 | 23 | ## 代码演示 24 | 25 | ### 基础用法 26 | 27 | ```ts 28 | import { sleep } from 'atom-tools' 29 | 30 | // 使用 async/await 31 | async function asyncFunction() { 32 | console.log('Start sleeping') 33 | await sleep(1000) // 延迟 1 秒 34 | console.log('Finished sleeping after 1 second') 35 | } 36 | 37 | asyncFunction() 38 | 39 | // 使用 Promise 链式调用 40 | sleep(500) // 延迟 0.5 秒 41 | .then(() => console.log('Finished sleeping after 0.5 second')) 42 | ``` 43 | -------------------------------------------------------------------------------- /docs/src/utils/public/HighOrderFunction/throttle.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Throttle Function 3 | --- 4 | 5 | # 节流函数 6 | 7 | ### throttle 8 | 9 | ## 说明 10 | 11 | `throttle` 函数用于限制传入函数的执行频率,确保函数在指定的时间间隔内最多执行一次。这对于处理诸如按钮点击、滚动事件等可能被频繁触发的操作特别有用。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | --------- | ---------------- | ---------- | ----------- | 17 | | func | 需要节流的函数 | `Function` | - | 18 | | limit | 时间间隔(毫秒) | `number` | `undefined` | 19 | | immediate | 是否立即执行 | `boolean` | `false` | 20 | 21 | ## 返回值 22 | 23 | `Function` - 返回一个新的函数,这个函数在指定的时间间隔内最多执行一次原始函数。 24 | 25 | ## 代码演示 26 | 27 | ### 基础用法 28 | 29 | ```typescript 30 | import { throttle } from 'atom-tools' 31 | 32 | export default function HelloWorld() { 33 | 34 | const throttleFun = throttle(function(){ 35 | console.log('throttle'); 36 | }, 1000) 37 | 38 | const handleClick = () => throttleFun() 39 | 40 | return ( 41 |
42 |

Hello, world!

43 | 44 |
45 | ) 46 | } 47 | ``` 48 | 49 | ### 注意: 50 | 51 | :::danger 52 | 节流函数注意事项类似防抖函数,但是节流函数的执行频率是固定的,而防抖函数的执行频率是可变的。具体可参考防抖函数 53 | ::: 54 | 55 | ## 立即执行 56 | 57 | 如果 `immediate` 参数设置为 `true`,则函数会在第一次调用时立即执行,而不是等待等待时间结束后再执行。 58 | -------------------------------------------------------------------------------- /docs/src/utils/public/Number/fillZero.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: fillZero 3 | --- 4 | 5 | # 补零 6 | 7 | ### fillZero 8 | 9 | ## 说明 10 | 11 | `fillZero` 函数用于将小于10的数字前面补0,以便格式化为两位数的字符串表示。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ---- | ------------------------ | -------- | ------ | 17 | | num | 传入的数字,需要补零处理 | `Number` | --- | 18 | 19 | ## 返回值 20 | 21 | `String` - 返回补零后的两位数字符串表示。 22 | 23 | ## 代码演示 24 | 25 | ### 基础用法 26 | 27 | ```ts 28 | import { fillZero } from 'atom-tools' 29 | 30 | // 传入一个小于10的数字 31 | console.log(fillZero(6)) // 输出:"06" 32 | 33 | // 传入一个大于等于10的数字 34 | console.log(fillZero(25)) // 输出:"25",不进行补零 35 | ``` 36 | -------------------------------------------------------------------------------- /docs/src/utils/public/Number/getRandomNumber.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: getRandomNumber 3 | --- 4 | 5 | # 随机数字 6 | 7 | ### getRandomNumber 8 | 9 | ## 说明 10 | 11 | `getRandomNumber` 函数用于生成一个指定长度的唯一随机数字。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ----- | ------------------ | -------- | ------ | 17 | | digit | 随机数字的期望长度 | `Number` | 2 | 18 | 19 | ## 返回值 20 | 21 | `string` - 返回一个指定长度的唯一随机数字字符串。 22 | 23 | ## 代码演示 24 | 25 | ### 基础用法 26 | 27 | ```ts 28 | import { getRandomNumber } from 'atom-tools' 29 | 30 | // 生成一个3位长度的随机数字 31 | console.log(getRandomNumber(3)) // 输出:一个3位长度的随机数字,例如 "258" 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/src/utils/public/Number/keepDecimal.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: keepDecimal 3 | --- 4 | 5 | # 保留小数 6 | 7 | ### keepDecimal 8 | 9 | ## 说明 10 | 11 | `keepDecimal` 函数用于将传入的数字保留指定位数的小数。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ----- | ---------- | -------- | ------ | 17 | | digit | 自定义长度 | `Number` | 2 | 18 | 19 | ## 返回值 20 | 21 | `string` 22 | 23 | ## 代码演示 24 | 25 | ### 基础用法 26 | 27 | ```ts 28 | import { keepDecimal } from 'atom-tools' 29 | 30 | console.log(keepDecimal(0.25656)) // 输出:0.26 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/src/utils/public/Object/pick.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: pick 3 | --- 4 | 5 | # 筛选对象属性 6 | 7 | ### pick 8 | 9 | ## 说明 10 | 11 | `pick` 函数用于从一个对象中筛选出指定键的属性,并返回一个包含这些属性的新对象。这对于减少对象大小或提取需要的属性子集非常有用。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ---- | ---------------------- | ------------------- | ------ | 17 | | obj | 需要筛选属性的对象 | `T`(普通对象类型) | --- | 18 | | keys | 需要筛选出来的键的数组 | `K[]`(键类型数组) | --- | 19 | 20 | ## 返回值 21 | 22 | `Partial>` - 返回一个新对象,其中只包含 `keys` 数组中指定的键及其对应的值。 23 | 24 | ## 代码演示 25 | 26 | ### 基础用法 27 | 28 | ```ts 29 | import { pick } from 'atom-tools' 30 | 31 | interface Person { 32 | name: string 33 | age: number 34 | email: string 35 | } 36 | 37 | const person: Person = { 38 | name: 'John Doe', 39 | age: 30, 40 | email: 'john.doe@example.com' 41 | } 42 | 43 | // 使用 pick 函数筛选出 'name' 和 'age' 属性 44 | const selectedFields = pick(person, ['name', 'age']) 45 | console.log(selectedFields) // 输出:{ name: 'John Doe', age: 30 } 46 | ``` 47 | -------------------------------------------------------------------------------- /docs/src/utils/public/String/getRandomString.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: getRandomString 3 | --- 4 | 5 | # 随机字符串 6 | 7 | ### getRandomString 8 | 9 | ## 说明 10 | 11 | `getRandomString` 函数用于生成一个指定长度的唯一随机字符串。该字符串可以用于多种需要唯一标识符的场合。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ----- | -------------------- | -------- | ------ | 17 | | digit | 随机字符串的期望长度 | `Number` | 32 | 18 | 19 | ## 返回值 20 | 21 | `string` - 返回一个指定长度的随机字符串。 22 | 23 | ## 代码演示 24 | 25 | ### 基础用法 26 | 27 | ```ts 28 | import { getRandomString } from 'atom-tools' 29 | 30 | // 生成一个6位长度的随机字符串 31 | console.log(getRandomString(6)) // 输出:一个6位长度的随机字符串,例如 "ashdha" 32 | ``` 33 | -------------------------------------------------------------------------------- /docs/src/utils/public/String/maskString.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 脱敏处理函数集 3 | --- 4 | 5 | # 脱敏处理函数集 6 | 7 | 本文档介绍了一系列用于不同场景下的脱敏处理函数,包括手机号、地址、姓氏、标签、身份证号、邮箱和银行卡号等。 8 | 9 | ## maskPhoneNumber 10 | 11 | ### 说明 12 | `maskPhoneNumber` 函数用于对手机号进行脱敏处理,只显示前三位和后四位,其余部分用星号(*)替代。 13 | 14 | ### 参数 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ----------- | ---------------- | ----------------------------- | ------ | 17 | | phoneNumber | 需要脱敏的手机号 | `string \| null \| undefined` | --- | 18 | 19 | ### 返回值 20 | `String` - 脱敏后的手机号字符串。 21 | 22 | ### 异常 23 | - 如果 `phoneNumber` 为 `null` 或 `undefined`,函数将抛出一个错误。 24 | - 如果 `phoneNumber` 的格式不正确(不是11位数字),将抛出一个错误。 25 | 26 | ### 代码演示 27 | 28 | ```typescript 29 | import { maskPhoneNumber } from 'atom-tools' 30 | 31 | // 对手机号进行脱敏处理 32 | console.log(maskPhoneNumber('13812345678')) // 输出:138****5678 33 | ``` 34 | 35 | ## 通用脱敏函数 maskString 36 | 以下脱敏函数均基于通用脱敏函数 maskString 实现。 37 | 38 | ### 参数 39 | 40 | | 参数名 | 说明 | 类型 | 默认值 | 41 | | ---------- | ------------------ | ------- | ------ | 42 | | input | 需要脱敏的原始字符串 | string | --- | 43 | | keepStart | 需要保留的开头字符数 | number | 0 | 44 | | keepEnd | 需要保留的结尾字符数 | number | 0 | 45 | | maskChar | 脱敏部分使用字符 | string | '*' | 46 | 47 | ### 返回值 48 | `String` - 脱敏后的字符串。 49 | 50 | ### 地址脱敏 addressHidePart 51 | 52 | ```typescript 53 | export const addressHidePart = (address: string,keepStart=3,keepEnd=4, maskChar='*'): string => { 54 | return maskString(address, keepStart, keepEnd, maskChar) 55 | } 56 | ``` 57 | 58 | ### 姓氏脱敏 nameHidePart 59 | 60 | ```typescript 61 | export const nameHidePart = (name: string,keepStart=1,keepEnd=1, maskChar='*'): string => { 62 | return maskString(name, keepStart, keepEnd, maskChar) 63 | } 64 | ``` 65 | 66 | ### 标签脱敏 tagHidePart 67 | 68 | ```typescript 69 | export const tagHidePart = (tag: string,keepStart=1,keepEnd=1, maskChar='*'): string => { 70 | return maskString(tag, keepStart, keepEnd, maskChar) 71 | } 72 | ``` 73 | 74 | ### 身份证号脱敏 idCardHidePart 75 | 76 | ```typescript 77 | export const idCardHidePart = (idCard: string,keepStart=6,keepEnd=4, maskChar='*'): string => { 78 | return maskString(idCard, keepStart, keepEnd, maskChar) 79 | } 80 | ``` 81 | 82 | ### 邮箱脱敏 emailHidePart 83 | 84 | ```typescript 85 | export const emailHidePart = (email: string,keepStart=3,keepEnd=4, maskChar='*'): string => { 86 | return maskString(email, keepStart, keepEnd, maskChar) 87 | } 88 | ``` 89 | 90 | ### 银行卡号脱敏 bankCardHidePart 91 | 92 | ```typescript 93 | export const bankCardHidePart = (bankCard: string,keepStart=4,keepEnd=4, maskChar='*'): string => { 94 | return maskString(bankCard, keepStart, keepEnd, maskChar) 95 | } 96 | ``` 97 | 98 | ### 使用示例 99 | 以下是使用上述脱敏函数的示例: 100 | 101 | ```typescript 102 | import { addressHidePart, nameHidePart, tagHidePart, idCardHidePart, emailHidePart, bankCardHidePart } from 'atom-tools' 103 | 104 | const address = '北京市朝阳区' 105 | const name = '张三' 106 | const tag = '公司' 107 | const idCard = '123456789012345678' 108 | const email = 'zhangsan@example.com' 109 | const bankCard = '123456789012345678' 110 | 111 | console.log(addressHidePart(address)) // 输出:北京市****朝阳区 112 | console.log(nameHidePart(name)) // 输出:张** 113 | console.log(tagHidePart(tag)) // 输出:公司 114 | console.log(idCardHidePart(idCard)) // 输出:1234****5678 115 | console.log(emailHidePart(email)) // 输出:zhangsan****@example.com 116 | console.log(bankCardHidePart(bankCard)) // 输出:1234****5678 117 | ``` 118 | -------------------------------------------------------------------------------- /docs/src/utils/public/String/toLower.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: toLower 3 | --- 4 | 5 | # 小写转换 6 | 7 | ### toLower 8 | 9 | ## 说明 10 | 11 | `toLower` 函数用于将字符串的首字母或全部字符转换为小写。当仅转换首字母时,其余部分保持原样;当转换全部字符时,整个字符串将转换为小写。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ----- | ---------------------- | --------- | ------ | 17 | | value | 需要转换的字符串 | `String` | --- | 18 | | all | 是否转换全部字符为小写 | `Boolean` | --- | 19 | 20 | ## 返回值 21 | 22 | `String` - 转换后的字符串。 23 | 24 | ## 代码演示 25 | 26 | ### 基础用法 27 | 28 | ```ts 29 | import { toLower } from 'atom-tools' 30 | 31 | // 转换首字母为小写 32 | console.log(toLower('ATOMTOOLS')) // 输出:aTOMTOOLS 33 | 34 | // 转换全部字符为小写 35 | console.log(toLower('ATOMTOOLS', true)) // 输出:atomtools 36 | ``` 37 | -------------------------------------------------------------------------------- /docs/src/utils/public/String/toUpper.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: toUpper 3 | --- 4 | 5 | # 大写转换 6 | 7 | ### toUpper 8 | 9 | ## 说明 10 | 11 | `toUpper` 函数用于将字符串的首字母或全部字符转换为大写。当仅转换首字母时,其余部分保持原样;当转换全部字符时,整个字符串将转换为大写。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ----- | ---------------------- | --------- | ------ | 17 | | value | 需要转换的字符串 | `String` | --- | 18 | | all | 是否转换全部字符为大写 | `Boolean` | --- | 19 | 20 | ## 返回值 21 | 22 | `String` - 转换后的字符串。 23 | 24 | ## 代码演示 25 | 26 | ### 基础用法 27 | 28 | ```ts 29 | import { toUpper } from 'atom-tools' 30 | 31 | // 转换首字母为大写 32 | console.log(toUpper('atomTools')) // 输出:AtomTools 33 | 34 | // 转换全部字符为大写 35 | console.log(toUpper('atomTools', true)) // 输出:ATOMTOOLS 36 | ``` 37 | -------------------------------------------------------------------------------- /docs/src/utils/public/TypeCheck/constant.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 类型判断函数MAP 3 | --- 4 | 5 | # 类型判断函数MAP 6 | 7 | ### TYPE_MAP 8 | 9 | ## 说明 10 | 11 | `TYPE_MAP` 是一个包含多种类型判断函数的集合,这些函数可以帮助你快速判断变量的类型。使用时,你可以直接从 `atom-tools` 导出所需的函数,其用法类似于 `isEmpty` 函数。 12 | 13 | ## 函数列表 14 | 15 | | 名称 | 说明 | 返回类型 | 16 | | ----------------- | ------------------------------------------ | -------- | 17 | | isDate | 判断是否是日期 | Boolean | 18 | | isDef | 检测一个值是否为 `undefined` | Boolean | 19 | | isObject | 检测一个值是否为 `object` | Boolean | 20 | | isNaN | 判断是否是 `NaN` | Boolean | 21 | | isNull | 判断是否是 `null` | Boolean | 22 | | isNullAndUnDef | 判断是否是 `undefined` 和 `null` 的交集 | Boolean | 23 | | isNumber | 判断是不是数字 | Boolean | 24 | | isPromise | 判断一个值是否为 `Promise` 对象 | Boolean | 25 | | isString | 判断一个值是否为字符串类型 | Boolean | 26 | | isFunction | 判断一个值是否为函数类型 | Boolean | 27 | | isBoolean | 判断一个值是否为布尔类型 | Boolean | 28 | | isRegExp | 判断一个值是否为正则表达式类型 | Boolean | 29 | | isArray | 判断一个值是否为数组类型 | Boolean | 30 | | isWindow | 判断当前环境是否为浏览器环境(非服务器端) | Boolean | 31 | | isServer | 判断当前环境是否为服务器端 | Boolean | 32 | | isClient | 判断当前环境是否为客户端(浏览器环境) | Boolean | 33 | | isElement | 判断一个值是否为 HTML 元素 | Boolean | 34 | | isMap | 判断一个值是否为 `Map` 类型 | Boolean | 35 | | isUrl | 判断一个字符串是否为有效的 URL 地址 | Boolean | 36 | | isMobileNumber | 判断一个字符串是否为有效的手机号码 | Boolean | 37 | | isTelePhoneNumber | 判断一个字符串是否为有效的座机号码 | Boolean | 38 | 39 | ## 代码演示 40 | 41 | ### 使用类型判断函数 42 | 43 | ```ts 44 | import { isString, isNumber, isArray } from 'atom-tools' 45 | 46 | const result1 = isString('hello') // 输出:true 47 | const result2 = isNumber(123) // 输出:true 48 | const result3 = isArray([1, 2, 3]) // 输出:true 49 | 50 | console.log(result1, result2, result3) 51 | ``` 52 | -------------------------------------------------------------------------------- /docs/src/utils/public/TypeCheck/is.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: is 3 | --- 4 | 5 | # 检测数据类型 6 | 7 | ### is 8 | 9 | ## 说明 10 | 11 | `is` 函数基于 `Object.prototype.toString` 调用对象的 `toString` 方法来检测数据类型。它接受两个参数:要检测的数据和要检测的数据类型。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ----- | ------------------------------ | -------- | ------ | 17 | | value | 要检测的数据 | `Any` | --- | 18 | | type | 要检测的数据类型(字符串形式) | `String` | --- | 19 | 20 | ## 返回值 21 | 22 | `boolean` - 返回一个布尔值,表示数据是否为指定类型。 23 | 24 | ## 代码演示 25 | 26 | ### 基础用法 27 | 28 | ```ts 29 | import { is } from 'atom-tools' 30 | 31 | // 检测字符串 32 | console.log(is('123', 'String')) // 输出:true 33 | 34 | // 检测数组 35 | console.log(is([1, 2, 3], 'array')) // 输出:true 36 | 37 | // 检测普通对象 38 | console.log(is({ a: 1, b: 2 }, 'object')) // 输出:true 39 | 40 | // 检测 null 41 | console.log(is(null, 'null')) // 输出:true 42 | 43 | // 检测 undefined 44 | console.log(is(undefined, 'undefined')) // 输出:true 45 | 46 | // 检测数字 47 | console.log(is(123, 'number')) // 输出:true 48 | 49 | // 检测布尔值 50 | console.log(is(true, 'boolean')) // 输出:true 51 | 52 | // 检测日期对象 53 | console.log(is(new Date(), 'date')) // 输出:true 54 | 55 | // 检测正则表达式对象 56 | console.log(is(new RegExp('abc'), 'regExp')) // 输出:true 57 | 58 | // 检测 Symbol 59 | console.log(is(Symbol('abc'), 'symbol')) // 输出:true 60 | 61 | // 检测函数 62 | console.log(is(function () {}, 'function')) // 输出:true 63 | ``` 64 | -------------------------------------------------------------------------------- /docs/src/utils/public/TypeCheck/isEmpty.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: isEmpty 3 | --- 4 | 5 | # 检查一个值是否为空 6 | 7 | ### isEmpty 8 | 9 | ## 说明 10 | 11 | `isEmpty` 函数用于检查传入的值是否被认为是“空”。空的定义包括但不限于:空数组、空字符串、空 Map、空 Set、不含任何键值对的对象、`null`、`NaN`、未定义或未声明的值。如果值为空,则函数返回 `true`;否则返回 `false`。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ----- | ------------ | ----- | ------ | 17 | | value | 要检测的数据 | `Any` | --- | 18 | 19 | ## 返回值 20 | 21 | `boolean` - 返回一个布尔值,表示传入的值是否为空。 22 | 23 | ## 代码演示 24 | 25 | ### 基础用法 26 | 27 | ```ts 28 | import { isEmpty } from 'atom-tools' 29 | 30 | // 检测 null 31 | console.log(isEmpty(null)) // 输出:true 32 | 33 | // 检测一个含有键值对的对象 34 | console.log(isEmpty({ a: 1 })) // 输出:false 35 | 36 | // 检测一个空对象 37 | console.log(isEmpty({})) // 输出:true 38 | 39 | // 检测一个空数组 40 | console.log(isEmpty([])) // 输出:true 41 | 42 | // 检测一个空字符串 43 | console.log(isEmpty('')) // 输出:true 44 | 45 | // 检测 NaN 46 | console.log(isEmpty(NaN)) // 输出:true 47 | 48 | // 检测未定义 49 | console.log(isEmpty(undefined)) // 输出:true 50 | ``` 51 | -------------------------------------------------------------------------------- /docs/src/utils/public/TypeCheck/optional.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: optional 3 | --- 4 | 5 | # 提供默认值的可选类型检查 6 | 7 | ### optional 8 | 9 | ## 说明 10 | 11 | `optional` 函数用于在传入的值是 `null`、`undefined` 或空字符串时提供默认值。这个函数特别适用于处理可能缺失的数据,例如在接口请求参数传值时,允许提供一个备用值来代替空值。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ---------- | ------------------------ | ---- | ------ | 17 | | value | 需要检查的原始值 | `T` | --- | 18 | | emptyValue | 当原始值为“空”时返回的值 | `T` | --- | 19 | 20 | ## 返回值 21 | 22 | `T | undefined` 23 | 24 | ## 代码演示 25 | 26 | ### 基础用法 27 | 28 | ```ts 29 | import { optional } from 'atom-tools' 30 | 31 | // 当传入值为空字符串时,返回 `undefined` 32 | const resultWithDefault = optional('', undefined) 33 | console.log(resultWithDefault) // 输出:undefined 34 | 35 | // 当传入值为 `null` 时,返回默认值 `'0'` 36 | const resultWithValue = optional(null, '0') 37 | console.log(resultWithValue) // 输出:'0' 38 | ``` 39 | 40 | ### 其他使用场景 41 | 42 | ```ts 43 | // 假设有一个接口类型 Person 44 | interface Person { 45 | name: string 46 | age: number 47 | } 48 | 49 | // 使用 optional 函数处理可能未定义的对象属性 50 | const person: Person | undefined = { 51 | name: 'John', 52 | age: 30 53 | } 54 | 55 | const nameWithDefault = optional(person?.name, '未知') 56 | console.log(nameWithDefault) // 如果 person.name 存在,输出其值;否则输出 '未知' 57 | ``` 58 | -------------------------------------------------------------------------------- /docs/src/utils/special/Vue/setupDirectivePlugins/before.md: -------------------------------------------------------------------------------- 1 | ## 安装与注册自定义指令 2 | 3 | :::danger 4 | :tada: 为了在您的 Vue 应用程序中启用 `VWaterMarker` 指令以及其他可能的自定义指令,您需要执行以下步骤进行安装和注册: 5 | 6 | 1. 打开项目根目录下的 `main.ts` 文件,这是 Vue 应用的入口文件和主要设置点。 7 | 8 | 2. 导入 `setupDirectivePlugins` 函数,该函数负责加载和注册所有的自定义指令集合。 9 | 10 | ```typescript 11 | import { setupDirectivePlugins } from 'atom-tool/vue' 12 | 13 | const app = createApp(App) 14 | 15 | // 使用 setupDirectivePlugins 函数注册所有自定义指令 16 | setupDirectivePlugins(app) 17 | 18 | // 挂载 Vue 应用到 DOM 元素 19 | app.mount('#app') 20 | ``` 21 | 22 | 3. 一旦完成上述步骤,您的 Vue 应用将会自动注册所有通过 setupDirectivePlugins 注册的自定义指令,使您能够在模板中无障碍地使用它们。 23 | 24 | 请注意,自定义指令是 Vue 应用中可复用代码的一种形式,它们允许您在不编写额外组件的情况下封装直接操作 DOM 的逻辑。:100:[详细地址](https://cn.vuejs.org/guide/reusability/custom-directives.html#custom-directives) 25 | -------------------------------------------------------------------------------- /docs/src/utils/special/Vue/setupDirectivePlugins/vCopy.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: v-copy Directive 3 | --- 4 | 5 | # 复制指令 6 | 7 | ## v-copy 8 | 9 | ## 说明 10 | 11 | `v-copy` 用于在用户执行指定的事件操作时复制特定的文本到剪贴板。该指令支持自定义复制的文本内容、触发复制的事件类型,并且允许在复制操作完成后执行一个回调函数。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | -------- | -------------------------------- | ---------- | -------------- | 17 | | content | 需要复制的文本(`可选`) | `string` | `el.innerText` | 18 | | type | 触发复制操作的事件(`可选`) | `string` | `click` | 19 | | callback | 复制操作完成后的回调函数(`可选`) | `function` | `undefined` | 20 | 21 | ## 返回值 22 | 23 | `无` —— 该指令不返回任何值,但会通过回调函数传递复制操作的结果。 24 | 25 | ## 异常 26 | 27 | - 如果 `content` 参数未提供且元素的 `innerText` 也无法获取,将不执行复制操作。 28 | - 如果 `type` 参数不是 '`click`' 或 '`dblclick`' 中的一个,将抛出错误。 29 | 30 | ## 使用 31 | 32 | 在 Vue 模板中,您可以通过以下方式使用 v-copy 指令: 33 | 34 | ```vue 35 | 40 | 41 | 46 | ``` 47 | 48 | ## 传递元素的文本、 49 | 50 | ```vue 51 | 54 | 55 | 60 | ``` 61 | -------------------------------------------------------------------------------- /docs/src/utils/special/Vue/setupDirectivePlugins/vDebounce.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: v-debounce Directive 3 | --- 4 | 5 | # 防抖指令 6 | 7 | ## v-debounce 8 | 9 | ## 说明 10 | 11 | `v-debounce` 用于在元素的事件处理中实现防抖功能。防抖是指在指定的时间内,无论触发了多少次事件,只有第一次事件被执行,然后在该时间过后,防抖效果重置。这个指令可以应用于任何需要防抖逻辑的事件侦听器。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | -------- | ---------------- | ---------- | ------------------ | 17 | | callback | 防抖后的回调函数 | `function` | 无默认值,必须提供 | 18 | | wait | 防抖时间(毫秒) | `number` | `1000` | 19 | 20 | ## 返回值 21 | 22 | 无 —— 该指令不返回任何值。 23 | 24 | ## 异常 25 | 26 | - 如果未提供 `callback` 参数,则会抛出错误。 27 | 28 | ## 使用 29 | 30 | 在 Vue 模板中,您可以通过以下方式使用 `v-debounce` 指令来为元素添加点击事件的防抖逻辑: 31 | 32 | ```vue 33 | 36 | 37 | 42 | ``` 43 | 44 | 在这个例子中,v-debounce:click 为按钮的点击事件添加了防抖逻辑。当用户点击按钮时,只有在最后一次点击后等待了1000毫秒(1秒)没有再次点击,才会执行 handleClick 回调函数。 45 | 46 | 此外,v-debounce 指令也可以应用于其他类型的事件,如输入框的输入事件,只需将指令的事件名改为对应的事件即可: 47 | 48 | ```vue 49 | 52 | 53 | 58 | ``` 59 | -------------------------------------------------------------------------------- /docs/src/utils/special/Vue/setupDirectivePlugins/vDraggable.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: VCopy Directive 3 | --- 4 | 5 | # 拖拽指令 6 | 7 | ## v-draggable 8 | 9 | ## 说明 10 | 11 | `v-draggable` 用于使元素可拖拽。用户可以通过鼠标拖拽来移动元素的位置。该指令允许指定拖拽的父元素,并可以限制拖拽范围不超过父元素的边界。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ---- | ------------------- | -------- | ------ | 17 | | arg | 父元素的 ID(可选) | `string` | --- | 18 | 19 | ## 返回值 20 | 21 | 无 —— 该指令不返回任何值。 22 | 23 | ## 异常 24 | 25 | - 如果提供了 `arg` 参数但未找到对应的父元素,则会在控制台打印错误信息。 26 | 27 | ## 使用 28 | 29 | 在 Vue 模板中,您可以通过以下方式使用 `v-draggable` 指令: 30 | 31 | ```vue 32 | 37 | ``` 38 | 39 | 如果您想要将整个网页作为拖拽区域,可以省略 v-draggable 指令的值 40 | 41 | ```vue 42 | 45 | ``` 46 | -------------------------------------------------------------------------------- /docs/src/utils/special/Vue/setupDirectivePlugins/vHighlight.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: v-highlight Directive 3 | --- 4 | 5 | # 高亮指令 6 | 7 | ## v-highlight 8 | 9 | ## 说明 10 | 11 | `v-highlight` 用于在页面元素中高亮显示特定的文本。该指令支持自定义高亮的文本内容、高亮样式。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ------- | ---------------------- | -------- | ------ | 17 | | keyword | 需要高亮的文本(`必需`) | `string` | `无` | 18 | | style | 高亮显示的样式(`可选`) | `object` | `{}` | 19 | 20 | ## 返回值 21 | 22 | `无` —— 该指令不返回任何值,但会在控制台中打印高亮的文本。 23 | 24 | ## 异常 25 | 26 | - 如果 `keyword` 参数未提供,将抛出错误。 27 | - 如果 `style` 参数不是对象类型,将抛出错误。 28 | 29 | ## 使用 30 | 31 | 在 Vue 模板中,您可以通过以下方式使用 v-highlight 指令: 32 | 33 | ```vue 34 | 39 | ``` 40 | 41 | ## 组件更新时重新高亮 42 | 43 | ```vue 44 | 49 | 50 | 55 | ``` 56 | -------------------------------------------------------------------------------- /docs/src/utils/special/Vue/setupDirectivePlugins/vObserveVisibility.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: v-observe-visibility Directive 3 | --- 4 | 5 | # 监听可见性指令 6 | 7 | ## v-observe-visibility 8 | 9 | ## 说明 10 | 11 | `v-observe-visibility` 指令用于监听一个元素在视口中的可见性变化。当元素的可见性发生变化时,该指令会调用一个用户提供的回调函数,并传递元素的可见性状态。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | -------- | ----------------------------- | ---------- | ------------------------------------------------- | 17 | | callback | 可见性变化时调用的函数 | `Function` | 无 | 18 | | options | IntersectionObserver 的配置项 | `Object` | `{ root: null, rootMargin: '0px', threshold: 0 }` | 19 | 20 | `options` 对象可包含以下属性: 21 | 22 | - `root`: 参照元素,用于定义视口。默认为 `null`,即浏览器视口。 23 | - `rootMargin`: 视口边缘到目标元素边缘之间的距离。默认为 `'0px'`。 24 | - `threshold`: 目标元素进入视口的最小比例,可以是一个值或一个数组。默认为 `0`。 25 | 26 | ## 返回值 27 | 28 | 无 —— 该指令不返回任何值。 29 | 30 | ## 异常 31 | 32 | - 如果未能正确创建 `IntersectionObserver` 实例,则会在控制台打印错误信息。 33 | 34 | ## 使用 35 | 36 | 在 Vue 模板中,您可以通过以下方式使用 `v-observe-visibility` 指令: 37 | 38 | ```vue 39 | 42 | 43 | 57 | ``` 58 | -------------------------------------------------------------------------------- /docs/src/utils/special/Vue/setupDirectivePlugins/vOutsideClick.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: v-outside-click Directive 3 | --- 4 | 5 | # 监听是否在元素外点击指令 6 | 7 | ## v-outside-click 8 | 9 | ## 说明 10 | 11 | `v-outside-click` 指令用于在用户点击组件外部时执行一个回调函数。当用户点击的元素不是绑定该指令的元素或其子元素时,指令会触发一个用户提供的函数。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ----- | -------------------- | ---------- | ------ | 17 | | value | 点击外部时调用的函数 | `Function` | 无 | 18 | 19 | ## 返回值 20 | 21 | 无 —— 该指令不返回任何值。 22 | 23 | ## 异常 24 | 25 | - 无特殊异常处理,但请注意,如果未能正确绑定或解绑事件,可能会导致内存泄漏。 26 | 27 | ## 使用 28 | 29 | 在 Vue 模板中,您可以通过以下方式使用 `v-outside-click` 指令: 30 | 31 | ```vue 32 | 37 | 38 | 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/src/utils/special/Vue/setupDirectivePlugins/vResize.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: v-resize Directive 3 | --- 4 | 5 | # 监听尺寸变化指令 6 | 7 | ## v-resize 8 | 9 | ## 说明 10 | 11 | `v-resize` 指令用于监听和响应元素尺寸的变化。当元素的尺寸发生变化时,该指令会调用一个用户提供的回调函数,传递变化的尺寸信息。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | ----- | -------- | ---------- | ------ | 17 | | value | 回调函数 | `Function` | 无 | 18 | 19 | ## 返回值 20 | 21 | 无 —— 该指令不返回任何值。 22 | 23 | ## 异常 24 | 25 | - 如果浏览器不支持 `ResizeObserver`,则无法使用此指令。 26 | 27 | ## 使用 28 | 29 | 在 Vue 模板中,您可以通过以下方式使用 `v-resize` 指令: 30 | 31 | ```vue 32 | 37 | 38 | 43 | ``` 44 | -------------------------------------------------------------------------------- /docs/src/utils/special/Vue/setupDirectivePlugins/vWaterMarker.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: v-waterMarker Directive 3 | --- 4 | 5 | # 水印指令 6 | 7 | ## v-waterMarker 8 | 9 | ## 说明 10 | 11 | `v-waterMarker` 用于在元素上添加水印效果。该指令会在元素的背景中添加一个旋转和半透明的文字效果,以实现水印的视觉表现。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | --------- | ------------------ | -------- | ---------------------------- | 17 | | text | 水印文字 | `string` | `'atom版权所有'` | 18 | | font | 水印文字的字体 | `string` | `'16px Microsoft JhengHei'` | 19 | | textColor | 水印文字的颜色 | `string` | `'rgba(180, 180, 180, 0.3)'` | 20 | | rotate | 水印文字的旋转角度 | `number` | `-20` | 21 | | size | 水印画布的大小 | `number` | `200` | 22 | 23 | ## 返回值 24 | 25 | 无 —— 该指令不返回任何值。 26 | 27 | ## 异常 28 | 29 | - 如果未能获取到 canvas 的 2D 绘图上下文,则会在控制台打印错误信息,并移除创建的 canvas 元素。 30 | 31 | ## 使用 32 | 33 | 在 Vue 模板中,您可以通过以下方式使用 `v-waterMarker` 指令: 34 | 35 | ```vue 36 | 41 | ``` 42 | 43 | 在这个例子中,v-waterMarker 指令将为绑定的 div 元素添加一个水印,水印文字为 "自定义水印文字",旋转角度为 45 度,画布大小为 300x300 像素。 44 | -------------------------------------------------------------------------------- /docs/src/utils/special/Vue/setupDirectivePlugins/vZoom.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: v-zoom Directive 3 | --- 4 | 5 | # 缩放指令 6 | 7 | ## v-zoom 8 | 9 | ## 说明 10 | 11 | `v-zoom` 用于在用户交互时(如点击和滚动)对元素进行放大和缩小。它通过监听鼠标滚轮事件来改变元素的缩放级别,并允许用户通过点击来进一步放大。 12 | 13 | ## 参数 14 | 15 | `v-zoom` 指令接受一个对象类型的参数,该对象可以包含以下属性: 16 | 17 | | 参数 | 说明 | 类型 | 默认值 | 18 | | -------- | ------------ | ------ | -------- | 19 | | step | 缩放步长 | number | 0.1 | 20 | | minScale | 最小缩放比例 | number | 0.1 | 21 | | maxScale | 最大缩放比例 | number | Infinity | 22 | 23 | ## 返回值 24 | 25 | 该指令不返回任何值。 26 | 27 | ## 使用 28 | 29 | 在 Vue 组件中,您可以通过以下方式使用 `v-zoom` 指令: 30 | 31 | ```vue 32 | 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/src/utils/special/Vue/utils/debounceRef.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: debounceRef 3 | --- 4 | 5 | # 防抖引用 6 | 7 | ## debounceRef 8 | 9 | ## 说明 10 | 11 | `debounceRef` 是一个 Vue3 Composition API 工具函数,它创建了一个防抖的响应式引用。当您在 Vue 组件中使用 `debounceRef` 时,用法同`ref`,可以方便地实现输入防抖逻辑,提高性能,避免因频繁更新数据而造成的性能问题。 12 | 13 | ## 参数 14 | 15 | `debounceRef` 函数接受以下参数: 16 | 17 | | 参数名 | 说明 | 类型 | 默认值 | 18 | |--------|----------------------|---------|--------| 19 | | value | 初始的响应式数据值 | `T` | -- | 20 | | delay | 延迟时间,单位毫秒 | `number` | `200` | 21 | 22 | ## 返回值 23 | 24 | `Ref` - 返回一个具有防抖功能的响应式引用。 25 | 26 | ## 使用 27 | 28 | 在 Vue 组件中,您可以通过以下方式使用 `debounceRef`: 29 | 30 | ```vue 31 | 37 | 38 | -------------------------------------------------------------------------------- /docs/src/utils/special/WeChat/createQRcode.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: QRCode Generator Function 3 | --- 4 | 5 | # 二维码生成 6 | 7 | ### createQRCode 8 | 9 | ## 说明 10 | 11 | `createQRCode` 函数用于生成一个二维码图片。用户可以指定要转换为二维码的内容和一些可选的配置参数。 12 | 13 | 个性化配置请参考 [qrcode](https://www.npmjs.com/package/qrcode) 库的文档。 14 | 15 | ## 参数 16 | 17 | | 参数 | 说明 | 类型 | 默认值 | 18 | | ------- | ---------------------- | -------- | ------ | 19 | | content | 需要转换为二维码的内容 | `string` | - | 20 | | options | 二维码的配置选项 | `Object` | - | 21 | 22 | `options` 对象可以包含以下属性: 23 | 24 | - `size`: 生成二维码的尺寸,默认为300。 25 | - `typeNumber`: 二维码的类型编号,默认为4。 26 | - `errorCorrectLevel`: 二维码的错误校正级别,默认为'M'。 27 | 28 | ## 返回值 29 | 30 | `Promise` - 返回一个Promise,解析为base64编码的二维码图片。 31 | 32 | ## 代码演示 33 | 34 | ### 基础用法 35 | 36 | ```typescript 37 | import { createQRCode } from 'atom-tools' 38 | 39 | // 使用 createQRCode 生成二维码 40 | createQRCode('Hello, World!') 41 | .then((base64QRCode) => { 42 | // 使用base64编码的二维码图片 43 | console.log(base64QRCode) 44 | }) 45 | .catch((error) => { 46 | // 处理可能发生的错误 47 | console.error(error) 48 | }) 49 | ``` 50 | 51 | ### 个性化配置 52 | 53 | ```typescript 54 | import { createQRCode } from 'atom-tools' 55 | 56 | // 使用 createQRCode 生成二维码,并设置自定义配置 57 | createQRCode('Hello, Custom QRCode!', { 58 | size: 500, 59 | typeNumber: 4, 60 | errorCorrectLevel: 'H' 61 | }) 62 | .then((base64QRCode) => { 63 | // 使用自定义配置生成的base64编码的二维码图片 64 | console.log(base64QRCode) 65 | }) 66 | .catch((error) => { 67 | // 处理可能发生的错误 68 | console.error(error) 69 | }) 70 | ``` 71 | -------------------------------------------------------------------------------- /docs/src/utils/special/WeChat/uploadFile.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Upload File Function 3 | --- 4 | 5 | # 文件上传 6 | 7 | ### uploadFile 8 | 9 | ## 说明 10 | 11 | `uploadFile` 函数用于在微信小程序环境中上传文件。它接受一个包含上传参数的对象。函数返回一个`Promise`,允许调用者通过链式调用`.then()`来处理上传成功的结果。 12 | 13 | ## 参数 14 | 15 | | 参数 | 说明 | 类型 | 默认值 | 16 | | --------------- | ------------------ | -------- | ------ | 17 | | params | 上传参数对象 | `Object` | - | 18 | | params.url | 上传接口的url | `string` | - | 19 | | params.filePath | 需要上传的文件路径 | `string` | - | 20 | | params.name | 文件对应的 key | `string` | - | 21 | | params.formData | 其他额外的表单数据 | `Object` | `{}` | 22 | 23 | ## 返回值 24 | 25 | `Promise` - 返回一个Promise,解析为上传成功的响应对象。 26 | 27 | ## 代码演示 28 | 29 | ### 基础用法 30 | 31 | ```javascript 32 | import { uploadFile } from 'atom-tools' 33 | 34 | const params = { 35 | url: 'https://example.com/upload', // 替换为实际的上传接口URL 36 | filePath: '/path/to/your/file', // 替换为实际的文件路径 37 | name: 'file', // 替换为实际的文件字段名 38 | // 其他额外的表单数据 39 | formData: { 40 | additionalField: 'value' 41 | } 42 | } 43 | 44 | uploadFile(params) 45 | .then((response) => { 46 | console.log('文件上传成功:', response) 47 | }) 48 | .catch((error) => { 49 | console.error('文件上传失败:', error) 50 | }) 51 | ``` 52 | -------------------------------------------------------------------------------- /extract-commit.mjs: -------------------------------------------------------------------------------- 1 | import { execSync } from 'child_process' 2 | import fs from 'fs/promises' 3 | import { resolve } from 'path' 4 | import { fileURLToPath } from 'url' 5 | 6 | const __dirname = fileURLToPath(new URL('.', import.meta.url)) 7 | 8 | const commitInfoDir = resolve(__dirname, 'docs') // 文件夹路径 9 | const commitInfoPath = resolve(__dirname, 'docs/src', 'commitInfo.js') // 文件路径 10 | 11 | console.log('Directory:', commitInfoDir) 12 | console.log('File Path:', commitInfoPath) 13 | 14 | // 检查文件是否存在,如果不存在,则创建文件 15 | async function createFileIfNotExists(filePath) { 16 | try { 17 | await fs.access(filePath) // 检查文件是否存在 18 | } catch (error) { 19 | // 如果文件不存在,创建文件并初始化为空 20 | await fs.writeFile(filePath, '') 21 | console.log('File did not exist, creating it now...') 22 | } 23 | } 24 | 25 | // 写入 commit 信息到文件 26 | async function extractCommitInfo() { 27 | try { 28 | // 确保文件存在 29 | await createFileIfNotExists(commitInfoPath) 30 | 31 | // 执行 Git 命令获取 commit 消息 32 | const commitMessagesRaw = execSync('git log --pretty=%B').toString() 33 | 34 | // 执行 Git 命令获取所有提交的时间 35 | const commitTime = execSync('git log --pretty=%ad --date=format:"%Y-%m-%d %H:%M:%S"') 36 | .toString() 37 | .trim() 38 | .split('\n') 39 | 40 | const commitHash = execSync('git log --pretty=format:"%h"').toString().trim().split('\n') 41 | 42 | // 使用正则表达式按两个换行符分割 message 43 | const commitMessages = commitMessagesRaw.split(/\n\n/).map((msg) => msg.trim()) 44 | 45 | // 创建新的 commit 对象数组 46 | const newCommitEntries = commitMessages.map((i, idx) => { 47 | return `{ 48 | hash: ${JSON.stringify(commitHash[idx])}, 49 | message:${JSON.stringify(i)}, 50 | commitTime:${JSON.stringify(commitTime[idx])} 51 | }` 52 | }) 53 | // 将 commit 信息格式化为对象 54 | const commitInfo = `export const commitHistory = [ 55 | ${newCommitEntries} 56 | ];` 57 | 58 | // 写入 commit 信息到文件 59 | await fs.writeFile(commitInfoPath, commitInfo) 60 | console.log('Commit information has been extracted.') 61 | } catch (error) { 62 | console.error('Error writing commit information:', error.message) 63 | } 64 | } 65 | 66 | // extractCommitInfo() 67 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinHanlove/atom-module-tools/34306a90311ee64144ad897281ab511883b7fc88/index.d.ts -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /lib/public/Array/index.ts: -------------------------------------------------------------------------------- 1 | import { TYPE } from '@/public/types/global' 2 | /** 3 | * @function 给定一个数组,根据数组的某一属性排序 4 | * @param array 需要排序的数组对象 5 | * @param key 以什么字段排序 6 | */ 7 | export const arraySortByKey = (params: TYPE.IArraySortByKey) => { 8 | const { array, key } = params 9 | return array.sort((a, b) => { 10 | const k1 = a[key] 11 | const k2 = b[key] 12 | if (k1 < k2) { 13 | return -1 14 | } else if (k1 > k2) { 15 | return 1 16 | } else { 17 | return 0 18 | } 19 | }) 20 | } 21 | 22 | /** 23 | * @function 给定一个数组,根据数组的某一属性去重 24 | * @param arr 要去重的数组 25 | * @param prop 属性值 26 | * @param callback 回调函数 27 | * @returns 去重后的数组 28 | */ 29 | export const uniqueByProperty = (params: TYPE.IUniqueByProperty) => { 30 | const { array, key, callback } = params 31 | const map = new Map() 32 | array.forEach((item) => map.set(item[key], item)) 33 | 34 | const result = Array.from(map.values()) 35 | 36 | return callback ? callback(result) : result 37 | } 38 | 39 | /** 40 | * @function 给定一个对象数组,根据指定的属性进行模糊匹配,并返回匹配到的对象 41 | * @param array 要去重的数组 42 | * @param prop 属性值 43 | * @param key 模糊字符串 44 | * @param callback 回调函数 45 | * @returns 46 | */ 47 | export const fuzzyMatchByProperty = (params: TYPE.IFuzzyMatchByProperty) => { 48 | const { array, prop, key, callback } = params 49 | const reg = new RegExp(key.split('').join('.*'), 'g') 50 | const fuzzyMatch = array.filter((item) => { 51 | return reg.test(item[prop]) ?? item[prop].includes(key) 52 | }) 53 | 54 | return callback ? callback(fuzzyMatch) : fuzzyMatch 55 | } 56 | -------------------------------------------------------------------------------- /lib/public/Browser/index.ts: -------------------------------------------------------------------------------- 1 | import { TYPE } from '@/public/types/global' 2 | /** 3 | * @function 一键复制 4 | * @param value 要复制的文本 5 | * @param callback 回调函数 6 | * @returns 7 | */ 8 | export const copyText = async (value: string) => { 9 | return new Promise((resolve, reject) => { 10 | try { 11 | if (window.navigator.clipboard) { 12 | window.navigator.clipboard.writeText(value) 13 | } else { 14 | const textarea = document.createElement('textarea') 15 | document.body.appendChild(textarea) 16 | textarea.value = value 17 | textarea.select() 18 | document.execCommand('copy') 19 | document.body.removeChild(textarea) 20 | } 21 | resolve(value) 22 | } catch (error) { 23 | reject(error) 24 | } 25 | }) 26 | } 27 | 28 | /** 29 | * @function 将rgb颜色灰度化 基于光感加权平均值 30 | * @param rgb 31 | * @returns 灰度值 32 | */ 33 | export const rgbGray = (rgb: string[] | string) => { 34 | let rgbValue = [] as string[] 35 | if (typeof rgb === 'string') rgbValue = rgb.split(',') 36 | if (Array.isArray(rgb)) rgbValue = rgb 37 | 38 | const r = parseInt(rgbValue[0]) 39 | const g = parseInt(rgbValue[1]) 40 | const b = parseInt(rgbValue[2]) 41 | console.log(r, g, b) 42 | 43 | return 0.2126 * r + 0.7152 * g + 0.0722 * b 44 | } 45 | 46 | /** 47 | * @function 解析url地址中的参数 返回一个对象 48 | * @param url 49 | * @returns 参数对象 50 | */ 51 | export const getUrlParams = (url: string, key?: string) => { 52 | const params = {} as TYPE.anyType 53 | url.replace(/[?&]+([^=&]+)=([^&]*)/gi, (_, key, value) => (params[key] = value)) 54 | if (key && !params[key]) { 55 | throw new Error(`Parameter ${key} not found in URL.`) 56 | } 57 | 58 | return key ? params[key] : params 59 | } 60 | 61 | /** 62 | * @function 生成随机HEX颜色 63 | * @returns 64 | */ 65 | export const randomHexColor = () => { 66 | return `#${Math.floor(Math.random() * 0xffffff) 67 | .toString(16) 68 | .padEnd(6, '0')}` 69 | } 70 | 71 | /** 72 | * @function 去掉标签字符串中的元素标记 73 | * @param str 元素标签字符串 74 | * @returns 75 | */ 76 | export const removeElementMark = (str: string) => { 77 | return new DOMParser().parseFromString(str, 'text/html').body.textContent || '' 78 | } 79 | 80 | /** 81 | * @function 全屏 82 | */ 83 | export const toFullScreen = (): void => { 84 | const element = document.documentElement as TYPE.IFullScreenAbleHTMLElement 85 | const requestFullScreenMethod = 86 | element.requestFullscreen || 87 | element.mozRequestFullScreen || 88 | element.webkitRequestFullscreen || 89 | element.msRequestFullscreen 90 | 91 | if (typeof requestFullScreenMethod === 'function') { 92 | requestFullScreenMethod.call(element) 93 | } else { 94 | console.error('浏览器不支持全屏') 95 | } 96 | } 97 | 98 | /** 99 | * @function 退出全屏 100 | */ 101 | export const exitFullScreen = (): void => { 102 | const document = window.document as TYPE.IExitFullScreenAbleHTMLElement 103 | const exitFullScreenMethod = 104 | document.exitFullscreen || 105 | document.mozCancelFullScreen || 106 | document.webkitExitFullscreen || 107 | document.msExitFullscreen 108 | 109 | if (typeof exitFullScreenMethod === 'function') { 110 | exitFullScreenMethod.call(document) 111 | } else { 112 | console.error('浏览器不支持退出全屏') 113 | } 114 | } 115 | 116 | /** 117 | * @function 禁止右键,选择,复制 118 | */ 119 | export const preventRightKey = () => { 120 | ['contextmenu', 'selectstart', 'copy'].forEach(function (e) { 121 | document.addEventListener(e, function (event) { 122 | return (event.returnValue = false) 123 | }) 124 | }) 125 | } 126 | 127 | /** 128 | * 清除指定的 cookie 或所有 cookie。 129 | * @param name 可选。如果提供,将清除指定名称的 cookie。 130 | */ 131 | export const clearAllCookie = (name?: string) => { 132 | if (name) { 133 | // 清除指定名称的 cookie 134 | document.cookie = name + '=0; path=/; expires=' + new Date(0).toUTCString() 135 | document.cookie = 136 | name + '=0; path=/; domain=' + document.domain + '; expires=' + new Date(0).toUTCString() 137 | } else { 138 | // 清除所有 cookie 139 | const cookies = document.cookie.split(';') 140 | for (let i = 0; i < cookies.length; i++) { 141 | let cookie = cookies[i].trim() 142 | const eqPos = cookie.indexOf('=') 143 | let name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie 144 | document.cookie = name + '=0; path=/; expires=' + new Date(0).toUTCString() 145 | document.cookie = 146 | name + '=0; path=/; domain=' + document.domain + '; expires=' + new Date(0).toUTCString() 147 | } 148 | } 149 | } 150 | 151 | /** 152 | * @function 判断是否是微信浏览器 153 | */ 154 | export const isWxBrowser = () => { 155 | const ua = window.navigator.userAgent.toLowerCase(); 156 | return /micromessenger/i.test(ua); 157 | }; 158 | 159 | /** 160 | * @function 判断是否是支付宝浏览器 161 | */ 162 | export const isAliBrowser = () => { 163 | const ua = window.navigator.userAgent.toLowerCase(); 164 | return /alipayclient/i.test(ua); 165 | }; 166 | 167 | /** 168 | * @function 判断是否是抖音客户端浏览器 169 | */ 170 | export const isDouyinBrowser = () => { 171 | const ua = window.navigator.userAgent.toLowerCase(); 172 | return /aweme/i.test(ua); 173 | }; 174 | 175 | /** 176 | * @function 判断是否是抖音极速版客户端浏览器 177 | */ 178 | export const isDouyinLiteBrowser = () => { 179 | const ua = window.navigator.userAgent.toLowerCase(); 180 | return /aweme_lite/i.test(ua); 181 | }; 182 | 183 | /** 184 | * @function 判断是否是QQ浏览器 185 | */ 186 | export const isQqBrowser = () => { 187 | const ua = window.navigator.userAgent.toLowerCase(); 188 | return /mqqbrowser|mobile qq/i.test(ua); 189 | }; 190 | 191 | /** 192 | * @function 判断是否是百度浏览器 193 | */ 194 | export const isBaiduBrowser = () => { 195 | const ua = window.navigator.userAgent.toLowerCase(); 196 | return /baidubrowser/i.test(ua); 197 | }; 198 | 199 | /** 200 | * @function 判断是否是Safari浏览器 201 | */ 202 | export const isSafariBrowser = () => { 203 | const ua = window.navigator.userAgent.toLowerCase(); 204 | return /safari/i.test(ua) && !/chrome/i.test(ua); 205 | }; 206 | 207 | /** 208 | * @function 判断是否是UC浏览器 209 | */ 210 | export const isUcBrowser = () => { 211 | const ua = window.navigator.userAgent.toLowerCase(); 212 | return /ucbrowser/i.test(ua); 213 | }; 214 | 215 | /** 216 | * @function 判断是否是360浏览器 217 | */ 218 | export const is360Browser = () => { 219 | const ua = window.navigator.userAgent.toLowerCase(); 220 | return /360browser/i.test(ua); 221 | }; 222 | 223 | /** 224 | * @function 判断是否是搜狗浏览器 225 | */ 226 | export const isSogouBrowser = () => { 227 | const ua = window.navigator.userAgent.toLowerCase(); 228 | return /sogoumobilebrowser/i.test(ua); 229 | }; -------------------------------------------------------------------------------- /lib/public/File/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 将文件转换为数据 URL。 3 | * @param file 要转换的文件。 4 | * @returns 返回数据 URL 字符串 5 | */ 6 | export const fileToDataURL = (file: File): Promise => { 7 | return new Promise((resolve, reject) => { 8 | if (!file) { 9 | reject(new Error('Invalid file object provided.')); 10 | return; 11 | } 12 | const reader = new FileReader(); 13 | reader.onload = function () { 14 | if (reader.result && typeof reader.result === 'string') { 15 | resolve(reader.result as string); 16 | } 17 | }; 18 | reader.onerror = function (e) { 19 | reject(e); 20 | }; 21 | reader.readAsDataURL(file); 22 | }); 23 | }; 24 | 25 | /** 26 | * 将数据 URL 转换为图像元素。 27 | * @param dataURL 图像的数据 URL。 28 | * @returns 返回图像元素 29 | */ 30 | export const dataURLToImage = (dataURL: string): Promise => { 31 | return new Promise((resolve, reject) => { 32 | if (!dataURL) { 33 | reject(new Error('Invalid data URL provided.')); 34 | return; 35 | } 36 | const img = new Image(); 37 | img.onload = () => resolve(img); 38 | img.onerror = () => reject(new Error('Failed to load image from data URL.')); 39 | img.src = dataURL; 40 | }); 41 | }; 42 | 43 | /** 44 | * 将画布转换为文件。 45 | * @param canvas 要转换的画布元素。 46 | * @param type 文件的类型(例如 'image/png')。 47 | * @param quality 输出文件的质量(对于 image/jpeg,范围是 0-1)。 48 | * @returns Blob 或 null。 49 | */ 50 | export const canvasToFile = ( 51 | canvas: HTMLCanvasElement, 52 | type: string, 53 | quality: number 54 | ): Promise => { 55 | return new Promise((resolve, reject) => { 56 | if (!canvas) { 57 | reject(new Error('Invalid canvas element provided.')); 58 | return; 59 | } 60 | if (typeof type !== 'string' || !type) { 61 | reject(new Error('Invalid file type provided.')); 62 | return; 63 | } 64 | if (quality < 0 || quality > 100) { 65 | reject(new Error('Quality must be between 0 and 100.')); 66 | return; 67 | } 68 | canvas.toBlob((blob) => resolve(blob), type, convertQualityToBit(quality)); 69 | }); 70 | }; 71 | 72 | /** 73 | * 将质量值转换为图像文件的比特率。 74 | * @param quality 质量值(0-100)。 75 | * @returns 对应的比特率(0-256)。 76 | */ 77 | export const convertQualityToBit = (quality: number): number => { 78 | if (quality < 0 || quality > 100) { 79 | throw new Error('Quality must be between 0 and 100.'); 80 | } 81 | return !quality ? 0 : Math.min(quality * 256 * 0.01, 256); 82 | }; 83 | 84 | /** 85 | * 将文件大小格式化为易读的字符串。 86 | * @param size 文件大小,单位为字节。 87 | * @returns 表示文件大小的字符串(B、KB、MB、GB)。 88 | */ 89 | export const formatFileSize = (size: number): string => { 90 | if (size < 0) { 91 | throw new Error('Size must be a non-negative number.'); 92 | } 93 | if (size < 1024) { 94 | return `${size}B`; 95 | } else if (size < 1024 * 1024) { 96 | return `${(size / 1024).toFixed(2)}KB`; 97 | } else if (size < 1024 * 1024 * 1024) { 98 | return `${(size / 1024 / 1024).toFixed(2)}MB`; 99 | } 100 | return `${(size / 1024 / 1024 / 1024).toFixed(2)}GB`; 101 | }; 102 | 103 | /** 104 | * 读取文件的内容作为文本。 105 | * @param file 要读取的文件。 106 | * @returns 返回文件内容作为字符串 107 | */ 108 | export const readFileAsText = (file: File): Promise => { 109 | return new Promise((resolve, reject) => { 110 | if (!file) { 111 | reject(new Error('Invalid file object provided.')); 112 | return; 113 | } 114 | const reader = new FileReader(); 115 | reader.onload = function () { 116 | if (reader.result && typeof reader.result === 'string') { 117 | resolve(reader.result as string); 118 | } 119 | }; 120 | reader.onerror = function (e) { 121 | reject(e); 122 | }; 123 | reader.readAsText(file); 124 | }); 125 | }; 126 | 127 | /** 128 | * 从给定的 Blob 和文件名创建文件。 129 | * @param blob 要转换为文件的 Blob。 130 | * @param filename 文件的名称。 131 | * @returns 一个新的 File 对象。 132 | */ 133 | export const createFileFromBlob = (blob: Blob, filename: string): File => { 134 | if (!blob) { 135 | throw new Error('Invalid Blob object provided.'); 136 | } 137 | if (!filename) { 138 | throw new Error('Filename must be provided.'); 139 | } 140 | return new File([blob], filename, { type: blob.type }); 141 | }; 142 | 143 | /** 144 | * 通过创建链接并触发下载来保存文件。 145 | * @param blob 要保存的 Blob。 146 | * @param filename 文件的名称。 147 | */ 148 | export const saveFile = (blob: Blob, filename: string) => { 149 | if (!blob) { 150 | throw new Error('Invalid Blob object provided.'); 151 | } 152 | if (!filename) { 153 | throw new Error('Filename must be provided.'); 154 | } 155 | const link = document.createElement('a'); 156 | link.href = window.URL.createObjectURL(blob); 157 | link.download = filename; 158 | link.click(); 159 | window.URL.revokeObjectURL(link.href); 160 | }; 161 | 162 | /** 163 | * 获取文件的扩展名。 164 | * @param file 要获取扩展名的文件。 165 | * @returns 文件的扩展名。 166 | */ 167 | export const getFileExtension = (file: File): string => { 168 | if (!file) { 169 | throw new Error('Invalid file object provided.'); 170 | } 171 | return file.name.split('.').pop() ?? ''; 172 | }; -------------------------------------------------------------------------------- /lib/public/FormatDate/constant.ts: -------------------------------------------------------------------------------- 1 | export const DATA_CONSTANT = { 2 | // 一天的毫秒数 3 | ONE_DAY: 24 * 60 * 60 * 1000, 4 | // 一小时的毫秒数 5 | ONE_HOUR: 60 * 60 * 1000, 6 | // 一分钟的毫秒数 7 | ONE_MINUTE: 60 * 1000, 8 | // 一秒的毫秒数 9 | ONE_SECOND: 1000, 10 | // 今天(当天00:00:00)的时间戳 11 | TODAY: new Date().setHours(0, 0, 0, 0), 12 | // 明天(第二天00:00:00)的时间戳 13 | TOMORROW: new Date().setHours(24, 0, 0, 0), 14 | // 昨天(前一天00:00:00)的时间戳 15 | YESTERDAY: new Date().setHours(-24, 0, 0, 0), 16 | // 本周的第一天(周一00:00:00)的时间戳 17 | THIS_WEEK: (() => { 18 | const day = new Date().getDay() || 7 19 | return new Date(new Date().setDate(new Date().getDate() - day)).getTime() 20 | })(), 21 | // 下周的第一天(周一00:00:00)的时间戳 22 | NEXT_WEEK: (() => { 23 | const day = new Date().getDay() || 7 24 | return new Date(new Date().setDate(new Date().getDate() + (7 - day))).getTime() 25 | })(), 26 | // 上周的最后一天(周日23:59:59)的时间戳 27 | LAST_WEEK: (() => { 28 | const day = new Date().getDay() || 8 29 | return new Date(new Date().setDate(new Date().getDate() - day + 1)).getTime() 30 | })(), 31 | // 本月第一天(00:00:00)的时间戳 32 | THIS_MONTH: (() => { 33 | return new Date(new Date().getFullYear(), new Date().getMonth(), 1).getTime() 34 | })(), 35 | // 下月第一天(00:00:00)的时间戳 36 | NEXT_MONTH: (() => { 37 | return new Date(new Date().getFullYear(), new Date().getMonth() + 1, 1).getTime() 38 | })(), 39 | // 上月最后一天(23:59:59)的时间戳 40 | LAST_MONTH: (() => { 41 | const lastDayOfMonth = new Date(new Date().getFullYear(), new Date().getMonth(), 0) 42 | return lastDayOfMonth.getTime() 43 | })() 44 | } 45 | -------------------------------------------------------------------------------- /lib/public/FormatDate/index.ts: -------------------------------------------------------------------------------- 1 | import * as CONSTANT from './constant' 2 | import { isNaN } from '../TypeCheck' 3 | import { TYPE } from '@/public/types/global' 4 | 5 | /** 6 | * @function 将传入的值转换为日期对象,如果无法转换则抛出错误。 7 | * @param date 需要转换的日期值,可以是字符串、时间戳、Date对象、null 或 undefined。 8 | * @return 如果转换成功,返回 Date 对象;如果失败,抛出错误。 9 | */ 10 | export const toDate = (date: string | number | Date | null | undefined): Date => { 11 | if (date === null || date === undefined) { 12 | throw new Error('日期参数为空,无法转换为日期对象') 13 | } 14 | 15 | let parsedDate: Date 16 | 17 | if (typeof date === 'string') { 18 | parsedDate = new Date(date) 19 | if (isNaN(parsedDate.getTime())) { 20 | throw new Error('无法识别日期类型: Invalid date format') 21 | } 22 | } else if (typeof date === 'number') { 23 | // 假设时间戳是以毫秒为单位的 24 | parsedDate = new Date(date) 25 | if (isNaN(parsedDate.getTime())) { 26 | throw new Error('提供的数字不是一个有效的时间戳') 27 | } 28 | } else if (date instanceof Date) { 29 | parsedDate = date 30 | } else { 31 | throw new Error('无法识别日期类型: Invalid date format') 32 | } 33 | 34 | return parsedDate 35 | } 36 | 37 | 38 | /** 39 | * @function 指定日期转星期 40 | */ 41 | export const transformDateWeekCN = (date: Date | number): string => { 42 | const WEEK = ['日', '一', '二', '三', '四', '五', '六'] 43 | const text = '周' 44 | 45 | if (typeof date === 'number' && date >= 0 && date <= 6) { 46 | // 如果是数字,直接通过数组索引获取对应的中文星期 47 | return text + WEEK[date] 48 | } else if (date instanceof Date) { 49 | // 如果是 Date 对象,获取 day 属性对应的星期 50 | return text + WEEK[date.getDay()] 51 | } else { 52 | // 如果输入类型不匹配,可以抛出错误或者返回一个默认值 53 | throw new Error('输入必须是 Date 对象或 0-6 之间的数字') 54 | } 55 | } 56 | 57 | /** 58 | * @function 获取某个日期是当年的第几天 59 | */ 60 | export const getDayOfYear = (value: Date | number) => { 61 | const date = toDate(value) 62 | const start = new Date(date.getFullYear(), 0, 1) 63 | const diff = (date as Date).valueOf() - start.valueOf() 64 | return Math.floor(diff / CONSTANT.DATA_CONSTANT.ONE_DAY) + 1 65 | } 66 | 67 | /** 68 | * @function 判断是闰年还是平年 69 | * @param year 年份 70 | * @returns 71 | */ 72 | export const isLeapYear = (year: number) => { 73 | return (year % 4 === 0 && !(year % 100 === 0)) || year % 400 === 0 74 | } 75 | 76 | /** 77 | * @function 计算两个日期之间的天数差 78 | * @param lastDate 开始日期 79 | * @param nextDate 结束日期 80 | * @returns 81 | */ 82 | export const getTwoDaysApart = ( 83 | lastDate: string | number | Date, 84 | nextDate: string | number | Date 85 | ) => { 86 | // 计算两个日期之间的天数差 87 | const timeDifference = Math.abs(toDate(lastDate).getTime() - toDate(nextDate).getTime()) 88 | // 将毫秒差转换为天数,并四舍五入 89 | return Math.ceil(timeDifference / CONSTANT.DATA_CONSTANT.ONE_DAY) 90 | } 91 | 92 | /** 93 | * 参数归一化函数,将传入的格式化字符串或函数规范化, 94 | * 以便于在日期格式化中使用。 95 | * 96 | * @param formatter 可以是日期格式化的字符串描述,或者是一个格式化函数 97 | * @returns 返回一个格式化函数 98 | */ 99 | const formatNormalize = (formatter: string | ((dateInfo: TYPE.IDateInfo) => string)) =>{ 100 | 101 | // 如果传入的是一个函数,则直接返回该函数 102 | if (typeof formatter === 'function') return formatter; 103 | 104 | // 边界情况:如果传入的不是字符串,则抛出错误 105 | if (typeof formatter !== 'string') { 106 | throw new Error('formatter must be a string or a function!'); 107 | } 108 | 109 | // 根据传入的格式化字符串关键字,映射到具体的格式化模板 110 | const formatMap: { [key: string]: string } = { 111 | date: 'yyyy-MM-dd', 112 | dateTime: 'yyyy-MM-dd HH:mm:ss', 113 | time: 'HH:mm:ss', 114 | year: 'yyyy', 115 | monthDay: 'MM-dd' 116 | }; 117 | 118 | // 使用查找表获取格式化模板 119 | const formatString = formatMap[formatter] || formatter; 120 | 121 | return (dateInfo:any) => { 122 | const { yyyy, MM, dd, HH, mm, ss } = dateInfo; 123 | 124 | // 使用正则替换,将格式化模板中的占位符替换为对应的日期时间信息 125 | return formatString.replace(/yyyy/g, yyyy) 126 | .replace(/MM/g, MM) 127 | .replace(/dd/g, dd) 128 | .replace(/HH/g, HH) 129 | .replace(/mm/g, mm) 130 | .replace(/ss/g, ss); 131 | }; 132 | } 133 | 134 | /** 135 | * 格式化日期函数,根据提供的格式化选项将 Date 对象转换为字符串 136 | * 137 | * @param date Date对象,需要被格式化的日期 138 | * @param formatter 日期的格式化描述或格式化函数 139 | * @param isPad 是否对日期时间的各个部分进行零填充 140 | * @returns 返回格式化后的日期字符串 141 | */ 142 | export const formatDate = (date: Date, formatter:string| ((dateInfo: any) => string), isPad: boolean = true) => { 143 | // 参数归一化 144 | formatter = formatNormalize(formatter) ; 145 | 146 | const pad = (value: number|string, length: number = 2) => { 147 | return isPad ? (value+'').padStart(length, '0') : String(value); 148 | }; 149 | 150 | const dateInfo: { [key: string]: string | number } = { 151 | yyyy: date.getFullYear(), 152 | MM: date.getMonth() + 1, 153 | dd: date.getDate(), 154 | HH: date.getHours(), 155 | mm: date.getMinutes(), 156 | ss: date.getSeconds() 157 | }; 158 | 159 | // 对日期信息中的年月日时分秒进行格式化,根据isPad选项决定是否进行零填充 160 | dateInfo.yyyy = pad(dateInfo.yyyy, 4); 161 | dateInfo.MM = pad(dateInfo.MM); 162 | dateInfo.dd = pad(dateInfo.dd); 163 | dateInfo.HH = pad(dateInfo.HH); 164 | dateInfo.mm = pad(dateInfo.mm); 165 | dateInfo.ss = pad(dateInfo.ss); 166 | 167 | // 使用传入的formatter函数进行格式化 168 | return formatter(dateInfo); 169 | }; -------------------------------------------------------------------------------- /lib/public/HighOrderFunction/KeepLoop.ts: -------------------------------------------------------------------------------- 1 | import { TYPE, log } from '../main'; 2 | 3 | 4 | 5 | /** 6 | *@class 定时轮询的类 7 | */ 8 | export class KeepLoop { 9 | // 参数列表 10 | option: TYPE.IKeepLoopOption; 11 | 12 | // 定时器 13 | private timer: NodeJS.Timeout | null = null; 14 | 15 | // 当前轮询次数 16 | private count: number = 0; 17 | 18 | // 控制轮询是否暂停 19 | private isPaused: boolean = false; 20 | 21 | 22 | constructor(option: TYPE.IKeepLoopOption) { 23 | this.option = this.init(option); 24 | } 25 | 26 | // 初始化参数 27 | private init(option: TYPE.IKeepLoopOption): TYPE.IKeepLoopOption { 28 | if (typeof option.run !== 'function') { 29 | throw new Error('The "run" option must be a function.'); 30 | } 31 | 32 | if (typeof option.interval !== 'number' || option.interval <= 0) { 33 | throw new Error('The "interval" option must be a positive number.'); 34 | } 35 | 36 | const params = { 37 | run: option.run, 38 | interval: option.maxCount ? Math.abs(parseInt(option.interval.toString(), 10)):1000, 39 | maxCount: option.maxCount ? Math.abs(parseInt(option.maxCount.toString(), 10)) : 0, 40 | }; 41 | 42 | return params; 43 | } 44 | 45 | public start(): void { 46 | // 如果 KeepLoop 已经运行,则不执行任何操作 47 | if (this.timer !== null) { 48 | log.info('KeepLoop is already running.'); 49 | return; 50 | } 51 | 52 | // 如果 KeepLoop 被暂停了,恢复轮询 53 | if (this.isPaused) { 54 | log.info('Resuming KeepLoop from paused state.'); 55 | this.isPaused = false; 56 | } else { 57 | // 重置计数器 58 | this.count = 0; 59 | log.info('Starting KeepLoop for the first time or after stopping.'); 60 | } 61 | 62 | // 执行轮询 63 | this.run(); 64 | } 65 | 66 | 67 | // 暂停轮询 68 | public pause(): void { 69 | if (!this.isPaused) { 70 | this.isPaused = true; 71 | } 72 | } 73 | 74 | // 恢复轮询 75 | public resume(): void { 76 | if (!this.isPaused) { 77 | log.warning('KeepLoop is not paused or has already been resumed.'); 78 | return; 79 | } 80 | this.isPaused = false; 81 | 82 | // 如果定时器不存在,需要重新设置 83 | if (this.timer === null) { 84 | // 重新设置定时器以继续轮询 85 | this.timer = setTimeout(this.run.bind(this), this.option.interval); 86 | } else { 87 | // 如果定时器存在,可能无需重新设置,但需要确保状态是正确的 88 | // 这里可以添加逻辑来调整定时器,以补偿因暂停造成的延迟 89 | // 例如,如果需要立即执行下一次轮询而不是等待当前定时器完成,可以这样做: 90 | clearTimeout(this.timer); 91 | this.timer = setTimeout(this.run.bind(this), 0); 92 | } 93 | } 94 | 95 | // 停止轮询 96 | public stop(): void { 97 | if (this.timer) { 98 | clearTimeout(this.timer); 99 | this.timer = null; 100 | this.count = 0; 101 | this.isPaused = false; // 确保停止时不再处于暂停状态 102 | log.info('KeepLoop has been stopped.'); 103 | } 104 | } 105 | 106 | //轮训处理函数 107 | private run(): void { 108 | try { 109 | 110 | if (this.isPaused) { 111 | log.info('KeepLoop is paused. Skipping run.'); 112 | return; 113 | } 114 | 115 | // 计数器加1 116 | this.count++; 117 | 118 | // 定义返回参数 119 | const returnInfo: TYPE.IReturnInfo = { 120 | currentCount: this.count, 121 | }; 122 | 123 | // 执行轮询函数 124 | this.option.run(returnInfo); 125 | 126 | // 判断是否达到最大次数或是否需要继续轮询 127 | if (!this.isPaused && (!this.option.maxCount || this.count < this.option.maxCount)) { 128 | // 继续轮询 129 | this.timer = setTimeout(this.run.bind(this), this.option.interval); 130 | } else { 131 | log.info('轮询完成或达到最大次数,不再继续。'); 132 | return 133 | } 134 | } catch (err) { 135 | log.error('Error during KeepLoop run:', err); 136 | this.stop(); // 确保出错时停止轮询 137 | } 138 | } 139 | } -------------------------------------------------------------------------------- /lib/public/HighOrderFunction/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * sleep 函数用于模拟异步操作的延迟。 3 | * 它接受一个表示延迟时间(以毫秒为单位)的参数,并返回一个 Promise 对象。 4 | * 当指定的延迟时间过后,Promise 会被 resolve。 5 | * @function 6 | * @param {number} duration - 延迟的时间,单位为毫秒。 7 | * @returns {Promise} - 一个在延迟时间过后解析的 Promise 对象。 8 | */ 9 | export const sleep = (duration: number | undefined) => { 10 | return new Promise((resolve) => { 11 | setTimeout(resolve, duration) 12 | }) 13 | } 14 | 15 | /** 16 | * @function 深度克隆一个值。 17 | * 使用 JSON 方法进行序列化和反序列化来实现深度克隆。 18 | * 注意:此方法不能克隆函数、undefined、循环引用的对象等。 19 | * 20 | * @param {*} value - 需要深度克隆的值。 21 | * @returns {*} 深度克隆后的值。 22 | */ 23 | export const cloneDeep = (value: unknown) => { 24 | return JSON.parse(JSON.stringify(value)) 25 | } 26 | 27 | /** 28 | * @function 创建一个节流函数,确保函数在指定的时间间隔内最多执行一次。 29 | * @param {Function} func - 需要节流的函数。 30 | * @param {number} limit - 时间间隔,单位为毫秒。必须是一个大于0的数字。 31 | * @param {boolean} immediate - 可选,是否立即执行函数。默认为 false。 32 | * @returns {Function} - 节流后的函数。 33 | */ 34 | export const throttle = (func: Function, limit: number, immediate?: boolean): Function => { 35 | if (typeof limit !== 'number' || limit <= 0) { 36 | throw new Error('throttle function expects a positive number as the limit') 37 | } 38 | 39 | let timeout: NodeJS.Timeout | null = null 40 | let lastExecution: number = 0 41 | let inThrottle: boolean = false 42 | 43 | return function (this: ThisParameterType, ...args: any[]): void { 44 | const context = this 45 | const now: number = Date.now() 46 | 47 | if (immediate && !inThrottle) { 48 | // 如果立即执行且当前不在节流状态,则立即执行函数 49 | func.apply(context, args) 50 | inThrottle = true 51 | lastExecution = now 52 | } else if (now - lastExecution >= limit) { 53 | // 如果不是立即执行,或者已经执行过且时间间隔已到,则执行函数 54 | func.apply(context, args) 55 | inThrottle = true 56 | lastExecution = now 57 | } 58 | 59 | // 清除之前的定时器 60 | if (timeout !== null) { 61 | clearTimeout(timeout) 62 | } 63 | 64 | // 设置新的定时器,以便在节流时间过后重置状态 65 | timeout = setTimeout(() => { 66 | inThrottle = false 67 | }, limit) 68 | } 69 | } 70 | 71 | /** 72 | * @function 创建一个防抖函数,确保函数在指定的时间间隔结束后才执行。 73 | * @param {Function} func - 需要防抖的函数。 74 | * @param {number} wait - 等待时间,单位为毫秒。 75 | * @param {boolean} immediate - 可选,是否立即执行函数。默认为 false。 76 | * @returns {Function} - 防抖后的函数。 77 | */ 78 | export const debounce = (func: Function, wait: number, immediate?: boolean): Function => { 79 | let timeout: NodeJS.Timeout | null 80 | 81 | return function (this: ThisParameterType, ...args: any[]) { 82 | // 保存当前的 this 上下文和参数 83 | const context = this 84 | 85 | // 清除之前的定时器 86 | if (timeout !== null) { 87 | clearTimeout(timeout) 88 | } 89 | 90 | // 设置新的定时器 91 | timeout = setTimeout(() => { 92 | // 如果 immediate 参数为 false,则在等待时间结束后执行函数 93 | if (!immediate) { 94 | func.apply(context, args) 95 | } 96 | }, wait) 97 | 98 | // 如果 immediate 参数为 true,则立即执行函数 99 | if (immediate) { 100 | const callNow = !timeout 101 | timeout = setTimeout(() => { 102 | timeout = null 103 | }, wait) 104 | 105 | if (callNow) { 106 | func.apply(context, args) 107 | } 108 | } 109 | } 110 | } 111 | 112 | /** 113 | * @function 创建一个单例模式,确保某个类只有一个实例。 114 | * @param className 需要单例的类 115 | * @returns 单例的类 116 | */ 117 | export const sington = any>(className: T): T=>{ 118 | let ins: InstanceType 119 | const proxy = new Proxy(className,{ 120 | construct(target,args){ 121 | if(!ins){ 122 | ins = Reflect.construct(target,args) 123 | } 124 | return ins 125 | } 126 | }) 127 | return proxy 128 | } 129 | 130 | 131 | export * from '@/public/HighOrderFunction/KeepLoop' -------------------------------------------------------------------------------- /lib/public/Number/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @function 保留小数 3 | */ 4 | export const keepDecimal = (num: number, digit = 2): number => { 5 | return Number(num.toFixed(digit)) 6 | } 7 | 8 | /** 9 | * @function 补零 10 | */ 11 | export const fillZero = (num: number) => { 12 | return num >= 10 ? num : `0${num}` 13 | } 14 | 15 | /** 16 | * @function 生成随机字数字,该数字唯一 17 | * @param len {string} 所需生成字符串的长度 18 | */ 19 | export const getRandomNumber = (digit = 8): number => { 20 | const $chars = '0123456789' 21 | const maxPos = $chars.length 22 | let str = '' 23 | for (let i = 0, length = digit; i < length; i++) { 24 | str += $chars.charAt(Math.floor(Math.random() * maxPos)) 25 | } 26 | return Number(str) 27 | } 28 | -------------------------------------------------------------------------------- /lib/public/Object/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @function 从对象中筛选出指定键的属性,并返回一个新对象。 3 | * @template T 表示对象的类型,它必须是带有键的普通对象。 4 | * @template K 表示要筛选的键的类型,它是 T 的键的子集。 5 | * @param obj 需要从中筛选属性的对象。 6 | * @param keys 需要筛选出来的键的数组。 7 | * @returns 返回一个新对象,它只包含 `keys` 数组中指定的键及其对应的值。 8 | */ 9 | export const pick = ( 10 | obj: T, 11 | keys: K[] 12 | ): Partial> => { 13 | return Object.fromEntries( 14 | Object.entries(obj).filter(([key]) => keys.includes(key as K) as boolean) 15 | ) as Partial> 16 | } 17 | -------------------------------------------------------------------------------- /lib/public/PrettyLog/index.ts: -------------------------------------------------------------------------------- 1 | import { isString } from '@/public/TypeCheck' 2 | 3 | const prettyLog = () => { 4 | // 检查是否处于生产环境 5 | // const isProduction = import.meta.env.MODE === 'production'; 6 | 7 | // 定义标题和颜色 8 | const enumType = { 9 | info: { 10 | title: 'Info', 11 | color: '#909399' 12 | }, 13 | error: { 14 | title: 'Error', 15 | color: '#F56C6C' 16 | }, 17 | warning: { 18 | title: 'Warning', 19 | color: '#E6A23C' 20 | }, 21 | success: { 22 | title: 'Success', 23 | color: '#67C23A' 24 | } 25 | } 26 | 27 | // 漂亮的打印函数,接受日志类型和任意数量的参数 28 | const prettyPrint = (type: keyof typeof enumType, ...args: any[]) => { 29 | // if (isProduction) return; // 如果是生产环境,则不执行打印 30 | 31 | // 获取日志类型对应的标题和颜色 32 | const { title, color } = enumType[type] 33 | 34 | // 检查参数列表是否含有引用类型 如果有则输出正常log, 并注明参数类型 35 | // 否则输出带有标题和颜色的log 36 | 37 | if (args.some((i) => !isString(i))) { 38 | // 分组打印 39 | console.group( 40 | `%c ${title} %c Type is a ${typeof args}, The details are as follows 👇`, 41 | `background:${color}; border:1px solid ${color}; padding: 2px; border-radius: 4px 0 0 4px; color: white;`, 42 | `border:1px solid ${color}; padding: 2px; border-radius: 0 4px 4px 0; color: ${color};` 43 | ) 44 | args.forEach((item) => { 45 | console.log(item) 46 | }) 47 | console.groupEnd() 48 | } else { 49 | console.log( 50 | `%c ${title} %c ${args.join(',')}`, 51 | `background:${color}; border:1px solid ${color}; padding: 2px; border-radius: 4px 0 0 4px; color: white;`, 52 | `border:1px solid ${color}; padding: 2px; border-radius: 0 4px 4px 0; color: ${color};` 53 | ) 54 | } 55 | } 56 | 57 | // 创建具体的日志函数 58 | const info = (...args: any[]) => prettyPrint('info', ...args) 59 | const error = (...args: any[]) => prettyPrint('error', ...args) 60 | const warning = (...args: any[]) => prettyPrint('warning', ...args) 61 | const success = (...args: any[]) => prettyPrint('success', ...args) 62 | 63 | // 返回所有的日志函数 64 | return { 65 | info, 66 | error, 67 | warning, 68 | success 69 | } 70 | } 71 | 72 | // 创建日志实例 73 | export const log = prettyLog() 74 | -------------------------------------------------------------------------------- /lib/public/String/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @function 生成随机字符串,该字符串唯一 3 | * @param digit {number} 所需生成字符串的长度 4 | */ 5 | export const getRandomString = (digit = 32) => { 6 | const timestampStr = new Date().getTime().toString() // 当前时间戳 7 | const $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678' // 默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1 8 | const maxPos = $chars.length 9 | let str = '' 10 | for (let i = 0, length = digit - 13; i < length; i++) { 11 | str += $chars.charAt(Math.floor(Math.random() * maxPos)) 12 | } 13 | return str + timestampStr 14 | } 15 | 16 | /** 17 | * @function 转换首字母为大写(或全部),如果转换全部则忽略首字母的转换 18 | * @param {string} value 需要转换的字符串 19 | * @param {boolean} [all=false] 是否转换整个字符串的大小写 20 | * @returns {string} 转换后的字符串 21 | */ 22 | export const toUpper = (value: string, all = false) => { 23 | return all ? value.toUpperCase() : value.charAt(0).toUpperCase() + value.slice(1) 24 | } 25 | 26 | /** 27 | * @function 转换首字母为小写(或全部),如果转换全部则忽略首字母的转换 28 | * @param {string} value 需要转换的字符串 29 | * @param {boolean} [all=false] 是否转换整个字符串的大小写 30 | * @returns {string} 转换后的字符串 31 | */ 32 | export const toLower = (value: string, all = false) => { 33 | return all ? value.toLowerCase() : value.charAt(0).toLowerCase() + value.slice(1) 34 | } 35 | 36 | 37 | /** 38 | * 对字符串进行脱敏处理,只显示前几位和最后几位,其余部分用星号或省略号替代。 39 | * @param {string} input - 需要脱敏的原始字符串。 40 | * @param {number} [keepStart=0] - 需要保留的开头字符数。 41 | * @param {number} [keepEnd=0] - 需要保留的结尾字符数。 42 | * @param {string} [maskChar='*'] - 脱敏部分使用的字符,默认为星号。 43 | * @returns {string} 脱敏后的字符串。 44 | */ 45 | export const maskString = (input: string, keepStart: number = 0, keepEnd: number = 0, maskChar: string = '*'): string => { 46 | if (!input) throw new Error('Input string is required') 47 | 48 | const inputStr: string = String(input) 49 | const length: number = inputStr.length 50 | 51 | if (length <= keepStart + keepEnd) { 52 | return inputStr 53 | } 54 | 55 | const maskLength: number = length - keepStart - keepEnd 56 | const mask: string = maskChar.repeat(maskLength) 57 | 58 | return inputStr.substring(0, keepStart) + mask + inputStr.substring(length - keepEnd) 59 | } 60 | 61 | 62 | /** 63 | * 对手机号进行脱敏处理,只显示前三位和后四位,其余部分用星号替代。 64 | * @param {string | null | undefined} phoneNumber - 需要脱敏的手机号。 65 | * @returns {string} 脱敏后的手机号字符串。 66 | */ 67 | export const maskPhoneNumber = (phoneNumber: string | null | undefined): string => { 68 | if (!phoneNumber) throw new Error('phoneNumber is required') 69 | 70 | const phoneStr: string = String(phoneNumber) 71 | // 正则表达式匹配 11 位数字的手机号 72 | const regex: RegExp = /^(\d{3})(\d{4})(\d{4})$/ 73 | 74 | // 确保输入的是一个11位的手机号码 75 | if (!regex.test(phoneStr)) throw new Error('Invalid phone number format') 76 | 77 | return phoneStr.replace(regex, '$1****$3') 78 | } 79 | 80 | /** 81 | * 对地址进行脱敏处理,只显示前三位和后四位,其余部分用星号替代。 82 | * @param {string | null | undefined} phoneNumber - 需要脱敏的手机号。 83 | * @returns {string} 脱敏后的地址字符串。 84 | */ 85 | export const addressHidePart = (address: string,keepStart=3,keepEnd=4, maskChar='*'): string => { 86 | return maskString(address, keepStart, keepEnd, maskChar) 87 | } 88 | 89 | // 姓氏脱敏 90 | export const nameHidePart = (name: string,keepStart=1,keepEnd=0,maskChar='*'): string => { 91 | // 假设姓氏脱敏只显示第一个字符后跟星号 92 | return maskString(name, keepStart, keepEnd, maskChar) 93 | } 94 | 95 | // 标签脱敏 96 | export const tagHidePart = (tag: string,keepStart=4,keepEnd=3,maskChar='...'): string => { 97 | return maskString(tag, keepStart, keepEnd, maskChar) 98 | } 99 | 100 | // 身份证脱敏 101 | export const idCardHidePart = (idCard: string,keepStart=6,keepEnd=4 ,maskChar='*'): string => { 102 | return maskString(idCard, keepStart, keepEnd, maskChar) 103 | } 104 | 105 | // 邮箱脱敏 106 | export const emailHidePart = (email: string,keepStart=2,keepEnd=2,maskChar='*'): string => { 107 | return maskString(email, keepStart, keepEnd, maskChar) 108 | } 109 | 110 | // 银行卡脱敏 111 | export const bankCardHidePart = (bankCard: string,keepStart=4,keepEnd=4,maskChar='*'): string => { 112 | return maskString(bankCard, keepStart, keepEnd, maskChar) 113 | } 114 | 115 | -------------------------------------------------------------------------------- /lib/public/TypeCheck/index.ts: -------------------------------------------------------------------------------- 1 | import { toUpper } from '../String/index' 2 | 3 | const toString = Object.prototype.toString 4 | 5 | /** 6 | * @function 在值是 null、undefined 或空字符串时返回一个指定的空值。 7 | * @template T 表示 value 参数的类型。 8 | * @param value - 需要检查的原始值,可以是 T 类型或 null/undefined。 9 | * @param emptyValue - 当原始值为 null、undefined 或空字符串时返回的值,应与 T 类型兼容。 10 | * @returns 返回原始值,或者当原始值为 null、undefined 或空字符串时返回 `emptyValue`。 11 | */ 12 | export const optional = (value: T | null | undefined, emptyValue: T) => { 13 | return (([null, undefined, ''] as any[]).includes(value) ? emptyValue : value) as T | undefined 14 | } 15 | /** 16 | * @function 检测数据类型 17 | * @param value 要检测的数据 18 | * @param type 类型 19 | * @returns 20 | */ 21 | export const is = (value: unknown, type: string) => { 22 | return toString.call(value) === `[object ${toUpper(type)}]` 23 | } 24 | 25 | /** 26 | * @function 检测一个数是否为undefined 27 | * @param value 28 | * @returns 29 | */ 30 | export const isDef = (value?: T): value is T => { 31 | return typeof value === 'undefined' 32 | } 33 | 34 | /** 35 | * @function 检测一个数是否为object 36 | * @param value 37 | * @returns 38 | */ 39 | export const isObject = (value: any): value is Record => { 40 | return value !== null && is(value, 'object') 41 | } 42 | 43 | /** 44 | * @function 检查一个值是否为空 45 | * 空的定义包括:数组、字符串、Map、Set、对象(无键值对)、null、NaN、未定义或未声明的值 46 | * @param value 需要检查的值 47 | * @returns 如果值为空,则返回true,否则返回false 48 | */ 49 | export const isEmpty = (value: T): value is T => { 50 | // 如果是数组或字符串,检查其长度是否为0 51 | if (isArray(value) || isString(value)) { 52 | return value.length === 0 53 | } 54 | 55 | // 如果是Map或Set实例,检查其size属性是否为0 56 | if (value instanceof Map || value instanceof Set) { 57 | return value.size === 0 58 | } 59 | 60 | // 如果是对象,检查其是否有可枚举的键 61 | if (isObject(value)) { 62 | return Object.keys(value).length === 0 63 | } 64 | 65 | // 如果是null,直接比较 66 | if (isNull(value)) { 67 | return value === null 68 | } 69 | 70 | // 如果是NaN,使用isNaN函数检查 71 | if (isNaN(value)) { 72 | return true 73 | } 74 | 75 | // 如果值未定义或未声明,返回true 76 | if (!isDef(value)) { 77 | return true 78 | } 79 | 80 | // 如果以上都不是,即值非空,返回false 81 | return false 82 | } 83 | 84 | /** 85 | * @function 判断是否是日期 86 | * @param value 87 | * @returns 88 | */ 89 | export const isDate = (value: unknown): value is Date => { 90 | return is(value, 'Date') 91 | } 92 | 93 | /** 94 | * @function 判断是否是NaN 95 | * @param value 96 | * @returns 97 | */ 98 | export const isNaN = (value: unknown) => { 99 | return Object.is(value, NaN) 100 | } 101 | 102 | /** 103 | * @function 判断是否是null 104 | * @param value 105 | * @returns 106 | */ 107 | export const isNull = (value: unknown): value is null => { 108 | return value === null 109 | } 110 | 111 | /** 112 | * @function 判断是否是undefine和null的交集 113 | * @param value 114 | * @returns 115 | */ 116 | export const isNullAndUnDef = (value: unknown): value is null | undefined => { 117 | return !isDef(value) && isNull(value) 118 | } 119 | 120 | /** 121 | * @function 判断是否是undefine和null的并集 122 | * @param value 123 | * @returns 124 | */ 125 | export const isNullOrUnDef = (value: unknown): value is null | undefined => { 126 | return !isDef(value) || isNull(value) 127 | } 128 | 129 | /** 130 | * @function 判断是不是数字 131 | * @param value 132 | * @returns 133 | */ 134 | export const isNumber = (value: unknown): value is number => { 135 | return is(value, 'Number') 136 | } 137 | 138 | /** 139 | * @function 判断一个值是否为 Promise 对象 140 | * @param value 需要判断的值 141 | * @returns 如果 value 是 Promise 对象,则返回 true,否则返回 false 142 | */ 143 | export const isPromise = (value: unknown): value is Promise => { 144 | return ( 145 | is(value, 'Promise') && isObject(value) && isFunction(value.then) && isFunction(value.catch) 146 | ) 147 | } 148 | 149 | /** 150 | * @function判断一个值是否为字符串类型 151 | * @param value 需要判断的值 152 | * @returns 如果 value 是字符串,则返回 true,否则返回 false 153 | */ 154 | export const isString = (value: unknown): value is string => { 155 | return is(value, 'String') 156 | } 157 | 158 | /** 159 | * @function 判断一个值是否为函数类型 160 | * @param value 需要判断的值 161 | * @returns 如果 value 是函数,则返回 true,否则返回 false 162 | */ 163 | export const isFunction = (value: unknown): value is Function => { 164 | return typeof value === 'function' 165 | } 166 | 167 | /** 168 | * @function 判断一个值是否为布尔类型 169 | * @param value 需要判断的值 170 | * @returns 如果 value 是布尔类型,则返回 true,否则返回 false 171 | */ 172 | export const isBoolean = (value: unknown): value is boolean => { 173 | return is(value, 'Boolean') 174 | } 175 | 176 | /** 177 | * @function 判断一个值是否为正则表达式类型 178 | * @param value 需要判断的值 179 | * @returns 如果 value 是正则表达式,则返回 true,否则返回 false 180 | */ 181 | export const isRegExp = (value: unknown): value is RegExp => { 182 | return is(value, 'RegExp') 183 | } 184 | 185 | /** 186 | * @function 判断一个值是否为数组类型 187 | * @param value 需要判断的值 188 | * @returns 如果 value 是数组,则返回 true,否则返回 false 189 | */ 190 | export const isArray = (value: any): value is Array => { 191 | return value && Array.isArray(value) 192 | } 193 | 194 | /** 195 | * @function 判断当前环境是否为浏览器环境(非服务器端) 196 | * @param value 需要判断的值(此处未使用,仅作为参数模板) 197 | * @returns 如果是浏览器环境,则返回 true,否则返回 false 198 | */ 199 | export const isWindow = (value: any): value is Window => { 200 | return typeof window !== 'undefined' && is(value, 'Window') 201 | } 202 | 203 | /** 204 | * @function 判断一个值是否为 HTML 元素 205 | * @param value 需要判断的值 206 | * @returns 如果 value 是 HTML 元素,则返回 true,否则返回 false 207 | */ 208 | export const isElement = (value: unknown): value is Element => { 209 | return isObject(value) && !!value.tagName 210 | } 211 | 212 | /** 213 | * @function 判断一个值是否为 Map 类型 214 | * @param value 需要判断的值 215 | * @returns 如果 value 是 Map 类型,则返回 true,否则返回 false 216 | */ 217 | export const isMap = (value: unknown): value is Map => { 218 | return is(value, 'Map') 219 | } 220 | 221 | /** 222 | * @function 判断当前环境是否为服务器端 223 | * @returns 如果是服务器端,则返回 true,否则返回 false 224 | */ 225 | export const isServer = typeof window === 'undefined' 226 | 227 | /** 228 | * @function 判断当前环境是否为客户端(浏览器环境) 229 | * @returns 如果是客户端,则返回 true,否则返回 false 230 | */ 231 | export const isClient = !isServer 232 | 233 | /** 234 | * @function 判断一个字符串是否为有效的 URL 地址 235 | * @param path 需要判断的字符串 236 | * @returns 如果 path 是有效的 URL 地址,则返回 true,否则返回 false 237 | */ 238 | export const isUrl = (path: string): boolean => { 239 | const reg = 240 | /(((^https?:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)$/ 241 | return reg.test(path) 242 | } 243 | 244 | /** 245 | * @function 判断一个字符串是否为有效的手机号码 246 | * @param value 需要判断的字符串 247 | * @returns 如果 value 是有效的手机号码,则返回 true,否则返回 false 248 | */ 249 | export const isMobileNumber = (value: string): boolean => { 250 | const reg = /^1[3456789]\d{9}$/ 251 | return reg.test(value) 252 | } 253 | 254 | /** 255 | * @function 判断一个字符串是否为有效的座机号码 256 | * @param value 需要判断的字符串 257 | * @returns 如果 value 是有效的座机号码,则返回 true,否则返回 false 258 | */ 259 | export const isTelePhoneNumber = (value: string): boolean => { 260 | const reg = /^(\(\d{3,4}\)|\d{3,4}-|\s)?\d{7,14}$/ 261 | return reg.test(value) 262 | } 263 | -------------------------------------------------------------------------------- /lib/public/main.ts: -------------------------------------------------------------------------------- 1 | export * from '@/public/Array/index' 2 | export * from '@/public/Browser/index' 3 | export * from '@/public/FormatDate/index' 4 | export * from '@/public/FormatDate/constant' 5 | export * from '@/public/HighOrderFunction/index' 6 | export * from '@/public/TypeCheck/index' 7 | export * from '@/public/Number/index' 8 | export * from '@/public/String/index' 9 | export * from '@/public/Object/index' 10 | export * from '@/public/PrettyLog/index' 11 | 12 | export type * from './types/global' 13 | -------------------------------------------------------------------------------- /lib/public/types/global.d.ts: -------------------------------------------------------------------------------- 1 | export declare namespace TYPE { 2 | interface IArraySortByKey { 3 | /** 需要排序的数组 */ 4 | array: any[] 5 | /* 以什么字段排序 */ 6 | key: string 7 | } 8 | 9 | interface IUniqueByProperty { 10 | /** 需要去重的数组 */ 11 | array: any[] 12 | /** 去重字段 */ 13 | key: string 14 | /** 回调函数 */ 15 | callback?: (args?: any) => void 16 | } 17 | 18 | interface IFuzzyMatchByProperty { 19 | /** 要进行模糊匹配的数组 */ 20 | array: any[] 21 | /** 模糊匹配针对的属性 */ 22 | prop: string 23 | /** 传入的字段 多用于本地输入框搜索 */ 24 | key: string 25 | /** 回调函数 */ 26 | callback?: (args?: any) => void 27 | } 28 | 29 | /** 30 | * @interface 全屏 31 | */ 32 | interface IFullScreenAbleHTMLElement { 33 | mozRequestFullScreen?: () => Promise | undefined 34 | webkitRequestFullscreen?: (options?: FullscreenOptions) => Promise | undefined 35 | msRequestFullscreen?: () => Promise | undefined 36 | requestFullscreen?: (options?: FullscreenOptions) => Promise | undefined 37 | } 38 | 39 | /** 40 | * @interface 退出全屏 41 | */ 42 | interface IExitFullScreenAbleHTMLElement { 43 | mozCancelFullScreen?: () => void 44 | webkitExitFullscreen?: () => Promise 45 | msExitFullscreen?: () => void 46 | exitFullscreen?: () => Promise 47 | } 48 | 49 | 50 | /** 51 | * @type KeepLoopOption 参数列表 52 | */ 53 | interface IKeepLoopOption { 54 | run: (returnInfo: IReturnInfo) => IReturnInfo; // 需要轮询的函数 55 | interval: number; // 轮询时间间隔,必须大于0 56 | maxCount?: number; // 最大轮询次数,传 0 || 不传 表示无限轮询 57 | } 58 | 59 | /** 60 | * @type IReturnInfo 返回信息 61 | */ 62 | interface IReturnInfo { 63 | currentCount: number; 64 | } 65 | 66 | 67 | /** 68 | * @interface 日期信息 69 | */ 70 | interface IDateInfo { 71 | yyyy: string; 72 | MM: string; 73 | dd: string; 74 | HH: string; 75 | mm: string; 76 | ss: string; 77 | } 78 | 79 | interface anyType { 80 | [key: string]: any 81 | } 82 | 83 | 84 | } 85 | -------------------------------------------------------------------------------- /lib/public/types/index.d.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinHanlove/atom-module-tools/34306a90311ee64144ad897281ab511883b7fc88/lib/public/types/index.d.ts -------------------------------------------------------------------------------- /lib/special/Vue/Directive/index.ts: -------------------------------------------------------------------------------- 1 | import type { App } from 'vue' 2 | import { setVCopyDirective } from './vCopy' 3 | import { setDraggableDirective } from './vDraggable' 4 | import { setVDebounceDirective } from './vDebounce' 5 | import { setWaterMarkerDirective } from './vWaterMarker' 6 | import { setHighlightDirective } from './vHighlight' 7 | import { setVOutsideClickDirective } from './vOutsideClick' 8 | import { setVResizeDirective } from './vResize' 9 | import { setVObserveVisibilityDirective } from './vObserveVisibility' 10 | import { setVZoomDirective } from './vZoom' 11 | 12 | /** 13 | * 抛出注册指令方法,需在挂载之前执行 14 | * @param app 15 | */ 16 | export function setupDirectivePlugins(app: App) { 17 | // 注册指令 18 | setVCopyDirective(app) 19 | setDraggableDirective(app) 20 | setVDebounceDirective(app) 21 | setWaterMarkerDirective(app) 22 | setHighlightDirective(app) 23 | setVOutsideClickDirective(app) 24 | setVResizeDirective(app) 25 | setVObserveVisibilityDirective(app) 26 | setVZoomDirective(app) 27 | } 28 | -------------------------------------------------------------------------------- /lib/special/Vue/Directive/vCopy.ts: -------------------------------------------------------------------------------- 1 | import type { Directive, App } from 'vue' 2 | import { copyText } from '@/public/Browser' 3 | 4 | // 复制指令 5 | const VCopy: Directive = { 6 | mounted(el, binding) { 7 | // 解构binding.value,设置默认值 8 | const { content = el.innerText, type = 'click', callback } = binding.value || {} 9 | const typeMap = ['click', 'dblclick'] 10 | 11 | // 验证type是否有效 12 | if (typeMap.indexOf(type) === -1) { 13 | throw new Error(`The "type" parameter must be one of the following: ${typeMap.join(', ')}.`) 14 | } 15 | 16 | console.log(content, callback) 17 | 18 | // 给该元素注册事件 19 | const eventType = type 20 | el.addEventListener(eventType, () => { 21 | copyText(content) 22 | .then((res) => { 23 | // 如果存在回调函数,则执行它 24 | callback && callback(res) 25 | }) 26 | .catch((error) => { 27 | console.error('Failed to copy text:', error) 28 | }) 29 | }) 30 | }, 31 | unmounted(el, binding) { 32 | // 移除事件监听,使用在mounted中定义的eventType 33 | const eventType = binding.value?.type || 'click' 34 | el.removeEventListener(eventType, el[`_${eventType}Handler`]) 35 | } 36 | } 37 | 38 | export function setVCopyDirective(app: App) { 39 | app.directive('copy', VCopy) 40 | } 41 | 42 | export default VCopy 43 | -------------------------------------------------------------------------------- /lib/special/Vue/Directive/vDebounce.ts: -------------------------------------------------------------------------------- 1 | import type { Directive, App } from 'vue' 2 | import { debounce } from '@/public/HighOrderFunction' 3 | 4 | // 防抖指令 5 | const VDebounce: Directive = { 6 | mounted(el, binding) { 7 | // 解构binding.value,设置默认值 8 | const { callback, wait = 1000 } = binding.value || {} 9 | 10 | // 从binding.arg获取事件类型,如果提供了binding.arg 11 | const eventType = binding.arg || 'click' 12 | 13 | // 确保callback是一个函数 14 | if (typeof callback !== 'function') { 15 | throw new Error('The "callback" parameter must be a function.') 16 | } 17 | 18 | const debouncedCallback = debounce(callback, wait) 19 | 20 | el.addEventListener(eventType, debouncedCallback) 21 | 22 | el[`_${eventType}Handler`] = debouncedCallback 23 | }, 24 | unmounted(el, binding) { 25 | const eventType = binding.arg || (binding.value && binding.value.type) || 'click' 26 | el.removeEventListener(eventType, el[`_${eventType}Handler`]) 27 | } 28 | } 29 | 30 | export function setVDebounceDirective(app: App) { 31 | app.directive('debounce', VDebounce) 32 | } 33 | 34 | export default VDebounce 35 | -------------------------------------------------------------------------------- /lib/special/Vue/Directive/vDraggable.ts: -------------------------------------------------------------------------------- 1 | import type { Directive, App } from 'vue' 2 | 3 | const vDraggable: Directive = { 4 | mounted(el, binding) { 5 | // 如果提供了 binding.arg 作为父元素的 ID,则根据 ID 查找父元素 6 | const parentId = binding.arg 7 | 8 | // 如果未提供父元素 ID,则拖拽区域是整个网页 9 | // 如果提供父元素 ID 但是找不到对应的父元素,则抛出错误 10 | const parentEl = parentId ? document.getElementById(parentId) : (el.parentNode as HTMLElement) 11 | 12 | if (!parentEl) { 13 | console.error(`Parent element with id '${parentId}' not found.`) 14 | return 15 | } 16 | 17 | // 初始化样式 18 | el.style = ` 19 | cursor: move; 20 | position: absolute; 21 | z-index: 999; 22 | user-select: none; 23 | touch-action: none; 24 | ` 25 | 26 | // 是否正在被拖拽 27 | let isDragging = false 28 | 29 | // 鼠标按下事件处理函数 30 | const mouseDown = (e: MouseEvent) => { 31 | // 拖拽状态 32 | isDragging = true 33 | 34 | addDragStyles(el) 35 | 36 | /** 37 | * 计算鼠标和元素的偏移 38 | * 计算从页面的左上角到鼠标点击位置的水平距离(e.pageX) 39 | * 减去从元素 el 的左上角到其父元素左上角的水平距离(el.offsetLeft) 40 | * 确定当用户开始拖拽时鼠标与元素的初始相对位置 41 | */ 42 | let disX = e.pageX - el.offsetLeft 43 | let disY = e.pageY - el.offsetTop 44 | 45 | // 鼠标移动事件处理函数 46 | const mouseMove = (e: MouseEvent) => { 47 | if (!isDragging) return 48 | 49 | // 计算鼠标在拖拽过程中的当前位置相对于元素初始拖拽位置的偏移量 50 | let x = e.pageX - disX 51 | let y = e.pageY - disY 52 | 53 | // 如果提供了父元素ID,获取父元素边界并设置边界条件 54 | if (parentId) { 55 | const { 56 | left: parentL, 57 | top: parentT, 58 | right: parentR, 59 | bottom: parentB 60 | } = parentEl.getBoundingClientRect() 61 | 62 | // 边界条件:确保元素的四个角都不会超出父元素的边界 63 | // 元素可以紧贴父元素的边缘,但不会超出 64 | x = Math.max(parentL, Math.min(x, parentR - el.offsetWidth)) 65 | y = Math.max(parentT, Math.min(y, parentB - el.offsetHeight)) 66 | 67 | // 是否贴边 68 | const isEdgeTouching = checkEdgeTouching(el, parentEl, disX, disY) 69 | 70 | if (isEdgeTouching) { 71 | // 元素贴边,给父元素加上虚线边框 72 | parentEl.style.border = '1px dashed #3498db' 73 | } else { 74 | // 元素没有贴边,移除父元素的边框 75 | parentEl.style.border = '' 76 | } 77 | } else { 78 | // 如果没有提供父元素ID,即拖拽区域是整个网页 79 | // 获取元素最大可移动的坐标范围 80 | const maxX = document.body.clientWidth - el.offsetWidth 81 | const maxY = document.body.clientHeight - el.offsetHeight 82 | 83 | // 边界条件:确保元素不会超出网页边界 84 | x = Math.max(0, Math.min(x, maxX)) 85 | y = Math.max(0, Math.min(y, maxY)) 86 | } 87 | 88 | // 更新元素的 left 和 top 属性 89 | el.style.left = x + 'px' 90 | el.style.top = y + 'px' 91 | } 92 | 93 | // 鼠标释放事件处理函数 94 | const mouseUp = () => { 95 | // 拖拽结束 96 | isDragging = false 97 | 98 | // 移除样式 99 | removeDragStyles(el) 100 | // 移除鼠标移动和鼠标释放的监听器 101 | document.removeEventListener('mousemove', mouseMove) 102 | document.removeEventListener('mouseup', mouseUp) 103 | 104 | // 无论元素是否贴边,停止拖拽时都移除父元素的边框 105 | if (parentId) parentEl.style.border = '' 106 | } 107 | 108 | // 添加鼠标移动和鼠标释放的监听器 109 | document.addEventListener('mousemove', mouseMove) 110 | document.addEventListener('mouseup', mouseUp) 111 | 112 | // 添加鼠标移动和鼠标释放的监听器,并存储它们的引用 113 | el._mouseMove = mouseMove 114 | el._mouseUp = mouseUp 115 | 116 | // 阻止事件冒泡 117 | e.stopPropagation() 118 | } 119 | 120 | // 给元素添加鼠标按下监听器 121 | el.addEventListener('mousedown', mouseDown) 122 | 123 | // 检查元素是否贴边的辅助函数 124 | const checkEdgeTouching = ( 125 | el: { getBoundingClientRect: () => any }, 126 | parentEl: HTMLElement, 127 | disX: number, 128 | disY: number 129 | ) => { 130 | const elRect = el.getBoundingClientRect() 131 | const parentRect = parentEl.getBoundingClientRect() 132 | 133 | // 检查元素的四个角是否在父元素边界内 134 | const isTopEdgeTouching = elRect.top - disY <= parentRect.top 135 | const isBottomEdgeTouching = elRect.bottom + disY >= parentRect.bottom 136 | const isLeftEdgeTouching = elRect.left + disX <= parentRect.left 137 | const isRightEdgeTouching = elRect.right - disX >= parentRect.right 138 | 139 | return isTopEdgeTouching || isBottomEdgeTouching || isLeftEdgeTouching || isRightEdgeTouching 140 | } 141 | 142 | // 拖拽时的样式 143 | const addDragStyles = (el: HTMLElement) => { 144 | el.style.border = '1px dashed #3498db' 145 | el.style.borderRadius = '2px' 146 | el.style.opacity = '0.6' 147 | el.style.boxShadow = '5px 5px 15px rgba(0, 0, 0, 0.2)' 148 | } 149 | 150 | // 拖拽结束移除样式 151 | const removeDragStyles = (el: HTMLElement) => { 152 | el.style.border = '' 153 | el.style.boxShadow = '' 154 | el.style.borderRadius = '' 155 | el.style.opacity = '1' 156 | } 157 | }, 158 | unmounted(el) { 159 | // 使用存储的引用移除鼠标移动和鼠标释放的监听器 160 | const mouseMove = el._mouseMove 161 | const mouseUp = el._mouseUp 162 | document.removeEventListener('mousemove', mouseMove) 163 | document.removeEventListener('mouseup', mouseUp) 164 | 165 | // 清除引用 166 | delete el._mouseMove 167 | delete el._mouseUp 168 | } 169 | } 170 | 171 | export function setDraggableDirective(app: App) { 172 | app.directive('draggable', vDraggable) 173 | } 174 | 175 | export default vDraggable 176 | -------------------------------------------------------------------------------- /lib/special/Vue/Directive/vHighlight.ts: -------------------------------------------------------------------------------- 1 | import type { Directive, App } from 'vue' 2 | 3 | // v-highlight 指令 4 | const vHighlight: Directive = { 5 | // 指令被绑定到元素时执行 6 | mounted(el, binding) { 7 | highlightText(el, binding) 8 | }, 9 | // 组件更新时重新高亮 10 | updated(el, binding) { 11 | if (binding.value !== binding.oldValue) { 12 | highlightText(el, binding) 13 | } 14 | } 15 | } 16 | 17 | const highlightText = (el: HTMLElement, binding: { value: { keyword: any; style: any } }) => { 18 | const { keyword, style } = binding.value 19 | 20 | // 如果没有提供关键词,则抛出错误 21 | if (!keyword) { 22 | throw new Error('Keyword for highlighting is required.') 23 | } 24 | 25 | const regex = new RegExp(keyword, 'gi') 26 | 27 | el.innerHTML = el.innerHTML.replace(regex, (match) => { 28 | // 创建一个 元素并应用样式 29 | const span = document.createElement('span') 30 | 31 | if (!style || typeof style !== 'object') { 32 | throw new Error('Style must be an object.') 33 | } 34 | 35 | Object.keys(style).forEach((prop) => { 36 | const cssProp = prop.replace(/([A-Z])/g, (match) => match.toLowerCase()) 37 | // 设置样式 38 | ;(span.style as any)[cssProp] = style[prop] 39 | }) 40 | 41 | span.textContent = match 42 | 43 | // 返回包裹后的文本 44 | return span.outerHTML 45 | }) 46 | } 47 | 48 | export function setHighlightDirective(app: App) { 49 | app.directive('highlight', vHighlight) 50 | } 51 | 52 | export default vHighlight 53 | -------------------------------------------------------------------------------- /lib/special/Vue/Directive/vObserveVisibility.ts: -------------------------------------------------------------------------------- 1 | import type { Directive, App } from 'vue' 2 | 3 | // v-observe-visibility 指令 4 | const vObserveVisibility: Directive = { 5 | mounted(el, binding) { 6 | const { callback, options } = binding.value || {} 7 | const { 8 | root = null, // 视口作为参照物 9 | rootMargin = '0px', // 视口边缘到目标元素边缘之间的距离 10 | threshold = 0 // 目标元素进入视口的最小比例 11 | } = options || {} 12 | 13 | // 创建 IntersectionObserver 实例 14 | const observer = new IntersectionObserver( 15 | (entries) => { 16 | entries.forEach((entry) => { 17 | // 执行回调函数,传入可见性状态 18 | callback?.(entry.isIntersecting) 19 | }) 20 | }, 21 | { 22 | root, 23 | rootMargin, 24 | threshold 25 | } 26 | ) 27 | 28 | // 开始观察元素的可见性变化 29 | observer.observe(el) 30 | 31 | // 保存 IntersectionObserver 实例的引用,以便后续可以停止观察 32 | el.observerVisibility = observer 33 | 34 | // 保存回调函数的引用 35 | el._observeVisibilityCallback = callback 36 | }, 37 | beforeUnmount(el) { 38 | // 获取之前保存的 IntersectionObserver 实例 39 | const observer = el.observerVisibility 40 | 41 | // 停止观察并删除引用 42 | if (observer) { 43 | observer.unobserve(el) 44 | delete el.observerVisibility 45 | } 46 | 47 | // 删除保存的回调函数引用 48 | delete el._observeVisibilityCallback 49 | } 50 | } 51 | 52 | export function setVObserveVisibilityDirective(app: App) { 53 | app.directive('observe-visibility', vObserveVisibility) 54 | } 55 | 56 | export default vObserveVisibility 57 | -------------------------------------------------------------------------------- /lib/special/Vue/Directive/vOutsideClick.ts: -------------------------------------------------------------------------------- 1 | import type { Directive, App } from 'vue' 2 | 3 | // v-outside-click 指令 4 | const vOutsideClick: Directive = { 5 | mounted(el, binding) { 6 | const callback = binding.value 7 | 8 | // 注册点击事件监听器到 document 9 | const handler = (e: Event) => { 10 | // 检查点击事件是否发生在 el 外部 11 | if (!el.contains(e.target as Node)) { 12 | // 如果是,则执行回调函数 13 | callback && callback(e) 14 | } 15 | } 16 | 17 | // 将事件监听器添加到 el 上,以便可以在 unmounted 钩子中引用 18 | el.outsideClickHandler = handler 19 | 20 | // 绑定全局点击事件监听器 21 | document.addEventListener('click', handler) 22 | }, 23 | updated(el) { 24 | // 如果组件更新且绑定值改变,可能需要重新定义回调 25 | el.outsideClickHandler = () => { 26 | const callback = el._outsideClickCallback 27 | callback && callback() 28 | } 29 | }, 30 | unmounted(el) { 31 | // 解绑点击事件监听器 32 | document.removeEventListener('click', el.outsideClickHandler) 33 | // 删除引用,避免内存泄漏 34 | delete el.outsideClickHandler 35 | } 36 | } 37 | 38 | export function setVOutsideClickDirective(app: App) { 39 | app.directive('outside-click', vOutsideClick) 40 | } 41 | 42 | export default vOutsideClick 43 | -------------------------------------------------------------------------------- /lib/special/Vue/Directive/vResize.ts: -------------------------------------------------------------------------------- 1 | import type { Directive, App } from 'vue' 2 | 3 | // v-resize 指令 4 | const vResize: Directive = { 5 | mounted(el, binding) { 6 | const callback = binding.value 7 | 8 | console.log(callback) 9 | 10 | // 创建 ResizeObserver 实例 11 | const resizeObserver = new ResizeObserver((entries) => { 12 | console.log(entries, '---') 13 | 14 | // 触发回调函数,传递每一个变化的 Entry 的内容尺寸 15 | entries.forEach((entry) => { 16 | callback(entry.contentRect) 17 | }) 18 | }) 19 | 20 | // 开始观察元素的尺寸变化 21 | resizeObserver.observe(el) 22 | 23 | // 保存 ResizeObserver 实例的引用,以便后续可以停止观察 24 | el.resizeObserver = resizeObserver 25 | }, 26 | unmounted(el: { resizeObserver: any }) { 27 | // 获取之前保存的 ResizeObserver 实例 28 | const resizeObserver = el.resizeObserver 29 | 30 | // 如果存在 ResizeObserver 实例,则停止观察并删除引用 31 | if (resizeObserver) { 32 | resizeObserver.unobserve(el) 33 | delete el.resizeObserver 34 | } 35 | } 36 | } 37 | 38 | export function setVResizeDirective(app: App) { 39 | app.directive('resize', vResize) 40 | } 41 | 42 | export default vResize 43 | -------------------------------------------------------------------------------- /lib/special/Vue/Directive/vWaterMarker.ts: -------------------------------------------------------------------------------- 1 | import type { Directive, App } from 'vue' 2 | 3 | // 添加水印的指令 4 | const vWaterMarker: Directive = { 5 | // 在绑定元素的mounted钩子中执行 6 | mounted(el, binding) { 7 | const { 8 | text = 'atom版权所有', 9 | font = '16px Microsoft JhengHei', 10 | textColor = 'rgba(180, 180, 180, 0.3)', 11 | rotate = -20, 12 | size = 200 // 可以设置水印大小的默认值 13 | } = binding.value || {} 14 | 15 | // 创建画布 16 | var can = document.createElement('canvas') 17 | // 添加到元素内 18 | el.appendChild(can) 19 | // 设置宽高 20 | can.width = size 21 | can.height = size 22 | 23 | can.style.display = 'none' 24 | 25 | // 获取 canvas 的 2D 上下文,并检查是否为 null 26 | var cans = can.getContext('2d') 27 | 28 | if (!cans) { 29 | // 如果没有获取到绘图上下文,就移除 canvas 元素并返回 30 | el.removeChild(can) 31 | console.error('Failed to get canvas rendering context') 32 | return 33 | } 34 | 35 | // 清除画布 36 | cans.clearRect(0, 0, can.width, can.height) 37 | 38 | // 设置旋转角度 39 | const radians = rotate * (Math.PI / 180) 40 | const textWidth = cans.measureText(text).width 41 | 42 | // 保存当前的绘图状态 43 | cans.save() 44 | 45 | // 移动到画布中心,然后再旋转 46 | cans.translate((can.width - textWidth) / 2, can.height / 2) 47 | cans.rotate(radians) 48 | 49 | // 设置文字样式 50 | cans.font = font 51 | cans.fillStyle = textColor 52 | cans.textAlign = 'center' 53 | cans.textBaseline = 'middle' 54 | 55 | // 绘制文字 56 | cans.fillText(text, 0, 0) 57 | 58 | // 恢复绘图状态 59 | cans.restore() 60 | 61 | // 设置背景图片 62 | el.style.backgroundImage = 'url(' + can.toDataURL('image/png') + ')' 63 | } 64 | } 65 | 66 | export function setWaterMarkerDirective(app: App) { 67 | app.directive('waterMarker', vWaterMarker) 68 | } 69 | 70 | export default vWaterMarker 71 | -------------------------------------------------------------------------------- /lib/special/Vue/Directive/vZoom.ts: -------------------------------------------------------------------------------- 1 | import type { Directive, App } from 'vue' 2 | 3 | interface ZoomOptions { 4 | minScale?: number 5 | maxScale?: number 6 | step?: number 7 | } 8 | 9 | const vZoom: Directive = { 10 | mounted(el, binding) { 11 | const options = binding.value as ZoomOptions 12 | const minScale = options.minScale || 0.1 13 | const maxScale = options.maxScale || Infinity 14 | const step = options.step || 0.1 15 | let scale = 1 // 初始缩放级别 16 | 17 | const setScale = (newScale: number) => { 18 | // 限制缩放级别在最小和最大值之间 19 | scale = Math.max(minScale, Math.min(maxScale, newScale)) 20 | el.style.transform = `scale(${scale})` 21 | } 22 | 23 | const mouseWheelHandler = (event: WheelEvent) => { 24 | event.preventDefault() 25 | const deltaScale = event.deltaY > 0 ? -step : step 26 | setScale(scale + deltaScale) 27 | } 28 | 29 | const clickHandler = () => { 30 | // 点击事件放大到 2 倍,但不超过最大缩放级别 31 | setScale(Math.min(scale * 2, maxScale)) 32 | } 33 | 34 | el.addEventListener('wheel', mouseWheelHandler) 35 | el.addEventListener('click', clickHandler) 36 | 37 | // 保存事件监听器引用,以便后续移除 38 | ;(el as any).zoomEventListeners = { 39 | wheel: mouseWheelHandler, 40 | click: clickHandler 41 | } 42 | }, 43 | beforeUnmount(el) { 44 | el.style.transform = '' 45 | }, 46 | unmounted(el) { 47 | const listeners = (el as any).zoomEventListeners 48 | if (listeners) { 49 | // 正确的类型断言,确保 event 是有效的字符串 50 | for (const [event, listener] of Object.entries(listeners)) { 51 | el.removeEventListener(event, listener) 52 | } 53 | ;(el as any).zoomEventListeners = null 54 | } 55 | } 56 | } 57 | 58 | export function setVZoomDirective(app: App) { 59 | app.directive('zoom', vZoom) 60 | } 61 | 62 | export default vZoom 63 | -------------------------------------------------------------------------------- /lib/special/Vue/main.ts: -------------------------------------------------------------------------------- 1 | export * from '@/special/Vue/Directive/index' 2 | export * from '@/special/Vue/utils/index' 3 | -------------------------------------------------------------------------------- /lib/special/Vue/types/global.d.ts: -------------------------------------------------------------------------------- 1 | export declare namespace TYPE {} 2 | -------------------------------------------------------------------------------- /lib/special/Vue/types/index.d.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinHanlove/atom-module-tools/34306a90311ee64144ad897281ab511883b7fc88/lib/special/Vue/types/index.d.ts -------------------------------------------------------------------------------- /lib/special/Vue/utils/debounceRef/index.ts: -------------------------------------------------------------------------------- 1 | import {customRef} from 'vue' 2 | 3 | /** 4 | * @function 防抖ref 5 | * @param value 响应式数据 6 | * @param delay 延迟时间 7 | * @returns 8 | */ 9 | export const debounceRef = (value: T, delay = 200) => { 10 | let timer: number| NodeJS.Timeout 11 | return customRef((track, trigger) => { 12 | return { 13 | get() { 14 | track() // 收集依赖 15 | return value 16 | }, 17 | set(newValue: T) { 18 | clearTimeout(timer) 19 | timer = setTimeout(() => { 20 | value = newValue 21 | trigger() // 派发更新 22 | }, delay) 23 | } 24 | } 25 | }) 26 | } -------------------------------------------------------------------------------- /lib/special/Vue/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './debounceRef' -------------------------------------------------------------------------------- /lib/special/WeChat/CreateQRCode/index.ts: -------------------------------------------------------------------------------- 1 | import QRCode from 'qrcode' 2 | 3 | /** 4 | * @function 生成二维码的函数 5 | * @param content 需要转换为二维码的内容 6 | * @param options 二维码的配置选项 7 | * @returns {Promise} 返回一个Promise,解析为base64编码的二维码图片 8 | */ 9 | export const createQRCode = ( 10 | content: string, 11 | options?: { 12 | size?: number 13 | typeNumber?: number 14 | errorCorrectLevel?: 'L' | 'M' | 'Q' | 'H' 15 | } 16 | ): Promise => { 17 | return new Promise((resolve, reject) => { 18 | // 设置默认配置 19 | const defaultOptions = { 20 | size: 300, 21 | typeNumber: 4, 22 | errorCorrectLevel: 'M' 23 | } 24 | 25 | const finalOptions = { ...defaultOptions, ...options } 26 | 27 | QRCode.toDataURL(content, finalOptions, (err: any, url: string | PromiseLike) => { 28 | if (err) { 29 | reject(err) 30 | } else { 31 | resolve(url) 32 | } 33 | }) 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /lib/special/WeChat/UploadFile/index.ts: -------------------------------------------------------------------------------- 1 | import { TYPE } from '@/special/WeChat/types/global' 2 | 3 | /** 4 | * @function 上传文件 5 | * @param params 需要上传的参数 6 | * @returns 7 | */ 8 | export const uploadFile = (params: TYPE.IWeChatUploadFile) => { 9 | return new Promise((resolve, reject) => { 10 | const { url, filePath, name, ...formData } = params 11 | 12 | if (!url || !filePath || !name) { 13 | return reject(new Error('uploadFile:缺少必要的参数: url, filePath, name')) 14 | } 15 | 16 | if (typeof wx === 'undefined' || typeof wx.uploadFile === 'undefined') { 17 | return reject(new Error('uploadFile:当前环境不支持微信小程序的上传功能')) 18 | } 19 | 20 | wx.uploadFile({ 21 | url, 22 | filePath, 23 | name, 24 | formData: formData, 25 | success(res: { data: string }) { 26 | if (res && res.data) { 27 | try { 28 | const response = JSON.parse(res.data) 29 | if (response && typeof response.data === 'string') { 30 | console.log('图片上传成功:', response.data) 31 | resolve(response.data) 32 | } else { 33 | throw new Error('uploadFile:响应数据格式不正确') 34 | } 35 | } catch (err) { 36 | console.error('uploadFile:解析响应数据出错:', err) 37 | reject(err) 38 | } 39 | } else { 40 | reject(new Error('uploadFile:上传成功,但响应数据不包含 data 属性')) 41 | } 42 | }, 43 | fail(err: any) { 44 | console.error('图片上传失败:', err) 45 | reject(err) 46 | } 47 | }) 48 | }) 49 | } 50 | -------------------------------------------------------------------------------- /lib/special/WeChat/main.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 思路:为了兼容微信小程序 3 | * 将小程序需要的公共函数从这里再导出一遍,在dist/wechat下扁平化处理 4 | */ 5 | 6 | export * from './CreateQRCode/index' 7 | export * from './UploadFile/index' 8 | 9 | // 小程序需要的函数 10 | export * from '@/public/Array/index' 11 | export * from '@/public/FormatDate/index' 12 | export * from '@/public/FormatDate/constant' 13 | export * from '@/public/HighOrderFunction/index' 14 | export * from '@/public/TypeCheck/index' 15 | export * from '@/public/Number/index' 16 | export * from '@/public/String/index' 17 | export * from '@/public/Object/index' 18 | // export type * from '@/public/types/global' 19 | export type * from './types/global' 20 | -------------------------------------------------------------------------------- /lib/special/WeChat/types/global.d.ts: -------------------------------------------------------------------------------- 1 | export declare namespace TYPE { 2 | interface anyType { 3 | [key: string]: any 4 | } 5 | interface IWeChatUploadFile extends anyType { 6 | url: string 7 | name: string 8 | filePath: string 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lib/special/WeChat/types/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'qrcode' 2 | declare const wx 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "atom-tools", 3 | "author": "linhan", 4 | "license": "MIT", 5 | "description": "A quick tool and function collection designed specifically for projects using the JavaScript language", 6 | "keywords": [ 7 | "JavaScript", 8 | "Typescript", 9 | "utils", 10 | "tool", 11 | "function", 12 | "quick", 13 | "atom", 14 | "vueUse", 15 | "vue-hooks", 16 | "atom-tools" 17 | ], 18 | "type": "module", 19 | "engines": { 20 | "node": "^18.0.0 || >=20.0.0" 21 | }, 22 | "files": [ 23 | "dist" 24 | ], 25 | "homepage": "https://tools.atomnotion.com/", 26 | "repository": { 27 | "type": "git", 28 | "url": "https://github.com/LinHanlove/atom-tools" 29 | }, 30 | "bugs": { 31 | "email": "2188817393@qq.com" 32 | }, 33 | "main": "./dist/AtomTools/index.js", 34 | "module": "./dist//AtomTools/index.js", 35 | "miniprogram": "./dist/AtomToolsWeChat", 36 | "types": "./dist/types/public/main.d.ts", 37 | "exports": { 38 | ".": { 39 | "types": "./dist/types/public/main.d.ts", 40 | "import": "./dist/AtomTools/index.js", 41 | "require": "./dist/AtomTools/index.js" 42 | }, 43 | "./vue": { 44 | "types": "./dist/types/special/Vue/main.d.ts", 45 | "import": "./dist/AtomToolsVue/index.js", 46 | "require": "./dist/AtomToolsVue/index.js" 47 | }, 48 | "./wechat": { 49 | "types": "./dist/types/special/WeChat/main.d.ts", 50 | "import": "./dist/AtomToolsWeChat/index.js", 51 | "require": "./dist/AtomToolsWeChat/index.js" 52 | } 53 | }, 54 | "scripts": { 55 | "dev": "vite --host", 56 | "build:special": "node buildSpecial.mjs", 57 | "build:tools": "vite build", 58 | "extract-commit": "node extract-commit.mjs", 59 | "prettier": " prettier --write . ", 60 | "build": "pnpm prettier && pnpm build:tools && pnpm build:special && tsc", 61 | "docs:dev": "pnpm extract-commit && vitepress dev docs --host", 62 | "docs:build": "vitepress build docs", 63 | "docs:preview": "vitepress preview docs" 64 | }, 65 | "devDependencies": { 66 | "@rollup/plugin-commonjs": "^25.0.7", 67 | "@types/node": "^20.12.7", 68 | "@vitejs/plugin-vue": "^5.0.4", 69 | "@vitejs/plugin-vue-jsx": "^3.1.0", 70 | "@vue/typescript": "^1.8.20", 71 | "autoprefixer": "^10.4.19", 72 | "postcss": "^8.4.38", 73 | "prettier": "^3.2.5", 74 | "qrcode": "^1.5.3", 75 | "sass": "^1.77.1", 76 | "tailwindcss": "^3.4.3", 77 | "terser": "^5.31.0", 78 | "ts-node": "^10.9.2", 79 | "typescript": "^5.4.5", 80 | "vite": "^5.2.10", 81 | "vite-plugin-dts": "^3.9.0", 82 | "vitepress": "^1.1.3", 83 | "vue": "^3.4.26", 84 | "vue-tsc": "^2.0.16" 85 | }, 86 | "publishConfig": { 87 | "access": "public" 88 | }, 89 | "dependencies": { 90 | "pnpm": "^9.1.3" 91 | } 92 | } -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {} 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import HelloWorld from './components/HelloWorld' 2 | 3 | export default function App() { 4 | return ( 5 |
6 | 7 |
8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /src/components/HelloWorld.tsx: -------------------------------------------------------------------------------- 1 | import Test from './Test.vue' 2 | 3 | export default function HelloWorld() { 4 | return ( 5 |
6 |

Hello, world!

7 | 8 |
9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /src/components/Test.vue: -------------------------------------------------------------------------------- 1 | 97 | 153 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import './style.css' 3 | import App from './App' 4 | import { setupDirectivePlugins } from '@/special/Vue/Directive/index' 5 | 6 | const app = createApp(App) 7 | 8 | setupDirectivePlugins(app) 9 | 10 | app.mount('#app') 11 | -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 7 | line-height: 1.5; 8 | font-weight: 400; 9 | 10 | color-scheme: light dark; 11 | color: rgba(255, 255, 255, 0.87); 12 | background-color: rgb(31, 31, 31); 13 | 14 | font-synthesis: none; 15 | text-rendering: optimizeLegibility; 16 | -webkit-font-smoothing: antialiased; 17 | -moz-osx-font-smoothing: grayscale; 18 | } 19 | 20 | a { 21 | font-weight: 500; 22 | color: #646cff; 23 | text-decoration: inherit; 24 | } 25 | a:hover { 26 | color: #535bf2; 27 | } 28 | 29 | body { 30 | margin: 0; 31 | display: flex; 32 | place-items: center; 33 | min-width: 320px; 34 | min-height: 100vh; 35 | } 36 | 37 | h1 { 38 | font-size: 3.2em; 39 | line-height: 1.1; 40 | } 41 | 42 | #app { 43 | max-width: 1280px; 44 | margin: 0 auto; 45 | padding: 2rem; 46 | text-align: center; 47 | } 48 | 49 | .logo { 50 | height: 6em; 51 | padding: 1.5em; 52 | will-change: filter; 53 | } 54 | .logo:hover { 55 | filter: drop-shadow(0 0 2em #646cffaa); 56 | } 57 | .logo.vanilla:hover { 58 | filter: drop-shadow(0 0 2em #3178c6aa); 59 | } 60 | 61 | .card { 62 | padding: 2em; 63 | } 64 | 65 | .read-the-docs { 66 | color: #888; 67 | } 68 | 69 | button { 70 | border-radius: 8px; 71 | border: 1px solid transparent; 72 | padding: 0.6em 1.2em; 73 | font-size: 1em; 74 | font-weight: 500; 75 | font-family: inherit; 76 | background-color: #1a1a1a; 77 | cursor: pointer; 78 | transition: border-color 0.25s; 79 | } 80 | button:hover { 81 | border-color: #646cff; 82 | } 83 | button:focus, 84 | button:focus-visible { 85 | outline: 4px auto -webkit-focus-ring-color; 86 | } 87 | 88 | @media (prefers-color-scheme: light) { 89 | :root { 90 | color: #213547; 91 | background-color: #ffffff; 92 | } 93 | a:hover { 94 | color: #747bff; 95 | } 96 | button { 97 | background-color: #f9f9f9; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/typescript.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | // 导入vue 类型声明,解决.tsx .vue 类型推断问题 4 | declare module '*.vue' { 5 | import { DefineComponent } from 'vue' 6 | // 有一些文档里import的是ComponentOptions,但是版本貌似比较低了 7 | const component: DefineComponent<{}, {}, any> 8 | export default component 9 | } 10 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: [ 4 | './index.html', 5 | './lib/**/*.{vue,js,ts,jsx,tsx}', 6 | './src/**/*.{vue,js,ts,jsx,tsx}', 7 | './docs/**/*.md' 8 | ], 9 | theme: { 10 | extend: {} 11 | }, 12 | plugins: [], 13 | important: true 14 | } 15 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ES2020", "DOM", "DOM.Iterable", "ESNext"], 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "Node", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true, 21 | 22 | /* 路径别名 */ 23 | "baseUrl": "./", 24 | "paths": { 25 | "@/*": ["./lib/*"], 26 | "@/docs/*": ["./docs/src/*"] 27 | }, 28 | 29 | /* 类型编译 */ 30 | "types": ["@vue/typescript", "@types/node"], 31 | "jsx": "preserve", 32 | "jsxImportSource": "vue" 33 | }, 34 | 35 | "include": [ 36 | "docs", 37 | "docs/**/*.md", 38 | "docs/**/*.mdx", 39 | "docs/**/*.vue", 40 | "docs/**/*.tsx", 41 | "docs/**/*.ts", 42 | "docs/**/*.tsx", 43 | "lib", 44 | "src", 45 | "lib/*.tsx", 46 | "lib/*.vue", 47 | "lib/**/*.ts", 48 | "lib/**/*.tsx", 49 | "lib/**/*.vue", 50 | "src/**/*.ts", 51 | "src/**/*.tsx", 52 | "src/**/*.vue", 53 | "src/*.tsx", 54 | "src/*.vue" 55 | ], 56 | "exclude": ["node_modules", "dist", "build", "out"] 57 | } 58 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import { resolve } from 'path' 3 | import dts from 'vite-plugin-dts' 4 | import vue from '@vitejs/plugin-vue' 5 | import commonjs from '@rollup/plugin-commonjs' 6 | import vueJsx from '@vitejs/plugin-vue-jsx' 7 | 8 | export default defineConfig({ 9 | base: './', 10 | resolve: { 11 | alias: { 12 | '@': resolve(__dirname, 'lib'), 13 | '@/docs': resolve(__dirname, 'docs/src') 14 | } 15 | }, 16 | server: { 17 | port: 5000, 18 | open: true, 19 | // 热更新 20 | fs: { 21 | strict: false 22 | } 23 | }, 24 | build: { 25 | target: 'es2015', 26 | sourcemap: true, // 映射文件 27 | minify: true, // 压缩方式 28 | lib: { 29 | entry: resolve(__dirname, './lib/public/main.ts'), 30 | name: 'AtomTools', 31 | fileName: 'index' 32 | }, 33 | rollupOptions: { 34 | output: { 35 | dir: 'dist/AtomTools' 36 | } 37 | } 38 | }, 39 | 40 | plugins: [ 41 | vue(), // 处理Vue单文件组件 42 | vueJsx(), // 处理Vue JSX 43 | commonjs(), // 处理CommonJS模块 44 | dts({ 45 | include: ['lib/**/*'], 46 | copyDtsFiles: true, // 自动把目录下的所有d.ts文件复制到dist文件夹 47 | outDir: 'dist/types' // 指定输出类型声明文件的目录 48 | }) 49 | ] 50 | }) 51 | --------------------------------------------------------------------------------