├── .gitignore
├── LICENSE
├── README.md
├── commit.md
├── log.ts
├── package-lock.json
├── package.json
├── rollup.config.js
├── src
├── animation
│ ├── animation.js
│ ├── imageloader.js
│ └── timeline.js
├── index.ts
└── utils
│ ├── assets.ts
│ ├── async
│ └── task.ts
│ ├── base.ts
│ ├── cache
│ ├── BaseCache.ts
│ ├── BaseLocalStorage.ts
│ ├── LocalStorageBrowser.ts
│ └── LocalStorageMiniApp.ts
│ ├── car.ts
│ ├── city
│ └── cityList.ts
│ ├── client.ts
│ ├── common.ts
│ ├── css.ts
│ ├── date.ts
│ ├── event.ts
│ ├── file.ts
│ ├── filterdata
│ └── index.ts
│ ├── idcard.ts
│ ├── locate.ts
│ ├── math.ts
│ ├── miniprogram.ts
│ ├── random
│ └── number.ts
│ ├── string.ts
│ ├── tree.ts
│ ├── url.ts
│ └── verification.ts
├── tsconfig.json
└── types
└── index.d.ts
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # TernJS port file
104 | .tern-port
105 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 惊蛰
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 | toa-tools, not just an js utils library!
3 | 一套移动端营销页常用的高质量高可持续的工具函数库
4 |
5 |
6 | ## 目录
7 |
8 | - [目录](#目录)
9 | - [简介](#简介)
10 | - [快速上手](#快速上手)
11 | - [安装](#安装)
12 | - [引入](#引入)
13 | - [讨论交流](#讨论交流)
14 | - [贡献代码](#贡献代码)
15 | - [开源协议](#开源协议)
16 |
17 | ## 简介
18 |
19 | toa-tools 是一套移动端营销页常用的高质量高可持续工具函数库。遵循简洁、易用、持续更新的开发原则。
20 |
21 | ## 快速上手
22 |
23 | ### 安装
24 |
25 | 1. 为你的项目添加 toa-tools 工具
26 |
27 | ```
28 | npm i toa-tools
29 | ```
30 |
31 | > **若你本地没有 Node.js 环境,无法使用 NPM 安装,则可以采用[CDN 安装](https://github.com/codeluosiyu/toa-tools/build/index.js)**
32 |
33 | ### 引入
34 |
35 | 2. 在页面中使用
36 | ```js
37 | import toa from "toa-tools";
38 | ```
39 | 或者
40 | ```js
41 | import { isInApp } from "toa-tools";
42 | ```
43 | **至此,Lin UI 已成功引入至你的项目中了!**
44 |
45 | ## 讨论交流
46 |
47 | ## 贡献代码
48 |
49 | 我们的代码基于 develop 分支开发,欢迎提交 Pull Request 进行代码贡献。
50 |
51 | 在提交 Pull Request 之前,请详细阅读我们的[开发规范](https://github.com/codeluosiyu/toa-tools/wiki),否则可能因为 Commit 信息不规范等原因被关闭 Pull Request。
52 |
53 | ## 开源协议
54 |
55 | [MIT](LICENSE) © 2018 codeluosiyu
56 |
57 |
--------------------------------------------------------------------------------
/commit.md:
--------------------------------------------------------------------------------
1 | 2022-12-03T08:16:00+08:00
2 | 随机数:50236
3 | 提交次数:1
--------------------------------------------------------------------------------
/log.ts:
--------------------------------------------------------------------------------
1 | const log = ""
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "toa-tools",
3 | "version": "0.0.1",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@trysound/sax": {
8 | "version": "0.2.0",
9 | "resolved": "http://registry.npm.release.ctripcorp.com/@trysound/sax/download/@trysound/sax-0.2.0.tgz",
10 | "integrity": "sha1-zMqrdYr1Z2Hre/N69vA/Mm3XmK0="
11 | },
12 | "@types/estree": {
13 | "version": "0.0.51",
14 | "resolved": "http://registry.npm.release.ctripcorp.com/@types/estree/download/@types/estree-0.0.51.tgz",
15 | "integrity": "sha1-z9cJJKJaP9MrIY5eQg5ol+GsT0A=",
16 | "dev": true
17 | },
18 | "@types/node": {
19 | "version": "17.0.21",
20 | "resolved": "http://registry.npm.release.ctripcorp.com/@types/node/download/@types/node-17.0.21.tgz",
21 | "integrity": "sha1-hkuYfAxo0HtDRYRcPmO3Xt0UNkQ=",
22 | "dev": true
23 | },
24 | "@types/resolve": {
25 | "version": "0.0.8",
26 | "resolved": "http://registry.npm.release.ctripcorp.com/@types/resolve/download/@types/resolve-0.0.8.tgz",
27 | "integrity": "sha1-8mB00jjgJlnjI84aE9BB7uKA4ZQ=",
28 | "dev": true,
29 | "requires": {
30 | "@types/node": "*"
31 | }
32 | },
33 | "ansi-styles": {
34 | "version": "4.3.0",
35 | "resolved": "http://registry.npm.release.ctripcorp.com/ansi-styles/download/ansi-styles-4.3.0.tgz",
36 | "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=",
37 | "requires": {
38 | "color-convert": "^2.0.1"
39 | }
40 | },
41 | "boolbase": {
42 | "version": "1.0.0",
43 | "resolved": "http://registry.npm.release.ctripcorp.com/boolbase/download/boolbase-1.0.0.tgz",
44 | "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
45 | },
46 | "browserslist": {
47 | "version": "4.20.0",
48 | "resolved": "http://registry.npm.release.ctripcorp.com/browserslist/download/browserslist-4.20.0.tgz",
49 | "integrity": "sha1-NZUeNUEHjBJdNt92BW6Uc4pS6+k=",
50 | "requires": {
51 | "caniuse-lite": "^1.0.30001313",
52 | "electron-to-chromium": "^1.4.76",
53 | "escalade": "^3.1.1",
54 | "node-releases": "^2.0.2",
55 | "picocolors": "^1.0.0"
56 | }
57 | },
58 | "builtin-modules": {
59 | "version": "3.2.0",
60 | "resolved": "http://registry.npm.release.ctripcorp.com/builtin-modules/download/builtin-modules-3.2.0.tgz",
61 | "integrity": "sha1-RdXbmefuXmvE82LgCL+RerUEmIc=",
62 | "dev": true
63 | },
64 | "caniuse-api": {
65 | "version": "3.0.0",
66 | "resolved": "http://registry.npm.release.ctripcorp.com/caniuse-api/download/caniuse-api-3.0.0.tgz",
67 | "integrity": "sha1-Xk2Q4idJYdRikZl99Znj7QCO5MA=",
68 | "requires": {
69 | "browserslist": "^4.0.0",
70 | "caniuse-lite": "^1.0.0",
71 | "lodash.memoize": "^4.1.2",
72 | "lodash.uniq": "^4.5.0"
73 | }
74 | },
75 | "caniuse-lite": {
76 | "version": "1.0.30001314",
77 | "resolved": "http://registry.npm.release.ctripcorp.com/caniuse-lite/download/caniuse-lite-1.0.30001314.tgz",
78 | "integrity": "sha1-Zcf5+35FlPygozO+wdiTlmI3dZY="
79 | },
80 | "chalk": {
81 | "version": "4.1.2",
82 | "resolved": "http://registry.npm.release.ctripcorp.com/chalk/download/chalk-4.1.2.tgz",
83 | "integrity": "sha1-qsTit3NKdAhnrrFr8CqtVWoeegE=",
84 | "requires": {
85 | "ansi-styles": "^4.1.0",
86 | "supports-color": "^7.1.0"
87 | }
88 | },
89 | "color-convert": {
90 | "version": "2.0.1",
91 | "resolved": "http://registry.npm.release.ctripcorp.com/color-convert/download/color-convert-2.0.1.tgz",
92 | "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=",
93 | "requires": {
94 | "color-name": "~1.1.4"
95 | }
96 | },
97 | "color-name": {
98 | "version": "1.1.4",
99 | "resolved": "http://registry.npm.release.ctripcorp.com/color-name/download/color-name-1.1.4.tgz",
100 | "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI="
101 | },
102 | "colord": {
103 | "version": "2.9.2",
104 | "resolved": "http://registry.npm.release.ctripcorp.com/colord/download/colord-2.9.2.tgz",
105 | "integrity": "sha1-JeK6y7qmWZFCLAfqIJ4giUKO/7E="
106 | },
107 | "commander": {
108 | "version": "7.2.0",
109 | "resolved": "http://registry.npm.release.ctripcorp.com/commander/download/commander-7.2.0.tgz",
110 | "integrity": "sha1-o2y1fQtQHOEI5NIFWaFQo5HZerc="
111 | },
112 | "concat-with-sourcemaps": {
113 | "version": "1.1.0",
114 | "resolved": "http://registry.npm.release.ctripcorp.com/concat-with-sourcemaps/download/concat-with-sourcemaps-1.1.0.tgz",
115 | "integrity": "sha1-1OqT8FriV5CVG5nns7CeOQikCC4=",
116 | "requires": {
117 | "source-map": "^0.6.1"
118 | }
119 | },
120 | "css-declaration-sorter": {
121 | "version": "6.1.4",
122 | "resolved": "http://registry.npm.release.ctripcorp.com/css-declaration-sorter/download/css-declaration-sorter-6.1.4.tgz",
123 | "integrity": "sha1-ub+07ZpB+NzKm/cYTYSeqUqClLQ=",
124 | "requires": {
125 | "timsort": "^0.3.0"
126 | }
127 | },
128 | "css-select": {
129 | "version": "4.2.1",
130 | "resolved": "http://registry.npm.release.ctripcorp.com/css-select/download/css-select-4.2.1.tgz",
131 | "integrity": "sha1-nmZdauTH+dZdvmnQMW4yIfsnTN0=",
132 | "requires": {
133 | "boolbase": "^1.0.0",
134 | "css-what": "^5.1.0",
135 | "domhandler": "^4.3.0",
136 | "domutils": "^2.8.0",
137 | "nth-check": "^2.0.1"
138 | }
139 | },
140 | "css-tree": {
141 | "version": "1.1.3",
142 | "resolved": "http://registry.npm.release.ctripcorp.com/css-tree/download/css-tree-1.1.3.tgz",
143 | "integrity": "sha1-60hw+2/XcHMn7JXC/yqwm16NuR0=",
144 | "requires": {
145 | "mdn-data": "2.0.14",
146 | "source-map": "^0.6.1"
147 | }
148 | },
149 | "css-what": {
150 | "version": "5.1.0",
151 | "resolved": "http://registry.npm.release.ctripcorp.com/css-what/download/css-what-5.1.0.tgz",
152 | "integrity": "sha1-P3tweq32M7r2LCzrhXm1RbtA9/4="
153 | },
154 | "cssesc": {
155 | "version": "3.0.0",
156 | "resolved": "http://registry.npm.release.ctripcorp.com/cssesc/download/cssesc-3.0.0.tgz",
157 | "integrity": "sha1-N3QZGZA7hoVl4cCep0dEXNGJg+4="
158 | },
159 | "cssnano": {
160 | "version": "5.1.3",
161 | "resolved": "http://registry.npm.release.ctripcorp.com/cssnano/download/cssnano-5.1.3.tgz",
162 | "integrity": "sha1-zqF5+RgyuXE1pRUIUO6Lu+fo3Jk=",
163 | "requires": {
164 | "cssnano-preset-default": "^5.2.3",
165 | "lilconfig": "^2.0.3",
166 | "yaml": "^1.10.2"
167 | }
168 | },
169 | "cssnano-preset-default": {
170 | "version": "5.2.3",
171 | "resolved": "http://registry.npm.release.ctripcorp.com/cssnano-preset-default/download/cssnano-preset-default-5.2.3.tgz",
172 | "integrity": "sha1-dPa+S0O2oKRfDv6jPjCoB0Zgoqo=",
173 | "requires": {
174 | "css-declaration-sorter": "^6.0.3",
175 | "cssnano-utils": "^3.1.0",
176 | "postcss-calc": "^8.2.3",
177 | "postcss-colormin": "^5.3.0",
178 | "postcss-convert-values": "^5.1.0",
179 | "postcss-discard-comments": "^5.1.1",
180 | "postcss-discard-duplicates": "^5.1.0",
181 | "postcss-discard-empty": "^5.1.1",
182 | "postcss-discard-overridden": "^5.1.0",
183 | "postcss-merge-longhand": "^5.1.1",
184 | "postcss-merge-rules": "^5.1.0",
185 | "postcss-minify-font-values": "^5.1.0",
186 | "postcss-minify-gradients": "^5.1.0",
187 | "postcss-minify-params": "^5.1.1",
188 | "postcss-minify-selectors": "^5.2.0",
189 | "postcss-normalize-charset": "^5.1.0",
190 | "postcss-normalize-display-values": "^5.1.0",
191 | "postcss-normalize-positions": "^5.1.0",
192 | "postcss-normalize-repeat-style": "^5.1.0",
193 | "postcss-normalize-string": "^5.1.0",
194 | "postcss-normalize-timing-functions": "^5.1.0",
195 | "postcss-normalize-unicode": "^5.1.0",
196 | "postcss-normalize-url": "^5.1.0",
197 | "postcss-normalize-whitespace": "^5.1.1",
198 | "postcss-ordered-values": "^5.1.0",
199 | "postcss-reduce-initial": "^5.1.0",
200 | "postcss-reduce-transforms": "^5.1.0",
201 | "postcss-svgo": "^5.1.0",
202 | "postcss-unique-selectors": "^5.1.1"
203 | }
204 | },
205 | "cssnano-utils": {
206 | "version": "3.1.0",
207 | "resolved": "http://registry.npm.release.ctripcorp.com/cssnano-utils/download/cssnano-utils-3.1.0.tgz",
208 | "integrity": "sha1-lWhNCMkVEe38cNJjYzjKN+86aGE="
209 | },
210 | "csso": {
211 | "version": "4.2.0",
212 | "resolved": "http://registry.npm.release.ctripcorp.com/csso/download/csso-4.2.0.tgz",
213 | "integrity": "sha1-6jpWE0bo3J9UbW/r7dUBh884lSk=",
214 | "requires": {
215 | "css-tree": "^1.1.2"
216 | }
217 | },
218 | "dom-serializer": {
219 | "version": "1.3.2",
220 | "resolved": "http://registry.npm.release.ctripcorp.com/dom-serializer/download/dom-serializer-1.3.2.tgz",
221 | "integrity": "sha1-YgZDfTLO767HFhgDIwx6ILwbTZE=",
222 | "requires": {
223 | "domelementtype": "^2.0.1",
224 | "domhandler": "^4.2.0",
225 | "entities": "^2.0.0"
226 | }
227 | },
228 | "domelementtype": {
229 | "version": "2.2.0",
230 | "resolved": "http://registry.npm.release.ctripcorp.com/domelementtype/download/domelementtype-2.2.0.tgz",
231 | "integrity": "sha1-mgtsJ4LtahxzI9QiZxg9+b2LHVc="
232 | },
233 | "domhandler": {
234 | "version": "4.3.0",
235 | "resolved": "http://registry.npm.release.ctripcorp.com/domhandler/download/domhandler-4.3.0.tgz",
236 | "integrity": "sha1-FsZYxibPlmln4wb5ZrQx931KViY=",
237 | "requires": {
238 | "domelementtype": "^2.2.0"
239 | }
240 | },
241 | "domutils": {
242 | "version": "2.8.0",
243 | "resolved": "http://registry.npm.release.ctripcorp.com/domutils/download/domutils-2.8.0.tgz",
244 | "integrity": "sha1-RDfe9dtuLR9dbuhZvZXKfQIEgTU=",
245 | "requires": {
246 | "dom-serializer": "^1.0.1",
247 | "domelementtype": "^2.2.0",
248 | "domhandler": "^4.2.0"
249 | }
250 | },
251 | "electron-to-chromium": {
252 | "version": "1.4.82",
253 | "resolved": "http://registry.npm.release.ctripcorp.com/electron-to-chromium/download/electron-to-chromium-1.4.82.tgz",
254 | "integrity": "sha1-UeEjykNLHrqMQ07OK1TwlbMEplE="
255 | },
256 | "entities": {
257 | "version": "2.2.0",
258 | "resolved": "http://registry.npm.release.ctripcorp.com/entities/download/entities-2.2.0.tgz",
259 | "integrity": "sha1-CY3JDruD2N/6CJ1VJWs1HTTE2lU="
260 | },
261 | "escalade": {
262 | "version": "3.1.1",
263 | "resolved": "http://registry.npm.release.ctripcorp.com/escalade/download/escalade-3.1.1.tgz",
264 | "integrity": "sha1-2M/ccACWXFoBdLSoLqpcBVJ0LkA="
265 | },
266 | "estree-walker": {
267 | "version": "0.6.1",
268 | "resolved": "http://registry.npm.release.ctripcorp.com/estree-walker/download/estree-walker-0.6.1.tgz",
269 | "integrity": "sha1-UwSRQ/QMbrkYsjZx0f4yGfOhs2I="
270 | },
271 | "eventemitter3": {
272 | "version": "4.0.7",
273 | "resolved": "http://registry.npm.release.ctripcorp.com/eventemitter3/download/eventemitter3-4.0.7.tgz",
274 | "integrity": "sha1-Lem2j2Uo1WRO9cWVJqG0oHMGFp8="
275 | },
276 | "fsevents": {
277 | "version": "2.3.2",
278 | "resolved": "http://registry.npm.release.ctripcorp.com/fsevents/download/fsevents-2.3.2.tgz",
279 | "integrity": "sha1-ilJveLj99GI7cJ4Ll1xSwkwC/Ro=",
280 | "dev": true,
281 | "optional": true
282 | },
283 | "function-bind": {
284 | "version": "1.1.1",
285 | "resolved": "http://registry.npm.release.ctripcorp.com/function-bind/download/function-bind-1.1.1.tgz",
286 | "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0="
287 | },
288 | "generic-names": {
289 | "version": "4.0.0",
290 | "resolved": "http://registry.npm.release.ctripcorp.com/generic-names/download/generic-names-4.0.0.tgz",
291 | "integrity": "sha1-C9ii/SP+jqFsvQonms1pwGkz2aM=",
292 | "requires": {
293 | "loader-utils": "^3.2.0"
294 | }
295 | },
296 | "has": {
297 | "version": "1.0.3",
298 | "resolved": "http://registry.npm.release.ctripcorp.com/has/download/has-1.0.3.tgz",
299 | "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=",
300 | "requires": {
301 | "function-bind": "^1.1.1"
302 | }
303 | },
304 | "has-flag": {
305 | "version": "4.0.0",
306 | "resolved": "http://registry.npm.release.ctripcorp.com/has-flag/download/has-flag-4.0.0.tgz",
307 | "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s="
308 | },
309 | "icss-replace-symbols": {
310 | "version": "1.1.0",
311 | "resolved": "http://registry.npm.release.ctripcorp.com/icss-replace-symbols/download/icss-replace-symbols-1.1.0.tgz",
312 | "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0="
313 | },
314 | "icss-utils": {
315 | "version": "5.1.0",
316 | "resolved": "http://registry.npm.release.ctripcorp.com/icss-utils/download/icss-utils-5.1.0.tgz",
317 | "integrity": "sha1-xr5oWKvQE9do6YNmrkfiXViHsa4="
318 | },
319 | "import-cwd": {
320 | "version": "3.0.0",
321 | "resolved": "http://registry.npm.release.ctripcorp.com/import-cwd/download/import-cwd-3.0.0.tgz",
322 | "integrity": "sha1-IIRVR3GAFRJuqbNna3WS+4vUz5I=",
323 | "requires": {
324 | "import-from": "^3.0.0"
325 | }
326 | },
327 | "import-from": {
328 | "version": "3.0.0",
329 | "resolved": "http://registry.npm.release.ctripcorp.com/import-from/download/import-from-3.0.0.tgz",
330 | "integrity": "sha1-BVz+w4zVon2AV8pRN219O/CJGWY=",
331 | "requires": {
332 | "resolve-from": "^5.0.0"
333 | }
334 | },
335 | "is-core-module": {
336 | "version": "2.8.1",
337 | "resolved": "http://registry.npm.release.ctripcorp.com/is-core-module/download/is-core-module-2.8.1.tgz",
338 | "integrity": "sha1-9Z/fynAdWHnQprEApAqhVgzichE=",
339 | "requires": {
340 | "has": "^1.0.3"
341 | }
342 | },
343 | "is-module": {
344 | "version": "1.0.0",
345 | "resolved": "http://registry.npm.release.ctripcorp.com/is-module/download/is-module-1.0.0.tgz",
346 | "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
347 | "dev": true
348 | },
349 | "is-reference": {
350 | "version": "1.2.1",
351 | "resolved": "http://registry.npm.release.ctripcorp.com/is-reference/download/is-reference-1.2.1.tgz",
352 | "integrity": "sha1-iy2sCzcfS8mU/eq6nrVC0DAC0Lc=",
353 | "dev": true,
354 | "requires": {
355 | "@types/estree": "*"
356 | }
357 | },
358 | "lilconfig": {
359 | "version": "2.0.4",
360 | "resolved": "http://registry.npm.release.ctripcorp.com/lilconfig/download/lilconfig-2.0.4.tgz",
361 | "integrity": "sha1-9FB9BD1wWLOAtqj1y3vNSzTO4II="
362 | },
363 | "loader-utils": {
364 | "version": "3.2.0",
365 | "resolved": "http://registry.npm.release.ctripcorp.com/loader-utils/download/loader-utils-3.2.0.tgz",
366 | "integrity": "sha1-vOzFGniYvudHPUvGuEWyOvgwTU8="
367 | },
368 | "lodash.camelcase": {
369 | "version": "4.3.0",
370 | "resolved": "http://registry.npm.release.ctripcorp.com/lodash.camelcase/download/lodash.camelcase-4.3.0.tgz",
371 | "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
372 | },
373 | "lodash.memoize": {
374 | "version": "4.1.2",
375 | "resolved": "http://registry.npm.release.ctripcorp.com/lodash.memoize/download/lodash.memoize-4.1.2.tgz",
376 | "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4="
377 | },
378 | "lodash.uniq": {
379 | "version": "4.5.0",
380 | "resolved": "http://registry.npm.release.ctripcorp.com/lodash.uniq/download/lodash.uniq-4.5.0.tgz",
381 | "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M="
382 | },
383 | "magic-string": {
384 | "version": "0.25.9",
385 | "resolved": "http://registry.npm.release.ctripcorp.com/magic-string/download/magic-string-0.25.9.tgz",
386 | "integrity": "sha1-3n+fr5HvihyR0CwuUxTIJ3283Rw=",
387 | "dev": true,
388 | "requires": {
389 | "sourcemap-codec": "^1.4.8"
390 | }
391 | },
392 | "mdn-data": {
393 | "version": "2.0.14",
394 | "resolved": "http://registry.npm.release.ctripcorp.com/mdn-data/download/mdn-data-2.0.14.tgz",
395 | "integrity": "sha1-cRP8QoGRfWPOKbQ0RvcB5owlulA="
396 | },
397 | "node-releases": {
398 | "version": "2.0.2",
399 | "resolved": "http://registry.npm.release.ctripcorp.com/node-releases/download/node-releases-2.0.2.tgz",
400 | "integrity": "sha1-cTn+ceL08RtH1NKYaq+MSGmeDAE="
401 | },
402 | "normalize-url": {
403 | "version": "6.1.0",
404 | "resolved": "http://registry.npm.release.ctripcorp.com/normalize-url/download/normalize-url-6.1.0.tgz",
405 | "integrity": "sha1-QNCIW1Nd7/4/MUe+yHfQX+TFZoo="
406 | },
407 | "nth-check": {
408 | "version": "2.0.1",
409 | "resolved": "http://registry.npm.release.ctripcorp.com/nth-check/download/nth-check-2.0.1.tgz",
410 | "integrity": "sha1-Lv4WL1w9oGoolZ+9PbddvuqfD8I=",
411 | "requires": {
412 | "boolbase": "^1.0.0"
413 | }
414 | },
415 | "p-finally": {
416 | "version": "1.0.0",
417 | "resolved": "http://registry.npm.release.ctripcorp.com/p-finally/download/p-finally-1.0.0.tgz",
418 | "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
419 | },
420 | "p-queue": {
421 | "version": "6.6.2",
422 | "resolved": "http://registry.npm.release.ctripcorp.com/p-queue/download/p-queue-6.6.2.tgz",
423 | "integrity": "sha1-IGip3PjmfdDsPnory3aBD6qF5CY=",
424 | "requires": {
425 | "eventemitter3": "^4.0.4",
426 | "p-timeout": "^3.2.0"
427 | }
428 | },
429 | "p-timeout": {
430 | "version": "3.2.0",
431 | "resolved": "http://registry.npm.release.ctripcorp.com/p-timeout/download/p-timeout-3.2.0.tgz",
432 | "integrity": "sha1-x+F6vJcdKnli74NiazXWNazyPf4=",
433 | "requires": {
434 | "p-finally": "^1.0.0"
435 | }
436 | },
437 | "path-parse": {
438 | "version": "1.0.7",
439 | "resolved": "http://registry.npm.release.ctripcorp.com/path-parse/download/path-parse-1.0.7.tgz",
440 | "integrity": "sha1-+8EUtgykKzDZ2vWFjkvWi77bZzU="
441 | },
442 | "picocolors": {
443 | "version": "1.0.0",
444 | "resolved": "http://registry.npm.release.ctripcorp.com/picocolors/download/picocolors-1.0.0.tgz",
445 | "integrity": "sha1-y1vcdP8/UYkiNur3nWi8RFZKuBw="
446 | },
447 | "pify": {
448 | "version": "5.0.0",
449 | "resolved": "http://registry.npm.release.ctripcorp.com/pify/download/pify-5.0.0.tgz",
450 | "integrity": "sha1-H17KP16H6+wozG1UoOSq8ArMEn8="
451 | },
452 | "postcss-calc": {
453 | "version": "8.2.4",
454 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-calc/download/postcss-calc-8.2.4.tgz",
455 | "integrity": "sha1-d7nCm/y+igf/ZpPchwUIKIiXOaU=",
456 | "requires": {
457 | "postcss-selector-parser": "^6.0.9",
458 | "postcss-value-parser": "^4.2.0"
459 | }
460 | },
461 | "postcss-colormin": {
462 | "version": "5.3.0",
463 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-colormin/download/postcss-colormin-5.3.0.tgz",
464 | "integrity": "sha1-PO6eXKYrLCfoT85jr/wM+1kBlWo=",
465 | "requires": {
466 | "browserslist": "^4.16.6",
467 | "caniuse-api": "^3.0.0",
468 | "colord": "^2.9.1",
469 | "postcss-value-parser": "^4.2.0"
470 | }
471 | },
472 | "postcss-convert-values": {
473 | "version": "5.1.0",
474 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-convert-values/download/postcss-convert-values-5.1.0.tgz",
475 | "integrity": "sha1-+NOr5AtM5LFHBwKgcGND6sF+fBA=",
476 | "requires": {
477 | "postcss-value-parser": "^4.2.0"
478 | }
479 | },
480 | "postcss-discard-comments": {
481 | "version": "5.1.1",
482 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-discard-comments/download/postcss-discard-comments-5.1.1.tgz",
483 | "integrity": "sha1-6QAZ4aDluZ3gX2NRbOZAvQ3z02k="
484 | },
485 | "postcss-discard-duplicates": {
486 | "version": "5.1.0",
487 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-discard-duplicates/download/postcss-discard-duplicates-5.1.0.tgz",
488 | "integrity": "sha1-nrT+hFZwak7r1tO3t3fQe60D6Eg="
489 | },
490 | "postcss-discard-empty": {
491 | "version": "5.1.1",
492 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-discard-empty/download/postcss-discard-empty-5.1.1.tgz",
493 | "integrity": "sha1-5XdiND/39QP+U/ylU9GNfww2nGw="
494 | },
495 | "postcss-discard-overridden": {
496 | "version": "5.1.0",
497 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-discard-overridden/download/postcss-discard-overridden-5.1.0.tgz",
498 | "integrity": "sha1-foxbUzJXR+nZATG7iGNSgvtKJ24="
499 | },
500 | "postcss-load-config": {
501 | "version": "3.1.3",
502 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-load-config/download/postcss-load-config-3.1.3.tgz",
503 | "integrity": "sha1-IZNbLEO5qG5lgaV2yn7hveK9HSM=",
504 | "requires": {
505 | "lilconfig": "^2.0.4",
506 | "yaml": "^1.10.2"
507 | }
508 | },
509 | "postcss-merge-longhand": {
510 | "version": "5.1.1",
511 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-merge-longhand/download/postcss-merge-longhand-5.1.1.tgz",
512 | "integrity": "sha1-hHs9uUbwXXzqx/N7YN5RTwv2J1g=",
513 | "requires": {
514 | "postcss-value-parser": "^4.2.0",
515 | "stylehacks": "^5.1.0"
516 | }
517 | },
518 | "postcss-merge-rules": {
519 | "version": "5.1.0",
520 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-merge-rules/download/postcss-merge-rules-5.1.0.tgz",
521 | "integrity": "sha1-otURfroJyGhqVHHZe9mvzzDRtB8=",
522 | "requires": {
523 | "browserslist": "^4.16.6",
524 | "caniuse-api": "^3.0.0",
525 | "cssnano-utils": "^3.1.0",
526 | "postcss-selector-parser": "^6.0.5"
527 | }
528 | },
529 | "postcss-minify-font-values": {
530 | "version": "5.1.0",
531 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-minify-font-values/download/postcss-minify-font-values-5.1.0.tgz",
532 | "integrity": "sha1-8d8AFKcmCD0mDTvYXXOF+4nR8Bs=",
533 | "requires": {
534 | "postcss-value-parser": "^4.2.0"
535 | }
536 | },
537 | "postcss-minify-gradients": {
538 | "version": "5.1.0",
539 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-minify-gradients/download/postcss-minify-gradients-5.1.0.tgz",
540 | "integrity": "sha1-3gJgpnoTt7MhqK3DFQcl8sZhI3c=",
541 | "requires": {
542 | "colord": "^2.9.1",
543 | "cssnano-utils": "^3.1.0",
544 | "postcss-value-parser": "^4.2.0"
545 | }
546 | },
547 | "postcss-minify-params": {
548 | "version": "5.1.1",
549 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-minify-params/download/postcss-minify-params-5.1.1.tgz",
550 | "integrity": "sha1-xfjn2sVl5XfdmZBHh/vsV2y9v7I=",
551 | "requires": {
552 | "browserslist": "^4.16.6",
553 | "cssnano-utils": "^3.1.0",
554 | "postcss-value-parser": "^4.2.0"
555 | }
556 | },
557 | "postcss-minify-selectors": {
558 | "version": "5.2.0",
559 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-minify-selectors/download/postcss-minify-selectors-5.2.0.tgz",
560 | "integrity": "sha1-F8K+Iz4Sso/6ikIaAvyLg5glU2w=",
561 | "requires": {
562 | "postcss-selector-parser": "^6.0.5"
563 | }
564 | },
565 | "postcss-modules": {
566 | "version": "4.3.1",
567 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-modules/download/postcss-modules-4.3.1.tgz",
568 | "integrity": "sha1-UXwGwJ6rB9Ezrg7/yixRCruhgEg=",
569 | "requires": {
570 | "generic-names": "^4.0.0",
571 | "icss-replace-symbols": "^1.1.0",
572 | "lodash.camelcase": "^4.3.0",
573 | "postcss-modules-extract-imports": "^3.0.0",
574 | "postcss-modules-local-by-default": "^4.0.0",
575 | "postcss-modules-scope": "^3.0.0",
576 | "postcss-modules-values": "^4.0.0",
577 | "string-hash": "^1.1.1"
578 | }
579 | },
580 | "postcss-modules-extract-imports": {
581 | "version": "3.0.0",
582 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-modules-extract-imports/download/postcss-modules-extract-imports-3.0.0.tgz",
583 | "integrity": "sha1-zaHwR8CugMl9vijD52pDuIAldB0="
584 | },
585 | "postcss-modules-local-by-default": {
586 | "version": "4.0.0",
587 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-modules-local-by-default/download/postcss-modules-local-by-default-4.0.0.tgz",
588 | "integrity": "sha1-67tU+uFZjuz99pGgKz/zs5ClpRw=",
589 | "requires": {
590 | "icss-utils": "^5.0.0",
591 | "postcss-selector-parser": "^6.0.2",
592 | "postcss-value-parser": "^4.1.0"
593 | }
594 | },
595 | "postcss-modules-scope": {
596 | "version": "3.0.0",
597 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-modules-scope/download/postcss-modules-scope-3.0.0.tgz",
598 | "integrity": "sha1-nvMVFFbTu/oSDKRImN/Kby+gHwY=",
599 | "requires": {
600 | "postcss-selector-parser": "^6.0.4"
601 | }
602 | },
603 | "postcss-modules-values": {
604 | "version": "4.0.0",
605 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-modules-values/download/postcss-modules-values-4.0.0.tgz",
606 | "integrity": "sha1-18Xn5ow7s8myfL9Iyguz/7RgLJw=",
607 | "requires": {
608 | "icss-utils": "^5.0.0"
609 | }
610 | },
611 | "postcss-normalize-charset": {
612 | "version": "5.1.0",
613 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-normalize-charset/download/postcss-normalize-charset-5.1.0.tgz",
614 | "integrity": "sha1-kwLeCykJS1LCWemyz43Ah5h58O0="
615 | },
616 | "postcss-normalize-display-values": {
617 | "version": "5.1.0",
618 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-normalize-display-values/download/postcss-normalize-display-values-5.1.0.tgz",
619 | "integrity": "sha1-cqu65YCBlg6e3XIA/PIauDJcPag=",
620 | "requires": {
621 | "postcss-value-parser": "^4.2.0"
622 | }
623 | },
624 | "postcss-normalize-positions": {
625 | "version": "5.1.0",
626 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-normalize-positions/download/postcss-normalize-positions-5.1.0.tgz",
627 | "integrity": "sha1-kCp8uXzwueixtlTUpD1FHkiWZFg=",
628 | "requires": {
629 | "postcss-value-parser": "^4.2.0"
630 | }
631 | },
632 | "postcss-normalize-repeat-style": {
633 | "version": "5.1.0",
634 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-normalize-repeat-style/download/postcss-normalize-repeat-style-5.1.0.tgz",
635 | "integrity": "sha1-9tb9WlT1GnQcyEo390WeYO96Y5g=",
636 | "requires": {
637 | "postcss-value-parser": "^4.2.0"
638 | }
639 | },
640 | "postcss-normalize-string": {
641 | "version": "5.1.0",
642 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-normalize-string/download/postcss-normalize-string-5.1.0.tgz",
643 | "integrity": "sha1-QRlhFp4HMIyCwfjFXz6KM3dX4ig=",
644 | "requires": {
645 | "postcss-value-parser": "^4.2.0"
646 | }
647 | },
648 | "postcss-normalize-timing-functions": {
649 | "version": "5.1.0",
650 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-normalize-timing-functions/download/postcss-normalize-timing-functions-5.1.0.tgz",
651 | "integrity": "sha1-1WFEEPjwsjiOnyQKpgEbpvUtr7s=",
652 | "requires": {
653 | "postcss-value-parser": "^4.2.0"
654 | }
655 | },
656 | "postcss-normalize-unicode": {
657 | "version": "5.1.0",
658 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-normalize-unicode/download/postcss-normalize-unicode-5.1.0.tgz",
659 | "integrity": "sha1-PSOu3jXhYAiaKF4nv3Fd4R3J23U=",
660 | "requires": {
661 | "browserslist": "^4.16.6",
662 | "postcss-value-parser": "^4.2.0"
663 | }
664 | },
665 | "postcss-normalize-url": {
666 | "version": "5.1.0",
667 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-normalize-url/download/postcss-normalize-url-5.1.0.tgz",
668 | "integrity": "sha1-7Z2IyoLiGr75n3Q0V9NymgQq3Nw=",
669 | "requires": {
670 | "normalize-url": "^6.0.1",
671 | "postcss-value-parser": "^4.2.0"
672 | }
673 | },
674 | "postcss-normalize-whitespace": {
675 | "version": "5.1.1",
676 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-normalize-whitespace/download/postcss-normalize-whitespace-5.1.1.tgz",
677 | "integrity": "sha1-CKGg0f+henzG7+HmydqWnMRJPPo=",
678 | "requires": {
679 | "postcss-value-parser": "^4.2.0"
680 | }
681 | },
682 | "postcss-ordered-values": {
683 | "version": "5.1.0",
684 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-ordered-values/download/postcss-ordered-values-5.1.0.tgz",
685 | "integrity": "sha1-BO9CngmRsCkryRixNc1MA497iJ8=",
686 | "requires": {
687 | "cssnano-utils": "^3.1.0",
688 | "postcss-value-parser": "^4.2.0"
689 | }
690 | },
691 | "postcss-reduce-initial": {
692 | "version": "5.1.0",
693 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-reduce-initial/download/postcss-reduce-initial-5.1.0.tgz",
694 | "integrity": "sha1-/DFlnqboXEkvsqe1RTcMIVgixdY=",
695 | "requires": {
696 | "browserslist": "^4.16.6",
697 | "caniuse-api": "^3.0.0"
698 | }
699 | },
700 | "postcss-reduce-transforms": {
701 | "version": "5.1.0",
702 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-reduce-transforms/download/postcss-reduce-transforms-5.1.0.tgz",
703 | "integrity": "sha1-Mztw53WLgC890N3+mLscz++Wtuk=",
704 | "requires": {
705 | "postcss-value-parser": "^4.2.0"
706 | }
707 | },
708 | "postcss-selector-parser": {
709 | "version": "6.0.9",
710 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-selector-parser/download/postcss-selector-parser-6.0.9.tgz",
711 | "integrity": "sha1-7nHDuf9j2c0TCDiHbBOi7BqZKy8=",
712 | "requires": {
713 | "cssesc": "^3.0.0",
714 | "util-deprecate": "^1.0.2"
715 | }
716 | },
717 | "postcss-svgo": {
718 | "version": "5.1.0",
719 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-svgo/download/postcss-svgo-5.1.0.tgz",
720 | "integrity": "sha1-CjF0AM7XifIzoogm53Uj8VhX2A0=",
721 | "requires": {
722 | "postcss-value-parser": "^4.2.0",
723 | "svgo": "^2.7.0"
724 | }
725 | },
726 | "postcss-unique-selectors": {
727 | "version": "5.1.1",
728 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-unique-selectors/download/postcss-unique-selectors-5.1.1.tgz",
729 | "integrity": "sha1-qfJz0erNCemqYIj0sFB7GLG1QbY=",
730 | "requires": {
731 | "postcss-selector-parser": "^6.0.5"
732 | }
733 | },
734 | "postcss-value-parser": {
735 | "version": "4.2.0",
736 | "resolved": "http://registry.npm.release.ctripcorp.com/postcss-value-parser/download/postcss-value-parser-4.2.0.tgz",
737 | "integrity": "sha1-cjwJkgg2um0+WvAZ+SvAlxwC5RQ="
738 | },
739 | "promise.series": {
740 | "version": "0.2.0",
741 | "resolved": "http://registry.npm.release.ctripcorp.com/promise.series/download/promise.series-0.2.0.tgz",
742 | "integrity": "sha1-LMfr6Vn8OmYZwEq029yeRS2GS70="
743 | },
744 | "resolve": {
745 | "version": "1.22.0",
746 | "resolved": "http://registry.npm.release.ctripcorp.com/resolve/download/resolve-1.22.0.tgz",
747 | "integrity": "sha1-XguMZ8Fd9XqJvbq+YDoALyFzEZg=",
748 | "requires": {
749 | "is-core-module": "^2.8.1",
750 | "path-parse": "^1.0.7",
751 | "supports-preserve-symlinks-flag": "^1.0.0"
752 | }
753 | },
754 | "resolve-from": {
755 | "version": "5.0.0",
756 | "resolved": "http://registry.npm.release.ctripcorp.com/resolve-from/download/resolve-from-5.0.0.tgz",
757 | "integrity": "sha1-w1IlhD3493bfIcV1V7wIfp39/Gk="
758 | },
759 | "rollup": {
760 | "version": "2.70.0",
761 | "resolved": "http://registry.npm.release.ctripcorp.com/rollup/download/rollup-2.70.0.tgz",
762 | "integrity": "sha1-F6kuWTjpKiUbliNS6QTJ9VgjDsc=",
763 | "dev": true,
764 | "requires": {
765 | "fsevents": "~2.3.2"
766 | }
767 | },
768 | "rollup-plugin-commonjs": {
769 | "version": "10.1.0",
770 | "resolved": "http://registry.npm.release.ctripcorp.com/rollup-plugin-commonjs/download/rollup-plugin-commonjs-10.1.0.tgz",
771 | "integrity": "sha1-QXrztUUDh44ITRJ6300cr4vrhvs=",
772 | "dev": true,
773 | "requires": {
774 | "estree-walker": "^0.6.1",
775 | "is-reference": "^1.1.2",
776 | "magic-string": "^0.25.2",
777 | "resolve": "^1.11.0",
778 | "rollup-pluginutils": "^2.8.1"
779 | }
780 | },
781 | "rollup-plugin-node-resolve": {
782 | "version": "5.2.0",
783 | "resolved": "http://registry.npm.release.ctripcorp.com/rollup-plugin-node-resolve/download/rollup-plugin-node-resolve-5.2.0.tgz",
784 | "integrity": "sha1-cw+T0Q7SAkc7H7VKWZen24xthSM=",
785 | "dev": true,
786 | "requires": {
787 | "@types/resolve": "0.0.8",
788 | "builtin-modules": "^3.1.0",
789 | "is-module": "^1.0.0",
790 | "resolve": "^1.11.1",
791 | "rollup-pluginutils": "^2.8.1"
792 | }
793 | },
794 | "rollup-plugin-postcss": {
795 | "version": "4.0.2",
796 | "resolved": "http://registry.npm.release.ctripcorp.com/rollup-plugin-postcss/download/rollup-plugin-postcss-4.0.2.tgz",
797 | "integrity": "sha1-FelGLzlHUFmzaM4OScgA+ksfcFA=",
798 | "requires": {
799 | "chalk": "^4.1.0",
800 | "concat-with-sourcemaps": "^1.1.0",
801 | "cssnano": "^5.0.1",
802 | "import-cwd": "^3.0.0",
803 | "p-queue": "^6.6.2",
804 | "pify": "^5.0.0",
805 | "postcss-load-config": "^3.0.0",
806 | "postcss-modules": "^4.0.0",
807 | "promise.series": "^0.2.0",
808 | "resolve": "^1.19.0",
809 | "rollup-pluginutils": "^2.8.2",
810 | "safe-identifier": "^0.4.2",
811 | "style-inject": "^0.3.0"
812 | }
813 | },
814 | "rollup-plugin-typescript": {
815 | "version": "1.0.1",
816 | "resolved": "http://registry.npm.release.ctripcorp.com/rollup-plugin-typescript/download/rollup-plugin-typescript-1.0.1.tgz",
817 | "integrity": "sha1-hlZQM7cUw9Hzq6UQqtPcUZ9wkek=",
818 | "dev": true,
819 | "requires": {
820 | "resolve": "^1.10.0",
821 | "rollup-pluginutils": "^2.5.0"
822 | }
823 | },
824 | "rollup-pluginutils": {
825 | "version": "2.8.2",
826 | "resolved": "http://registry.npm.release.ctripcorp.com/rollup-pluginutils/download/rollup-pluginutils-2.8.2.tgz",
827 | "integrity": "sha1-cvKvB0i1kjZNvTOJ5gDlqURKNR4=",
828 | "requires": {
829 | "estree-walker": "^0.6.1"
830 | }
831 | },
832 | "safe-identifier": {
833 | "version": "0.4.2",
834 | "resolved": "http://registry.npm.release.ctripcorp.com/safe-identifier/download/safe-identifier-0.4.2.tgz",
835 | "integrity": "sha1-z2v8oxwol8WICS0XUNMO9QHVn8s="
836 | },
837 | "source-map": {
838 | "version": "0.6.1",
839 | "resolved": "http://registry.npm.release.ctripcorp.com/source-map/download/source-map-0.6.1.tgz",
840 | "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM="
841 | },
842 | "sourcemap-codec": {
843 | "version": "1.4.8",
844 | "resolved": "http://registry.npm.release.ctripcorp.com/sourcemap-codec/download/sourcemap-codec-1.4.8.tgz",
845 | "integrity": "sha1-6oBL2UhXQC5pktBaOO8a41qatMQ=",
846 | "dev": true
847 | },
848 | "stable": {
849 | "version": "0.1.8",
850 | "resolved": "http://registry.npm.release.ctripcorp.com/stable/download/stable-0.1.8.tgz",
851 | "integrity": "sha1-g26zyDgv4pNv6vVEYxAXzn1Ho88="
852 | },
853 | "string-hash": {
854 | "version": "1.1.3",
855 | "resolved": "http://registry.npm.release.ctripcorp.com/string-hash/download/string-hash-1.1.3.tgz",
856 | "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs="
857 | },
858 | "style-inject": {
859 | "version": "0.3.0",
860 | "resolved": "http://registry.npm.release.ctripcorp.com/style-inject/download/style-inject-0.3.0.tgz",
861 | "integrity": "sha1-0hxHev/skYEcyCNVgypwDSK/jdM="
862 | },
863 | "stylehacks": {
864 | "version": "5.1.0",
865 | "resolved": "http://registry.npm.release.ctripcorp.com/stylehacks/download/stylehacks-5.1.0.tgz",
866 | "integrity": "sha1-pABmSQygysoE6WxrAhU93DmRNSA=",
867 | "requires": {
868 | "browserslist": "^4.16.6",
869 | "postcss-selector-parser": "^6.0.4"
870 | }
871 | },
872 | "supports-color": {
873 | "version": "7.2.0",
874 | "resolved": "http://registry.npm.release.ctripcorp.com/supports-color/download/supports-color-7.2.0.tgz",
875 | "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=",
876 | "requires": {
877 | "has-flag": "^4.0.0"
878 | }
879 | },
880 | "supports-preserve-symlinks-flag": {
881 | "version": "1.0.0",
882 | "resolved": "http://registry.npm.release.ctripcorp.com/supports-preserve-symlinks-flag/download/supports-preserve-symlinks-flag-1.0.0.tgz",
883 | "integrity": "sha1-btpL00SjyUrqN21MwxvHcxEDngk="
884 | },
885 | "svgo": {
886 | "version": "2.8.0",
887 | "resolved": "http://registry.npm.release.ctripcorp.com/svgo/download/svgo-2.8.0.tgz",
888 | "integrity": "sha1-T/gMzmcQ3CeV8MfHQQHmdkz8zSQ=",
889 | "requires": {
890 | "@trysound/sax": "0.2.0",
891 | "commander": "^7.2.0",
892 | "css-select": "^4.1.3",
893 | "css-tree": "^1.1.3",
894 | "csso": "^4.2.0",
895 | "picocolors": "^1.0.0",
896 | "stable": "^0.1.8"
897 | }
898 | },
899 | "timsort": {
900 | "version": "0.3.0",
901 | "resolved": "http://registry.npm.release.ctripcorp.com/timsort/download/timsort-0.3.0.tgz",
902 | "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q="
903 | },
904 | "tslib": {
905 | "version": "2.3.1",
906 | "resolved": "http://registry.npm.release.ctripcorp.com/tslib/download/tslib-2.3.1.tgz",
907 | "integrity": "sha1-6KM1rdXOrlGqJh0ypJAVjvBC7wE=",
908 | "dev": true
909 | },
910 | "typescript": {
911 | "version": "4.6.2",
912 | "resolved": "http://registry.npm.release.ctripcorp.com/typescript/download/typescript-4.6.2.tgz",
913 | "integrity": "sha1-/hLScntwj07vQPUVmLM5i6qWEdQ=",
914 | "dev": true
915 | },
916 | "util-deprecate": {
917 | "version": "1.0.2",
918 | "resolved": "http://registry.npm.release.ctripcorp.com/util-deprecate/download/util-deprecate-1.0.2.tgz",
919 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
920 | },
921 | "yaml": {
922 | "version": "1.10.2",
923 | "resolved": "http://registry.npm.release.ctripcorp.com/yaml/download/yaml-1.10.2.tgz",
924 | "integrity": "sha1-IwHF/78StGfejaIzOkWeKeeSDks="
925 | }
926 | }
927 | }
928 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "toa-tools",
3 | "version": "0.0.1",
4 | "description": "javascript tools",
5 | "author": "",
6 | "license": "ISC",
7 | "bugs": {
8 | "url": "https://github.com/codeluosiyu/toa-tools/issues"
9 | },
10 | "homepage": "https://github.com/codeluosiyu/toa-tools#readme",
11 | "main": "index.js",
12 | "scripts": {
13 | "build": "rollup -c",
14 | "build:dev": "npm run clean && env_type=development npm run build",
15 | "build:prod": "npm run clean && env_type=production npm run build",
16 | "clean": "rimraf umd",
17 | "test": "echo \"Error: no test specified\" && exit 1"
18 | },
19 | "repository": {
20 | "type": "git",
21 | "url": "git+https://github.com/codeluosiyu/toa-tools.git"
22 | },
23 | "keywords": [
24 | "toolkit",
25 | "rollup",
26 | "typescript"
27 | ],
28 | "browser": "dist/index.ts",
29 | "devDependencies": {
30 | "rollup": "^2.70.0",
31 | "rollup-plugin-commonjs": "^10.1.0",
32 | "rollup-plugin-node-resolve": "^5.2.0",
33 | "rollup-plugin-typescript": "^1.0.1",
34 | "tslib": "^2.3.1",
35 | "typescript": "^4.6.2"
36 | },
37 | "dependencies": {
38 | "rollup-plugin-postcss": "^4.0.2"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import resolve from 'rollup-plugin-node-resolve';
2 | import commonjs from 'rollup-plugin-commonjs';
3 | import typescript from 'rollup-plugin-typescript';
4 | import pkg from './package.json';
5 |
6 | export default {
7 | input: 'src/index.ts', // 打包入口
8 | output: { // 打包出口
9 | file: pkg.browser, // 最终打包出来的文件路径和文件名,这里是在package.json的browser: 'dist/index.js'字段中配置的
10 | format: 'umd', // umd是兼容amd/cjs/iife的通用打包格式,适合浏览器
11 | sourcemap: true // 生成源码映射文件
12 | },
13 | plugins: [ // 打包插件
14 | resolve(), // 查找和打包node_modules中的第三方模块
15 | commonjs(), // 将 CommonJS 转换成 ES2015 模块供 Rollup 处理
16 | typescript() // 解析TypeScript
17 | ]
18 | };
19 |
--------------------------------------------------------------------------------
/src/animation/animation.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var Timeline = require('./timeline');
4 | var loadImage = require('./imageloader');
5 |
6 | //初始化状态
7 | var STATE_INITIAL = 0;
8 | //开始状态
9 | var STATE_START = 1;
10 | //停止状态
11 | var STATE_STOP = 2;
12 |
13 | //同步任务
14 | var TASK_SYNC = 0;
15 | //异步任务
16 | var TASK_ASYNC = 1;
17 |
18 |
19 | /**
20 | * 简单的函数封装,执行callback
21 | * @param callback 执行的函数
22 | */
23 | function next(callback) {
24 | callback && callback();
25 | }
26 |
27 | /**
28 | * 帧动画库类
29 | * @constructor
30 | */
31 | function Animation() {
32 | this.taskQueue = [];
33 | this.timeline = new Timeline();
34 | this.state = STATE_INITIAL;
35 | this.index = 0;
36 | }
37 |
38 | /**
39 | * 添加一个同步任务,预加载图片
40 | * @param imglist 图片数组
41 | */
42 | Animation.prototype.loadImage = function (imglist) {
43 |
44 | var taskFn = function (next) {
45 | loadImage(imglist.slice(), next);
46 | };
47 | var type = TASK_SYNC;
48 |
49 | return this._add(taskFn, type);
50 | };
51 |
52 | /**
53 | * 添加一个异步定时任务,通过定时改变图片背景位置,实现帧动画
54 | * @param ele dom对象
55 | * @param positions 背景位置数组
56 | * @param imageUrl 图片地址
57 | */
58 | Animation.prototype.changePosition = function (ele, positions, imageUrl) {
59 | var len = positions.length;
60 | var taskFn;
61 | var type;
62 | if (len) {
63 | var me = this;
64 | taskFn = function (next, time) {
65 | //如果指定图片,则设置dom对象的背景图片地址
66 | if (imageUrl) {
67 | ele.style.backgroundImage = 'url(' + imageUrl + ')';
68 | }
69 | //获得当前背景图片位置索引
70 | var index = Math.min(time / me.interval | 0, len);
71 | var position = positions[index - 1].split(' ');
72 | //改变dom对象的背景图片位置
73 | ele.style.backgroundPosition = position[0] + 'px ' + position[1] + 'px';
74 | //当前任务执行完毕
75 | if (index === len) {
76 | next();
77 | }
78 | };
79 | type = TASK_ASYNC;
80 | } else {
81 | taskFn = next;
82 | type = TASK_SYNC;
83 | }
84 |
85 | return this._add(taskFn, type);
86 | };
87 |
88 | /**
89 | * 添加一个异步定时任务,通过定时改变背景图片地址,实现帧动画
90 | * @param ele dom(Image对象)
91 | * @param imglist 图片地址数组
92 | */
93 | Animation.prototype.changeSrc = function (ele, imglist) {
94 | var len = imglist.length;
95 | var taskFn;
96 | var type;
97 | if (len) {
98 | var me = this;
99 | taskFn = function (next, time) {
100 | //获得当前的图片索引
101 | var index = Math.min(time / me.interval | 0, len);
102 | //改变image对象的图片地址
103 | ele.src = imglist[index - 1];
104 | //当前任务执行完毕
105 | if (index === len) {
106 | next();
107 | }
108 | };
109 | type = TASK_ASYNC;
110 | } else {
111 | taskFn = next;
112 | type = TASK_SYNC;
113 | }
114 |
115 | return this._add(taskFn, type);
116 | };
117 |
118 | /**
119 | * 高级用法,添加一个异步定时执行的任务,
120 | * 该任务自定义动画每帧执行的任务函数
121 | * @param taskFn 每帧执行的任务函数
122 | */
123 | Animation.prototype.enterFrame = function (taskFn) {
124 | return this._add(taskFn, TASK_ASYNC);
125 | };
126 |
127 | /**
128 | * 添加一个同步任务,可在上一个任务完成执行回调函数
129 | * @param callback 回调函数
130 | */
131 | Animation.prototype.then = function (callback) {
132 | var taskFn = function (next) {
133 | callback(this);
134 | next();
135 | };
136 | var type = TASK_SYNC;
137 |
138 | return this._add(taskFn, type);
139 | };
140 |
141 | /**
142 | * 开始执行任务
143 | * @param interval 异步定时任务执行的间隔
144 | */
145 | Animation.prototype.start = function (interval) {
146 | //如果任务已经开始,则返回
147 | if (this.state === STATE_START)
148 | return this;
149 | //如果任务链中没有任务,则返回
150 | if (!this.taskQueue.length)
151 | return this;
152 | this.state = STATE_START;
153 |
154 | this.interval = interval;
155 | this._runTask();
156 | return this;
157 | };
158 |
159 | /**
160 | * 添加一个同步任务,该任务就是回退到上一个任务中,
161 | * 实现重复上一个任务的效果,可定义重复的次数。
162 | * @param times 重复次数
163 | */
164 | Animation.prototype.repeat = function (times) {
165 | var me = this;
166 | var taskFn = function () {
167 | if (typeof times === 'undefined') {
168 | //无限回退到上一个任务
169 | me.index--;
170 | me._runTask();
171 | return;
172 | }
173 | if (times) {
174 | times--;
175 | //回退到上一个任务
176 | me.index--;
177 | me._runTask();
178 | } else {
179 | //达到重复执行次数,则跳转到下一个任务
180 | var task = me.taskQueue[me.index];
181 | me._next(task);
182 | }
183 | };
184 | var type = TASK_SYNC;
185 |
186 | return this._add(taskFn, type);
187 | };
188 |
189 | /**
190 | * 添加一个同步任务,该任务就是无线循环上一次任务
191 | */
192 | Animation.prototype.repeatForever = function () {
193 | return this.repeat();
194 | };
195 |
196 | /**
197 | * 设置当前任务结束后下一个任务开始前的等待时间
198 | * @param time 等待的时长
199 | */
200 | Animation.prototype.wait = function (time) {
201 | if (this.taskQueue && this.taskQueue.length > 0) {
202 | this.taskQueue[this.taskQueue.length - 1].wait = time;
203 | }
204 | return this;
205 | };
206 |
207 | /**
208 | * 暂停当前执行的异步定时任务
209 | */
210 | Animation.prototype.pause = function () {
211 | if (this.state === STATE_START) {
212 | this.state = STATE_STOP;
213 | this.timeline.stop();
214 | return this;
215 | }
216 | return this;
217 | };
218 |
219 | /**
220 | * 重新开始执行当前异步定时任务
221 | */
222 | Animation.prototype.restart = function () {
223 | if (this.state === STATE_STOP) {
224 | this.state = STATE_START;
225 | this.timeline.restart();
226 | return this;
227 | }
228 | return this;
229 | };
230 |
231 | /**
232 | * 释放资源
233 | */
234 | Animation.prototype.dispose = function () {
235 | if (this.state !== STATE_INITIAL) {
236 | this.state = STATE_INITIAL;
237 | this.taskQueue = null;
238 | this.timeline.stop();
239 | this.timeline = null;
240 | return this;
241 | }
242 | return this;
243 | };
244 |
245 | /**
246 | * 添加一个任务到任务队列中
247 | * @param taskFn 任务方法
248 | * @param type 任务类型
249 | * @returns {Animation}
250 | * @private
251 | */
252 | Animation.prototype._add = function (taskFn, type) {
253 | this.taskQueue.push({
254 | taskFn: taskFn,
255 | type: type
256 | });
257 | return this;
258 | };
259 |
260 | /**
261 | * 执行任务
262 | * @private
263 | */
264 | Animation.prototype._runTask = function () {
265 | if (!this.taskQueue || this.state !== STATE_START)
266 | return;
267 | //如果任务链任务执行完则释放资源
268 | if (this.index === this.taskQueue.length) {
269 | this.dispose();
270 | return;
271 | }
272 | //获得任务链上的一个任务
273 | var task = this.taskQueue[this.index];
274 | if (task.type === TASK_SYNC) {
275 | this._syncTask(task);
276 | } else {
277 | this._asyncTask(task);
278 | }
279 | };
280 |
281 | /**
282 | * 同步任务
283 | * @param task 执行任务的函数
284 | * @private
285 | */
286 | Animation.prototype._syncTask = function (task) {
287 | var me = this;
288 | var next = function () {
289 | //切换到下一个任务
290 | me._next(task);
291 | };
292 | var taskFn = task.taskFn;
293 | taskFn(next);
294 | };
295 |
296 | /**
297 | * 异步任务
298 | * @param task 执行异步的函数
299 | * @private
300 | */
301 | Animation.prototype._asyncTask = function (task) {
302 | var me = this;
303 | //定义每一帧执行的回调函数
304 | var enterframe = function (time) {
305 | var taskFn = task.taskFn;
306 | var next = function () {
307 | //停止执行当前任务
308 | me.timeline.stop();
309 | //执行下一个任务
310 | me._next(task);
311 | };
312 | taskFn(next, time);
313 | };
314 |
315 | this.timeline.onenterframe = enterframe;
316 | this.timeline.start(this.interval);
317 | };
318 |
319 | /**
320 | * 切换到下一个任务,如果当前任务需要等待,则延时执行
321 | * @param task 下一个任务
322 | * @private
323 | */
324 | Animation.prototype._next = function (task) {
325 | var me = this;
326 | this.index++;
327 | task.wait ? setTimeout(function () {
328 | me._runTask();
329 | }, task.wait) : this._runTask();
330 | };
331 |
332 |
333 | function createAnimation() {
334 | return new Animation();
335 | }
336 |
337 | createAnimation.version = __VERSION__;
338 |
339 | module.exports = createAnimation;
340 |
341 |
--------------------------------------------------------------------------------
/src/animation/imageloader.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var __id = 0;
4 |
5 | /**
6 | * 动态创建id
7 | * @returns {number}
8 | */
9 | function getId() {
10 | return ++__id;
11 | }
12 |
13 | /**
14 | * 预加载图片函数
15 | * @param images 加载的图片数组或对象
16 | * @param callback 全部图片加载完毕后调用的回调函数
17 | * @param timeout 加载超时的时长
18 | */
19 | function loadImage(images, callback, timeout) {
20 | //加载完成图片的计数器
21 | var count = 0;
22 | //全部图片成功加载完图片的标志位
23 | var success = true;
24 | //超时timer的id
25 | var timeoutId = 0;
26 | //是否加载超时的标志位
27 | var isTimeout = false;
28 | //对图片数组(或对象)进行遍历
29 | for (var key in images) {
30 | //过滤掉prototype的属性
31 | if (!images.hasOwnProperty(key))
32 | continue;
33 | //获得每个图片元素
34 | //期望格式是个object: {src:xxx}
35 | var item = images[key];
36 |
37 | // 如果item是个字符串,则构造object
38 | if (typeof item === 'string') {
39 | item = images[key] = {
40 | src: item
41 | };
42 | }
43 |
44 | //如果格式不满足期望,则丢弃此条数据进行下一次遍历
45 | if (!item || !item.src)
46 | continue;
47 |
48 | //计数+1
49 | count++;
50 | //设置图片元素的id
51 | item.id = "__img_" + key + getId();
52 | //设置图片元素的img,是一个Image对象
53 | item.img = window[item.id] = new Image();
54 |
55 | doLoad(item);
56 | }
57 |
58 | //遍历完成如果计数为0,则直接调用
59 | if (!count) {
60 | callback(success);
61 | }
62 | //如果设置了加载时长,则设置超时函数计时器
63 | else if (timeout) {
64 | timeoutId = setTimeout(onTimeout, timeout);
65 | }
66 |
67 | /**
68 | * 真正进行图片加载的函数
69 | * @param item 图片元素对象
70 | */
71 | function doLoad(item) {
72 | item.status = "loading";
73 |
74 | var img = item.img;
75 | //定义图片加载成功的回调函数
76 | img.onload = function () {
77 | //如果每张图片都成功才算成功
78 | success = success && true;
79 | item.status = "loaded";
80 | done();
81 | };
82 | img.onerror = function () {
83 | //若有一张图片加载失败,则为失败
84 | success = false;
85 | item.status = "error";
86 | done();
87 | };
88 | //发起一个http(s)请求加载图片
89 | img.src = item.src;
90 |
91 | /**
92 | * 每张图片加载完成的回调函数
93 | */
94 | function done() {
95 | //事件清理
96 | img.onload = img.onerror = null;
97 |
98 | try {
99 | //删除window上注册的属性
100 | delete window[item.id];
101 | }
102 | catch (e) {
103 |
104 | }
105 | //每张图片加载完成,计数器减一,当所有图片加载完毕且没有超时的情况下,
106 | //清除超时计时器,且执行回调函数
107 | if (!--count && !isTimeout) {
108 | clearTimeout(timeoutId);
109 | callback(success);
110 | }
111 | }
112 | }
113 |
114 | /**
115 | * 超时函数
116 | */
117 | function onTimeout() {
118 | isTimeout = true;
119 | callback(false);
120 | }
121 | }
122 |
123 | module.exports = loadImage;
124 |
--------------------------------------------------------------------------------
/src/animation/timeline.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var DEFAULT_INTERVAL = 1000 / 60;
4 |
5 | //初始化状态
6 | var STATE_INITIAL = 0;
7 | //开始状态
8 | var STATE_START = 1;
9 | //停止状态
10 | var STATE_STOP = 2;
11 |
12 | /**
13 | * Timline时间轴类
14 | * @constructor
15 | */
16 | function Timeline() {
17 | this.animationHandler = 0;
18 | this.state = STATE_INITIAL;
19 | }
20 |
21 | /**
22 | * 时间轴上每一次回调执行的函数
23 | * @param time 从动画开始到当前执行的时间
24 | */
25 | Timeline.prototype.onenterframe = function (time) {
26 | };
27 |
28 | /**
29 | * 动画开始
30 | * @param interval 每一次回调的间隔时间
31 | */
32 | Timeline.prototype.start = function (interval) {
33 | if (this.state === STATE_START)
34 | return;
35 | this.state = STATE_START;
36 |
37 | this.interval = interval || DEFAULT_INTERVAL;
38 | startTimeline(this, +new Date());
39 | };
40 |
41 | /**
42 | * 重新开始动画
43 | */
44 | Timeline.prototype.restart = function () {
45 | if (this.state === STATE_START)
46 | return;
47 | if (!this.dur || !this.interval)
48 | return;
49 |
50 | this.state = STATE_START;
51 |
52 | //无缝连接停止动画的状态
53 | startTimeline(this, +new Date() - this.dur);
54 | };
55 |
56 | /**
57 | * 动画停止
58 | */
59 | Timeline.prototype.stop = function () {
60 | if (this.state !== STATE_START)
61 | return;
62 | this.state = STATE_STOP;
63 |
64 | //如果动画开始过,则记录动画从开始到当前所经历的时间
65 | if (this.startTime) {
66 | this.dur = +new Date() - this.startTime;
67 | }
68 | cancelAnimationFrame(this.animationHandler);
69 | };
70 |
71 | /**
72 | * 时间轴动画启动函数
73 | * @param timeline 时间轴实例
74 | * @param startTime 动画开始时间戳
75 | */
76 | function startTimeline(timeline, startTime) {
77 | //记录上一次回调的时间戳
78 | var lastTick = +new Date();
79 |
80 | timeline.startTime = startTime;
81 | nextTick.interval = timeline.interval;
82 | nextTick();
83 |
84 | /**
85 | * 每一帧执行的函数
86 | */
87 | function nextTick() {
88 | var now = +new Date();
89 |
90 | timeline.animationHandler = requestAnimationFrame(nextTick);
91 |
92 | //如果当前时间与上一次回调的时间戳相差大于我们设置的间隔时间,表示可以执行一次回调函数。
93 | if (now - lastTick >= timeline.interval) {
94 | timeline.onenterframe(now - startTime);
95 | lastTick = now;
96 | }
97 | }
98 | }
99 |
100 | /**
101 | * raf
102 | */
103 | var requestAnimationFrame = (function () {
104 | return window.requestAnimationFrame ||
105 | window.webkitRequestAnimationFrame ||
106 | window.mozRequestAnimationFrame ||
107 | window.oRequestAnimationFrame ||
108 | //所有都不支持,用setTimeout兼容
109 | function (callback) {
110 | return window.setTimeout(callback, (callback.interval || DEFAULT_INTERVAL)); // make interval as precise as possible.
111 | };
112 | })();
113 |
114 | /**
115 | * cancel raf
116 | */
117 | var cancelAnimationFrame = (function () {
118 | return window.cancelAnimationFrame ||
119 | window.webkitCancelAnimationFrame ||
120 | window.mozCancelAnimationFrame ||
121 | window.oCancelAnimationFrame ||
122 | function (id) {
123 | window.clearTimeout(id);
124 | };
125 | })();
126 |
127 | module.exports = Timeline;
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import { randomUniqueArr } from "./utils/base.ts"
2 |
--------------------------------------------------------------------------------
/src/utils/assets.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 获取资源后缀
3 | * @param obj
4 | * @returns
5 | */
6 | export const getAssetsType = async (obj: string) => {
7 | // 获取字符串中.之后的所有字符
8 | var index = obj.lastIndexOf(".");
9 | obj = obj.substring(index + 1, obj.length);
10 | return obj;
11 | };
12 |
13 | /**
14 | * 已知宽高获取图片相对于屏幕的高度使得自适应
15 | * @param obj
16 | * @param targetWidth
17 | * @returns
18 | */
19 | export const getMediaHeight = async (obj: any, targetWidth = 750) => {
20 | let ratio = obj.width / obj.height;
21 | let targetHeight = targetWidth / ratio;
22 | return (targetHeight + 2).toFixed(2);
23 | };
24 |
25 |
26 | /**
27 | * 获取资源后缀
28 | * @param {*} file
29 | * @returns
30 | */
31 | export const getType = (file) => {
32 | var index1 = filename.lastIndexOf(".");
33 | var index2 = file.length;
34 | var type = file.substring(index1, index2).toUpperCase();
35 | return type;
36 | }
37 |
--------------------------------------------------------------------------------
/src/utils/async/task.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 写一个函数,可以控制最大并发数
3 | */
4 | function concurrentPoll() {
5 | this.tasks = [];
6 | this.max = 10;
7 | setTimeout(() => {
8 | this.run();
9 | }, 0);
10 | }
11 | concurrentPoll.prototype.addTask = function (task) {
12 | this.tasks.push(task);
13 | };
14 | concurrentPoll.prototype.run = function () {
15 | if (this.tasks.length == 0) {
16 | return;
17 | }
18 | var min = Math.min(this.tasks.length, max);
19 | for (var i = 0; i < min; i++) {
20 | this.max--;
21 | var task = this.tasks.shift();
22 | task()
23 | .then((res) => {
24 | console.log(res);
25 | })
26 | .catch((err) => {
27 | console.log(err);
28 | })
29 | .finally(() => {
30 | this.max++;
31 | this.run();
32 | });
33 | }
34 | };
35 |
36 | class PromisePool {
37 | constructor(max, fn) {
38 | this.max = max; //最大并发量
39 | this.fn = fn; //自定义的请求函数
40 | this.pool = []; //并发池
41 | this.urls = []; //剩余的请求地址
42 | }
43 | start(urls) {
44 | this.urls = urls; //先循环把并发池塞满
45 | while (this.pool.length < this.max) {
46 | let url = this.urls.shift();
47 | this.setTask(url);
48 | }
49 | //利用Promise.race方法来获得并发池中某任务完成的信号
50 | let race = Promise.race(this.pool);
51 | return this.run(race);
52 | }
53 | run(race) {
54 | race
55 | .then(res => {
56 | //每当并发池跑完一个任务,就再塞入一个任务
57 | let url = this.urls.shift();
58 | this.setTask(url);
59 | return this.run(Promise.race(this.pool));
60 | })
61 | }
62 | setTask(url) {
63 | if (!url) return
64 | let task = this.fn(url);
65 | this.pool.push(task); //将该任务推入pool并发池中
66 | console.log(`\x1B[43m ${url} 开始,当前并发数:${this.pool.length}`)
67 | task.then(res => {
68 | //请求结束后将该Promise任务从并发池中移除
69 | this.pool.splice(this.pool.indexOf(task), 1);
70 | console.log(`\x1B[43m ${url} 结束,当前并发数:${this.pool.length}`);
71 | })
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/utils/base.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 数组合并
3 | * @returns
4 | */
5 | export const arrayConcat = function () {
6 | var tmpArr = [];
7 | for (let i = 0; i < arguments.length; i++) {
8 | tmpArr = tmpArr.concat(arguments[i]);
9 | }
10 | return tmpArr;
11 | };
12 |
13 | /**
14 | * 删除数组指定部分
15 | * @returns
16 | */
17 | export const arrayDrop = function (array, index, howmany) {
18 | if (!index) {
19 | index = 0;
20 | }
21 | if (!howmany) {
22 | howmany = 1;
23 | }
24 | array.splice(index, howmany);
25 | return array;
26 | };
27 |
28 | /**
29 | * 检查数组是否包含
30 | * @returns
31 | */
32 | export const arrayIndexOf = function (arr: Array, needFind: String | Number | Boolean | unknown) {
33 | var index = -1;
34 | for (let i = 0; i < arr.length; i++) {
35 | if (arr[i] == needFind) {
36 | index = i;
37 | return i;
38 | }
39 | }
40 | return index;
41 | };
42 |
43 | /**
44 | * 检查数组不同
45 | * @returns
46 | */
47 | export const arrayDifference = function (a, b) {
48 | const set = new Set(b);
49 | return a.filter((x) => !set.has(x));
50 | };
51 |
52 | export const arrayShuffle = function (arr) {
53 | let l = arr.length;
54 | while (l) {
55 | const i = Math.floor(Math.random() * l--);
56 | [arr[l], arr[i]] = [arr[i], arr[l]];
57 | console.log(i);
58 | }
59 | return arr;
60 | };
61 |
62 | export const arraySum = function (arr) {
63 | return arr.reduce((acc, val) => acc + val, 0);
64 | };
65 |
66 | export const arrayAvg = function (arr) {
67 | return arr.reduce((acc, val) => acc + val, 0) / arr.length;
68 | };
69 |
70 | export const arrayEach = function (arr, fun) {
71 | for (let i = 0; i < arr.length; i++) {
72 | fun(arr[i], i);
73 | }
74 | };
75 |
76 | /**
77 | * 2数之间的随机数
78 | * @param min
79 | * @param max
80 | * @returns
81 | */
82 | export const random = function (min: number, max: number): number {
83 | switch (arguments.length) {
84 | case 1:
85 | return parseInt(Math.random() * min + 1 + "", 10);
86 | break;
87 | case 2:
88 | return parseInt(Math.random() * (max - min + 1) + min + "", 10);
89 | break;
90 | default:
91 | return 0;
92 | }
93 | };
94 |
95 | /**
96 | * 判断是不是一个空对象
97 | * @param obj
98 | * @returns
99 | */
100 | export const isEmptyObj = function (obj) {
101 | return JSON.stringify(obj) === "{}";
102 | };
103 |
104 | /**
105 | * 判断是不是一个空对象
106 | * @param obj
107 | * @returns
108 | */
109 | export const isPlainObject = (obj) => {
110 | return typeof obj == "object" && Object.getPrototypeOf(obj) === Object.prototype
111 | }
112 |
113 | /**
114 | * 生成一个不重复的随机数组
115 | * @param {number} len 数组长度
116 | * @param {number} min 最小随机数
117 | * @param {number} max 最大随机数
118 | * @return {array} 不重复的随机数组
119 | */
120 | export const randomUniqueArr = (len, min, max) => {
121 | if (max - min < len) {
122 | return null;
123 | }
124 | const hash = [];
125 |
126 | while (hash.length < len) {
127 | const num = Math.floor(Math.random() * 100);
128 |
129 | if (hash.indexOf(num) === -1) {
130 | hash.push(num);
131 | }
132 | }
133 | return hash;
134 | };
135 |
136 |
137 | /**
138 | * 判断以X开头
139 | * @param target
140 | * @param str
141 | * @param ignorecase
142 | * @returns
143 | */
144 | export const startsWith = (target: String, str: string, ignorecase: boolean) => {
145 | var start_str = target.substr(0, str.length);
146 | return ignorecase ? start_str.toLowerCase() === str.toLowerCase() : start_str === str;
147 | }
148 |
149 | /**
150 | * 判断以X结尾
151 | * @param target
152 | * @param str
153 | * @param ignorecase
154 | * @returns
155 | */
156 | export const endsWith = (target: String, str: string, ignorecase: boolean) => {
157 | var end_str = target.substring(target.length - str.length);
158 | return ignorecase ? end_str.toLowerCase() === str.toLowerCase() : end_str === str;
159 | }
160 |
161 | /**
162 | * limit方法,超出区间外,则取最近的区间边界值
163 | * @param target
164 | * @param n1
165 | * @param n2
166 | * @returns
167 | */
168 | export const limitNumber = (target, n1, n2) => {
169 | var a = [n1, n2].sort()
170 | if (target < a[0]) return target = a[0]
171 | if (target > a[1]) return target = a[1]
172 | return target
173 | }
174 |
175 | /**
176 | * 分割数组
177 | * @param nums
178 | * @returns
179 | */
180 | export const partitionDisjoint = (nums: string | any[]) => {
181 | let n = nums.length;
182 | let maxLeft = new Array(n).fill(Number.MIN_SAFE_INTEGER);
183 | let minRight = new Array(n).fill(Number.MAX_SAFE_INTEGER);
184 | maxLeft[0] = nums[0];
185 | minRight[n - 1] = nums[n - 1];
186 | for (let i = 1, j = n - 2; i < n; i++, j--) {
187 | maxLeft[i] = Math.max(nums[i], maxLeft[i - 1]);
188 | minRight[j] = Math.min(nums[j], minRight[j + 1]);
189 | }
190 | for (let i = 1; i < n; i++) {
191 | if (maxLeft[i - 1] <= minRight[i]) return i;
192 | }
193 | return -1;
194 | }
195 |
196 | /**
197 | * 判断是不是伪数组
198 | * @param obj
199 | * @returns
200 | */
201 | export const isArrayList = (obj) => {
202 | var toString = Object.toString
203 | var rarraylike = /(ArraylLi stlColl ectionlMaplArguments)\]$/
204 | var rfunction = /^\s*\bfunction\b/
205 | if (!obj) {
206 | return false
207 | }
208 |
209 | const n = obj.length
210 | if (n === n >>> 0) {
211 | const type = toString.call(obj).slice(8, -1)
212 | if (rarraylike.test(type)) {
213 | return false
214 | }
215 | if (type === "Array") {
216 | return true
217 | }
218 | try {
219 | if (obj.property.isEnumerable.call(obj, 'length') === false) {
220 | return rfunction.test(obj.item || obj.callee)
221 | }
222 | } catch (e) {
223 | return !obj.window
224 | }
225 | }
226 | return false
227 |
228 | }
229 |
230 | /**
231 | * 比较2个NPM包的版本号
232 | * @param version1
233 | * @param version2
234 | * @returns
235 | */
236 | export const compareVersion = function (version1, version2) {
237 | let a1 = version1.split(".");
238 | let a2 = version2.split(".");
239 | let i = 0;
240 | let result = 0;
241 | while (i < a1.length || i < a2.length) {
242 | a1[i] = a1[i] ? a1[i] / 1 : 0;
243 | a2[i] = a2[i] ? a2[i] / 1 : 0;
244 | if (a1[i] > a2[i]) {
245 | result = 1;
246 | break;
247 | } else if (a1[i] < a2[i]) {
248 | result = -1;
249 | break;
250 | }
251 | i++;
252 | }
253 | return result;
254 | };
255 |
256 | /**
257 | * 手写trim方法
258 | * @param str
259 | */
260 | export const trim = (str) => {
261 | var whitespace = ' \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\n\
262 | \u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000';
263 | for (var i = 0; i < str.length; i++) {
264 | if (whitespace.indexOf(str.charAt(i)) === -1) {
265 | str = str.substring(i)
266 | break;
267 | }
268 | }
269 |
270 | for (i = str.length - 1; i >= 0; i--) {
271 | if (whitespace.indexOf(str.charAt(i)) === -1) {
272 | str = str.substring(0, i + 1)
273 | break;
274 | }
275 | }
276 | return whitespace.indexOf(str.charAt(0)) === -1 ? str : ''
277 | }
278 |
279 |
280 | /**
281 | * 连续数组
282 | * @param nums
283 | * @returns
284 | */
285 | export const findMaxLengthFromArr = (nums) => {
286 | const n = nums.length;
287 | const map = new Map();
288 | map.set(0, -1);
289 | let pre = 0;
290 | let res = 0;
291 | for (let i = 0; i < n; i++) {
292 | pre += nums[i] == 0 ? -1 : 1;
293 | if (map.has(pre)) {
294 | res = Math.max(res, i - map.get(pre));
295 | } else {
296 | map.set(pre, i);
297 | }
298 | }
299 | return res;
300 | };
301 |
302 | /**
303 | * 数组嵌套
304 | * @param nums
305 | * @returns
306 | */
307 | export const arrayNesting = (nums: number[]): number => {
308 | const dfs = (idx: number): number => {
309 | if (nums[idx] == -1) {
310 | return 0
311 | }
312 | let nxt = nums[idx]
313 | nums[idx] = -1
314 | return 1 + dfs(nxt)
315 | }
316 | let ans = 0
317 | for (let i = 0; i < nums.length; i++) {
318 | ans = Math.max(ans, dfs(i))
319 | }
320 | return ans
321 | };
322 |
323 | /**
324 | * 替换数组中的元素
325 | * @param {number[]} nums
326 | * @param {number[][]} operations
327 | * @return {number[]}
328 | */
329 | export const arrayChange = (nums, operations) => {
330 | const pos = new Map()
331 | for (let i = 0; i < nums.length; i++) {
332 | pos.set(nums[i], i)
333 | }
334 | for (const [prev, next] of operations) {
335 | const prePos = pos.get(prev)
336 | pos.delete(prev)
337 | pos.set(next, prePos)
338 | nums[prePos] = next
339 | }
340 | return nums
341 | };
342 |
343 | /** 检查是不是数组 */
344 | export const isArray = (arg) => {
345 | return Object.prototype.toString.call(arg) === '[object Array]'
346 | }
347 |
348 | export const browserType = () => {
349 | // 权重:系统 + 系统版本 > 平台 > 内核 + 载体 + 内核版本 + 载体版本 > 外壳 + 外壳版本
350 | const ua = navigator.userAgent.toLowerCase();
351 | const testUa = regexp => regexp.test(ua);
352 | const testVs = regexp => (ua.match(regexp) + "")
353 | .replace(/[^0-9|_.]/ig, "")
354 | .replace(/_/ig, ".");
355 |
356 | // 系统
357 | let system = "unknown";
358 | if (testUa(/windows|win32|win64|wow32|wow64/ig)) {
359 | system = "windows"; // window系统
360 | } else if (testUa(/macintosh|macintel/ig)) {
361 | system = "osx"; // osx系统
362 | } else if (testUa(/x11/ig)) {
363 | system = "linux"; // linux系统
364 | } else if (testUa(/android|adr/ig)) {
365 | system = "android"; // android系统
366 | } else if (testUa(/ios|iphone|ipad|ipod|iwatch/ig)) {
367 | system = "ios"; // ios系统
368 | }
369 |
370 | // 系统版本
371 | let systemVs = "unknown";
372 | if (system === "windows") {
373 | if (testUa(/windows nt 5.0|windows 2000/ig)) {
374 | systemVs = "2000";
375 | } else if (testUa(/windows nt 5.1|windows xp/ig)) {
376 | systemVs = "xp";
377 | } else if (testUa(/windows nt 5.2|windows 2003/ig)) {
378 | systemVs = "2003";
379 | } else if (testUa(/windows nt 6.0|windows vista/ig)) {
380 | systemVs = "vista";
381 | } else if (testUa(/windows nt 6.1|windows 7/ig)) {
382 | systemVs = "7";
383 | } else if (testUa(/windows nt 6.2|windows 8/ig)) {
384 | systemVs = "8";
385 | } else if (testUa(/windows nt 6.3|windows 8.1/ig)) {
386 | systemVs = "8.1";
387 | } else if (testUa(/windows nt 10.0|windows 10/ig)) {
388 | systemVs = "10";
389 | }
390 | } else if (system === "osx") {
391 | systemVs = testVs(/os x [\d._]+/ig);
392 | } else if (system === "android") {
393 | systemVs = testVs(/android [\d._]+/ig);
394 | } else if (system === "ios") {
395 | systemVs = testVs(/os [\d._]+/ig);
396 | }
397 |
398 | // 平台
399 | let platform = "unknow";
400 | if (system === "windows" || system === "osx" || system === "linux") {
401 | platform = "desktop"; // 桌面端
402 | } else if (system === "android" || system === "ios" || testUa(/mobile/ig)) {
403 | platform = "mobile"; // 移动端
404 | }
405 |
406 | // 内核和载体
407 | let engine = "unknow";
408 | let supporter = "unknow";
409 | if (testUa(/applewebkit/ig) && testUa(/safari/ig)) {
410 | engine = "webkit"; // webkit内核
411 | if (testUa(/edge/ig)) {
412 | supporter = "edge"; // edge浏览器
413 | } else if (testUa(/opr/ig)) {
414 | supporter = "opera"; // opera浏览器
415 | } else if (testUa(/chrome/ig)) {
416 | supporter = "chrome"; // chrome浏览器
417 | } else {
418 | supporter = "safari"; // safari浏览器
419 | }
420 | } else if (testUa(/gecko/ig) && testUa(/firefox/ig)) {
421 | engine = "gecko"; // gecko内核
422 | supporter = "firefox"; // firefox浏览器
423 | } else if (testUa(/presto/ig)) {
424 | engine = "presto"; // presto内核
425 | supporter = "opera"; // opera浏览器
426 | } else if (testUa(/trident|compatible|msie/ig)) {
427 | engine = "trident"; // trident内核
428 | supporter = "iexplore"; // iexplore浏览器
429 | }
430 |
431 | // 内核版本
432 | let engineVs = "unknow";
433 | if (engine === "webkit") {
434 | engineVs = testVs(/applewebkit\/[\d.]+/ig);
435 | } else if (engine === "gecko") {
436 | engineVs = testVs(/gecko\/[\d.]+/ig);
437 | } else if (engine === "presto") {
438 | engineVs = testVs(/presto\/[\d.]+/ig);
439 | } else if (engine === "trident") {
440 | engineVs = testVs(/trident\/[\d.]+/ig);
441 | }
442 |
443 | // 载体版本
444 | let supporterVs = "unknow";
445 | if (supporter === "chrome") {
446 | supporterVs = testVs(/chrome\/[\d.]+/ig);
447 | } else if (supporter === "safari") {
448 | supporterVs = testVs(/version\/[\d.]+/ig);
449 | } else if (supporter === "firefox") {
450 | supporterVs = testVs(/firefox\/[\d.]+/ig);
451 | } else if (supporter === "opera") {
452 | supporterVs = testVs(/opr\/[\d.]+/ig);
453 | } else if (supporter === "iexplore") {
454 | supporterVs = testVs(/(msie [\d.]+)|(rv:[\d.]+)/ig);
455 | } else if (supporter === "edge") {
456 | supporterVs = testVs(/edge\/[\d.]+/ig);
457 | }
458 |
459 | // 外壳和外壳版本
460 | let shell = "none";
461 | let shellVs = "unknow";
462 | if (testUa(/micromessenger/ig)) {
463 | shell = "wechat"; // 微信浏览器
464 | shellVs = testVs(/micromessenger\/[\d.]+/ig);
465 | } else if (testUa(/qqbrowser/ig)) {
466 | shell = "qq"; // QQ浏览器
467 | shellVs = testVs(/qqbrowser\/[\d.]+/ig);
468 | } else if (testUa(/ubrowser/ig)) {
469 | shell = "uc"; // UC浏览器
470 | shellVs = testVs(/ubrowser\/[\d.]+/ig);
471 | } else if (testUa(/2345explorer/ig)) {
472 | shell = "2345"; // 2345浏览器
473 | shellVs = testVs(/2345explorer\/[\d.]+/ig);
474 | } else if (testUa(/metasr/ig)) {
475 | shell = "sougou"; // 搜狗浏览器
476 | } else if (testUa(/lbbrowser/ig)) {
477 | shell = "liebao"; // 猎豹浏览器
478 | } else if (testUa(/maxthon/ig)) {
479 | shell = "maxthon"; // 遨游浏览器
480 | shellVs = testVs(/maxthon\/[\d.]+/ig);
481 | } else if (testUa(/bidubrowser/ig)) {
482 | shell = "baidu"; // 百度浏览器
483 | shellVs = testVs(/bidubrowser [\d.]+/ig);
484 | }
485 |
486 | return Object.assign({
487 | engine, // webkit gecko presto trident
488 | engineVs,
489 | platform, // desktop mobile
490 | supporter, // chrome safari firefox opera iexplore edge
491 | supporterVs,
492 | system, // windows osx linux android ios
493 | systemVs
494 | }, shell === "none" ? {} : {
495 | shell, // wechat qq uc 2345 sougou liebao maxthon baidu
496 | shellVs
497 | });
498 | }
499 |
500 |
501 |
502 |
--------------------------------------------------------------------------------
/src/utils/cache/BaseCache.ts:
--------------------------------------------------------------------------------
1 | export const setSession = (name, val) => {
2 | return sessionStorage.setItem(name, JSON.stringify({ v: val }));
3 | };
4 |
5 | export const getSession = (name) => {
6 | if (!sessionStorage.getItem(name)) {
7 | return "";
8 | } else {
9 | let v = "";
10 | try {
11 | v = JSON.parse(sessionStorage.getItem(name)).v;
12 | if (v === undefined) {
13 | v = JSON.parse(sessionStorage.getItem(name));
14 | }
15 | } catch (e) {
16 | v = sessionStorage.getItem(name);
17 | }
18 | return v;
19 | }
20 | };
21 |
22 | export const setLocal = (name, val) => {
23 | return localStorage.setItem(name, JSON.stringify({ v: val }));
24 | };
25 |
26 | export const getLocal = (name) => {
27 | if (!JSON.parse(localStorage.getItem(name))) {
28 | return "";
29 | } else {
30 | let v = "";
31 | try {
32 | v = JSON.parse(localStorage.getItem(name)).v;
33 | if (v === undefined) {
34 | v = JSON.parse(localStorage.getItem(name));
35 | }
36 | } catch (e) {
37 | v = localStorage.getItem(name);
38 | }
39 | return v;
40 | }
41 | };
42 |
43 | export const sessionClear = () => {
44 | return sessionStorage.clear();
45 | };
46 |
47 | export const localClear = () => {
48 | return localStorage.clear();
49 | };
50 |
51 | export const removeSession = (name) => {
52 | return sessionStorage.removeItem(name);
53 | };
54 |
55 | export const getCookit = (key) => {
56 | if (document.cookie.length > 0) {
57 | let c_start = document.cookie.indexOf(key + "=");
58 | if (c_start != -1) {
59 | c_start = c_start + key.length + 1;
60 | let c_end = document.cookie.indexOf(";", c_start);
61 | if (c_end == -1) {
62 | c_end = document.cookie.length;
63 | }
64 | return unescape(document.cookie.substring(c_start, c_end));
65 | }
66 | }
67 | return "";
68 | };
69 |
70 | export const getCookie = (key, cookies) => {
71 | var value = "";
72 | var isInBrowser = typeof window !== "undefined";
73 | if (!cookies) {
74 | if (isInBrowser) {
75 | cookies = document.cookie;
76 | } else {
77 | return value;
78 | }
79 | }
80 | var cookieArr = cookies.split("; ");
81 | for (var i = 0, cookie = void 0, index = void 0; i < cookieArr.length; i++) {
82 | cookie = cookieArr[i];
83 | index = cookie.indexOf("=");
84 | if (cookie.substr(0, index) === key) {
85 | value = cookie.substr(index + 1);
86 | }
87 | }
88 | return value;
89 | };
90 |
--------------------------------------------------------------------------------
/src/utils/cache/BaseLocalStorage.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 兼容浏览器和小程序的缓存方法
3 | */
4 | export abstract class BaseLocalStorage {
5 | keyPrefix = "";
6 | abstract getItem(key: string): T | undefined;
7 | abstract setItem(key: string, value: any): void;
8 | abstract removeItem(key: string): void;
9 | abstract clear(): void;
10 | abstract keys(): string[];
11 | }
12 |
--------------------------------------------------------------------------------
/src/utils/cache/LocalStorageBrowser.ts:
--------------------------------------------------------------------------------
1 | import { BaseLocalStorage } from "./BaseLocalStorage";
2 |
3 | export class LocalStorageBrowser extends BaseLocalStorage {
4 | setItem(key: string, value: unknown) {
5 | localStorage.setItem(this.keyPrefix + key, JSON.stringify(value));
6 | }
7 |
8 | getItem(key: string) {
9 | let raw = localStorage.getItem(this.keyPrefix + key);
10 | try {
11 | if (raw == undefined) {
12 | return undefined;
13 | } else {
14 | return JSON.parse(raw);
15 | }
16 | } catch (e) {
17 | console.warn(
18 | "Parse JSON Error when getItem from localStorage: " + key,
19 | raw,
20 | e
21 | );
22 | return undefined;
23 | }
24 | }
25 |
26 | removeItem(key: string): void {
27 | localStorage.removeItem(this.keyPrefix + key);
28 | }
29 |
30 | clear(): void {
31 | localStorage.clear();
32 | }
33 |
34 | keys(): string[] {
35 | return Object.keys(localStorage)
36 | .filter((v) => v.indexOf(this.keyPrefix) === 0)
37 | .map((v) => v.substr(this.keyPrefix.length));
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/utils/cache/LocalStorageMiniApp.ts:
--------------------------------------------------------------------------------
1 | import { BaseLocalStorage } from "./BaseLocalStorage";
2 |
3 | export class LocalStorageMiniapp extends BaseLocalStorage {
4 | private _miniAppObj: any;
5 |
6 | constructor(miniAppObj: any) {
7 | super();
8 | this._miniAppObj = miniAppObj;
9 | }
10 |
11 | // 同步
12 | setItem(key: string, value: unknown) {
13 | return this._miniAppObj.setStorageSync(
14 | this.keyPrefix + key,
15 | JSON.stringify(value)
16 | );
17 | }
18 |
19 | getItem(key: string) {
20 | let raw = this._miniAppObj.getStorageSync(this.keyPrefix + key);
21 | try {
22 | if (raw == undefined || raw == "") {
23 | return undefined;
24 | } else {
25 | return JSON.parse(raw);
26 | }
27 | } catch (e) {
28 | console.warn(
29 | "Parse JSON Error when getItem from localStorage: " + key,
30 | raw,
31 | e
32 | );
33 | return undefined;
34 | }
35 | }
36 |
37 | removeItem(key: string) {
38 | this._miniAppObj.removeStorageSync(this.keyPrefix + key);
39 | }
40 |
41 | clear() {
42 | this._miniAppObj.clearStorageSync();
43 | }
44 |
45 | keys() {
46 | return (this._miniAppObj.getStorageInfoSync().keys as string[])
47 | .filter((v) => v.indexOf(this.keyPrefix) === 0)
48 | .map((v) => v.substr(this.keyPrefix.length));
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/utils/car.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 验证车牌号
3 | * @param val
4 | * @returns
5 | */
6 | export const isCarNum = (val: string) => {
7 | var patrn = /^([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1})$/
8 | var patrn2 = /^([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))$/
9 | if (!patrn.test(val) && !patrn2.test(val)) {
10 | return false
11 | } else {
12 | return true
13 | }
14 | }
15 |
16 | /**
17 | * 校验车架号
18 | * @param val
19 | * @returns
20 | */
21 | export const isVehicle = (val: string) => {
22 | var patrn = /^[A-HJ-NP-Za-hj-np-z0-9]+$/
23 | if (!patrn.test(val) || val === '') {
24 | return false
25 | } else {
26 | return true
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/utils/client.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 判断是否在服务端
3 | * @type {Boolean}
4 | */
5 | export const isServer = (() => {
6 | const ret = typeof window === "undefined";
7 | return () => ret;
8 | })();
9 |
10 | /**
11 | * 判断是否在客户端
12 | * @type {Boolean}
13 | */
14 | export const isClient = () => {
15 | return !isServer();
16 | };
17 |
18 | /**
19 | * 取url参数
20 | * @param {String} name url参数
21 | * @param {Boolean} decodeSearch 是否对location.search整体解码一次, 默认true
22 | * @return {String} url值
23 | */
24 | export const getQuery = (name = "", decodeSearch = true) => {
25 | const reg = new RegExp("(?:^|&)" + name + "=([^&]*)(?:&|$)", "i");
26 | let search = location.search;
27 | search = decodeSearch ? decodeURIComponent(search) : search;
28 | const ret = search.substr(1).match(reg);
29 | if (ret) return decodeURIComponent(ret[1]);
30 | return "";
31 | };
32 |
33 | /**
34 | * 获取所有url参数
35 | * @param {Array} 需要排除的参数数组
36 | * @return {Object} 参数键值对
37 | */
38 | export const getQueryAll = (exclude = []) => {
39 | if (typeof window !== "undefined") {
40 | const search: any = window.location.search;
41 | const paramArr =
42 | search !== "" ? search.split("?").pop().split("&") : [];
43 | const paramObj = {};
44 | paramArr.forEach(entry => {
45 | const [key, value] = entry.split("=");
46 | if (!exclude.includes(key)) {
47 | paramObj[key] = decodeURIComponent(value);
48 | }
49 | });
50 | return paramObj;
51 | } else {
52 | return ""
53 | }
54 | };
55 |
56 | /**
57 | * object转query
58 | * @param {Object} object参数
59 | * @return {String} query参数
60 | * @example {x:1,y:2}转化为x=1&y=2
61 | */
62 | export const formatQuery = (obj: string | object) => {
63 | const retArr = Object.entries(obj).map(([key, val]) => {
64 | let queryVal = "";
65 | if (typeof val === "object") {
66 | queryVal = JSON.stringify(val);
67 | } else {
68 | queryVal = val;
69 | }
70 | const retStr = `${key}=${encodeURIComponent(queryVal)}`;
71 | return retStr;
72 | });
73 | return retArr.join("&");
74 | };
75 |
76 | /**
77 | * 判断是否在iOS中
78 | * @return {Boolean}
79 | */
80 | export const isInIOS = (() => {
81 | if (isClient()) {
82 | const ua = navigator.userAgent;
83 | const ret = !!ua.match(/iphone|ipad|ipod/i);
84 | return () => ret;
85 | }
86 | })();
87 |
88 | /**
89 | * 判断是否在微信中(包含微信H5, 微信小程序)
90 | * @type {Boolean}
91 | */
92 | export const isInWechat = (() => {
93 | if (isClient()) {
94 | const ua = navigator.userAgent;
95 | const ret = !!ua.match(/micromessenger/i);
96 | return () => ret;
97 | }
98 | })();
99 |
100 | /**
101 | * 判断是否在快应用
102 | */
103 | export const isInQuickApp = (() => {
104 | const ua = navigator.userAgent;
105 | const ret = ua.includes("mode-quickapp");
106 | return () => ret;
107 | })();
108 |
109 | /**
110 | * 判断是否在百度小程序
111 | */
112 | export const isInBaidu = (() => {
113 | const ua = navigator.userAgent;
114 | const ret = /swan\//.test(ua) || /^webswan-/.test((window as any).name);
115 | return () => ret;
116 | })();
117 |
118 | /**
119 | * 判断是否在头条小程序
120 | */
121 | export const isInToutiao = (() => {
122 | const ua = navigator.userAgent;
123 | const ret = !!ua.match(/toutiaomicroapp/i);
124 | return () => ret;
125 | })();
126 |
127 | /**
128 | * 判断是否在支付宝中
129 | */
130 | export const isInAlipay = (() => {
131 | const ua = navigator.userAgent;
132 | const ret = !!ua.match(/AlipayClient/i);
133 | return () => ret;
134 | })();
135 |
136 | /**
137 | * 判断是否在支付宝小程序
138 | */
139 | export const isInAlipayMp = (() => {
140 | const ua = navigator.userAgent;
141 | const ret = isInAlipay() && !!ua.match(/MiniProgram/i);
142 | return () => ret;
143 | })();
144 |
145 | /**
146 | * 判断是否在支付宝H5中
147 | */
148 | export const isInAlipayH5 = (() => {
149 | const ret = isInAlipay() && !isInAlipayMp();
150 | return () => ret;
151 | })();
152 |
153 | /**
154 | * 判断是否在QQ小程序
155 | */
156 | export const isInQQ = (() => {
157 | const ua = navigator.userAgent;
158 | const ret = ua.includes("qq");
159 | return () => ret;
160 | })();
161 |
162 | /**
163 | * 判断是否需要适配iphoneX
164 | */
165 | export const isIPhoneXSeries = (() => {
166 | const ret = (() => {
167 | const ua = navigator.userAgent;
168 |
169 | if (ua.match(/iphone/i)) {
170 | const xSeriesConfig = [
171 | {
172 | devicePixelRatio: 3, // iPhone X, iPhone Xs
173 | width: 375,
174 | height: 812,
175 | },
176 | {
177 | devicePixelRatio: 2, // iPhone XR, iPhone 11
178 | width: 414,
179 | height: 896,
180 | },
181 | {
182 | devicePixelRatio: 3, // iPhone Xs Max, iPhone 11 Pro Max
183 | width: 414,
184 | height: 896,
185 | },
186 | {
187 | devicePixelRatio: 3, // iPhone 11 Pro
188 | width: 375,
189 | height: 812,
190 | },
191 | {
192 | devicePixelRatio: 3, // iPhone 12 mini
193 | width: 360,
194 | height: 780,
195 | },
196 | {
197 | devicePixelRatio: 3, // iPhone 12, iPhone 12 Pro
198 | width: 390,
199 | height: 844,
200 | },
201 | {
202 | devicePixelRatio: 3, // iPhone 12 Pro Max
203 | width: 428,
204 | height: 926,
205 | },
206 | ];
207 | const {
208 | devicePixelRatio,
209 | screen: { width, height },
210 | } = window;
211 | return xSeriesConfig.some(
212 | (item) =>
213 | item.devicePixelRatio === devicePixelRatio &&
214 | item.width === width &&
215 | item.height === height
216 | );
217 | }
218 | return false;
219 | })();
220 | return () => ret;
221 | })();
222 |
223 | /**
224 | * 获取窗口可视范围的高度
225 | * @returns
226 | */
227 | export function getClientHeight() {
228 | let clientHeight = 0;
229 | if (document.body.clientHeight && document.documentElement.clientHeight) {
230 | clientHeight =
231 | document.body.clientHeight < document.documentElement.clientHeight
232 | ? document.body.clientHeight
233 | : document.documentElement.clientHeight;
234 | } else {
235 | clientHeight =
236 | document.body.clientHeight > document.documentElement.clientHeight
237 | ? document.body.clientHeight
238 | : document.documentElement.clientHeight;
239 | }
240 | return clientHeight;
241 | }
242 |
243 | /**
244 | * 获取窗口可视范围宽度
245 | * @returns
246 | */
247 | export function getPageViewWidth() {
248 | let d = document,
249 | a = d.compatMode == "BackCompat" ? d.body : d.documentElement;
250 | return a.clientWidth;
251 | }
252 |
253 | /**
254 | * 获取窗口宽度
255 | * @returns
256 | */
257 | export function getPageWidth() {
258 | let g = document,
259 | a = g.body,
260 | f = g.documentElement,
261 | d = g.compatMode == "BackCompat" ? a : g.documentElement;
262 | return Math.max(f.scrollWidth, a.scrollWidth, d.clientWidth);
263 | }
264 |
265 | /**
266 | * 获取窗口尺寸
267 | * @returns
268 | */
269 | export function getViewportOffset() {
270 | if (window.innerWidth) {
271 | return {
272 | w: window.innerWidth,
273 | h: window.innerHeight,
274 | };
275 | } else {
276 | // ie8及其以下
277 | if (document.compatMode === "BackCompat") {
278 | // 怪异模式
279 | return {
280 | w: document.body.clientWidth,
281 | h: document.body.clientHeight,
282 | };
283 | } else {
284 | // 标准模式
285 | return {
286 | w: document.documentElement.clientWidth,
287 | h: document.documentElement.clientHeight,
288 | };
289 | }
290 | }
291 | }
292 |
293 | /**
294 | * 获取滚动条距顶部高度
295 | * @returns
296 | */
297 | export function getPageScrollTop() {
298 | let a = document;
299 | return a.documentElement.scrollTop || a.body.scrollTop;
300 | }
301 |
302 | /**
303 | * 获取滚动条距左边的高度
304 | * @returns
305 | */
306 | export function getPageScrollLeft() {
307 | let a = document;
308 | return a.documentElement.scrollLeft || a.body.scrollLeft;
309 | }
310 |
311 | /**
312 | * 开启全屏
313 | * @param {*} element
314 | */
315 | export function launchFullscreen(element) {
316 | if (element.requestFullscreen) {
317 | element.requestFullscreen();
318 | } else if (element.mozRequestFullScreen) {
319 | element.mozRequestFullScreen();
320 | } else if (element.msRequestFullscreen) {
321 | element.msRequestFullscreen();
322 | } else if (element.webkitRequestFullscreen) {
323 | element.webkitRequestFullScreen();
324 | }
325 | }
326 |
327 | /**
328 | * 滚动到指定元素区域
329 | */
330 | export const smoothScroll = (element) => {
331 | document.querySelector(element).scrollIntoView({
332 | behavior: "smooth",
333 | });
334 | };
335 |
336 | /**
337 | * http跳转https
338 | */
339 | export const scrollToTop = () => {
340 | const c = document.documentElement.scrollTop || document.body.scrollTop;
341 | if (c > 0) {
342 | window.requestAnimationFrame(scrollToTop);
343 | window.scrollTo(0, c - c / 8);
344 | }
345 | };
346 |
347 | /**
348 | * 检查页面底部是否可见
349 | * @returns
350 | */
351 | export const bottomVisible = () => {
352 | return (
353 | document.documentElement.clientHeight + window.scrollY >=
354 | (document.documentElement.scrollHeight ||
355 | document.documentElement.clientHeight)
356 | );
357 | };
358 |
359 | /**
360 | * 打开一个窗口
361 | * @param { string } url
362 | * @param { string } windowName
363 | * @param { number } width
364 | * @param { number } height
365 | */
366 | export function openWindow(
367 | url: string,
368 | windowName: string,
369 | width: number,
370 | height: number
371 | ) {
372 | var x = parseInt(`${screen.width / 2.0}`) - width / 2.0;
373 | var y = parseInt(`${screen.height / 2.0}`) - height / 2.0;
374 | var isMSIE = navigator.appName == "Microsoft Internet Explorer";
375 | if (isMSIE) {
376 | var p = "resizable=1,location=no,scrollbars=no,width=";
377 | p = p + width;
378 | p = p + ",height=";
379 | p = p + height;
380 | p = p + ",left=";
381 | p = p + x;
382 | p = p + ",top=";
383 | p = p + y;
384 | window.open(url, windowName, p);
385 | } else {
386 | var win = window.open(
387 | url,
388 | "ZyiisPopup",
389 | "top=" +
390 | y +
391 | ",left=" +
392 | x +
393 | ",scrollbars=" +
394 | scrollbars +
395 | ",dialog=yes,modal=yes,width=" +
396 | width +
397 | ",height=" +
398 | height +
399 | ",resizable=no"
400 | );
401 | eval("try { win.resizeTo(width, height); } catch(e) { }");
402 | window.focus();
403 | }
404 | }
405 |
406 | /**
407 | * 客户端检测,并返回客户端的详细信息
408 | * @param w
409 | * @param nav
410 | * @returns
411 | */
412 | export const clientInfo = (w, nav) => {
413 | var _Client = function () {
414 | // 呈现引擎
415 | this.engine = {};
416 | // 浏览器
417 | this.brower = {};
418 | // 系统平台
419 | this.system = {};
420 | // 初始化
421 | this.init();
422 | };
423 | _Client.prototype.init = function () {
424 | var ua = nav.userAgent,
425 | p = nav.platform;
426 | // 检测呈现引擎和浏览器
427 | if (w.opera) {
428 | // opera
429 | this.engine.name = this.brower.name = "opera";
430 | this.engine.ver = this.brower.ver = w.opera.version();
431 | } else if (/AppleWebKit\/(\S+)/.test(ua)) {
432 | this.engine.name = "webkit";
433 | this.engine.ver = RegExp["$1"];
434 | if (/Chrome\/(\S+)/.test(ua)) {
435 | // chrome
436 | this.brower.name = "chrome";
437 | this.brower.ver = RegExp["$1"];
438 | } else if (/Version\/(\S)+/.test(ua)) {
439 | // safari
440 | this.brower.name = "safari";
441 | this.brower.ver = RegExp["$1"];
442 | } else {
443 | // 近似确定版本号
444 | var safariVersion = 1,
445 | webkitVersion = parseFloat(this.engine.ver);
446 | if (webkitVersion < 100) {
447 | safariVersion = 1;
448 | } else if (webkitVersion < 312) {
449 | safariVersion = 1.2;
450 | } else if (webkitVersion < 412) {
451 | safariVersion = 1.3;
452 | } else {
453 | safariVersion = 2;
454 | }
455 | this.brower.name = "safari";
456 | this.brower.ver = safariVersion;
457 | }
458 | } else if (/KHTML\/(\S+)/.test(ua) || /Konqueror\/([^;]+)/.test(ua)) {
459 | // konq
460 | this.engine.name = "khtml";
461 | this.brower.name = "konq";
462 | this.engine.ver = this.brower.ver = RegExp["$1"];
463 | } else if (/rv:([^\)]+)\) Gecko\/\d{8}/.test(ua)) {
464 | this.engine.name = "gecko";
465 | this.engine.ver = RegExp["$1"];
466 | if (/Firefox\/(\S+)/.test(ua)) {
467 | // firefox
468 | this.brower.name = "firefox";
469 | this.brower.ver = RegExp["$1"];
470 | } else {
471 | this.brower.name = null;
472 | this.brower.ver = null;
473 | }
474 | } else if (/MSIE ([^;]+)/.test(ua)) {
475 | // IE
476 | this.engine.name = this.brower.name = "ie";
477 | this.engine.ver = this.brower.ver = RegExp["$1"];
478 | } else {
479 | this.engine.name = this.brower.name = null;
480 | this.engine.ver = this.brower.ver = null;
481 | }
482 |
483 | // 检测系统平台
484 | // 移动设备
485 | if (ua.indexOf("iPhone") > -1) {
486 | this.system.mobile = {};
487 | this.system.mobile.name = "iphone";
488 | this.system.mobile.ver = null;
489 | } else if (ua.indexOf("iPod") > -1) {
490 | this.system.mobile = {};
491 | this.system.mobile.name = "ipod";
492 | this.system.mobile.ver = null;
493 | } else if (ua.indexOf("iPad") > -1) {
494 | this.system.mobile = {};
495 | this.system.mobile.name = "ipad";
496 | this.system.mobile.ver = null;
497 | } else if (ua.indexOf("NokiaN") > -1) {
498 | this.system.mobile = {};
499 | this.system.mobile.name = "nokian";
500 | this.system.mobile.ver = null;
501 | } else if (/Android (\d+\.\d+)/.test(ua)) {
502 | this.system.mobile = {};
503 | this.system.mobile.name = "android";
504 | this.system.mobile.ver = RegExp["$1"];
505 | }
506 | // 游戏设备
507 | if (ua.indexOf("Wii") > -1) {
508 | this.system.game = {};
509 | this.system.game.name = "wii";
510 | this.system.game.ver = null;
511 | } else if (/playstation/i.test(ua)) {
512 | this.system.game = {};
513 | this.system.game.name = "ps";
514 | this.system.game.ver = null;
515 | }
516 |
517 | if (p.indexOf("Win") == 0) {
518 | // Windows
519 | this.system.name = "win";
520 | if (/Win(?:dows )?([^do]{2})\s?(\d+\.\d+)?/.test(ua)) {
521 | if (RegExp["$1"] == "NT") {
522 | switch (RegExp["$2"]) {
523 | case "5.0":
524 | this.system.ver = "2000";
525 | break;
526 | case "5.1":
527 | this.system.ver = "XP";
528 | break;
529 | case "6.0":
530 | this.system.ver = "Vista";
531 | break;
532 | case "6.1":
533 | this.system.ver = "7";
534 | break;
535 | default:
536 | this.system.ver = "NT";
537 | }
538 | } else if (RegExp["$1"] == "9x") {
539 | this.system.ver = "ME";
540 | } else {
541 | this.system.ver = RegExp["$1"];
542 | }
543 | // 检测Windows CE或Windows Phone
544 | if (this.system.ver == "CE") {
545 | this.system.mobile = {};
546 | this.system.mobile.name = "ce";
547 | this.system.mobile.ver = "CE";
548 | } else if (this.system.ver == "Ph") {
549 | if (/Windows Phone OS (\d+.\d+)/.test(ua)) {
550 | this.system.ver = "Phone";
551 | this.system.mobile = {};
552 | this.system.mobile.name = "phone";
553 | this.system.mobile.ver = RegExp["$1"];
554 | }
555 | }
556 | }
557 | } else if (p.indexOf("Mac") == 0) {
558 | // Mac
559 | this.system.name = "mac";
560 | this.system.ver = null;
561 | // 检测IOS版本号
562 | if (ua.indexOf("Mobile") > -1) {
563 | if (/CPU (?:iPhone )?OS (\d+_\d+)/.test(ua)) {
564 | this.system.mobile.ver = RegExp.$1.replace("_", ".");
565 | } else {
566 | this.system.mobile.ver = 2;
567 | }
568 | }
569 | } else if (p == "X11" || p.indexOf("Linux") == 0) {
570 | // Unix or Linux
571 | this.system.name = "x11";
572 | this.system.ver = null;
573 | }
574 | };
575 | // 对象是否包含此方法
576 | _Client.prototype.isHostMethod = function (object, property) {
577 | // author: Peter Michaux
578 | var t = typeof object[property];
579 | return (
580 | t == "function" || !!(t == "object" && object[property]) || t == "object"
581 | );
582 | };
583 | // 是否是移动设备
584 | _Client.prototype.isMobile = function () {
585 | var t = typeof this.system.mobile;
586 | return t != "undefined";
587 | };
588 | return _Client;
589 | };
590 |
591 |
592 | /**
593 | * 获取浏览器光标信息
594 | * @param win
595 | * @returns
596 | */
597 | export const getSelectionCoords = (win) => {
598 | win = win || window;
599 | var doc = win.document;
600 | var sel = doc.selection, range, rects, rect;
601 | var x = 0, y = 0;
602 | if (sel) {
603 | if (sel.type != "Control") {
604 | range = sel.createRange();
605 | range.collapse(true);
606 | x = range.boundingLeft;
607 | y = range.boundingTop;
608 | }
609 | } else if (win.getSelection) {
610 | sel = win.getSelection();
611 | if (sel.rangeCount) {
612 | range = sel.getRangeAt(0).cloneRange();
613 | if (range.getClientRects) {
614 | range.collapse(true);
615 | rects = range.getClientRects();
616 | if (rects.length > 0) {
617 | rect = rects[0];
618 | }
619 | if (rect) {
620 | x = rect.left;
621 | y = rect.top;
622 | }
623 | }
624 | if ((x == 0 && y == 0) || rect === undefined) {
625 | var span = doc.createElement("span");
626 | if (span.getClientRects) {
627 | span.appendChild(doc.createTextNode("\u200b"));
628 | range.insertNode(span);
629 | rect = span.getClientRects()[0];
630 | x = rect.left;
631 | y = rect.top;
632 | var spanParent = span.parentNode;
633 | spanParent.removeChild(span);
634 | spanParent.normalize();
635 | }
636 | }
637 | }
638 | }
639 | return { x: x, y: y };
640 | }
641 |
--------------------------------------------------------------------------------
/src/utils/common.ts:
--------------------------------------------------------------------------------
1 | /** 拼接秒数 */
2 | export const formatNumber = (n) => {
3 | const s = n.toString();
4 | return s[1] ? s : "0" + s;
5 | };
6 |
7 | /** 过滤表情 */
8 | export const filterEmoji = (name = "") => {
9 | if (name) {
10 | const str = name.replace(
11 | /[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF][\u200D|\uFE0F]|[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF]|[0-9|*|#]\uFE0F\u20E3|[0-9|#]\u20E3|[\u203C-\u3299]\uFE0F\u200D|[\u203C-\u3299]\uFE0F|[\u2122-\u2B55]|\u303D|[\A9|\AE]\u3030|\uA9|\uAE|\u3030/gi,
12 | ""
13 | );
14 | return str;
15 | }
16 | return "";
17 | };
18 |
19 | /** 验证税号 */
20 | export const isNumber = (num) =>
21 | /^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$/.test(num);
22 |
23 | /** 验证手机号 */
24 | export const isPhone = (phone) => /^[1][0-9]{10}$/.test(phone);
25 |
26 | /** 验证邮箱 */
27 | export const isEmail = (email) =>
28 | /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/.test(
29 | email
30 | );
31 |
32 | /** 对象数组根据对象某一个属性去重 */
33 | export const unique = (arr, key, hash = {}) =>
34 | arr.reduce(function (item, next) {
35 | hash[next[key]] ? "" : (hash[next[key]] = true && item.push(next));
36 | return item;
37 | }, []);
38 |
39 | // 验证emoji表情
40 | export const hasEmoji = function (value, tips = "") {
41 | let char =
42 | /[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF][\u200D|\uFE0F]|[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF]|[0-9|*|#]\uFE0F\u20E3|[0-9|#]\u20E3|[\u203C-\u3299]\uFE0F\u200D|[\u203C-\u3299]\uFE0F|[\u2122-\u2B55]|\u303D|[\A9|\AE]\u3030|\uA9|\uAE|\u3030/gi;
43 | if (char.test(value)) {
44 | console.log(`${tips}不能含有特殊字符`);
45 | return true;
46 | }
47 | return false;
48 | };
49 |
50 | /** 保留N位小数 */
51 | export const getFloat = function (number, n) {
52 | n = n ? parseInt(n) : 0;
53 | if (n <= 0) {
54 | return Math.round(number);
55 | }
56 | number = Math.round(number * Math.pow(10, n)) / Math.pow(10, n);
57 | number = Number(number).toFixed(n);
58 | return number;
59 | };
60 |
61 | /** 时间戳转 YY-mm-dd HH:ii:ss */
62 | export const timeStrtoUtc = function (timeStamp, returnType) {
63 | timeStamp = parseInt(timeStamp);
64 | var date = new Date();
65 | if (timeStamp < 90000000000) {
66 | date.setTime(timeStamp * 1000);
67 | } else {
68 | date.setTime(timeStamp);
69 | }
70 | var y = date.getFullYear();
71 | var m: any = date.getMonth() + 1;
72 | m = m < 10 ? "0" + m : m;
73 | var d: any = date.getDate();
74 | d = d < 10 ? "0" + d : d;
75 | var h: any = date.getHours();
76 | h = h < 10 ? "0" + h : h;
77 | var minute: any = date.getMinutes();
78 | var second: any = date.getSeconds();
79 | minute = minute < 10 ? "0" + minute : minute;
80 | second = second < 10 ? "0" + second : second;
81 | if (returnType == "str") {
82 | return y + "-" + m + "-" + d + " " + h + ":" + minute + ":" + second;
83 | }
84 | return [y, m, d, h, minute, second];
85 | };
86 |
87 | /** 查询数组中第N大的数据 */
88 | export const insertQueryArrIndex = function (arr, index) {
89 | if (arr.length == 0) {
90 | return;
91 | }
92 | if (index > arr.length - 1 || index - 1 < 0) {
93 | return;
94 | }
95 | for (let i = 1; i < arr.length; i++) {
96 | var current = arr[i];
97 | var preIndex = i - 1;
98 | while (preIndex >= 0 && arr[preIndex] < current) {
99 | arr[preIndex + 1] = arr[preIndex];
100 | preIndex--;
101 | }
102 | arr[preIndex + 1] = current;
103 | }
104 | return arr[index - 1];
105 | };
106 |
107 | /** 验证函数节流 */
108 | export const throttle = (fn, wait) => {
109 | let canRun = true;
110 | return function () {
111 | if (!canRun) return;
112 | canRun = false;
113 | setTimeout(() => {
114 | fn.apply(this, arguments);
115 | canRun = true;
116 | }, wait);
117 | };
118 | };
119 |
--------------------------------------------------------------------------------
/src/utils/css.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 检查是否支持CSS动画
3 | * @returns
4 | */
5 | export const checkCssAnimation = function () {
6 | var styles = document.createElement("div").style;
7 | var animations = [
8 | "animation",
9 | "webkitAnimation",
10 | "msAnimation",
11 | "MozAnimation",
12 | "-moz-animation",
13 | "-webkit-animation",
14 | ];
15 | for (var i = 0, len = animations.length; i < len; i++) {
16 | if (animations[i] in styles) {
17 | return true;
18 | }
19 | }
20 | return false;
21 | };
22 |
--------------------------------------------------------------------------------
/src/utils/date.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 返回时分秒中的秒
3 | * @param n
4 | * @returns
5 | */
6 | export const formatNumber = (n: number) => {
7 | const s = n.toString();
8 | return s[1] ? s : "0" + s;
9 | };
10 |
11 | /**
12 | * UTC时间转YYYY-MM-DD HH:MM:SS
13 | * @param date
14 | * @param num
15 | * @param interval
16 | * @returns
17 | */
18 | export const formatDateTime = (
19 | date: string,
20 | num: number = 3,
21 | interval: string = "-"
22 | ) => {
23 | const arr = date.split("T");
24 | const d = arr[0];
25 | const darr = d.split("-");
26 | const t = arr[1];
27 | const tarr = t.split("+");
28 | const marr = tarr[0].split(":");
29 | const tzone = Number(tarr[1].substr(0, 2));
30 | const dd =
31 | parseInt(darr[0]) +
32 | "/" +
33 | parseInt(darr[1]) +
34 | "/" +
35 | parseInt(darr[2]) +
36 | " " +
37 | parseInt(marr[0]) +
38 | ":" +
39 | parseInt(marr[1]) +
40 | ":" +
41 | parseInt(marr[2]);
42 | let time = new Date(Date.parse(dd));
43 | time.setTime(time.setHours(time.getHours() + (8 - tzone)));
44 | let Y = time.getFullYear() + interval;
45 | const addZero = (num: number) => (num < 10 ? "0" + num : num);
46 | let M = addZero(time.getMonth() + 1) + interval;
47 | let D = addZero(time.getDate());
48 | let h = " " + addZero(time.getHours());
49 | let m = ":" + addZero(time.getMinutes());
50 | let s = ":" + addZero(time.getSeconds());
51 | let result = Y + M + D;
52 | switch (num) {
53 | case 2:
54 | result = h + m;
55 | break;
56 | case 3:
57 | result = Y + M + D;
58 | break;
59 | case 4:
60 | result = Y + M + D + h;
61 | break;
62 | case 5:
63 | result = Y + M + D + h + m;
64 | break;
65 | case 6:
66 | result = Y + M + D + h + m + s;
67 | break;
68 | }
69 | return result;
70 | };
71 |
72 | /**
73 | * 时间戳转 YY-mm-dd HH:ii:ss
74 | * @param timeStamp
75 | * @param returnType
76 | * @returns
77 | */
78 | export const timeStampToDate = function (
79 | timeStamp: any,
80 | returnType: string | undefined
81 | ) {
82 | timeStamp = parseInt(timeStamp);
83 | var date = new Date();
84 | if (timeStamp < 90000000000) {
85 | date.setTime(timeStamp * 1000);
86 | } else {
87 | date.setTime(timeStamp);
88 | }
89 | var y = date.getFullYear();
90 | var m: number | string = date.getMonth() + 1;
91 | m = m < 10 ? "0" + m : m;
92 | var d: number | string = date.getDate();
93 | d = d < 10 ? "0" + d : d;
94 | var h: number | string = date.getHours();
95 | h = h < 10 ? "0" + h : h;
96 | var minute: number | string = date.getMinutes();
97 | var second: number | string = date.getSeconds();
98 | minute = minute < 10 ? "0" + minute : minute;
99 | second = second < 10 ? "0" + second : second;
100 | if (returnType == "str") {
101 | return y + "-" + m + "-" + d + " " + h + ":" + minute + ":" + second;
102 | }
103 | return [y, m, d, h, minute, second];
104 | };
105 |
106 | /**
107 | * 字符串转时间戳
108 | * @param timeStamp
109 | * @returns
110 | */
111 | export const toTimeStamp = function (timeStamp) {
112 | var reg =
113 | /^([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})$/;
114 | var res = timeStamp.match(reg);
115 | if (res == null) {
116 | var reg2 =
117 | /^([0-9]{2})\/([0-9]{2})\/([0-9]{4}) ([0-9]{2}):([0-9]{2}):([0-9]{2})$/;
118 | var res2 = timeStamp.match(reg2);
119 | if (res2 == null) {
120 | console.log("时间格式错误 E001");
121 | return false;
122 | }
123 | var year = parseInt(res2[3]);
124 | var month = parseInt(res2[1]);
125 | var day = parseInt(res2[2]);
126 | var h = parseInt(res2[4]);
127 | var i = parseInt(res2[5]);
128 | var s = parseInt(res2[6]);
129 | } else {
130 | var year = parseInt(res[1]);
131 | var month = parseInt(res[2]);
132 | var day = parseInt(res[3]);
133 | var h = parseInt(res[4]);
134 | var i = parseInt(res[5]);
135 | var s = parseInt(res[6]);
136 | }
137 | if (year < 1000) {
138 | console.log("时间格式错误");
139 | return false;
140 | }
141 | if (h < 0 || h > 24) {
142 | console.log("时间格式错误");
143 | return false;
144 | }
145 | if (i < 0 || i > 60) {
146 | console.log("时间格式错误");
147 | return false;
148 | }
149 | if (s < 0 || s > 60) {
150 | console.log("时间格式错误");
151 | return false;
152 | }
153 | return Date.parse(new Date(year, month - 1, day, h, i, s) + "");
154 | };
155 |
156 | /**
157 | * 根据时间戳计算多少分钟/小时/天之前
158 | * @param time
159 | * @returns
160 | */
161 | export const fromTime = function (time: number) {
162 | if (time < 90000000000) {
163 | time *= 1000;
164 | }
165 | var timer = new Date().getTime() - time;
166 | timer = parseInt(timer / 1000 + "");
167 | if (timer < 180) {
168 | return "刚刚";
169 | } else if (timer >= 180 && timer < 3600) {
170 | return parseInt(timer / 60 + "") + "分钟前";
171 | } else if (timer >= 3600 && timer < 86400) {
172 | return parseInt(timer / 3600 + "") + "小时前";
173 | } else if (timer >= 86400 && timer < 2592000) {
174 | return parseInt(timer / 86400 + "") + "天前";
175 | } else {
176 | return this.toDate(time, "str");
177 | }
178 | };
179 |
180 | /**
181 | * 计算当前时间,传入类型
182 | * @param type
183 | * @param addTime
184 | * @returns
185 | */
186 | export const nowTimeStemp = (type: string, addTime: number) => {
187 | var dateObj = new Date();
188 | var cTime = dateObj.getTime();
189 | try {
190 | if (addTime) {
191 | cTime += addTime;
192 | }
193 | if (!type) {
194 | type = "number";
195 | }
196 | if (type == "number") {
197 | return cTime;
198 | } else if (type == "str") {
199 | return timerToUTC(cTime / 1000, "str");
200 | } else if (type == "array") {
201 | return timerToUTC(cTime / 1000, "array");
202 | }
203 | } catch (error) {
204 | return cTime;
205 | }
206 | };
207 |
208 | /**
209 | * 时间戳 转 UTC格式时间, 入参是时间戳、返回的类型
210 | * @param timeStamp
211 | * @param returnType
212 | * @returns
213 | */
214 | export const timerToUTC = (timeStamp, returnType) => {
215 | timeStamp = parseInt(timeStamp);
216 | var date = new Date();
217 | if (timeStamp < 90000000000) {
218 | date.setTime(timeStamp * 1000);
219 | } else {
220 | date.setTime(timeStamp);
221 | }
222 | var y = date.getFullYear();
223 | var m: String | Number = date.getMonth() + 1;
224 | m = m < 10 ? "0" + m : m;
225 | var d: String | Number = date.getDate();
226 | d = d < 10 ? "0" + d : d;
227 | var h: String | Number = date.getHours();
228 | h = h < 10 ? "0" + h : h;
229 | var minute: String | Number = date.getMinutes();
230 | var second: String | Number = date.getSeconds();
231 | minute = minute < 10 ? "0" + minute : minute;
232 | second = second < 10 ? "0" + second : second;
233 | if (returnType == "str") {
234 | return y + "-" + m + "-" + d + " " + h + ":" + minute + ":" + second;
235 | }
236 | if (returnType == "assistEndTime") {
237 | return y * 1 - 2000 + "/" + m + "/" + d;
238 | }
239 | return [y, m, d, h, minute, second];
240 | };
241 |
242 | /**
243 | * 根据时间戳 检查 时间是否过期 true 表示没过期, false 表示过期
244 | * @param time
245 | * @returns
246 | */
247 | export const checkTimeStamp = (time: number) => {
248 | if (time < 90000000000) {
249 | time *= 1000;
250 | }
251 | var timer: number = time - new Date().getTime();
252 | timer = parseInt(`${timer / 1000}`);
253 | if (timer < 0) {
254 | return false;
255 | } else {
256 | return true;
257 | }
258 | };
259 |
260 | /**
261 | * IOS格式时间 转 国际UTC标准时间
262 | * @param data
263 | * @returns
264 | */
265 | export const iosDateToUtc = (data: string) => {
266 | return JSON.parse(
267 | JSON.stringify(data).replace(
268 | /\/Date\(\-?(\d+)(?:\-|\+)(?:\d+)\)\//g,
269 | function () {
270 | return new Date(Number(arguments[1]) + 8 * 3600 * 1000)
271 | .toISOString()
272 | .replace(/^(.*)T(.*)\.\d+Z$/, "$1 $2");
273 | }
274 | )
275 | );
276 | };
277 |
278 | /**
279 | * 返回当前时间
280 | * @param type
281 | * @param addTime
282 | * @returns
283 | */
284 | export function returnNowTime(type, addTime) {
285 | var dateObj = new Date();
286 | var cTime: any = dateObj.getTime();
287 | if (addTime) {
288 | cTime += addTime;
289 | }
290 | if (!type) {
291 | type = "number";
292 | }
293 | if (type == "number") {
294 | return cTime;
295 | }
296 | if (type == "YYYYMMDD") {
297 | var timeStamp = parseInt(cTime);
298 | var date = new Date();
299 | if (timeStamp < 90000000000) {
300 | date.setTime(timeStamp * 1000);
301 | } else {
302 | date.setTime(timeStamp);
303 | }
304 | var y = date.getFullYear();
305 | var m: any = date.getMonth() + 1;
306 | m = m < 10 ? "0" + m : m;
307 | var d: any = date.getDate();
308 | d = d < 10 ? "0" + d : d;
309 | return y + m + d;
310 | }
311 | return this.toDate(cTime / 1000, "str");
312 | }
313 |
314 | /**
315 | * 返回2个UTC时间之间的时间差
316 | * @param startTime
317 | * @param endTime
318 | * @returns
319 | */
320 | export const getDateDiff = (startTime: any, endTime: any) => {
321 | var sTime: any = new Date(startTime).getTime();
322 | var eTime: any = new Date(endTime).getTime();
323 | var divNumSecond = 1000;
324 | var divNumMinute = 1000 * 60;
325 | var divNumHour = 1000 * 3600;
326 | var divNumDay = 1000 * 3600 * 24;
327 |
328 | const day: any = parseInt(`${(eTime - sTime) / parseInt(`${divNumDay}`)}`);
329 | const hour: any = parseInt(`${((eTime - sTime) % parseInt(`${divNumDay}`)) / parseInt(`${divNumHour}`)}`);
330 | const minute: any = parseInt(`${parseInt(`${((eTime - sTime) % parseInt(`${divNumDay}`)) % parseInt(`${divNumHour}`)}`) /
331 | parseInt(`${divNumMinute}`)}`);
332 | const second: any =
333 | (parseInt(`${((eTime - sTime) % parseInt(`${divNumDay}`)) % parseInt(`${divNumHour}`)}`) %
334 | parseInt(`${divNumMinute}`)) /
335 | parseInt(`${divNumSecond}`);
336 | const str: any = day + "天" + hour + "小时" + minute + "分" + second + "秒";
337 | return str;
338 | };
339 |
340 | /**
341 | * 计算星座
342 | * @param mon
343 | * @param day
344 | * @returns
345 | */
346 | export const constellation = (mon, day) => {
347 | const days = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
348 | mon = parseInt(mon);
349 | day = parseInt(day);
350 |
351 | const words = [
352 | "白羊座",
353 | "金牛座",
354 | "双子座",
355 | "巨蟹座",
356 | "狮子座",
357 | "处女座",
358 | "天秤座",
359 | "天蝎座",
360 | "射手座",
361 | "摩羯座",
362 | "水瓶座",
363 | "双鱼座",
364 | ];
365 |
366 | if (mon < 1 || mon > 12) {
367 | throw new Error("Invalid month.");
368 | }
369 |
370 | if (day < 1 || day > days[mon - 1]) {
371 | throw new Error("Invalid day.");
372 | }
373 |
374 | var val = mon * 100 + day;
375 |
376 | if (val >= 321 && val <= 419) {
377 | return words[0];
378 | } else if (val >= 420 && val <= 520) {
379 | return words[1];
380 | } else if (val >= 521 && val <= 621) {
381 | return words[2];
382 | } else if (val >= 622 && val <= 722) {
383 | return words[3];
384 | } else if (val >= 723 && val <= 822) {
385 | return words[4];
386 | } else if (val >= 823 && val <= 922) {
387 | return words[5];
388 | } else if (val >= 923 && val <= 1023) {
389 | return words[6];
390 | } else if (val >= 1024 && val <= 1122) {
391 | return words[7];
392 | } else if (val >= 1123 && val <= 1221) {
393 | return words[8];
394 | } else if (val >= 1222 || val <= 119) {
395 | return words[9];
396 | } else if (val >= 120 && val <= 218) {
397 | return words[10];
398 | } else if (val >= 219 && val <= 320) {
399 | return words[11];
400 | }
401 | return "";
402 | };
403 |
404 |
405 | /**
406 | * 判断某一年是否是闰年
407 | * @param year 可以是一个date类型,也可以是一个int类型的年份,不传默认当前时间
408 | */
409 | export const _isLeapYear = (year) => {
410 | if (year === undefined) year = new Date();
411 | if (year instanceof Date) year = year.getFullYear();
412 | return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
413 | }
414 |
415 | /**
416 | * 获取某一年某一月的总天数,没有任何参数时获取当前月份的
417 | * 方式一:dateUtils.getDaysOfMonth();
418 | * 方式二:dateUtils.getDaysOfMonth(new Date());
419 | * 方式三:dateUtils.getDaysOfMonth(2013, 12);
420 | */
421 | export const _getDaysOfMonth = (date, month) => {
422 | var y, m;
423 | if (date == undefined) date = new Date();
424 | if (date instanceof Date) {
425 | y = date.getFullYear();
426 | m = date.getMonth();
427 | }
428 | else if (typeof date == 'number') {
429 | y = date;
430 | m = month - 1;
431 | } else if (typeof date === 'string') {
432 | var strdate = new Date(date);
433 | y = strdate.getFullYear();
434 | m = strdate.getMonth();
435 | }
436 | var days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; // 非闰年的一年中每个月份的天数
437 | //如果是闰年并且是2月
438 | if (m == 1 && _isLeapYear(y)) return days[m] + 1;
439 | return days[m];
440 | }
441 |
442 | /**
443 | * 转换时间,带星期
444 | * @param date
445 | * @param format
446 | * @returns
447 | */
448 | export const formatDate = (date, format = 'yyyy-MM-dd') => {
449 | var v = "";
450 | var year = date.getFullYear();
451 | var month = date.getMonth() + 1;
452 | var day = date.getDate();
453 | var hour = date.getHours();
454 | var minute = date.getMinutes();
455 | var second = date.getSeconds();
456 | var weekDay = date.getDay();
457 | var ms = date.getMilliseconds();
458 | var weekDayString = "";
459 | if (weekDay == 1) {
460 | weekDayString = "星期一";
461 | } else if (weekDay == 2) {
462 | weekDayString = "星期二";
463 | } else if (weekDay == 3) {
464 | weekDayString = "星期三";
465 | } else if (weekDay == 4) {
466 | weekDayString = "星期四";
467 | } else if (weekDay == 5) {
468 | weekDayString = "星期五";
469 | } else if (weekDay == 6) {
470 | weekDayString = "星期六";
471 | } else if (weekDay == 7) {
472 | weekDayString = "星期日";
473 | }
474 | v = format;
475 | //Year
476 | v = v.replace(/yyyy/g, year);
477 | v = v.replace(/YYYY/g, year);
478 | v = v.replace(/yy/g, (year + "").substring(2, 4));
479 | v = v.replace(/YY/g, (year + "").substring(2, 4));
480 | //Month
481 | var monthStr = ("0" + month);
482 | v = v.replace(/MM/g, monthStr.substring(monthStr.length - 2));
483 | //Day
484 | var dayStr = ("0" + day);
485 | v = v.replace(/dd/g, dayStr.substring(dayStr.length - 2));
486 | //hour
487 | var hourStr = ("0" + hour);
488 | v = v.replace(/HH/g, hourStr.substring(hourStr.length - 2));
489 | v = v.replace(/hh/g, hourStr.substring(hourStr.length - 2));
490 | //minute
491 | var minuteStr = ("0" + minute);
492 | v = v.replace(/mm/g, minuteStr.substring(minuteStr.length - 2));
493 | //Millisecond
494 | v = v.replace(/sss/g, ms);
495 | v = v.replace(/SSS/g, ms);
496 | //second
497 | var secondStr = ("0" + second);
498 | v = v.replace(/ss/g, secondStr.substring(secondStr.length - 2));
499 | v = v.replace(/SS/g, secondStr.substring(secondStr.length - 2));
500 | //weekDay
501 | v = v.replace(/E/g, weekDayString);
502 | return v;
503 | }
504 |
--------------------------------------------------------------------------------
/src/utils/event.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 客户端环境下Event事件
3 | */
4 | export const _Event = function () { };
5 | // 添加事件处理
6 | _Event.prototype.addHandler = function (element, type, handler) {
7 | if (element.addEventListener) {
8 | element.addEventListener(type, handler, false);
9 | } else if (element.attachEvent) {
10 | element.attachEvent("on" + type, handler);
11 | } else {
12 | element["on" + type] = handler;
13 | }
14 | };
15 | // 移除事件处理
16 | _Event.prototype.removeHandler = function (element, type, handler) {
17 | if (element.removeEventListener) {
18 | element.removeEventListener(type, handler, false);
19 | } else if (element.detachEvent) {
20 | element.detachEvent("on" + type, handler);
21 | } else {
22 | element["on" + type] = null;
23 | }
24 | };
25 | // 获取event对象
26 | _Event.prototype.getEvent = function (event) {
27 | return event ? event : w.event;
28 | };
29 | // 获取目标对象
30 | _Event.prototype.getTarget = function (event) {
31 | return event.target || event.srcElement;
32 | };
33 | // 获取相关目标对象
34 | _Event.prototype.getRelatedTarget = function (event) {
35 | if (event.relatedTarget) {
36 | return event.relatedTarget;
37 | } else if (event.toElement) {
38 | return event.toElement;
39 | } else if (event.fromElement) {
40 | return fromElement;
41 | } else {
42 | return null;
43 | }
44 | };
45 | // 阻止默认事件
46 | _Event.prototype.preventDefault = function (event) {
47 | if (event.preventDefault) {
48 | event.preventDefault();
49 | } else {
50 | event.returnValue = false;
51 | }
52 | };
53 | // 阻止冒泡事件
54 | _Event.prototype.stopPropagation = function (event) {
55 | if (event.stopPropagation) {
56 | event.stopPropagation();
57 | } else {
58 | event.cancelBubble = true;
59 | }
60 | };
61 | return _Event;
62 | }
--------------------------------------------------------------------------------
/src/utils/file.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 输入一个数组,然后拍平输出,保证文件名唯一
3 | * @param names
4 | * @returns
5 | */
6 | export const getFolderNames = (names: string[]): string[] => {
7 | let d: { [_: string]: number } = {};
8 | return names.map((name) => {
9 | let s = name;
10 | while (s in d) {
11 | s = `${name}(${d[name]})`;
12 | ++d[name];
13 | }
14 | d[s] = 1;
15 | return s;
16 | });
17 | };
18 |
19 | /**
20 | * 计算文件占用体积
21 | * @param size
22 | * @returns
23 | */
24 | export const handleSize = (size) => {
25 | const KB = size / 1024;
26 | const MB = KB / 1024;
27 | const GB = MB / 1024;
28 | const TB = GB / 1024;
29 | if (MB < 1) {
30 | return `${KB.toFixed(2)} KB`;
31 | } else if (GB < 1) {
32 | return `${MB.toFixed(2)} MB`;
33 | } else if (TB < 1) {
34 | return `${GB.toFixed(2)} GB`;
35 | } else {
36 | return `${TB.toFixed(2)} TB`;
37 | }
38 | };
39 |
40 |
41 | function charToBinary(text) {
42 | var code = "";
43 | for (let i of text) {
44 | // 字符编码
45 | let number = i.charCodeAt().toString(2);
46 | // 1 bytes = 8bit,将 number 不足8位的0补上
47 | for (let a = 0; a <= 8 - number.length; a++) {
48 | number = 0 + number;
49 | }
50 | code += number;
51 | }
52 | return code;
53 | }
54 |
55 | /**
56 | * 将二进制数据每 6bit 位替换成一个 base64 字符
57 | * @param code
58 | * @returns
59 | */
60 | export const binaryTobase64 = (code) => {
61 | let base64Code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
62 | let res = '';
63 | if (code.length % 24 === 8) {
64 | code += '0000';
65 | res += '=='
66 | }
67 | if (code.length % 24 === 16) {
68 | code += '00';
69 | res += '='
70 | }
71 |
72 | let encode = '';
73 | for (let i = 0; i < code.length; i += 6) {
74 | let item = code.slice(i, i + 6);
75 | encode += base64Code[parseInt(item, 2)];
76 | }
77 | return encode + res;
78 | }
79 |
--------------------------------------------------------------------------------
/src/utils/filterdata/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * @param {number[]} nums
3 | * @return {number[]}
4 | */
5 | export const findDuplicates = function (nums) {
6 | const res = [];
7 |
8 | for (const num of nums) {
9 | const absNum = Math.abs(num);
10 | if (nums[absNum - 1] < 0) {
11 | res.push(absNum);
12 | } else {
13 | nums[absNum - 1] *= -1;
14 | }
15 | }
16 |
17 | return res;
18 | };
19 |
20 | /**
21 | * 数组对象去重
22 | * @param arr
23 | * @param key
24 | * @param hash
25 | * @returns
26 | */
27 | export const unique = (arr: AnyArray, key: string, hash: any = {}) =>
28 | arr.reduce(function (item, next) {
29 | hash[next[key]] ? "" : (hash[next[key]] = true && item.push(next));
30 | return item;
31 | }, []);
32 |
33 | /**
34 | * 校验输入框是都有表情
35 | * @param substring
36 | * @returns
37 | */
38 | export const isEmojiCharacter = (substring) => {
39 | for (var i = 0; i < substring.length; i++) {
40 | const hs = substring.charCodeAt(i);
41 | if (hs >= 0xd800 && hs <= 0xdbff) {
42 | if (substring.length > 1) {
43 | const ls = substring.charCodeAt(i + 1);
44 | var uc = (hs - 0xd800) * 0x400 + (ls - 0xdc00) + 0x10000;
45 | if (uc >= 0x1d000 && uc <= 0x1f77f) {
46 | return true;
47 | }
48 | }
49 | } else if (substring.length > 1) {
50 | const ls = substring.charCodeAt(i + 1);
51 | if (ls === 0x20e3) {
52 | return true;
53 | }
54 | } else {
55 | if (hs >= 0x2100 && hs <= 0x27ff) {
56 | return true;
57 | } else if (hs >= 0x2b05 && hs <= 0x2b07) {
58 | return true;
59 | } else if (hs >= 0x2934 && hs <= 0x2935) {
60 | return true;
61 | } else if (hs >= 0x3297 && hs <= 0x3299) {
62 | return true;
63 | } else if (
64 | hs === 0xa9 ||
65 | hs === 0xae ||
66 | hs === 0x303d ||
67 | hs === 0x3030 ||
68 | hs === 0x2b55 ||
69 | hs === 0x2b1c ||
70 | hs === 0x2b1b ||
71 | hs === 0x2b50
72 | ) {
73 | return true;
74 | }
75 | }
76 | }
77 | };
78 |
79 | /**
80 | * 根据指定条件(如回调对象的某个属性)进行分组 构成对象返回。
81 | * @param target
82 | * @param val
83 | */
84 | export const groupBy = (target, val) => {
85 | var result = {};
86 | var iterator = typeof val == "function" ? val : function (obj) {
87 | return obj[val];
88 | }
89 | target.forEach(function (value, index) {
90 | var key = iterator(value, index);
91 | (result[key] || (result[key] = [])).push(value);
92 | });
93 | return result;
94 | }
--------------------------------------------------------------------------------
/src/utils/idcard.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 校验身份证的合法性
3 | * @param idcard
4 | * @returns
5 | */
6 | export const checkIdcard = (idcard: number | string) => {
7 | var Errors = new Array(
8 | "ok",
9 | "身份证号码位数错误",
10 | "身份证号码出生日期错误",
11 | "身份证号码校验错误",
12 | "身份证地区错误"
13 | );
14 | var area = {
15 | 11: "北京",
16 | 12: "天津",
17 | 13: "河北",
18 | 14: "山西",
19 | 15: "内蒙古",
20 | 21: "辽宁",
21 | 22: "吉林",
22 | 23: "黑龙江",
23 | 31: "上海",
24 | 32: "江苏",
25 | 33: "浙江",
26 | 34: "安徽",
27 | 35: "福建",
28 | 36: "江西",
29 | 37: "山东",
30 | 41: "河南",
31 | 42: "湖北",
32 | 43: "湖南",
33 | 44: "广东",
34 | 45: "广西",
35 | 46: "海南",
36 | 50: "重庆",
37 | 51: "四川",
38 | 52: "贵州",
39 | 53: "云南",
40 | 54: "西藏",
41 | 61: "陕西",
42 | 62: "甘肃",
43 | 63: "青海",
44 | 64: "宁夏",
45 | 65: "新疆",
46 | 71: "台湾",
47 | 81: "香港",
48 | 82: "澳门",
49 | 91: "国外",
50 | };
51 |
52 | var idcard, Y, JYM, ereg;
53 | var S, M;
54 | var idcard_array = new Array();
55 | idcard_array = idcard.split("");
56 | //地区检验
57 | if (area[parseInt(idcard.substr(0, 2))] == null) return Errors[4];
58 | //身份号码位数及格式检验
59 | switch (idcard.length) {
60 | case 15:
61 | if (
62 | (parseInt(idcard.substr(6, 2)) + 1900) % 4 == 0 ||
63 | ((parseInt(idcard.substr(6, 2)) + 1900) % 100 == 0 &&
64 | (parseInt(idcard.substr(6, 2)) + 1900) % 4 == 0)
65 | ) {
66 | ereg =
67 | /^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}$/; //测试出生日期的合法性
68 | } else {
69 | ereg =
70 | /^[1-9][0-9]{5}[0-9]{2}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}$/; //测试出生日期的合法性
71 | }
72 | if (ereg.test(idcard)) return Errors[0];
73 | else return Errors[2];
74 | break;
75 | case 18:
76 | //18位身份号码检测
77 | //出生日期的合法性检查
78 | //闰年月日:((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))
79 | //平年月日:((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))
80 | if (
81 | parseInt(idcard.substr(6, 4)) % 4 == 0 ||
82 | (parseInt(idcard.substr(6, 4)) % 100 == 0 &&
83 | parseInt(idcard.substr(6, 4)) % 4 == 0)
84 | ) {
85 | ereg =
86 | /^[1-9][0-9]{5}[1-2]+[0-9]{3}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|[1-2][0-9]))[0-9]{3}[0-9Xx]$/; //闰年出生日期的合法性正则表达式
87 | } else {
88 | ereg =
89 | /^[1-9][0-9]{5}[1-2]+[0-9]{3}((01|03|05|07|08|10|12)(0[1-9]|[1-2][0-9]|3[0-1])|(04|06|09|11)(0[1-9]|[1-2][0-9]|30)|02(0[1-9]|1[0-9]|2[0-8]))[0-9]{3}[0-9Xx]$/; //平年出生日期的合法性正则表达式
90 | }
91 | // 测试出生日期的合法性
92 | if (ereg.test(idcard)) {
93 | //计算校验位
94 | S =
95 | (parseInt(idcard_array[0]) + parseInt(idcard_array[10])) * 7 +
96 | (parseInt(idcard_array[1]) + parseInt(idcard_array[11])) * 9 +
97 | (parseInt(idcard_array[2]) + parseInt(idcard_array[12])) * 10 +
98 | (parseInt(idcard_array[3]) + parseInt(idcard_array[13])) * 5 +
99 | (parseInt(idcard_array[4]) + parseInt(idcard_array[14])) * 8 +
100 | (parseInt(idcard_array[5]) + parseInt(idcard_array[15])) * 4 +
101 | (parseInt(idcard_array[6]) + parseInt(idcard_array[16])) * 2 +
102 | parseInt(idcard_array[7]) * 1 +
103 | parseInt(idcard_array[8]) * 6 +
104 | parseInt(idcard_array[9]) * 3;
105 | Y = S % 11;
106 | M = "F";
107 | JYM = "10X98765432";
108 | M = JYM.substr(Y, 1); //判断校验位
109 | if (M == idcard_array[17]) return Errors[0]; //检测ID的校验位
110 | else return Errors[3];
111 | } else {
112 | return Errors[2];
113 | }
114 | break;
115 | default:
116 | return Errors[1];
117 | break;
118 | }
119 | };
120 |
121 | /**
122 | * 计算最后一位应该是多少
123 | * @param idCard
124 | * @returns
125 | */
126 | function idCardEndNum(idCard) {
127 | idCard = idCard.toString();
128 | var factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
129 | var parity = [1, 0, "X", 9, 8, 7, 6, 5, 4, 3, 2];
130 | var sum = 0;
131 | var ai = 0;
132 | var wi = 0;
133 | for (var i = 0; i < 17; i++) {
134 | ai = idCard[i];
135 | wi = factor[i];
136 | sum += ai * wi;
137 | }
138 | var last = parity[sum % 11];
139 | return last;
140 | }
141 |
142 | // 解析生日信息
143 | function birthDay(idCard) {
144 | idCard = idCard.toString();
145 | var birthday, month, day, nong;
146 | let year = idCard.substr(6, 4);
147 | month = idCard.substr(10, 2);
148 | day = idCard.substr(12, 2);
149 | birthday = year + "/" + month + "/" + day;
150 | nong = Nong(birthday);
151 | let nongyear = nong.substr(0, 4);
152 | return {
153 | date: birthday,
154 | nong: nong,
155 | year: year,
156 | month: month,
157 | day: day,
158 | nongCn: NongCn(birthday),
159 | week: dict.week(birthday), // 星期几
160 | zodiac: dict.zodiac(month, day), // 星座
161 | zodiac_zh: dict.zodiac_zh(nongyear), // 生肖
162 | };
163 | }
164 |
165 | // 验证身份证号是否正确
166 | function checkIdCard(idCard) {
167 | idCard = idCard.toString();
168 | if (/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(idCard)) {
169 | if (idCard.length >= 18) {
170 | return idCardEndNum(idCard) == idCard[17].toUpperCase();
171 | } else {
172 | return false;
173 | }
174 | }
175 | return false;
176 | }
177 |
178 | // 补全身份证号
179 | function repairIdCard(idCard) {
180 | idCard = idCard.toString();
181 | if (/(^\d{17}$)/.test(idCard)) return idCard + idCardEndNum(idCard);
182 | if (/(^\d{18}$)/.test(idCard))
183 | return idCard.slice(0, 17) + idCardEndNum(idCard);
184 | }
185 |
186 | // 15位转换18位
187 | function num15to18(idCard) {
188 | idCard = idCard.toString();
189 | if (/(^\d{15}$)/.test(idCard))
190 | return repairIdCard(idCard.slice(0, 6) + "19" + idCard.slice(6, 15));
191 | }
192 |
193 | // 性别解析
194 | function sex(idCard) {
195 | idCard = idCard.toString();
196 | if (idCard[16] % 2) return "男";
197 | return "女";
198 | }
199 |
200 |
201 |
202 | export default {
203 | checkIdcard: checkIdcard,
204 | };
205 |
--------------------------------------------------------------------------------
/src/utils/locate.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 判断当前设备的IP地址
3 | * @param callback
4 | */
5 | export const getIPs = (callback) => {
6 | var ip_dups = {};
7 |
8 | //compatibility for firefox and chrome
9 | var RTCPeerConnection =
10 | window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
11 | var useWebKit = !!window.webkitRTCPeerConnection;
12 |
13 | //bypass naive webrtc blocking using an iframe
14 | if (!RTCPeerConnection) {
15 | var win = iframe.contentWindow;
16 | RTCPeerConnection =
17 | win.RTCPeerConnection || win.mozRTCPeerConnection || win.webkitRTCPeerConnection;
18 | useWebKit = !!win.webkitRTCPeerConnection;
19 | }
20 |
21 | //minimal requirements for data connection
22 | var mediaConstraints = {
23 | optional: [{ RtpDataChannels: true }],
24 | };
25 |
26 | var servers = { iceServers: [{ urls: 'stun:stun.services.mozilla.com' }] };
27 |
28 | //construct a new RTCPeerConnection
29 | var pc = new RTCPeerConnection(servers, mediaConstraints);
30 |
31 | function handleCandidate(candidate) {
32 | //match just the IP address
33 | var ip_regex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/;
34 | var ip_addr = ip_regex.exec(candidate)[1];
35 |
36 | //remove duplicates
37 | if (ip_dups[ip_addr] === undefined) callback(ip_addr);
38 |
39 | ip_dups[ip_addr] = true;
40 | }
41 |
42 | //listen for candidate events
43 | pc.onicecandidate = function (ice) {
44 | //skip non-candidate events
45 | if (ice.candidate) handleCandidate(ice.candidate.candidate);
46 | };
47 |
48 | //create a bogus data channel
49 | pc.createDataChannel('');
50 |
51 | //create an offer sdp
52 | pc.createOffer(
53 | function (result) {
54 | //trigger the stun server request
55 | pc.setLocalDescription(
56 | result,
57 | function () {},
58 | function () {},
59 | );
60 | },
61 | function () {},
62 | );
63 |
64 | //wait for a while to let everything done
65 | setTimeout(function () {
66 | //read candidate info from local description
67 | var lines = pc.localDescription.sdp.split('\n');
68 |
69 | lines.forEach(function (line) {
70 | if (line.indexOf('a=candidate:') === 0) handleCandidate(line);
71 | });
72 | }, 1000);
73 | };
74 |
75 | /**
76 | * 计算2个坐标之间的距离
77 | * @param lat1
78 | * @param lng1
79 | * @param lat2
80 | * @param lng2
81 | * @returns
82 | */
83 | export const getDistance = function (lat1, lng1, lat2, lng2) {
84 | var radLat1 = (lat1 * Math.PI) / 180.0;
85 | var radLat2 = (lat2 * Math.PI) / 180.0;
86 | var a = radLat1 - radLat2;
87 | var b = (lng1 * Math.PI) / 180.0 - (lng2 * Math.PI) / 180.0;
88 | var s =
89 | 2 *
90 | Math.asin(
91 | Math.sqrt(
92 | Math.pow(Math.sin(a / 2), 2) +
93 | Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2),
94 | ),
95 | );
96 | s = s * 6378.137;
97 | s = Math.round(s * 10000) / 10000;
98 | return s;
99 | };
100 |
101 | /**
102 | * 导出GPS的工具函数
103 | */
104 | export const GPSTools = {
105 | delta: function (lat, lon) {
106 | var a = 6378245.0;
107 | var ee = 0.00669342162296594323;
108 | var dLat = this.transformLat(lon - 105.0, lat - 35.0);
109 | var dLon = this.transformLon(lon - 105.0, lat - 35.0);
110 | var radLat = (lat / 180.0) * Math.PI;
111 | var magic = Math.sin(radLat);
112 | magic = 1 - ee * magic * magic;
113 | var sqrtMagic = Math.sqrt(magic);
114 | dLat = (dLat * 180.0) / (((a * (1 - ee)) / (magic * sqrtMagic)) * Math.PI);
115 | dLon = (dLon * 180.0) / ((a / sqrtMagic) * Math.cos(radLat) * Math.PI);
116 | return { lat: dLat, lon: dLon };
117 | },
118 | gcj_encrypt: function (wgsLat, wgsLon) {
119 | if (this.outOfChina(wgsLat, wgsLon)) {
120 | return { lat: wgsLat, lng: wgsLon };
121 | }
122 | var d = this.delta(wgsLat, wgsLon);
123 | return { lat: wgsLat + d.lat, lng: wgsLon + d.lon };
124 | },
125 | outOfChina: function (lat, lon) {
126 | if (lon < 72.004 || lon > 137.8347) {
127 | return true;
128 | }
129 | if (lat < 0.8293 || lat > 55.8271) {
130 | return true;
131 | }
132 | return false;
133 | },
134 | transformLat: function (x, y) {
135 | var ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
136 | ret += ((20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0) / 3.0;
137 | ret += ((20.0 * Math.sin(y * Math.PI) + 40.0 * Math.sin((y / 3.0) * Math.PI)) * 2.0) / 3.0;
138 | ret +=
139 | ((160.0 * Math.sin((y / 12.0) * Math.PI) + 320 * Math.sin((y * Math.PI) / 30.0)) * 2.0) / 3.0;
140 | return ret;
141 | },
142 | transformLon: function (x, y) {
143 | var ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
144 | ret += ((20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0) / 3.0;
145 | ret += ((20.0 * Math.sin(x * Math.PI) + 40.0 * Math.sin((x / 3.0) * Math.PI)) * 2.0) / 3.0;
146 | ret +=
147 | ((150.0 * Math.sin((x / 12.0) * Math.PI) + 300.0 * Math.sin((x / 30.0) * Math.PI)) * 2.0) /
148 | 3.0;
149 | return ret;
150 | },
151 | };
152 |
153 | /**
154 | * 高德转百度坐标系
155 | * @param lng
156 | * @param lat
157 | * @returns
158 | */
159 | export const aMapToBMap = function (lng, lat) {
160 | var x_pi = (3.14159265358979324 * 3000.0) / 180.0;
161 | var x = lng,
162 | y = lat;
163 | var z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
164 | var theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
165 | return {
166 | lng: z * Math.cos(theta) + 0.0065,
167 | lat: z * Math.sin(theta) + 0.006,
168 | };
169 | };
170 |
171 | /**
172 | * 百度坐标系转高德坐标系
173 | * @param lng
174 | * @param lat
175 | * @returns
176 | */
177 | export const bMapToAMap = function (lng, lat) {
178 | var x_pi = (3.14159265358979324 * 3000.0) / 180.0;
179 | var x = lng - 0.0065,
180 | y = lat - 0.006;
181 | var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
182 | var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
183 | return {
184 | lng: z * Math.cos(theta),
185 | lat: z * Math.sin(theta),
186 | isBMap: false,
187 | };
188 | };
189 |
190 | /**
191 | * 高德坐标系转谷歌坐标系
192 | * @param lon
193 | * @param lat
194 | * @returns
195 | */
196 | export const aMapToGMap = function (lon, lat) {
197 | var a = 6378245.0;
198 | var ee = 0.00669342162296594323;
199 | var x = lon - 105.0;
200 | var y = lat - 35.0;
201 | var dLon = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
202 | dLon += ((20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0) / 3.0;
203 | dLon += ((20.0 * Math.sin(x * Math.PI) + 40.0 * Math.sin((x / 3.0) * Math.PI)) * 2.0) / 3.0;
204 | dLon +=
205 | ((150.0 * Math.sin((x / 12.0) * Math.PI) + 300.0 * Math.sin((x / 30.0) * Math.PI)) * 2.0) / 3.0;
206 | var dLat = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
207 | dLat += ((20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0) / 3.0;
208 | dLat += ((20.0 * Math.sin(y * Math.PI) + 40.0 * Math.sin((y / 3.0) * Math.PI)) * 2.0) / 3.0;
209 | dLat +=
210 | ((160.0 * Math.sin((y / 12.0) * Math.PI) + 320 * Math.sin((y * Math.PI) / 30.0)) * 2.0) / 3.0;
211 | var radLat = (lat / 180.0) * Math.PI;
212 | var magic = Math.sin(radLat);
213 | magic = 1 - ee * magic * magic;
214 | var sqrtMagic = Math.sqrt(magic);
215 | dLat = (dLat * 180.0) / (((a * (1 - ee)) / (magic * sqrtMagic)) * Math.PI);
216 | dLon = (dLon * 180.0) / ((a / sqrtMagic) * Math.cos(radLat) * Math.PI);
217 | var wgsLon = lon - dLon;
218 | var wgsLat = lat - dLat;
219 | return {
220 | lat: wgsLat,
221 | lng: wgsLon,
222 | };
223 | };
224 |
225 | /**
226 | * 谷歌坐标系转高德坐标系
227 | * @param lng
228 | * @param lat
229 | * @returns
230 | */
231 | export const gMapToAMap = function (lng, lat) {
232 | return GPS.gcj_encrypt(lat, lng);
233 | };
234 |
235 | /**
236 | * 谷歌坐标系转百度坐标系
237 | * @param lng
238 | * @param lat
239 | * @returns
240 | */
241 | export const gMapToBMap = function (lng, lat) {
242 | var aPoint = gMapToAMap(lng, lat);
243 | return aMapToBMap(aPoint.lng, aPoint.lat);
244 | };
245 |
246 | /**
247 | * 百度坐标转化为腾讯坐标
248 | * @param lng
249 | * @param lat
250 | * @returns
251 | */
252 | export const qqMapToBMap = (lng, lat) => {
253 | if (lng == null || lng == '' || lat == null || lat == '') return [lng, lat];
254 | var x_pi = 3.14159265358979324;
255 | var x = parseFloat(lng);
256 | var y = parseFloat(lat);
257 | var z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
258 | var theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
259 | lng = (z * Math.cos(theta) + 0.0065).toFixed(5);
260 | lat = (z * Math.sin(theta) + 0.006).toFixed(5);
261 | return lat + ',' + lng;
262 | };
263 |
264 | /**
265 | * 火星坐标(gcj02)转化为百度坐标
266 | * @param mars_point
267 | * @returns
268 | */
269 | export const transformGCtoBMap = (mars_point) => {
270 | const x_pi = (3.14159265358979324 * 3000.0) / 180.0;
271 | var baidu_point = { lon: 0, lat: 0 };
272 | var x = mars_point.lon;
273 | var y = mars_point.lat;
274 | var z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
275 | var theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
276 | baidu_point.lon = z * Math.cos(theta) + 0.0065;
277 | baidu_point.lat = z * Math.sin(theta) + 0.006;
278 | return baidu_point;
279 | };
280 |
--------------------------------------------------------------------------------
/src/utils/math.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 保留N位小数
3 | * @param number
4 | * @param n
5 | * @returns
6 | */
7 | export const getFloat = function (number: any, n: any) {
8 | n = n ? parseInt(n) : 0;
9 | if (n <= 0) {
10 | return Math.round(number);
11 | }
12 | number = Math.round(number * Math.pow(10, n)) / Math.pow(10, n);
13 | number = Number(number).toFixed(n);
14 | return number;
15 | };
16 |
17 | /**
18 | * 从一个给定的数组arr中,随机返回num个不重复项
19 | * @param arr
20 | * @param num
21 | * @returns
22 | */
23 | export const getArrayItems = function (arr: Array, num: number) {
24 | //新建一个数组,将传入的数组复制过来,用于运算,而不要直接操作传入的数组;
25 | var temp_array = new Array();
26 | for (var index in arr) {
27 | temp_array.push(arr[index]);
28 | }
29 | //取出的数值项,保存在此数组
30 | var return_array = new Array();
31 | for (var i = 0; i < num; i++) {
32 | //判断如果数组还有可以取出的元素,以防下标越界
33 | if (temp_array.length > 0) {
34 | //在数组中产生一个随机索引
35 | var arrIndex = Math.floor(Math.random() * temp_array.length);
36 | //将此随机索引的对应的数组元素值复制出来
37 | return_array[i] = temp_array[arrIndex];
38 | //然后删掉此索引的数组元素,这时候temp_array变为新的数组
39 | temp_array.splice(arrIndex, 1);
40 | } else {
41 | //数组中数据项取完后,退出循环,比如数组本来只有10项,但要求取出20项.
42 | break;
43 | }
44 | }
45 | return return_array;
46 | };
47 |
48 | /**
49 | * 返回数组种重复数据的列表
50 | * @param nums
51 | * @returns
52 | */
53 | export const findDuplicates = function (nums: Array) {
54 | const res: Array = [];
55 |
56 | for (const num of nums) {
57 | const absNum = Math.abs(num);
58 | if (nums[absNum - 1] < 0) {
59 | res.push(absNum);
60 | } else {
61 | nums[absNum - 1] *= -1;
62 | }
63 | }
64 |
65 | return res;
66 | };
67 |
68 | /**
69 | * 在M*N网格内筛选出最短路径,寻路
70 | * @param grid 0 空、1 障碍
71 | * @param k
72 | * @returns
73 | */
74 | export const shortestPath = function (grid: Array>, k: number) {
75 | const directions = [
76 | [1, 0],
77 | [0, 1],
78 | [-1, 0],
79 | [0, -1],
80 | ];
81 | const height = grid.length;
82 | const width = grid[0].length;
83 | const dp = Array(height).fill(null).map((_) =>
84 | Array(width).fill(null).map((_) => Array(k + 1).fill(Infinity))
85 | );
86 | dp[0][0][0] = 0;
87 | const queue: Array = [[0, 0]];
88 | while (queue.length > 0) {
89 | const [x, y] = queue.shift();
90 | const status = dp[y][x];
91 |
92 | for (const [offsetX, offsetY] of directions) {
93 | const nextXY = [x + offsetX, y + offsetY];
94 | const [nextX, nextY] = nextXY;
95 |
96 | if (nextX >= 0 && nextY >= 0 && nextX < width && nextY < height) {
97 | const nextStatus = dp[nextY][nextX];
98 | const isObstacle = grid[nextY][nextX] == 1;
99 |
100 | let available = false;
101 | if (!isObstacle) {
102 | for (let i = 0; i < k + 1; i++) {
103 | const nextStep = status[i] + 1;
104 | if (nextStep < nextStatus[i]) {
105 | nextStatus[i] = nextStep;
106 | available = true;
107 | }
108 | }
109 | } else {
110 | for (let i = 0; i < k; i++) {
111 | const nextStep = status[i] + 1;
112 | if (nextStep < nextStatus[i + 1]) {
113 | nextStatus[i + 1] = nextStep;
114 | available = true;
115 | }
116 | }
117 | }
118 | if (available) queue.push(nextXY);
119 | }
120 | }
121 | }
122 | let totalSteps = Math.min(...dp[height - 1][width - 1]);
123 | return totalSteps == Infinity ? -1 : totalSteps;
124 | };
125 |
126 | /** 生成指定范围内的随机数 */
127 | export const randomNum = (min: number, max: number) => {
128 | return Math.floor(Math.random() * (max - min + 1)) + min;
129 | }
130 |
131 | /** 数组乱序 */
132 | export const arrScrambling = (arr: Array) => {
133 | for (let i = 0; i < arr.length; i++) {
134 | const randomIndex = Math.round(Math.random() * (arr.length - 1 - i)) + i;
135 | [arr[i], arr[randomIndex]] = [arr[randomIndex], arr[i]];
136 | }
137 | return arr;
138 | };
139 |
140 | /** 数组扁平化 */
141 | export const flatten = (arr: Array) => {
142 | let result: Array = [];
143 |
144 | for (let i = 0; i < arr.length; i++) {
145 | if (Array.isArray(arr[i])) {
146 | result = result.concat(flatten(arr[i]));
147 | } else {
148 | result.push(arr[i]);
149 | }
150 | }
151 | return result;
152 | };
153 |
154 | /** 数组中获取随机数 */
155 | export const sample = (arr) => arr[Math.floor(Math.random() * arr.length)];
156 |
157 | /** 生成随机字符串 */
158 | export const randomString = (len) => {
159 | let chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz123456789";
160 | let strLen = chars.length;
161 | let randomStr = "";
162 | for (let i = 0; i < len; i++) {
163 | randomStr += chars.charAt(Math.floor(Math.random() * strLen));
164 | }
165 | return randomStr;
166 | };
167 |
168 | /** 字符串首字母大写 */
169 | export const fistLetterUpper = (str) => {
170 | return str.charAt(0).toUpperCase() + str.slice(1);
171 | };
172 |
173 | /** 手机号中间四位变成* */
174 | export const telFormat = (tel) => {
175 | tel = String(tel);
176 | return tel.substr(0, 3) + "****" + tel.substr(7);
177 | };
178 |
179 | /** 驼峰命名转换成短横线命名 */
180 | export const getKebabCase = (str) => {
181 | return str.replace(/[A-Z]/g, (item) => "-" + item.toLowerCase());
182 | };
183 |
184 | /** 短横线命名转换成驼峰命名 */
185 | export const getCamelCase = (str) => {
186 | return str.replace(/-([a-z])/g, (i, item) => item.toUpperCase());
187 | };
188 |
189 | /** 全角转换为半角 */
190 | export const toCDB = (str) => {
191 | let result = "";
192 | for (let i = 0; i < str.length; i++) {
193 | var code = str.charCodeAt(i);
194 | if (code >= 65281 && code <= 65374) {
195 | result += String.fromCharCode(str.charCodeAt(i) - 65248);
196 | } else if (code == 12288) {
197 | result += String.fromCharCode(str.charCodeAt(i) - 12288 + 32);
198 | } else {
199 | result += str.charAt(i);
200 | }
201 | }
202 | return result;
203 | };
204 |
205 | /** 半角转换为全角 */
206 | export const toDBC = (str) => {
207 | let result = "";
208 | for (let i = 0; i < str.length; i++) {
209 | var code = str.charCodeAt(i);
210 | if (code >= 33 && code <= 126) {
211 | result += String.fromCharCode(str.charCodeAt(i) + 65248);
212 | } else if (code == 32) {
213 | result += String.fromCharCode(str.charCodeAt(i) + 12288 - 32);
214 | } else {
215 | result += str.charAt(i);
216 | }
217 | }
218 | return result;
219 | };
220 |
221 | /** 数字转化为大写金额 */
222 | export const digitUppercase = (n) => {
223 | const fraction = ["角", "分"];
224 | const digit = ["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"];
225 | const unit = [
226 | ["元", "万", "亿"],
227 | ["", "拾", "佰", "仟"],
228 | ];
229 | n = Math.abs(n);
230 | let s = "";
231 | for (let i = 0; i < fraction.length; i++) {
232 | s += (
233 | digit[Math.floor(n * 10 * Math.pow(10, i)) % 10] + fraction[i]
234 | ).replace(/零./, "");
235 | }
236 | s = s || "整";
237 | n = Math.floor(n);
238 | for (let i = 0; i < unit[0].length && n > 0; i++) {
239 | let p = "";
240 | for (let j = 0; j < unit[1].length && n > 0; j++) {
241 | p = digit[n % 10] + unit[1][j] + p;
242 | n = Math.floor(n / 10);
243 | }
244 | s = p.replace(/(零.)*零$/, "").replace(/^$/, "零") + unit[0][i] + s;
245 | }
246 | return s
247 | .replace(/(零.)*零元/, "元")
248 | .replace(/(零.)+/g, "零")
249 | .replace(/^整$/, "零元整");
250 | };
251 |
252 | /** 数字转化为中文数字 */
253 | export const intToChinese = (value) => {
254 | const str = String(value);
255 | const len = str.length - 1;
256 | const idxs = [
257 | "",
258 | "十",
259 | "百",
260 | "千",
261 | "万",
262 | "十",
263 | "百",
264 | "千",
265 | "亿",
266 | "十",
267 | "百",
268 | "千",
269 | "万",
270 | "十",
271 | "百",
272 | "千",
273 | "亿",
274 | ];
275 | const num = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"];
276 | return str.replace(/([1-9]|0+)/g, ($, $1, idx, full) => {
277 | let pos = 0;
278 | if ($1[0] !== "0") {
279 | pos = len - idx;
280 | if (idx == 0 && $1[0] == 1 && idxs[len - idx] == "十") {
281 | return idxs[len - idx];
282 | }
283 | return num[$1[0]] + idxs[len - idx];
284 | } else {
285 | let left = len - idx;
286 | let right = len - idx + $1.length;
287 | if (Math.floor(right / 4) - Math.floor(left / 4) > 0) {
288 | pos = left - (left % 4);
289 | }
290 | if (pos) {
291 | return idxs[pos] + num[$1[0]];
292 | } else if (idx + $1.length >= len) {
293 | return "";
294 | } else {
295 | return num[$1[0]];
296 | }
297 | }
298 | });
299 | };
300 |
301 | /**
302 | * 拆分整数和小数
303 | * @param tranvalue
304 | * @returns
305 | */
306 | export const splits = (tranvalue: string) => {
307 | let value = new Array("", "");
308 | const temp = tranvalue.split(".");
309 | for (var i = 0; i < temp.length; i++) {
310 | value = temp;
311 | }
312 | return value;
313 | };
314 |
--------------------------------------------------------------------------------
/src/utils/miniprogram.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codeluosiyu/toa-tools/99c0cf757eaa076a028324010c0254f780ab3743/src/utils/miniprogram.ts
--------------------------------------------------------------------------------
/src/utils/random/number.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 生成随机字符串(可指定长度)
3 | * @param len
4 | * @returns {string}
5 | */
6 | export const randomString = function (len) {
7 | len = len || 8;
8 | var $chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678";
9 | var maxPos = $chars.length;
10 | var pwd = "";
11 | for (var i = 0; i < len; i++) {
12 | pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
13 | }
14 | return pwd;
15 | };
16 |
17 | /**
18 | * 数组乱序
19 | * @param arr
20 | * @returns
21 | */
22 | export const shuffleArray = (arr) => {
23 | let m = arr.length;
24 | while (m > 1) {
25 | let index = Math.floor(Math.random() * m--);
26 | [arr[m], arr[index]] = [arr[index], arr[m]]
27 | }
28 | return arr;
29 | }
30 |
31 | /**
32 | * 切分数组
33 | * @param nums
34 | * @returns
35 | */
36 | export const splitArray = (nums) => {
37 | return bfs(nums, divide(nums));
38 | function bfs(nums, { factors, multiples }) {
39 | const n = nums.length;
40 | const steps = Array.from({ length: n + 1 }, () => Infinity);
41 | steps[0] = 0;
42 | let status: any = new Set([0]);
43 | while (status.size) {
44 | const status2 = new Set();
45 | for (const i of status) {
46 | const step = steps[i] + 1;
47 | for (const [factor, next] of factors[i]) {
48 | const multiple = multiples.get(factor);
49 | for (let j = next; j < multiple.length; j++) {
50 | const index = multiple[j] + 1;
51 | if (step < steps[index]) {
52 | steps[index] = step;
53 | if (index < n) status2.add(index);
54 | }
55 | }
56 | }
57 | }
58 | status = status2;
59 | }
60 | return steps[n];
61 | }
62 |
63 | function divide(nums) {
64 | const n = nums.length;
65 | const max = Math.max(...nums);
66 | const positions = new Map();
67 | for (let i = 0; i < n; i++) {
68 | const num = nums[i];
69 | if (!positions.has(num)) {
70 | positions.set(num, []);
71 | }
72 | positions.get(num).push(i);
73 | }
74 |
75 | const factors = Array.from({ length: n }, () => new Map());
76 | const multiples = new Map();
77 |
78 | const isPrimes = Array(max + 1).fill(true);
79 | isPrimes[0] = false;
80 | isPrimes[1] = false;
81 | for (let i = 2; i <= max; i++) {
82 | if (isPrimes[i]) {
83 | if (positions.has(i)) {
84 | for (const index of positions.get(i)) {
85 | addFactor(i, index);
86 | }
87 | }
88 | for (let j = i + i; j <= max; j += i) {
89 | isPrimes[j] = false;
90 | if (positions.has(j)) {
91 | for (const index of positions.get(j)) {
92 | addFactor(i, index);
93 | }
94 | }
95 | }
96 | if (multiples.has(i)) {
97 | multiples.get(i).sort((a, b) => a - b);
98 | }
99 | }
100 | }
101 | return { factors, multiples };
102 |
103 | function addFactor(factor, i) {
104 | if (!multiples.has(factor)) {
105 | multiples.set(factor, []);
106 | }
107 | factors[i].set(factor, multiples.get(factor).push(i) - 1);
108 | }
109 | }
110 | };
111 |
112 |
--------------------------------------------------------------------------------
/src/utils/string.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 字符串长度计算
3 | * @param str
4 | * @param countSpace
5 | * @returns
6 | */
7 | export const count = (str, countSpace = true) => {
8 | if (countSpace) {
9 | return str.length;
10 | }
11 | return removeAllSpace(str).length;
12 | };
13 |
14 | /**
15 | * 去除全部空格
16 | * @param str
17 | * @returns
18 | */
19 | export const removeAllSpace = (str) => {
20 | return str.replace(/\s+/g, "");
21 | };
22 |
23 | /**
24 | * 去除首尾空格
25 | * @param str
26 | * @returns
27 | */
28 | export const trim = (str) => {
29 | return str.trim();
30 | };
31 |
32 | /**
33 | * 去除左侧空格
34 | * @param str
35 | * @returns
36 | */
37 | export const trimL = (str) => {
38 | return str.replace(/^\s+/g, "");
39 | };
40 |
41 | /**
42 | * 去除右侧空格
43 | * @param str
44 | * @returns
45 | */
46 | export const trimR = (str) => {
47 | return str.replace(/\s+$/g, "");
48 | };
49 |
50 | /**
51 | * 字符串搜索
52 | * @param str
53 | * @param kwd
54 | * @param caseSensitive
55 | * @returns
56 | */
57 | export const search = (str, kwd, caseSensitive = true) => {
58 | if (!caseSensitive) {
59 | kwd = kwd.toLowerCase();
60 | str = str.toLowerCase();
61 | }
62 | return str.indexOf(kwd);
63 | };
64 |
65 | /**
66 | * 获取 扩展名
67 | * @param str
68 | * @returns
69 | */
70 | export const getExtension = (str) => {
71 | str = str.split(".");
72 | return str.pop();
73 | };
74 |
75 | /**
76 | * 全部替换
77 | * @param str
78 | * @param replaceKey
79 | * @param replaceVal
80 | * @returns
81 | */
82 | export const replaceAll = (str, replaceKey, replaceVal) => {
83 | var reg = new RegExp(replaceKey, 'g');
84 | return str.replace(reg, replaceVal || '');
85 | }
86 |
87 | /**
88 | * 均分数组
89 | * @param array
90 | * @param subGroupLength
91 | * @returns
92 | */
93 | export const averageArrGroup = (array, subGroupLength) => {
94 | let index = 0;
95 | let newArray = [];
96 | while (index < array.length) {
97 | newArray.push(array.slice(index, index += subGroupLength));
98 | }
99 | return newArray;
100 | }
101 |
102 | /**
103 | * toFixed修正版
104 | * @param number
105 | * @param m
106 | * @returns
107 | */
108 | export const toFixed = (number, m) => {
109 | if (typeof number !== 'number') {
110 | throw new Error("target is not a number");
111 | }
112 | let result = Math.round(Math.pow(10, m) * number) / Math.pow(10, m);
113 | result = String(result);
114 | if (result.indexOf(".") == -1) {
115 | if (m != 0) {
116 | result += ".";
117 | result += new Array(m + 1).join('0');
118 | }
119 | } else {
120 | let arr = result.split('.');
121 | if (arr[1].length < m) {
122 | arr[1] += new Array(m - arr[1].length + 1).join('0')
123 | }
124 | result = arr.join('.')
125 | }
126 | return result
127 | }
128 |
129 | /**
130 | * 判断字符串是否为json字符串
131 | * @param str
132 | * @returns
133 | */
134 | export const isJsonString = (str) => {
135 | try {
136 | if (typeof (JSON.parse(str)) === 'object') {
137 | return true
138 | }
139 | } catch (e) {
140 | return false
141 | }
142 | return false
143 | }
144 |
145 |
146 | /**
147 | * "Safer" String.toLowerCase()
148 | */
149 | function lowerCase(str) {
150 | return str.toLowerCase();
151 | }
152 |
153 | /**
154 | * "Safer" String.toUpperCase()
155 | */
156 | function upperCase(str) {
157 | return str.toUpperCase();
158 | }
159 |
160 | /**
161 | * Convert string to camelCase text.
162 | */
163 | function camelCase(str) {
164 | str = replaceAccents(str);
165 | str = removeNonWord(str)
166 | .replace(/\-/g, ' ') //convert all hyphens to spaces
167 | .replace(/\s[a-z]/g, upperCase) //convert first char of each word to UPPERCASE
168 | .replace(/\s+/g, '') //remove spaces
169 | .replace(/^[A-Z]/g, lowerCase); //convert first char to lowercase
170 | return str;
171 | }
172 |
173 | /**
174 | * Add space between camelCase text.
175 | */
176 | function unCamelCase(str) {
177 | str = str.replace(/([a-z\xE0-\xFF])([A-Z\xC0\xDF])/g, '$1 $2');
178 | str = str.toLowerCase(); //add space between camelCase text
179 | return str;
180 | }
181 |
182 | /**
183 | * UPPERCASE first char of each word.
184 | */
185 | function properCase(str) {
186 | return lowerCase(str).replace(/^\w|\s\w/g, upperCase);
187 | }
188 |
189 | /**
190 | * camelCase + UPPERCASE first char
191 | */
192 | function pascalCase(str) {
193 | return camelCase(str).replace(/^[a-z]/, upperCase);
194 | }
195 |
196 | function normalizeLineBreaks(str, lineEnd) {
197 | lineEnd = lineEnd || 'n';
198 |
199 | return str
200 | .replace(/rn/g, lineEnd) // DOS
201 | .replace(/r/g, lineEnd) // Mac
202 | .replace(/n/g, lineEnd); // Unix
203 | }
204 |
205 | /**
206 | * UPPERCASE first char of each sentence and lowercase other chars.
207 | */
208 | function sentenceCase(str) {
209 | // Replace first char of each sentence (new line or after '.\s+') to
210 | // UPPERCASE
211 | return lowerCase(str).replace(/(^\w)|\.\s+(\w)/gm, upperCase);
212 | }
213 |
214 | /**
215 | * Convert to lower case, remove accents, remove non-word chars and
216 | * replace spaces with the specified delimeter.
217 | * Does not split camelCase text.
218 | */
219 | function slugify(str, delimeter) {
220 | if (delimeter == null) {
221 | delimeter = "-";
222 | }
223 |
224 | str = replaceAccents(str);
225 | str = removeNonWord(str);
226 | str = trim(str) //should come after removeNonWord
227 | .replace(/ +/g, delimeter) //replace spaces with delimeter
228 | .toLowerCase();
229 |
230 | return str;
231 | }
232 |
233 | /**
234 | * Replaces spaces with hyphens, split camelCase text, remove non-word chars, remove accents and convert to lower case.
235 | */
236 | function hyphenate(str) {
237 | str = unCamelCase(str);
238 | return slugify(str, "-");
239 | }
240 |
241 | /**
242 | * Replaces hyphens with spaces. (only hyphens between word chars)
243 | */
244 | function unhyphenate(str) {
245 | return str.replace(/(\w)(-)(\w)/g, '$1 $3');
246 | }
247 |
248 | /**
249 | * Replaces spaces with underscores, split camelCase text, remove
250 | * non-word chars, remove accents and convert to lower case.
251 | */
252 | function underscore(str) {
253 | str = unCamelCase(str);
254 | return slugify(str, "_");
255 | }
256 |
257 | /**
258 | * Remove non-word chars.
259 | */
260 | function removeNonWord(str) {
261 | return str.replace(/[^0-9a-zA-Z\xC0-\xFF \-]/g, '');
262 | }
263 |
264 | /**
265 | * Convert line-breaks from DOS/MAC to a single standard (UNIX by default)
266 | */
267 | function normalizeLineBreaks(str, lineEnd) {
268 | lineEnd = lineEnd || '\n';
269 |
270 | return str
271 | .replace(/\r\n/g, lineEnd) // DOS
272 | .replace(/\r/g, lineEnd) // Mac
273 | .replace(/\n/g, lineEnd); // Unix
274 | }
275 |
276 | /**
277 | * Replaces all accented chars with regular ones
278 | */
279 | function replaceAccents(str) {
280 | // verifies if the String has accents and replace them
281 | if (str.search(/[\xC0-\xFF]/g) > -1) {
282 | str = str
283 | .replace(/[\xC0-\xC5]/g, "A")
284 | .replace(/[\xC6]/g, "AE")
285 | .replace(/[\xC7]/g, "C")
286 | .replace(/[\xC8-\xCB]/g, "E")
287 | .replace(/[\xCC-\xCF]/g, "I")
288 | .replace(/[\xD0]/g, "D")
289 | .replace(/[\xD1]/g, "N")
290 | .replace(/[\xD2-\xD6\xD8]/g, "O")
291 | .replace(/[\xD9-\xDC]/g, "U")
292 | .replace(/[\xDD]/g, "Y")
293 | .replace(/[\xDE]/g, "P")
294 | .replace(/[\xE0-\xE5]/g, "a")
295 | .replace(/[\xE6]/g, "ae")
296 | .replace(/[\xE7]/g, "c")
297 | .replace(/[\xE8-\xEB]/g, "e")
298 | .replace(/[\xEC-\xEF]/g, "i")
299 | .replace(/[\xF1]/g, "n")
300 | .replace(/[\xF2-\xF6\xF8]/g, "o")
301 | .replace(/[\xF9-\xFC]/g, "u")
302 | .replace(/[\xFE]/g, "p")
303 | .replace(/[\xFD\xFF]/g, "y");
304 | }
305 |
306 | return str;
307 | }
308 |
309 | /**
310 | * Searches for a given substring
311 | */
312 | function contains(str, substring, fromIndex) {
313 | return str.indexOf(substring, fromIndex) !== -1;
314 | }
315 |
316 | /**
317 | * Truncate string at full words.
318 | */
319 | function crop(str, maxChars, append) {
320 | return truncate(str, maxChars, append, true);
321 | }
322 |
323 | /**
324 | * Escape RegExp string chars.
325 | */
326 | function escapeRegExp(str) {
327 | var ESCAPE_CHARS = /[\\.+*?\^$\[\](){}\/'#]/g;
328 | return str.replace(ESCAPE_CHARS, '\\$&');
329 | }
330 |
331 | /**
332 | * Escapes a string for insertion into HTML.
333 | */
334 | function escapeHtml(str) {
335 | str = str
336 | .replace(/&/g, '&')
337 | .replace(//g, '>')
339 | .replace(/'/g, ''')
340 | .replace(/"/g, '"');
341 |
342 | return str;
343 | }
344 |
345 | /**
346 | * Unescapes HTML special chars
347 | */
348 | function unescapeHtml(str) {
349 | str = str
350 | .replace(/&/g, '&')
351 | .replace(/</g, '<')
352 | .replace(/>/g, '>')
353 | .replace(/'/g, "'")
354 | .replace(/"/g, '"');
355 | return str;
356 | }
357 |
358 | /**
359 | * Escape string into unicode sequences
360 | */
361 | function escapeUnicode(str, shouldEscapePrintable) {
362 | return str.replace(/[\s\S]/g, function (ch) {
363 | // skip printable ASCII chars if we should not escape them
364 | if (!shouldEscapePrintable && (/[\x20-\x7E]/).test(ch)) {
365 | return ch;
366 | }
367 | // we use "000" and slice(-4) for brevity, need to pad zeros,
368 | // unicode escape always have 4 chars after "\u"
369 | return '\\u' + ('000' + ch.charCodeAt(0).toString(16)).slice(-4);
370 | });
371 | }
372 |
373 | /**
374 | * Remove HTML tags from string.
375 | */
376 | function stripHtmlTags(str) {
377 | return str.replace(/<[^>]*>/g, '');
378 | }
379 |
380 | /**
381 | * Remove non-printable ASCII chars
382 | */
383 | function removeNonASCII(str) {
384 | // Matches non-printable ASCII chars -
385 | // http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters
386 | return str.replace(/[^\x20-\x7E]/g, '');
387 | }
388 |
389 | /**
390 | * String interpolation
391 | */
392 | function interpolate(template, replacements, syntax) {
393 | var stache = /\{\{(\w+)\}\}/g; //mustache-like
394 |
395 | var replaceFn = function (match, prop) {
396 | return (prop in replacements) ? replacements[prop] : '';
397 | };
398 |
399 | return template.replace(syntax || stache, replaceFn);
400 | }
401 |
402 | /**
403 | * Pad string with `char` if its' length is smaller than `minLen`
404 | */
405 | function rpad(str, minLen, ch) {
406 | ch = ch || ' ';
407 | return (str.length < minLen) ? str + repeat(ch, minLen - str.length) : str;
408 | }
409 |
410 | /**
411 | * Pad string with `char` if its' length is smaller than `minLen`
412 | */
413 | function lpad(str, minLen, ch) {
414 | ch = ch || ' ';
415 |
416 | return ((str.length < minLen)
417 | ? repeat(ch, minLen - str.length) + str : str);
418 | }
419 |
420 | /**
421 | * Repeat string n times
422 | */
423 | function repeat(str, n) {
424 | return (new Array(n + 1)).join(str);
425 | }
426 |
427 | /**
428 | * Limit number of chars.
429 | */
430 | function truncate(str, maxChars, append, onlyFullWords) {
431 | append = append || '...';
432 | maxChars = onlyFullWords ? maxChars + 1 : maxChars;
433 |
434 | str = trim(str);
435 | if (str.length <= maxChars) {
436 | return str;
437 | }
438 | str = str.substr(0, maxChars - append.length);
439 | //crop at last space or remove trailing whitespace
440 | str = onlyFullWords ? str.substr(0, str.lastIndexOf(' ')) : trim(str);
441 | return str + append;
442 | }
443 |
444 | var WHITE_SPACES = [
445 | ' ', '\n', '\r', '\t', '\f', '\v', '\u00A0', '\u1680', '\u180E',
446 | '\u2000', '\u2001', '\u2002', '\u2003', '\u2004', '\u2005', '\u2006',
447 | '\u2007', '\u2008', '\u2009', '\u200A', '\u2028', '\u2029', '\u202F',
448 | '\u205F', '\u3000'
449 | ];
450 |
451 | /**
452 | * Remove chars from beginning of string.
453 | */
454 | function ltrim(str, chars) {
455 | chars = chars || WHITE_SPACES;
456 |
457 | var start = 0,
458 | len = str.length,
459 | charLen = chars.length,
460 | found = true,
461 | i, c;
462 |
463 | while (found && start < len) {
464 | found = false;
465 | i = -1;
466 | c = str.charAt(start);
467 |
468 | while (++i < charLen) {
469 | if (c === chars[i]) {
470 | found = true;
471 | start++;
472 | break;
473 | }
474 | }
475 | }
476 |
477 | return (start >= len) ? '' : str.substr(start, len);
478 | }
479 |
480 | /**
481 | * Remove chars from end of string.
482 | */
483 | function rtrim(str, chars) {
484 | chars = chars || WHITE_SPACES;
485 |
486 | var end = str.length - 1,
487 | charLen = chars.length,
488 | found = true,
489 | i, c;
490 |
491 | while (found && end >= 0) {
492 | found = false;
493 | i = -1;
494 | c = str.charAt(end);
495 |
496 | while (++i < charLen) {
497 | if (c === chars[i]) {
498 | found = true;
499 | end--;
500 | break;
501 | }
502 | }
503 | }
504 |
505 | return (end >= 0) ? str.substring(0, end + 1) : '';
506 | }
507 |
508 | /**
509 | * Remove white-spaces from beginning and end of string.
510 | */
511 | function trim(str, chars) {
512 | chars = chars || WHITE_SPACES;
513 | return ltrim(rtrim(str, chars), chars);
514 | }
515 |
516 | /**
517 | * Capture all capital letters following a word boundary (in case the
518 | * input is in all caps)
519 | */
520 | function abbreviate(str) {
521 | return str.match(/\b([A-Z])/g).join('');
522 | }
523 |
--------------------------------------------------------------------------------
/src/utils/tree.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 扁平数据结构转Tree
3 | * @param items
4 | * @param childId
5 | * @param parentId
6 | * @returns
7 | */
8 | function arrayToTree(items, childId, parentId) {
9 | const result = [];
10 | const itemMap = {}; //
11 | for (const item of items) {
12 | const id = item[childId];
13 | const pid = item[parentId];
14 |
15 | if (!itemMap[id]) {
16 | itemMap[id] = {
17 | children: [],
18 | };
19 | }
20 |
21 | itemMap[id] = {
22 | ...item,
23 | children: itemMap[id]["children"],
24 | };
25 |
26 | const treeItem = itemMap[id];
27 |
28 | if (pid === 0) {
29 | result.push(treeItem);
30 | } else {
31 | if (!itemMap[pid]) {
32 | itemMap[pid] = {
33 | children: [],
34 | };
35 | }
36 | itemMap[pid].children.push(treeItem);
37 | }
38 | }
39 | return result;
40 | }
41 |
--------------------------------------------------------------------------------
/src/utils/url.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 获取所有URL参数 getAllUrlParams
3 | * @description: 把url参数 转换为json对象(但是# 后面的 都不会解析 ),所以在 Vue 中 history模式可以使用,但是 hash模式 他会返回一个空
4 | * @param {type} 路径 || 在页面或者组件里面调用,他会自己取的当前页面路径
5 | * @return {type} Object 注:无参数的时候,返回一个json
6 | */
7 | export function getAllUrlParams(url) {
8 | // 用JS拿到URL,如果函数接收了URL,那就用函数的参数。如果没传参,就使用当前页面的URL
9 | let queryString = url ? url.split("?")[1] : window.location.search.slice(1);
10 | // 用来存储我们所有的参数
11 | let obj = {};
12 | // 如果没有传参,返回一个空对象
13 | if (!queryString) {
14 | return obj;
15 | }
16 | // #后面的东西不是查询字符串的一部分,所以去掉它
17 | queryString = queryString.split("#")[0];
18 | // 将参数分成数组
19 | let arr = queryString.split("&");
20 | for (let i = 0; i < arr.length; i++) {
21 | // 分离成key:value的形式
22 | let a = arr[i].split("=");
23 | // 将undefined标记为true
24 | let paramName = a[0];
25 | let paramValue = typeof a[1] === "undefined" ? true : a[1];
26 | // 如果调用对象时要求大小写区分,可删除这两行代码
27 | paramName = paramName.toLowerCase();
28 | if (typeof paramValue === "string") paramValue = paramValue.toLowerCase();
29 | // 如果paramName以方括号结束, e.g. colors[] or colors[2]
30 | if (paramName.match(/[(\d+)?]$/)) {
31 | // 如果paramName不存在,则创建key
32 | let key = paramName.replace(/[(\d+)?]/, "");
33 | if (!obj[key]) obj[key] = [];
34 | // 如果是索引数组 e.g. colors[2]
35 | if (paramName.match(/[\d+]$/)) {
36 | // 获取索引值并在对应的位置添加值
37 | let index = /[(\d+)]/.exec(paramName)[1];
38 | obj[key][index] = paramValue;
39 | } else {
40 | // 如果是其它的类型,也放到数组中
41 | obj[key].push(paramValue);
42 | }
43 | } else {
44 | // 处理字符串类型
45 | if (!obj[paramName]) {
46 | // 如果如果paramName不存在,则创建对象的属性
47 | obj[paramName] = paramValue;
48 | } else if (obj[paramName] && typeof obj[paramName] === "string") {
49 | // 如果属性存在,并且是个字符串,那么就转换为数组
50 | obj[paramName] = [obj[paramName]];
51 | obj[paramName].push(paramValue);
52 | } else {
53 | // 如果是其它的类型,还是往数组里丢
54 | obj[paramName].push(paramValue);
55 | }
56 | }
57 | }
58 | return obj;
59 | }
60 |
61 | /**
62 | * parseQueryString
63 | * @description: 这个所有模式下 都可以使用,他会 取得 ? 号后面的 所有内容
64 | * @param {type} 路径 || 在页面或者组件里面调用,他会自己取的当前页面路径
65 | * @return {type} Object 注:无参数的时候,返回一个空json
66 | */
67 | export function parseQueryString(url) {
68 | let queryString = url ? url.split("?")[1] : window.location.href;
69 | let obj = {};
70 | //这个 去查找是否,传了参数过来
71 | if (queryString.indexOf("?") === -1) {
72 | return obj;
73 | }
74 | let keyvalue = [];
75 | let key = "",
76 | value = "";
77 | let paraString = queryString
78 | .substring(queryString.indexOf("?") + 1, queryString.length)
79 | .split("&");
80 | for (let i in paraString) {
81 | keyvalue = paraString[i].split("=");
82 | key = keyvalue[0];
83 | value = keyvalue[1];
84 | obj[key] = value;
85 | }
86 | return obj;
87 | }
88 |
89 | /**
90 | * 修改url中的参数
91 | * @param { string } paramName
92 | * @param { string } replaceWith
93 | */
94 | export function replaceParamVal(paramName: string, replaceWith: any) {
95 | var oUrl = location.href.toString();
96 | var re = eval("/(" + paramName + "=)([^&]*)/gi");
97 | location.href = oUrl.replace(re, paramName + "=" + replaceWith);
98 | return location.href;
99 | }
100 |
101 | /**
102 | * 删除url中指定的参数
103 | * @param { string } name
104 | */
105 | export function funcUrlDel(name: string) {
106 | var loca = location;
107 | var baseUrl = loca.origin + loca.pathname + "?";
108 | var query = loca.search.substr(1);
109 | if (query.indexOf(name) > -1) {
110 | var obj = {};
111 | var arr: Array = query.split("&");
112 | for (var i = 0; i < arr.length; i++) {
113 | arr[i] = arr[i].split("=");
114 | obj[arr[i][0]] = arr[i][1];
115 | }
116 | delete obj[name];
117 | var url =
118 | baseUrl +
119 | JSON.stringify(obj)
120 | .replace(/[\"\{\}]/g, "")
121 | .replace(/\:/g, "=")
122 | .replace(/\,/g, "&");
123 | return url;
124 | }
125 | }
126 |
127 | /**
128 | * 解析页面URL参数params(并处理 decodeURIComponent )
129 | * @param name
130 | * @returns
131 | */
132 | export const delUrlParam = (name: string) => {
133 | let loca = window.location;
134 | let baseUrl = loca.origin + loca.pathname + "?";
135 | let query = decodeURIComponent(loca.search.split("?")[1]);
136 | if (!query) return loca;
137 |
138 | if (loca.href.indexOf(name) < 0) return loca.href;
139 |
140 | let obj = {};
141 | let arr: any = query.indexOf("&") > -1 ? query.split("&") : [query];
142 | for (let i = 0; i < arr.length; i++) {
143 | arr[i] = arr[i].split("=");
144 | obj[arr[i][0]] = arr[i][1];
145 | }
146 | delete obj[name];
147 |
148 | const url =
149 | baseUrl +
150 | JSON.stringify(obj)
151 | .replace(/[\"\{\}]/g, "")
152 | .replace(/\:/g, "=")
153 | .replace(/\,/g, "&");
154 | return url;
155 | };
156 |
157 | /**
158 | * URLSearchParams
159 | * @param url String 可选参数, url地址
160 | * @param OneKey String 可选参数, 获取当前网址指定参数
161 | * @param Delete_key Array 可选参数, 过滤指定参数
162 | * @returns
163 | */
164 | export const getUrlData = function (url, OneKey, Delete_key = []) {
165 | if (!url) url = window.location.search;
166 | var url_l = url.split("?")[1];
167 | var url_ll = url_l.split("&"),
168 | obj = {};
169 | url_ll.forEach((item, idx) => {
170 | var key = item.split("=")[0];
171 | var val = item.split("=")[1];
172 | if (Delete_key.indexOf(key) == -1) obj[key] = val;
173 | });
174 | if (OneKey && url_l.indexOf(OneKey)) return obj[OneKey];
175 | return obj;
176 | };
177 |
178 | /**
179 | * 获取单个参数
180 | * @param {String} name
181 | * @param {String} url [default:location.href]
182 | * @return {String|Boolean}
183 | */
184 | export const getParam = (name, url) => {
185 | if (typeof name !== "string") return false;
186 | if (!url) url = window.location.href;
187 | // 当遇到name[xx]时,对方括号做一下转义为 name\[xxx\],因为下面还需要使用name做正则
188 | name = name.replace(/[\[\]]/g, "\\$&");
189 | var regex = new RegExp("[?&]" + name + "(=([^]*)|&|#|$)");
190 | var results = regex.exec(url);
191 | if (!results) return null;
192 | if (!results[2]) return "";
193 | return decodeURIComponent(results[2].replace(/\+/g, " "));
194 | };
195 |
196 | /**
197 | * 设置单个参数
198 | * @param name
199 | * @param val
200 | * @param url
201 | * @returns
202 | */
203 | export const setParam = (name, val, url) => {
204 | if (typeof name !== "string") return false;
205 | if (!url) url = window.location.href;
206 | var _name = name.replace(/[\[\]]/g, "\\$&");
207 | var value = name + "=" + encodeURIComponent(val);
208 | var regex = new RegExp(_name + "=[^&]*");
209 | var urlArr = url.split("#");
210 | var result = "";
211 |
212 | if (regex.exec(url)) {
213 | result = url.replace(regex, value);
214 | } else {
215 | result = urlArr[0] + "&" + value + (urlArr[1] || "");
216 | }
217 |
218 | return result;
219 | };
220 |
221 | /**
222 | * 移除单个参数
223 | * @param name
224 | * @param url
225 | * @returns
226 | */
227 | export const removeParam = (name, url) => {
228 | if (typeof name !== "string") return false;
229 | if (!url) url = window.location.href;
230 | var urlparts = url.split("?");
231 | var prefix = encodeURIComponent(name + "=");
232 | var pars = urlparts[1].split(/[&;]/g);
233 | var i = 0,
234 | len = pars.length;
235 |
236 | for (; i < len; i++) {
237 | if (encodeURIComponent(pars[i]).lastIndexOf(prefix, 0) !== -1) {
238 | pars.splice(i, 1);
239 | }
240 | }
241 |
242 | url = urlparts[0] + (pars.length > 0 ? "?" + pars.join("&") : "");
243 |
244 | return url;
245 | };
246 |
247 | /**
248 | * 获取多个参数
249 | * @param {String} names
250 | * @param {String} url
251 | * @return {[String|Boolean]}
252 | */
253 | export const getParams = (names, url) => {
254 | if (typeof name !== "string") return false;
255 | var names = names.split(" ");
256 | var result = {};
257 | var i = 0,
258 | len = names.length;
259 | if (names.length === 0) return false;
260 | for (; i < len; i++) {
261 | result[names[i]] = getParam(names[i], url);
262 | }
263 | return result;
264 | };
265 |
266 | /**
267 | * 设置多个参数
268 | * @param {Object} obj
269 | * @param {String} url
270 | * @return {[String|Boolean]}
271 | */
272 | export const setParams = (obj, url) => {
273 | var result = url || "";
274 | if (Object.prototype.toString.call(obj) !== "[object Object]") return false;
275 | for (var name in obj) {
276 | result = setParam(name, obj[name], result);
277 | }
278 | return result;
279 | };
280 |
281 | /**
282 | * 移除多个参数
283 | * @param {String} names
284 | * @param {String} url
285 | * @return {[String|Boolean]}
286 | */
287 | export const removeParams = (names, url) => {
288 | var result = url || "";
289 | var names = names.split(" ");
290 | var i = 0,
291 | len = names.length;
292 | if (names.length === 0) return false;
293 |
294 | for (; i < len; i++) {
295 | result = removeParam(names[i], result);
296 | }
297 | return result;
298 | };
299 |
--------------------------------------------------------------------------------
/src/utils/verification.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 过滤表情
3 | * @param name
4 | * @returns
5 | */
6 | export const filterEmoji = (name) => {
7 | const str = name.replace(
8 | /[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF][\u200D|\uFE0F]|[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF]|[0-9|*|#]\uFE0F\u20E3|[0-9|#]\u20E3|[\u203C-\u3299]\uFE0F\u200D|[\u203C-\u3299]\uFE0F|[\u2122-\u2B55]|\u303D|[\A9|\AE]\u3030|\uA9|\uAE|\u3030/gi,
9 | ""
10 | );
11 | return str;
12 | };
13 |
14 | /**
15 | * 过滤税号
16 | * @param num
17 | * @returns
18 | */
19 | export const isNumber = (num: string) =>
20 | /^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$/.test(num);
21 |
22 | /**
23 | * 验证手机号
24 | * @param phone
25 | * @returns
26 | */
27 | export const isPhone = (phone: any) => /^[1][0-9]{10}$/.test(phone);
28 |
29 | /**
30 | * 验证邮箱
31 | * @param email
32 | * @returns
33 | */
34 | export const isEmail = (email: string) =>
35 | /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/.test(
36 | email
37 | );
38 |
39 | /**
40 | * 验证是否存在特殊符号或者表情
41 | * @param value
42 | * @param tips
43 | * @returns
44 | */
45 | export const hasEmoji = function (value: string, tips = "") {
46 | let char =
47 | /[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF][\u200D|\uFE0F]|[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF]|[0-9|*|#]\uFE0F\u20E3|[0-9|#]\u20E3|[\u203C-\u3299]\uFE0F\u200D|[\u203C-\u3299]\uFE0F|[\u2122-\u2B55]|\u303D|[\A9|\AE]\u3030|\uA9|\uAE|\u3030/gi;
48 | if (char.test(value)) {
49 | return true;
50 | }
51 | return false;
52 | };
53 |
54 | /**
55 | * 获取数组索引值
56 | * @param param0
57 | * @returns
58 | */
59 | export const getIndexArr = function ({
60 | id = "",
61 | productTree = [],
62 | idKey = "id",
63 | childrenKey = "child",
64 | }: {
65 | id: string;
66 | productTree?: Array;
67 | idKey?: string;
68 | childrenKey?: string;
69 | }) {
70 | let indexArr: number[] = [];
71 | let fn: (arr: Array) => boolean = (arr) =>
72 | arr.some((elem: any, index) => {
73 | if (elem[idKey] == id) {
74 | indexArr.push(index);
75 | return true;
76 | } else if (
77 | elem[childrenKey] &&
78 | elem[childrenKey] instanceof Array &&
79 | elem[childrenKey].length
80 | ) {
81 | return fn(elem[childrenKey]) && indexArr.push(index);
82 | }
83 | return false;
84 | });
85 | fn(productTree);
86 | indexArr.reverse();
87 | return indexArr;
88 | };
89 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowUnreachableCode": true, // 不报告执行不到的代码错误。
4 | "allowUnusedLabels": false, // 不报告未使用的标签错误
5 | "alwaysStrict": false, // 以严格模式解析并为每个源文件生成 "use strict"语句
6 | "baseUrl": ".", // 工作根目录
7 | "experimentalDecorators": true, // 启用实验性的ES装饰器
8 | "jsx": "react", // 在 .tsx文件里支持JSX
9 | "sourceMap": true, // 是否生成map文件
10 | "module": "ES2015", // 指定生成哪个模块系统代码
11 | "noImplicitAny": false, // 是否默认禁用 any
12 | "removeComments": true, // 是否移除注释
13 | "target": "ESNext", // 编译的目标是什么版本的
14 | "outDir": "./dist", // 输出目录
15 | "declaration": true, // 是否自动创建类型声明文件
16 | "declarationDir": "./ts/lib", // 类型声明文件的输出目录
17 | "allowJs": true, // 允许编译javascript文件。
18 | "moduleResolution": "node",
19 | "allowSyntheticDefaultImports": true,
20 | "lib": [ // 编译过程中需要引入的库文件的列表
21 | "es5",
22 | "es2015",
23 | "es2016",
24 | "es2017",
25 | "es2018",
26 | "dom"
27 | ]
28 | },
29 | // 指定一个匹配列表(属于自动指定该路径下的所有ts相关文件)
30 | "include": [
31 | "src/**/*"
32 | ],
33 | // 指定一个排除列表(include的反向操作)
34 | "exclude": [
35 | "node_modules",
36 | "dist"
37 | ]
38 | }
39 |
--------------------------------------------------------------------------------
/types/index.d.ts:
--------------------------------------------------------------------------------
1 | declare module "toa-tools" {
2 | export const loading: {
3 | show: (options?: {
4 | content?: string;
5 | isShowCancel?: boolean;
6 | needMask?: boolean;
7 | }) => void;
8 | hide: () => void;
9 | };
10 | export const appVersion: () => string;
11 | export const isInApp: () => boolean;
12 | export const isInWechat: () => boolean;
13 | export const isInWechatH5: () => boolean;
14 | export const isInWechatMp: () => boolean;
15 | export const isInQuickApp: () => boolean;
16 | export const isInBaiDu: () => boolean;
17 | export const isInToutiao: () => boolean;
18 | export const isInAlipay: () => boolean;
19 | export const isInAlipayH5: () => boolean;
20 | export const isInAlipayMp: () => boolean;
21 | export const isInQQ: () => boolean;
22 | export const isInIOS: () => boolean;
23 | export const isIPhoneXSeries: () => boolean;
24 | export const isInCtApp: () => boolean;
25 | export const isInCtWeb: () => boolean;
26 | export const isInZhixingApp: () => boolean;
27 | export const getEnvByHost: () => string;
28 | export const jump: (arg0: string | object) => void;
29 | export const back: () => {};
30 | export const getQuery: (arg0: string, arg1?: boolean) => string;
31 | export const getQueryAll: () => object;
32 | export const url: {
33 | dirname: () => string;
34 | basename: () => string;
35 | filename: () => string;
36 | };
37 | export const isLogin: () => boolean;
38 | export const forceLogin: (options?: {
39 | env?: string;
40 | from?: string;
41 | backUrl?: string;
42 | dynamic?: boolean;
43 | appCallback?: () => void;
44 | }) => void;
45 | export const login: (
46 | callback?: () => void,
47 | options?: {
48 | env?: string;
49 | from?: string;
50 | backUrl?: string;
51 | dynamic?: boolean;
52 | appCallback?: () => void;
53 | }
54 | ) => void;
55 | export const setShare: (
56 | options: {
57 | appType?: any[];
58 | icon?: string;
59 | title?: string;
60 | desc?: string;
61 | href?: string;
62 | image?: string;
63 | wechatMp?: string | object;
64 | quickApp?: string;
65 | baidu?: string;
66 | toutiao?: string;
67 | alipayMp?: string;
68 | qq?: string;
69 | miniProgramID?: string;
70 | },
71 | success?: () => void,
72 | cancel?: () => void
73 | ) => any;
74 | export const callOneShare: (
75 | options: {
76 | type?: string;
77 | icon?: string;
78 | title?: string;
79 | desc?: string;
80 | href?: string;
81 | image?: string;
82 | wechatMp?: string;
83 | },
84 | success?: () => void,
85 | cancel?: () => void
86 | ) => void;
87 | export const wechatReady: (callback?: (wx: object) => void) => void;
88 | export const quickAppReady: (callback?: (qa: object) => void) => void;
89 | export const baiduReady: (callback?: (swan: object) => void) => void;
90 | export const toutiaoReady: (callback?: (tt: object) => void) => void;
91 | export const alipayReady: (callback?: (my: object) => void) => void;
92 | export const qqReady: (callback?: (qq: object) => void) => void;
93 | export const openWechatMp: (options: { path: string }) => void;
94 | export const setTitle: (title?: string) => void;
95 | export const setNavBar: (options: { hide?: boolean; color?: string }) => void;
96 | export const getWechatUserInfo: (
97 | callback?: (userInfo: object) => void
98 | ) => void;
99 | export const activateApp: (
100 | url?: string,
101 | downloadApp?: boolean,
102 | callback?: () => void
103 | ) => void;
104 | export const getUnion: () => object;
105 | export const getRmsToken: (callback?: (rmsToken) => void) => void;
106 | export const pay: (options: object) => void;
107 | export const pay2: (options: object) => void;
108 | export const localStorage: {
109 | setItem: (
110 | key: string,
111 | value: string | number | object,
112 | timeout: number
113 | ) => void;
114 | getItem: (key: string) => string | object;
115 | removeItem: (key: string) => void;
116 | };
117 | export const sessionStorage: {
118 | setItem: (key: string, value: string | number | object) => void;
119 | getItem: (key: string) => string | object;
120 | removeItem: (key: string) => void;
121 | };
122 | export const app: {
123 | on: (key: string, callback: (...args) => void) => void;
124 | off: (key: string) => void;
125 | };
126 | export const on: (key: string, callback: (...args) => void) => void;
127 | export const emit: (key: string, ...args) => void;
128 | export const off: (key: string) => void;
129 | export const $: () => any;
130 | export const debounce: (
131 | func: () => void,
132 | wait: number,
133 | immediate?: boolean
134 | ) => any;
135 | export const throttle: (
136 | func: () => void,
137 | wait: number,
138 | options?: {
139 | leading?: boolean;
140 | trailing?: boolean;
141 | }
142 | ) => any;
143 |
144 | // server methods
145 | export const version: () => string;
146 | export const isString: () => boolean;
147 | export const isNumber: () => boolean;
148 | export const isArray: () => boolean;
149 | export const isObject: () => boolean;
150 | export const isFunction: () => boolean;
151 | export const isUndefined: () => boolean;
152 | export const isServer: () => boolean;
153 | export const isClient: () => boolean;
154 | export const getGateway: (config: {
155 | req?: object;
156 | env?: string;
157 | code?: string;
158 | name?: string;
159 | }) => string;
160 | export const model: (
161 | code: string | object,
162 | name?: string,
163 | body?: object,
164 | req?: object,
165 | env?: string
166 | ) => Promise;
167 | export const modelSet: (params: object) => void;
168 | export const modelLog: (callback: () => void, keepOne?: boolean) => void;
169 | export const CModel: (config?: object) => any;
170 | export const base64: {
171 | encode: (arg0: string) => void;
172 | decode: (arg0: string) => void;
173 | };
174 | export const time2Date: (time?: number, type?: string) => string;
175 | export const date2Time: (date?: string) => number;
176 | export const formatDate: (arg0: T) => T;
177 | export const formatQuery: (arg0: object) => string;
178 | export const randomInt: (lower: number, upper: number) => number;
179 | }
180 |
--------------------------------------------------------------------------------