rx-util

rxliuli 在浏览器上使用的 js 工具集

当前为 2019-04-22 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/382120/691633/rx-util.js

  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  3. typeof define === 'function' && define.amd ? define(['exports'], factory) :
  4. (global = global || self, factory(global.rx = {}));
  5. }(this, function (exports) { 'use strict';
  6.  
  7. /**
  8. * 在浏览器上下载二进制资源
  9. * @param {Blob} blob 要下载的二进制资源
  10. * @param {String} filename 文件名
  11. */
  12. function download (blob, filename = 'unknown') {
  13. // 创建隐藏的可下载链接
  14. const eleLink = document.createElement('a');
  15. eleLink.download = filename;
  16. eleLink.style.display = 'none';
  17. // 为 link 赋值
  18. eleLink.href = URL.createObjectURL(blob);
  19. // 触发点击
  20. document.body.appendChild(eleLink);
  21. eleLink.click();
  22. // 然后移除
  23. document.body.removeChild(eleLink);
  24. }
  25.  
  26. /**
  27. * 在浏览器上下载文本内容
  28. * @param {String} str 字符串内容
  29. * @param {String} [filename='unknown.txt'] 下载文件名,没有则默认为链接中的文件名
  30. */
  31. async function downloadString (str, filename = 'unknown.txt') {
  32. const blob = new Blob([str], {
  33. type: 'text/plain'
  34. });
  35. download(blob, filename);
  36. }
  37.  
  38. /**
  39. * 根据 url 下载二进制资源
  40. * @param {String} url 下载请求信息
  41. * @param {String} [filename] 下载文件名,没有则默认为链接中的文件名
  42. */
  43. async function downloadUrl (
  44. url,
  45. filename = url.substr(url.lastIndexOf('/'))
  46. ) {
  47. try {
  48. const res = await fetch(url);
  49. const blob = await res.blob();
  50. download(blob, filename);
  51. } catch (error) {
  52. return console.log('下载出错了 ', error)
  53. }
  54. }
  55.  
  56. /**
  57. * 获取 cookie 键值映射 Map
  58. * @returns {Map.<String,String>} cookie 键值映射 Map
  59. */
  60. function getCookies () {
  61. return document.cookie
  62. .split(';')
  63. .map(str => str.split('='))
  64. .map(arr => [arr[0].trim(), arr[1].trim()])
  65. .reduce((res, [k, v]) => res.set(k, v), new Map())
  66. }
  67.  
  68. /**
  69. * 将 url 中的内容加载到元素上
  70. * 注:domSelector 必须有 src 属性用以将加载完成的资源赋值给其,加载默认是异步的
  71. * @param {RequestInfo} url url 资源
  72. * @param {HTMLImageElement | HTMLAudioElement | HTMLVideoElement | HTMLTrackElement | HTMLScriptElement} dom dom 元素
  73. * @param {RequestInit} [init] 初始化参数, 实为 fetch() 的参数以及一些自定义的参数,默认 {}
  74. * 关于 fetch 具体可以参考 <https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch>
  75. */
  76. async function loadResource (url, dom, init = {}) {
  77. const res = await fetch(url, init);
  78. const blob = await res.blob();
  79. // 生成一个本地的 url 并赋值给 src 属性
  80. dom.src = window.URL.createObjectURL(blob);
  81. }
  82.  
  83. /**
  84. * Url 对象
  85. * @class UrlObject
  86. */
  87. class UrlObject {
  88. /**
  89. * 构造函数
  90. * @param {Object} option 可选项
  91. * @param {String} [option.href=''] 不包含网站域名的链接
  92. * @param {String} [option.website=''] URL 站点
  93. * @param {String} [option.protocol=''] 协议
  94. * @param {String} [option.domain=''] 域名
  95. * @param {String} [option.accessPath=''] 绝对路径,不包含参数
  96. * @param {Object} [option.params={}] 参数列表,
  97. * @param {String} [option.url=''] 原 url 链接
  98. * @param {Number} [option.port=0] 端口号
  99. */
  100. constructor ({
  101. href = '',
  102. website = '',
  103. protocol = '',
  104. domain = '',
  105. accessPath = '',
  106. params = {},
  107. url = '',
  108. port = 0
  109. } = {}) {
  110. /**
  111. * @type {String} 不包含网站域名的链接
  112. */
  113. this.href = href;
  114. /**
  115. * @type {String} URL 站点
  116. */
  117. this.website = website;
  118. /**
  119. * @type {String} 协议
  120. */
  121. this.protocol = protocol;
  122. /**
  123. * @type {String} 域名
  124. */
  125. this.domain = domain;
  126. /**
  127. * @type {String} 绝对路径,不包含参数
  128. */
  129. this.accessPath = accessPath;
  130. /**
  131. * @type {Object} 参数列表,
  132. */
  133. this.params = params;
  134. /**
  135. * @type {String} 原 url 链接
  136. */
  137. this.url = url;
  138. /**
  139. * @type {Number} 端口号
  140. */
  141. this.port = port;
  142. }
  143. }
  144.  
  145. /**
  146. * 协议与默认端口映射表
  147. */
  148. const protocol2Port = {
  149. http: 80,
  150. https: 443,
  151. ssh: 22,
  152. ftp: 21
  153. };
  154.  
  155. /**
  156. * 解析 url 字符串
  157. * @param {String} url url 字符串,不能为空
  158. * @returns {UrlObject} url 对象
  159. */
  160. function parseUrl (url) {
  161. if (!url) {
  162. throw new Error('url 不能为空')
  163. }
  164.  
  165. const regexp = new RegExp('^((\\w+)://([\\w\\.]*)(:(\\d+))?)(.*)');
  166. const temps = regexp.exec(url);
  167. const res = new UrlObject({
  168. url: url,
  169. website: temps[1],
  170. protocol: temps[2],
  171. domain: temps[3],
  172. // @ts-ignore
  173. port: temps[5],
  174. href: temps[6]
  175. });
  176. let temp = url.substr(res.website.length);
  177. const markIndex = temp.indexOf('?');
  178. if (markIndex === -1) {
  179. res.accessPath = temp;
  180. return res
  181. }
  182. res.accessPath = temp.substr(0, markIndex);
  183. if (res.accessPath.endsWith('/')) {
  184. res.accessPath = res.accessPath.substring(0, res.accessPath.length - 1);
  185. }
  186. res.port = res.port || protocol2Port[res.protocol] || '';
  187. // 解析参数列表
  188. res.params = temp
  189. .substr(markIndex + 1)
  190. .split('&')
  191. .map(str => str.split('='))
  192. .filter(arr => arr[0] !== '')
  193. .reduce((params, arr) => {
  194. const k = decodeURIComponent(arr[0]);
  195. const v = decodeURIComponent(arr.length === 1 ? '' : arr[1]);
  196. // 如果已经存在了就认为是数组参数
  197. const vs = params[k];
  198. if (vs !== undefined) {
  199. if (!Array.isArray(vs)) {
  200. params[k] = [vs];
  201. }
  202. params[k].push(v);
  203. } else {
  204. params[k] = v;
  205. }
  206. return params
  207. }, {});
  208. return res
  209. }
  210.  
  211. /**
  212. * 读取本地浏览器选择的文件
  213. * @param {File} file 选择的文件
  214. * @param {Object} option 可选项参数
  215. * @param { readLocal.DataURL | readLocal.Text | readLocal.BinaryString | readLocal.ArrayBuffer } [option.type=readLocal.DataURL] 读取的类型,默认按照二进制 url 读取
  216. * @param {String} [option.encoding='UTF-8'] 读取的编码格式,默认为 UTF-8
  217. * @returns {Promise} 返回了读取到的内容(异步)
  218. */
  219. function readLocal (
  220. file,
  221. { type = readLocal.DataURL, encoding = 'UTF-8' } = {}
  222. ) {
  223. return new Promise((resolve, reject) => {
  224. if (!file) {
  225. reject(new Error('file not exists'));
  226. }
  227. const fr = new FileReader();
  228. fr.onload = event => {
  229. // @ts-ignore
  230. resolve(event.target.result);
  231. };
  232. fr.onerror = error => {
  233. reject(error);
  234. };
  235. fr[type](file, encoding);
  236. })
  237. }
  238. readLocal.DataURL = 'readAsDataURL';
  239. readLocal.Text = 'readAsText';
  240. readLocal.BinaryString = 'readAsBinaryString';
  241. readLocal.ArrayBuffer = 'readAsArrayBuffer';
  242.  
  243. /**
  244. * 为 js 中的 Date 对象原型添加 format 格式化方法
  245. * @param {Date} date 要进行格式化的日期
  246. * @param {String} fmt 日期的格式
  247. * @returns {String} 格式化得到的结果
  248. */
  249. function dateFormat (date, fmt) {
  250. var o = {
  251. 'y+': date.getFullYear(),
  252. 'M+': date.getMonth() + 1, // 月份
  253. 'd+': date.getDate(), // 日
  254. 'h+': date.getHours(), // 小时
  255. 'm+': date.getMinutes(), // 分
  256. 's+': date.getSeconds(), // 秒
  257. 'q+': Math.floor((date.getMonth() + 3) / 3), // 季度
  258. 'S+': date.getMilliseconds() // 毫秒
  259. };
  260. for (var k in o) {
  261. if (!new RegExp('(' + k + ')').test(fmt)) {
  262. continue
  263. }
  264. if (k === 'y+') {
  265. fmt = fmt.replace(RegExp.$1, ('' + o[k]).substr(4 - RegExp.$1.length));
  266. } else if (k === 'S+') {
  267. var lens = RegExp.$1.length;
  268. lens = lens === 1 ? 3 : lens;
  269. fmt = fmt.replace(
  270. RegExp.$1,
  271. ('00' + o[k]).substr(('' + o[k]).length - 1, lens)
  272. );
  273. } else {
  274. fmt = fmt.replace(
  275. RegExp.$1,
  276. RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
  277. );
  278. }
  279. }
  280. return fmt
  281. }
  282.  
  283. /**
  284. * 默认的日期格式
  285. * 不加 Z 为本地日期时间
  286. */
  287. const deteFormatter = 'yyyy-MM-ddThh:mm:ss.SSS';
  288. /**
  289. * 编码函数
  290. * @param {String} k 参数的名字
  291. * @param {String} v 参数的值
  292. */
  293. const encode = (k, v) => encodeURIComponent(k) + '=' + encodeURIComponent(v);
  294.  
  295. /**
  296. * 拼接参数字符串
  297. * @param {Object} params 参数对象
  298. * @returns {String} 拼接后的字符串
  299. */
  300. function spliceParams (params = {}) {
  301. if (!(params instanceof Object)) {
  302. throw new Error(`The parameter type must be Object: ${params}`)
  303. }
  304. return Array.from(Object.entries(params)).reduce((res, [k, v]) => {
  305. if (v === undefined || v === null) {
  306. return res
  307. } else if (v instanceof Date) {
  308. res += encode(k, dateFormat(v, deteFormatter));
  309. } else if (v instanceof Array) {
  310. res += v
  311. .map(item =>
  312. encode(
  313. k,
  314. item instanceof Date ? dateFormat(item, deteFormatter) : item
  315. )
  316. )
  317. .join('&');
  318. } else {
  319. res += encode(k, v);
  320. }
  321. return (res += '&')
  322. }, '')
  323. }
  324.  
  325. /**
  326. * 为 fetch 请求添加超时选项
  327. * 注:超时选项并非真正意义上的超时即取消请求,请求依旧正常执行完成,但会提前返回 reject 结果
  328. * @param {Promise} fetchPromise fetch 请求的 Promise
  329. * @param {Number} timeout 超时时间
  330. * @returns {Promise} 如果超时就提前返回 reject, 否则正常返回 fetch 结果
  331. */
  332. function fetchTimeout (fetchPromise, timeout) {
  333. var abortFn = null;
  334. // 这是一个可以被 reject 的 Promise
  335. var abortPromise = new Promise(function (resolve, reject) {
  336. abortFn = function () {
  337. reject(new Error('abort promise'));
  338. };
  339. });
  340. // 有一个 Promise 完成就立刻结束
  341. var abortablePromise = Promise.race([fetchPromise, abortPromise]);
  342. setTimeout(function () {
  343. abortFn();
  344. }, timeout);
  345. return abortablePromise
  346. }
  347.  
  348. /**
  349. * 将字符串转为字符流
  350. *
  351. * @param {String} str 字符串
  352. * @returns {ArrayBuffer} 字符流对象
  353. */
  354. function strToArrayBuffer (str) {
  355. const buf = new ArrayBuffer(str.length);
  356. const view = new Uint8Array(buf);
  357. for (let i = 0; i !== str.length; ++i) {
  358. view[i] = str.charCodeAt(i) & 0xff;
  359. }
  360. return buf
  361. }
  362.  
  363. /**
  364. * 等待指定的时间/等待指定表达式成立
  365. * 如果未指定等待条件则立刻执行
  366. * @param {Number|Function} [param] 等待时间/等待条件
  367. * @returns {Promise} Promise 对象
  368. */
  369. const wait = param => {
  370. return new Promise(resolve => {
  371. if (typeof param === 'number') {
  372. setTimeout(resolve, param);
  373. } else if (typeof param === 'function') {
  374. var timer = setInterval(() => {
  375. if (param()) {
  376. clearInterval(timer);
  377. resolve();
  378. }
  379. }, 100);
  380. } else {
  381. resolve();
  382. }
  383. })
  384. };
  385.  
  386. /**
  387. * 限制并发请求数量的 fetch 封装
  388. * @class FetchLimiting
  389. * @example
  390. * const fetchLimiting = new FetchLimiting()
  391. * fetchLimiting._fetch('/')
  392. * .then(res => res.json())
  393. * .then(json => console.log(json))
  394. */
  395. class FetchLimiting {
  396. /**
  397. * 构造函数
  398. * @param {Object} [option] 可选配置项
  399. * @param {Number} [option.timeout=10000] 超时毫秒数
  400. * @param {Number} [option.limit=10] 最大并发数限制
  401. */
  402. constructor ({ timeout = 10000, limit = 10 }) {
  403. /**
  404. * @field timeout 超时毫秒数
  405. */
  406. this.timeout = timeout;
  407. /**
  408. * @field limit 最大并发数限制
  409. */
  410. this.limit = limit;
  411. /**
  412. * @field execCount 当前正在执行异步的数量
  413. */
  414. this.execCount = 0;
  415. /**
  416. * @field waitArr 等待的队列
  417. * @type {Array.<IArguments>}
  418. */
  419. this.waitArr = [];
  420. }
  421.  
  422. /**
  423. * 执行一个请求
  424. * 如果到达最大并发限制时就进行等待
  425. * @param {RequestInfo} url 请求 url 信息
  426. * @param {RequestInit} [init=undefined] 请求的其他可选项,默认为 undefined
  427. * @returns {Promise} 如果超时就提前返回 reject, 否则正常返回 fetch 结果
  428. */
  429. async fetch (url, init) {
  430. const _innerFetch = async () => {
  431. this.execCount++;
  432. const args = this.waitArr.shift();
  433. try {
  434. // 这里的 args 实际上就是 arguments 对象,即上面的 url 和 init
  435. // @ts-ignore
  436. return await fetchTimeout(fetch(...args), this.timeout)
  437. } finally {
  438. this.execCount--;
  439. }
  440. };
  441. this.waitArr.push(arguments);
  442. await wait(() => this.execCount < this.limit);
  443. // 尝试启动等待队列
  444. return _innerFetch()
  445. }
  446. }
  447.  
  448. /**
  449. * 将一个 Iterator 迭代器转换为一个 Array
  450. * 目前 {@override Array.from} 已取代改函数
  451. * @param {Iterator.<Object>} iterator Iterator 迭代器
  452. * @return {Array.<Object>} Iterator 中每一项元素转换而得到的 Array
  453. */
  454. function asIterator (iterator) {
  455. var arr = [];
  456. while (true) {
  457. var next = iterator.next();
  458. if (next.done) {
  459. break
  460. }
  461. arr.push(next.value);
  462. }
  463. return arr
  464. }
  465.  
  466. /**
  467. * 将数组异步压平一层
  468. * @param {Array.<Object>} arr 数组
  469. * @param {Function} fn 映射函数,将一个元素映射为一个数组
  470. * @returns {Promise.<Array.<Object>>} 压平一层的数组
  471. */
  472. async function asyncFlatMap (arr, fn) {
  473. let res = [];
  474. for (const i in arr) {
  475. res = res.concat(await fn(arr[i]));
  476. }
  477. return res
  478. }
  479.  
  480. /**
  481. * 自行实现 flatMap,将数组压平一层
  482. * @param {Array.<Object>} arr 数组
  483. // @ts-ignore
  484. * @param {function(item:Object):Array.<Object>} fn 映射方法,将一个元素映射为一个数组
  485. * @returns {Array.<Object>} 压平一层的数组
  486. */
  487. function flatMap (arr, fn) {
  488. // @ts-ignore
  489. return arr.reduce((res, item) => res.concat(fn(item)), [])
  490. }
  491.  
  492. /**
  493. * js 数组按照某个条件进行分组
  494. *
  495. * @param {Array<Object>} arr 要进行分组的数组
  496. * @param {Function} fn 元素分组的方法
  497. * @returns {Map<Object,Object>} 对象 -> 数组映射对象
  498. */
  499. function groupBy (arr, fn) {
  500. // 将元素按照分组条件进行分组得到一个 条件 -> 数组 的对象
  501. return arr.reduce((res, item) => {
  502. const name = fn(item);
  503. // 如果已经有这个键了就直接追加, 否则先将之赋值为 [] 再追加元素
  504. if (!res.has(name)) {
  505. res.set(name, []);
  506. }
  507. res.get(name).push(item);
  508. return res
  509. }, new Map())
  510. }
  511.  
  512. /**
  513. * 创建一个等差数列数组
  514. * @param {Number} start 开始(包含)
  515. * @param {Number} end 结束(不包含)
  516. * @param {Number} [sep] 步长,默认为 1
  517. * @returns {Array.<Number>} 等差数列数组
  518. */
  519. function range (start, end, sep = 1) {
  520. const arr = [];
  521. for (let i = start; i < end; i += sep) {
  522. arr.push(i);
  523. }
  524. return arr
  525. }
  526.  
  527. /**
  528. * 将数组转化为一个 Object 对象
  529. * @deprecated 已废弃,请使用更好的 @override arrayToMap 替代
  530. * @param {Array.<Object>} arr 需要进行转换的数组
  531. * @param {Function} kFn 生成对象属性名的函数
  532. * @param {Function} [vFn] 生成对象属性值的函数,默认为数组中的迭代元素
  533. * @returns {Object} 转化得到的对象
  534. */
  535. function toObject (arr, kFn, vFn = item => item) {
  536. return arr.reduce((res, item) => {
  537. if (!res.hasOwnProperty(kFn(item))) {
  538. res[kFn(item)] = vFn(item);
  539. }
  540. return res
  541. }, {})
  542. }
  543.  
  544. /**
  545. * js 的数组去重方法
  546. * @param {Array.<Object>} arr 要进行去重的数组
  547. * @param {Function} [fn=item => JSON.stringify(item)] 唯一标识元素的方法,默认使用 {@link JSON.stringify()}
  548. * @returns {Array.<Object>} 进行去重操作之后得到的新的数组 (原数组并未改变)
  549. */
  550. function uniqueBy (arr, fn = item => JSON.stringify(item)) {
  551. const obj = {};
  552. return arr.filter(item =>
  553. obj.hasOwnProperty(fn(item)) ? false : (obj[fn(item)] = true)
  554. )
  555. }
  556.  
  557. /**
  558. * 将数组映射为 Map
  559. * @param {Array.<Object>} array 数组
  560. * @param {function} kFn 产生 Map 元素唯一标识的函数
  561. * @param {Function} [vFn] 产生 Map 值的函数,默认为返回数组的元素
  562. * @returns {Map.<Object,Object>} 映射产生的 map 集合
  563. */
  564. function arrayToMap (array, kFn, vFn = v => v) {
  565. return array.reduce((res, item) => {
  566. res.set(kFn(item), vFn(item));
  567. return res
  568. }, new Map())
  569. }
  570.  
  571. /**
  572. * 填充字符串到指定长度
  573. * @param {String} item 填充的字符串
  574. * @param {Number} len 填充的长度
  575. * @returns {String} 填充完成的字符串
  576. */
  577. function fill (item, len) {
  578. if (len <= 0) {
  579. return ''
  580. }
  581. return item + fill(item, len - 1)
  582. }
  583.  
  584. /**
  585. * 日期格式化类
  586. * @class DateFormat
  587. */
  588. class DateFormat {
  589. /**
  590. * 构造函数
  591. * @param {String} name 日期格式的名称
  592. * @param {String} format 日期的格式值
  593. * @param {String} value 格式化得到的值
  594. * @param {Number} index 需要替换位置的索引
  595. */
  596. constructor (name, format, value, index) {
  597. /**
  598. * @field 日期格式的名称
  599. */
  600. this.name = name;
  601. /**
  602. * @field 日期的格式值
  603. */
  604. this.format = format;
  605. /**
  606. * @field 格式化得到的值
  607. */
  608. this.value = value;
  609. /**
  610. * @field 需要替换位置的索引
  611. */
  612. this.index = index;
  613. }
  614. }
  615.  
  616. /**
  617. * 日期时间的正则表达式
  618. */
  619. const dateFormats = {
  620. year: 'y{4}|y{2}',
  621. month: 'M{1,2}',
  622. day: 'd{1,2}',
  623. hour: 'h{1,2}',
  624. minute: 'm{1,2}',
  625. second: 's{1,2}',
  626. milliSecond: 'S{1,3}'
  627. };
  628.  
  629. /**
  630. * 解析字符串为 Date 对象
  631. * @param {String} dateStr 日期字符串
  632. * @param {String} fmt 日期字符串的格式,目前仅支持使用 y(年),M(月),d(日),h(时),m(分),s(秒),S(毫秒)
  633. * @returns {Date} 解析得到的 Date 对象
  634. */
  635. function dateParse (dateStr, fmt) {
  636. const now = new Date();
  637. // 如果没有格式化某项的话则设置为默认时间
  638. const defaultDateValues = {
  639. year: now.getFullYear().toString(),
  640. month: '01',
  641. day: '01',
  642. hour: '00',
  643. minute: '00',
  644. second: '00',
  645. milliSecond: '000'
  646. };
  647. // 保存对传入的日期字符串进行格式化的全部信息数组列表
  648. const dateUnits = [];
  649. for (const fmtName in dateFormats) {
  650. const regExp = new RegExp(dateFormats[fmtName]);
  651. if (regExp.test(fmt)) {
  652. const matchStr = regExp.exec(fmt)[0];
  653. const regexStr = fill('`', matchStr.length);
  654. const index = fmt.indexOf(matchStr);
  655. fmt = fmt.replace(matchStr, regexStr);
  656. dateUnits.push(
  657. new DateFormat(fmtName, fill('\\d', matchStr.length), null, index)
  658. );
  659. } else {
  660. dateUnits.push(
  661. new DateFormat(fmtName, null, defaultDateValues[fmtName], -1)
  662. );
  663. }
  664. }
  665. // 进行验证是否真的是符合传入格式的字符串
  666. fmt = fmt.replace(new RegExp('`', 'g'), '\\d');
  667. if (!new RegExp(`^${fmt}$`).test(dateStr)) {
  668. return null
  669. }
  670. // 进行一次排序, 依次对字符串进行截取
  671. dateUnits
  672. // 过滤掉没有得到格式化的对象
  673. .filter(({ format }) => format)
  674. // 按照字符串中日期片段的索引进行排序
  675. .sort(function (a, b) {
  676. return a.index - b.index
  677. })
  678. // 获取到匹配的日期片段的值
  679. .map(format => {
  680. const matchDateUnit = new RegExp(format.format).exec(dateStr);
  681. if (matchDateUnit !== null && matchDateUnit.length > 0) {
  682. dateStr = dateStr.replace(matchDateUnit[0], '');
  683. format.value = matchDateUnit[0];
  684. }
  685. return format
  686. })
  687. // 覆写到 dateStr 上面
  688. .forEach(({ format }, i) => {
  689. const matchDateUnit = new RegExp(format).exec(dateStr);
  690. if (matchDateUnit !== null && matchDateUnit.length > 0) {
  691. dateStr = dateStr.replace(matchDateUnit[0], '');
  692. dateUnits[i].value = matchDateUnit[0];
  693. }
  694. });
  695. // 将截取完成的信息封装成对象并格式化标准的日期字符串
  696. const map = arrayToMap(dateUnits, item => item.name, item => item.value);
  697. if (map.get('year').length === 2) {
  698. map.set(
  699. 'year',
  700. defaultDateValues.year.substr(0, 2).concat(map.get('year'))
  701. );
  702. }
  703. // 注意:此处使用的是本地时间而非 UTC 时间
  704. const date = `${map.get('year')}-${map.get('month')}-${map.get(
  705. 'day'
  706. )}T${map.get('hour')}:${map.get('minute')}:${map.get('second')}.${map.get(
  707. 'milliSecond'
  708. )}`;
  709. return new Date(date)
  710. }
  711.  
  712. /**
  713. * 解析字符串为 Date 对象
  714. * @deprecated 已弃用,请使用可读性更好的 {@link dateParse} 代替
  715. * @param {String} dateStr 日期字符串
  716. * @param {String} fmt 日期字符串的格式
  717. * 目前仅支持使用 y(年),M(月),d(日),h(时),m(分),s(秒),S(毫秒)
  718. * @returns {Date} 解析得到的 Date 对象
  719. */
  720. function strToDate (dateStr, fmt) {
  721. return dateParse(dateStr, fmt)
  722. }
  723.  
  724. /**
  725. * 复制一段文本内容
  726. * @param {String} text 要进行复制的文本
  727. * @returns {Boolean} 是否复制成功
  728. */
  729. function copyText (text) {
  730. const input = document.createElement('input');
  731. document.body.appendChild(input);
  732. input.setAttribute('value', text);
  733. input.select();
  734. const res = document.execCommand('copy');
  735. document.body.removeChild(input);
  736. return res
  737. }
  738.  
  739. /**
  740. * 根据 html 字符串创建 Element 元素
  741. * @param {String} str html 字符串
  742. * @returns {Element} 创建的 Element 元素
  743. */
  744. function createElByString (str) {
  745. var root = document.createElement('div');
  746. root.innerHTML = str;
  747. return root.querySelector('*')
  748. }
  749.  
  750. /**
  751. * 获取输入框中光标所在位置
  752. * @param {HTMLFormElement} el 需要获取的输入框元素
  753. * @returns {Number} 光标所在位置的下标
  754. */
  755. function getCusorPostion (el) {
  756. return el.selectionStart
  757. }
  758.  
  759. /**
  760. * 设置输入框中选中的文本/光标所在位置
  761. * @param {HTMLFormElement} el 需要设置的输入框元素
  762. * @param {Number} start 光标所在位置的下标
  763. * @param {Number} [end=start] 结束位置,默认为输入框结束
  764. */
  765. function setCusorPostion (el, start, end = start) {
  766. el.focus();
  767. el.setSelectionRange(start, end);
  768. }
  769.  
  770. /**
  771. * 在指定位置后插入文本
  772. * @param {HTMLFormElement} el 需要设置的输入框元素
  773. * @param {String} text 要插入的值
  774. * @param {Number} [start] 开始位置,默认为当前光标处
  775. */
  776. function insertText (el, text, start = getCusorPostion(el)) {
  777. var value = el.value;
  778. el.value = value.substr(0, start) + text + value.substr(start);
  779. setCusorPostion(el, start + text.length);
  780. }
  781.  
  782. /**
  783. * 字符串安全的转换为小写
  784. * @param {String} str 字符串
  785. * @returns {String} 转换后得到的全小写字符串
  786. */
  787. function toLowerCase (str) {
  788. if (!str || typeof str !== 'string') {
  789. return str
  790. }
  791. return str.toLowerCase()
  792. }
  793.  
  794. /**
  795. * 判断指定元素是否是可编辑元素
  796. * 注:可编辑元素并不一定能够进行编辑,例如只读的 input 元素
  797. * @param {Element} el 需要进行判断的元素
  798. * @returns {Boolean} 是否为可编辑元素
  799. */
  800. function isEditable (el) {
  801. var inputEls = ['input', 'date', 'datetime', 'select', 'textarea'];
  802. return (
  803. // 此处需要判断是否存在属性 isContentEditable
  804. // @ts-ignore
  805. el && (el.isContentEditable || inputEls.includes(toLowerCase(el.tagName)))
  806. )
  807. }
  808.  
  809. let lastFocusEl;
  810.  
  811. document.addEventListener(
  812. 'focus',
  813. event => {
  814. lastFocusEl = event.target;
  815. },
  816. true
  817. );
  818. document.addEventListener(
  819. 'blur',
  820. () => {
  821. lastFocusEl = null;
  822. },
  823. true
  824. );
  825. /**
  826. * 获取到最后一个获得焦点的元素
  827. * @returns {Element} 最后一个获取到焦点的元素
  828. */
  829. function lastFocus () {
  830. return lastFocusEl
  831. }
  832.  
  833. /**
  834. * 直接删除指定元素
  835. * @param {Element} el 需要删除的元素
  836. * @returns {Element} 返回被删除的元素
  837. */
  838. function removeEl (el) {
  839. const parent = el.parentElement;
  840. return parent.removeChild(el)
  841. }
  842.  
  843. /**
  844. * 在指定范围内删除文本
  845. * @param {HTMLFormElement} el 需要设置的输入框元素
  846. * @param {Number} [start] 开始位置,默认为当前选中开始位置
  847. * @param {Number} [end] 结束位置,默认为当前选中结束位置
  848. */
  849. function removeText (
  850. el,
  851. start = el.selectionStart,
  852. end = el.selectionEnd
  853. ) {
  854. // 删除之前必须要 [记住] 当前光标的位置
  855. const index = getCusorPostion(el);
  856. const value = el.value;
  857. el.value = value.substr(0, start) + value.substr(end, value.length);
  858. setCusorPostion(el, index);
  859. }
  860.  
  861. /**
  862. * 监听 event 的添加
  863. * 注:必须及早添加
  864. */
  865. function watchEventListener () {
  866. /**
  867. * 监听所有的 addEventListener, removeEventListener 事件
  868. */
  869. const documentAddEventListener = document.addEventListener;
  870. const eventTargetAddEventListener = EventTarget.prototype.addEventListener;
  871. const documentRemoveEventListener = document.removeEventListener;
  872. const eventTargetRemoveEventListener =
  873. EventTarget.prototype.removeEventListener;
  874. const events = [];
  875.  
  876. /**
  877. * 用来保存监听到的事件信息
  878. */
  879. class Event {
  880. constructor (el, type, listener, useCapture) {
  881. this.el = el;
  882. this.type = type;
  883. this.listener = listener;
  884. this.useCapture = useCapture;
  885. }
  886. }
  887.  
  888. /**
  889. * 自定义的添加事件监听函数
  890. * @param {String} type 事件类型
  891. * @param {EventListener} listener 事件监听函数
  892. * @param {Boolean} [useCapture=true] 是否需要捕获事件冒泡,默认为 false
  893. */
  894. function addEventListener (type, listener, useCapture = false) {
  895. const _this = this;
  896. const $addEventListener =
  897. _this === document
  898. ? documentAddEventListener
  899. : eventTargetAddEventListener;
  900. events.push(new Event(_this, type, listener, useCapture));
  901. $addEventListener.apply(this, arguments);
  902. }
  903.  
  904. /**
  905. * 自定义的根据类型删除事件函数
  906. * 该方法会删除这个类型下面全部的监听函数,不管数量
  907. * @param {String} type 事件类型
  908. */
  909. // @ts-ignore
  910. function removeEventListenerByType (type) {
  911. const _this = this;
  912. const $removeEventListener =
  913. _this === document
  914. ? documentRemoveEventListener
  915. : eventTargetRemoveEventListener;
  916. const removeIndexArr = events
  917. .map((e, i) => (e.el === _this || e.type === arguments[0] ? i : -1))
  918. .filter(i => i !== -1);
  919. removeIndexArr.forEach(i => {
  920. const e = events[i];
  921. $removeEventListener.apply(e.el, [e.type, e.listener, e.useCapture]);
  922. });
  923. removeIndexArr.sort((a, b) => b - a).forEach(i => events.splice(i, 1));
  924. }
  925.  
  926. (function initWatchDOM () {
  927. document.addEventListener = EventTarget.prototype.addEventListener = addEventListener;
  928. // 此处是为了新增函数 removeEventListenerByType
  929. // @ts-ignore
  930. document.removeEventListenerByType = EventTarget.prototype.removeEventListenerByType = removeEventListenerByType;
  931. })();
  932. }
  933.  
  934. /**
  935. * FormData 批量添加方法
  936. * 注:该方法不会覆盖掉原本的属性
  937. * @param {FormData} fd FormData 对象
  938. * @param {Object} obj 键值对对象
  939. * @returns {FormData} 添加完成后的 FormData 对象
  940. */
  941. function appends (fd, obj) {
  942. for (const key in obj) {
  943. fd.append(key, obj[key]);
  944. }
  945. return fd
  946. }
  947.  
  948. /**
  949. * FormData 批量删除方法
  950. * @param {FormData} fd FormData 对象
  951. * @param {Array} keys 删除的 key 列表
  952. * @returns {FormData} 返回删除后的 FormData 对象
  953. */
  954. function deletes (fd, keys) {
  955. keys.forEach(key => fd.delete(key));
  956. return fd
  957. }
  958.  
  959. /**
  960. * FormData 批量设置方法
  961. * 注:该方法会覆盖掉原本的属性
  962. * @param {FormData} fd 表单对象
  963. * @param {Object} obj 键值对对象
  964. * @returns {FormData} 设置完成后的 FormData 对象
  965. */
  966. function sets (fd, obj) {
  967. for (const k in obj) {
  968. fd.set(k, obj[k]);
  969. }
  970. return fd
  971. }
  972.  
  973. /**
  974. * FormData 添加转换为包含所有键值数组的二维数组函数
  975. * @deprecated 已被原生函数 Array.from 取代
  976. * @param {FormData} fd 需要转换的 FormData 对象
  977. * @returns {Array} 转换后的数组
  978. */
  979. function formDataToArray (fd) {
  980. return asIterator(fd.entries())
  981. }
  982.  
  983. /**
  984. * 将参数对象转换为 FormData,只转换一层
  985. * @param data 参数对象
  986. * @return {FormData} 转换后的表单对象
  987. */
  988. function objToFormData (data) {
  989. const fd = new FormData();
  990. if (data) {
  991. for (const k in data) {
  992. if (data.hasOwnProperty(k)) {
  993. const v = data[k];
  994. fd.append(k, v);
  995. }
  996. }
  997. }
  998. return fd
  999. }
  1000.  
  1001. /**
  1002. * 函数去抖
  1003. * 去抖 (debounce) 去抖就是对于一定时间段的连续的函数调用,只让其执行一次
  1004. * 注: 包装后的函数如果两次操作间隔小于 delay 则不会被执行, 如果一直在操作就会一直不执行, 直到操作停止的时间大于 delay 最小间隔时间才会执行一次, 不管任何时间调用都需要停止操作等待最小延迟时间
  1005. * 应用场景主要在那些连续的操作, 例如页面滚动监听, 包装后的函数只会执行最后一次
  1006. * @param {Number} delay 最小延迟时间,单位为 ms
  1007. * @param {Function} action 真正需要执行的操作
  1008. * @return {Function} 包装后有去抖功能的函数
  1009. */
  1010. const debounce = (delay, action) => {
  1011. let tId;
  1012. return function (...args) {
  1013. if (tId) clearTimeout(tId);
  1014. tId = setTimeout(() => {
  1015. action.call(this, ...args);
  1016. }, delay);
  1017. }
  1018. };
  1019.  
  1020. /**
  1021. * 返回参数本身的函数
  1022. * @param {Object} obj 任何对象
  1023. * @returns {Object} 传入的参数
  1024. */
  1025. function returnItself (obj) {
  1026. return obj
  1027. }
  1028.  
  1029. /**
  1030. * 安全执行某个函数
  1031. * @param {Function} fn 需要执行的函数
  1032. * @param {Object} [defaultVal=undefined] 发生异常后的默认返回值,默认为 undefined
  1033. * @param {...Object} [args] 可选的函数参数
  1034. * @returns {Object|undefined} 函数执行的结果,或者其默认值
  1035. */
  1036. const safeExec = (fn, defaultVal = undefined, ...args) => {
  1037. try {
  1038. return fn(...args)
  1039. } catch (err) {
  1040. return defaultVal
  1041. }
  1042. };
  1043.  
  1044. /**
  1045. * 通用的单例模式
  1046. * @param {Object} clazz 需要包装为单例的类型
  1047. * @returns {Object} 包装后的单例模式类,使用 {@code new} 创建将只在第一次有效
  1048. */
  1049. function singleModel (clazz) {
  1050. let instance;
  1051. return class SingleClass extends clazz {
  1052. /**
  1053. * @param {...Object} args
  1054. */
  1055. constructor (...args) {
  1056. if (instance) {
  1057. return instance
  1058. }
  1059. super(...args);
  1060. instance = this;
  1061. }
  1062. }
  1063. }
  1064.  
  1065. /**
  1066. * 状态机
  1067. * 用于避免使用 if-else 的一种方式
  1068. */
  1069. class StateMachine {
  1070. /**
  1071. * 获取到一个状态工厂
  1072. */
  1073. static getFactory () {
  1074. const classMap = new Map();
  1075. /**
  1076. * 状态注册器
  1077. * 更好的有限状态机,分离子类与构建的关系,无论子类如何增删该都不影响基类及工厂类
  1078. */
  1079. return new class Builder {
  1080. /**
  1081. * 注册一个 class,创建子类时调用,用于记录每一个 [状态 => 子类] 对应
  1082. * @param {Number|String} state 作为键的状态
  1083. * @param {Object} clazz 对应的子类型
  1084. * @returns {Object} 返回 clazz 本身
  1085. */
  1086. register (state, clazz) {
  1087. classMap.set(state, singleModel(clazz));
  1088. return clazz
  1089. }
  1090.  
  1091. // noinspection JSMethodCanBeStatic
  1092. /**
  1093. * 获取一个标签子类对象
  1094. * @param {Number|String} state 状态索引
  1095. * @returns {Object} 子类对象
  1096. */
  1097. getInstance (state) {
  1098. const Class = classMap.get(state);
  1099. if (!Class) {
  1100. return null
  1101. }
  1102. // 构造函数的参数
  1103. return new Class(...Array.from(arguments).slice(1))
  1104. }
  1105. }()
  1106. }
  1107. }
  1108.  
  1109. // @ts-check
  1110. /**
  1111. * 函数节流
  1112. * 节流 (throttle) 让一个函数不要执行的太频繁,减少执行过快的调用,叫节流
  1113. * 类似于上面而又不同于上面的函数去抖, 包装后函数在上一次操作执行过去了最小间隔时间后会直接执行, 否则会忽略该次操作
  1114. * 与上面函数去抖的明显区别在连续操作时会按照最小间隔时间循环执行操作, 而非仅执行最后一次操作
  1115. *
  1116. * @param {Number} delay 最小间隔时间,单位为 ms
  1117. * @param {Function} action 真正需要执行的操作
  1118. * @return {Function} 包装后有节流功能的函数
  1119. */
  1120. function throttle (delay, action) {
  1121. let last = 0;
  1122. return function () {
  1123. const curr = Date.now();
  1124. if (curr - last > delay) {
  1125. action.apply(this, arguments);
  1126. last = curr;
  1127. }
  1128. }
  1129. }
  1130.  
  1131. /**
  1132. * 测试函数的执行时间
  1133. * 注:如果函数返回 Promise,则该函数也会返回 Promise,否则直接返回执行时间
  1134. * @param {Function} fn 需要测试的函数
  1135. * @returns {Number|Promise} 执行的毫秒数
  1136. */
  1137. const timing = fn => {
  1138. const begin = performance.now();
  1139. const result = fn();
  1140. if (!(result instanceof Promise)) {
  1141. return performance.now() - begin
  1142. }
  1143. return result.then(() => performance.now() - begin)
  1144. };
  1145.  
  1146. /**
  1147. * 轮询等待指定资源加载完毕再执行操作
  1148. * 使用 Promises 实现,可以使用 ES7 的 {@async}/{@await} 调用
  1149. * @param {Function} fn 判断必须的资源是否存在的方法
  1150. * @param {Object} option 可配置项
  1151. * @param {Number} [option.interval=100] 轮询间隔
  1152. * @param {Number} [option.max=10] 最大轮询次数
  1153. * @returns Promise 对象
  1154. */
  1155. const waitResource = (fn, { interval = 100, max = 10 } = {}) => {
  1156. var current = 0;
  1157. return new Promise((resolve, reject) => {
  1158. var timer = setInterval(() => {
  1159. if (fn()) {
  1160. clearInterval(timer);
  1161. resolve();
  1162. }
  1163. current++;
  1164. if (current >= max) {
  1165. clearInterval(timer);
  1166. reject(new Error('等待超时'));
  1167. }
  1168. }, interval);
  1169. })
  1170. };
  1171.  
  1172. /**
  1173. * 监视指定函数返回值的变化
  1174. * @param {Function} fn 需要监视的函数
  1175. * @param {Function} callback 回调函数
  1176. * @param {Number} [interval=100] 每次检查的间隔时间,默认为 100ms
  1177. * @returns {Function} 关闭这个监视函数
  1178. */
  1179. const watch = (fn, callback, interval = 100) => {
  1180. let oldVal = safeExec(fn);
  1181. const timer = setInterval(() => {
  1182. const newVal = safeExec(fn);
  1183. if (oldVal !== newVal) {
  1184. callback(newVal, oldVal);
  1185. oldVal = newVal;
  1186. }
  1187. }, interval);
  1188. return () => clearInterval(timer)
  1189. };
  1190.  
  1191. /**
  1192. * 定义监听对象时的回调函数 doc
  1193. * @callback WatchObjectCallback
  1194. * @param {Object} target 代理的对象变化后的值
  1195. * @param {String} k 变化的属性名
  1196. * @param {Object} v 变化的属性值
  1197. */
  1198.  
  1199. /**
  1200. * 深度监听指定对象属性的变化
  1201. * 注:指定对象不能是原始类型,即不可变类型,而且对象本身的引用不能改变,最好使用 const 进行声明
  1202. * @param {Object} object 需要监视的对象
  1203. * @param {WatchObjectCallback} callback 当代理对象发生改变时的回调函数,回调函数有三个参数,分别是
  1204. * @returns {Object} 返回源对象的一个代理
  1205. */
  1206. function watchObject (object, callback) {
  1207. const handler = {
  1208. get (target, property, receiver) {
  1209. try {
  1210. return new Proxy(target[property], handler)
  1211. } catch (err) {
  1212. return Reflect.get(target, property, receiver)
  1213. }
  1214. },
  1215. set (target, key, value, receiver) {
  1216. callback(target, key, value);
  1217. return Reflect.set(target, key, value, receiver)
  1218. }
  1219. };
  1220. return new Proxy(object, handler)
  1221. }
  1222.  
  1223. /**
  1224. * 字符串格式化
  1225. *
  1226. * @param {String} str 要进行格式化的值
  1227. * @param {Object} args 格式化参数值,替换字符串中的 {} 的值
  1228. * @returns {String} 替换完成的字符串
  1229. * @deprecated 已废弃,请使用 ES6 模板字符串 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/template_strings
  1230. */
  1231. function format (str, args) {
  1232. if (!args) {
  1233. return str
  1234. }
  1235. return Object.keys(args).reduce(
  1236. (res, k) => res.replace(new RegExp(`{${k}}`, 'g'), args[k]),
  1237. str
  1238. )
  1239. }
  1240.  
  1241. /**
  1242. * 判断是否为小数的正则表达式
  1243. */
  1244. const regexp = new RegExp('^(-?\\d+)(.\\d+)?$');
  1245. /**
  1246. * 判断字符串是否位小数
  1247. * @param {String} str 需要进行判断的字符串
  1248. * @returns {Boolean} 是否为小数
  1249. */
  1250. function isFloat (str) {
  1251. return regexp.test(str)
  1252. }
  1253.  
  1254. /**
  1255. * 判断是否为整数的正则表达式
  1256. */
  1257. const regexp$1 = new RegExp('^-?\\d+$');
  1258. /**
  1259. * 判断字符串是否位整数
  1260. * @param {String} str 需要进行判断的字符串
  1261. * @returns {Boolean} 是否为小数
  1262. */
  1263. function isNumber (str) {
  1264. return regexp$1.test(str)
  1265. }
  1266.  
  1267. /**
  1268. * 字符串安全的转换为大写
  1269. * @param {String} str 字符串
  1270. * @returns {String} 转换后得到的全大写字符串
  1271. */
  1272. function toUpperCase (str) {
  1273. if (!str || typeof str !== 'string') {
  1274. return str
  1275. }
  1276. return str.toUpperCase()
  1277. }
  1278.  
  1279. /**
  1280. * 将空白字符串转换为 null
  1281. *
  1282. * @param {String} str 将空字符串转换为 {@code null}
  1283. * @returns {String} 可能为 {@code null}
  1284. */
  1285. function blankToNull (str) {
  1286. return !str || str.trim().length === 0 ? null : str
  1287. }
  1288.  
  1289. /**
  1290. * 置空对象所有空白的属性
  1291. *
  1292. * @param {Object} obj 对象
  1293. * @returns {Object} 将所有的空白属性全部转换为 null 的新对象
  1294. */
  1295. function blankToNullField (obj) {
  1296. const res = {};
  1297. for (const k in obj) {
  1298. const v = obj[k];
  1299. res[k] = typeof v === 'string' ? blankToNull(v) : v;
  1300. }
  1301. return res
  1302. }
  1303.  
  1304. /**
  1305. * 将对象的所有属性置空
  1306. * @param {Object} obj 需要置空属性的对象
  1307. * @returns {Object} 返回一个新的对象
  1308. */
  1309. function emptyAllField (obj) {
  1310. const res = {};
  1311. for (const k in obj) {
  1312. res[k] = null;
  1313. }
  1314. return res
  1315. }
  1316.  
  1317. /**
  1318. * 排除对象中的指定字段
  1319. * 注: 此处将获得一个浅拷贝对象
  1320. * @param {Object} object 排除对象
  1321. * @param {...String} fields 要排除的字段
  1322. * @returns {Object} 排除完指定字段得到的新的对象
  1323. */
  1324. function excludeFields (object, ...fields) {
  1325. const set = new Set(fields);
  1326. return Object.entries(object).reduce((res, [k, v]) => {
  1327. if (!set.has(k)) {
  1328. res[k] = v;
  1329. }
  1330. return res
  1331. }, {})
  1332. }
  1333.  
  1334. /**
  1335. * 将 map 转换为 Object 对象
  1336. * @param {Map} map map 键值表
  1337. * @returns {Object} 转换得到的 Object 对象
  1338. */
  1339. function mapToObject (map) {
  1340. const res = {};
  1341. for (let [k, v] of map) {
  1342. res[k] = v;
  1343. }
  1344. return res
  1345. }
  1346.  
  1347. /**
  1348. * 生成一个随机的数字
  1349. * 如果没有参数,则会抛出异常
  1350. * @param {Number} args 参数列表,如果只有一个参数,则认为是最大值,最小值为 0。否则认为第一个是最小值,第二个是最大值,忽略剩余的参数
  1351. * @returns {Number} 生成的随机整数
  1352. */
  1353. function randomInt (...args) {
  1354. let min;
  1355. let max;
  1356. if (args.length === 0) {
  1357. throw new Error('非法参数,必须指定最大值')
  1358. } else if (args.length === 1) {
  1359. min = 0;
  1360. max = args[0];
  1361. } else if (args.length > 1) {
  1362. min = args[0];
  1363. max = args[1];
  1364. }
  1365. return min + Math.floor(Math.random() * (max - min))
  1366. }
  1367.  
  1368. /**
  1369. * 获取一年内的第多少星期
  1370. * @deprecated 不推荐使用,请使用 {@link dateEnhance} 代替
  1371. * @returns {Number}
  1372. */
  1373. function getYearWeek (date) {
  1374. /*
  1375. date1是当前日期
  1376. date2是当年第一天
  1377. d是当前日期是今年第多少天
  1378. 用d + 当前年的第一天的周差距的和在除以7就是本年第几周
  1379. */
  1380. const nowTime = date.getTime();
  1381. const startTime = new Date(date.getFullYear(), 0, 1).getTime();
  1382. var difTime = nowTime - startTime;
  1383. return Math.floor(difTime / (24 * 3600 * 1000) / 7)
  1384. }
  1385.  
  1386. /**
  1387. * 日期固定时间点
  1388. * @class DateConstants
  1389. */
  1390. class DateConstants {
  1391. /**
  1392. * 获取指定日期一天的开始时间
  1393. * @param {Date} [date=new Date()] 指定的时间,默认为当前日期
  1394. * @returns {Date} 一天的开始时间
  1395. */
  1396. dayStart (date = new Date()) {
  1397. return new Date(`${dateFormat(date, 'yyyy-MM-dd')}T00:00:00.000`)
  1398. }
  1399. /**
  1400. * 获取指定日期一天的结束时间
  1401. * @param {Date} [date=new Date()] 指定的时间,默认为当前日期
  1402. * @returns {Date} 一天的结束时间
  1403. */
  1404. dayEnd (date = new Date()) {
  1405. return new Date(`${dateFormat(date, 'yyyy-MM-dd')}T23:59:59.999`)
  1406. }
  1407. /**
  1408. * 获取指定日期所在年份的新年开始时间
  1409. * @param {Date} [date=new Date()] 指定的时间,默认为当前日期
  1410. * @returns {Date} 新年开始时间
  1411. */
  1412. yearStart (date = new Date()) {
  1413. return new Date(`${date.getFullYear()}-01-01T00:00:00.000`)
  1414. }
  1415. /**
  1416. * 获取指定日期所在年份的旧年结束时间
  1417. * @param {Date} [date=new Date()] 指定的时间,默认为当前日期
  1418. * @returns {Date} 旧年结束时间
  1419. */
  1420. yearEnd (date = new Date()) {
  1421. return new Date(`${date.getFullYear()}-12-31T23:59:59.999`)
  1422. }
  1423. }
  1424.  
  1425. /**
  1426. * 导出一个日期固定时间点的对象
  1427. * @type {DateConstants}
  1428. */
  1429. const dateConstants = new DateConstants();
  1430.  
  1431. /**
  1432. * 判断数字是否在指定区间之中
  1433. * @param {Number} num 指定数字
  1434. * @param {Number} min 最小值
  1435. * @param {Number} max 最大值(不包含)
  1436. */
  1437. function isRange (num, min, max) {
  1438. return num >= min && num < max
  1439. }
  1440.  
  1441. /**
  1442. * 日期固定时间点
  1443. * @class DateConstants
  1444. */
  1445. class DateConstants$1 {
  1446. /**
  1447. * 获取指定日期一天的开始时间
  1448. * @param {Date} [date=new Date()] 指定的时间,默认为当前日期
  1449. * @returns {Date} 一天的开始时间
  1450. */
  1451. dayStart (date = new Date()) {
  1452. return new Date(`${dateFormat(date, 'yyyy-MM-dd')}T00:00:00.000`)
  1453. }
  1454. /**
  1455. * 获取指定日期一天的结束时间
  1456. * @param {Date} [date=new Date()] 指定的时间,默认为当前日期
  1457. * @returns {Date} 一天的结束时间
  1458. */
  1459. dayEnd (date = new Date()) {
  1460. return new Date(`${dateFormat(date, 'yyyy-MM-dd')}T23:59:59.999`)
  1461. }
  1462. /**
  1463. * 获取指定日期所在年份的新年开始时间
  1464. * @param {Date} [date=new Date()] 指定的时间,默认为当前日期
  1465. * @returns {Date} 新年开始时间
  1466. */
  1467. yearStart (date = new Date()) {
  1468. return new Date(`${date.getFullYear()}-01-01T00:00:00.000`)
  1469. }
  1470. /**
  1471. * 获取指定日期所在年份的旧年结束时间
  1472. * @param {Date} [date=new Date()] 指定的时间,默认为当前日期
  1473. * @returns {Date} 旧年结束时间
  1474. */
  1475. yearEnd (date = new Date()) {
  1476. return new Date(`${date.getFullYear()}-12-31T23:59:59.999`)
  1477. }
  1478. }
  1479.  
  1480. /**
  1481. * 导出一个日期固定时间点的对象
  1482. * @type {DateConstants}
  1483. */
  1484. const dateConstants$1 = new DateConstants$1();
  1485.  
  1486. /**
  1487. * 一天标准的毫秒数
  1488. */
  1489. const DAY_UNIT_TIME = 1000 * 60 * 60 * 24;
  1490. /**
  1491. * 日期增强
  1492. * @property {Date} date
  1493. */
  1494. class DateEnhance {
  1495. /**
  1496. * 构造函数
  1497. * @param {Date} date 要增强的日期
  1498. */
  1499. constructor (date) {
  1500. /**
  1501. * @field 要增强的日期
  1502. */
  1503. this.date = date;
  1504. }
  1505. /**
  1506. * 获取到年份
  1507. * @returns {Number}
  1508. */
  1509. year () {
  1510. return this.date.getFullYear()
  1511. }
  1512. /**
  1513. * 获取月份
  1514. * @returns {Number}
  1515. */
  1516. month () {
  1517. return this.date.getMonth()
  1518. }
  1519. /**
  1520. * 获取一年内的第多少天
  1521. * @returns {Number}
  1522. */
  1523. dayOfYear () {
  1524. return Math.floor(
  1525. (this.date.getTime() - dateConstants$1.yearStart().getTime()) /
  1526. DAY_UNIT_TIME
  1527. )
  1528. }
  1529. /**
  1530. * 获取一个月内的第多少天
  1531. * @returns {Number}
  1532. */
  1533. dayOfMonth () {
  1534. return this.date.getDate()
  1535. }
  1536. /**
  1537. * 获取一个星期内的第多少天
  1538. * @returns {Number}
  1539. */
  1540. dayOfWeek () {
  1541. return this.date.getDay()
  1542. }
  1543. /**
  1544. * 获取一年内的第多少星期
  1545. * @returns {Number}
  1546. */
  1547. weekOfYear () {
  1548. const day = this.dayOfYear();
  1549. return Math.floor(day / 7 + (day % 7 === 0 ? 0 : 1))
  1550. }
  1551. /**
  1552. * 获取一个月内的第多少星期
  1553. * @returns {Number}
  1554. */
  1555. weekOfMonth () {
  1556. const day = this.dayOfMonth();
  1557. return Math.floor(day / 7 + (day % 7 === 0 ? 0 : 1))
  1558. }
  1559. /**
  1560. * 获取季度
  1561. * @returns {Number}
  1562. */
  1563. quarter () {
  1564. const month = this.month();
  1565. if (isRange(month, 0, 3)) {
  1566. return 1
  1567. } else if (isRange(month, 3, 6)) {
  1568. return 2
  1569. } else if (isRange(month, 6, 9)) {
  1570. return 3
  1571. } else {
  1572. return 4
  1573. }
  1574. }
  1575. /**
  1576. * 获取小时
  1577. * @returns {Number}
  1578. */
  1579. hour () {
  1580. return this.date.getHours()
  1581. }
  1582. /**
  1583. * 获取分钟
  1584. * @returns {Number}
  1585. */
  1586. minute () {
  1587. return this.date.getMinutes()
  1588. }
  1589. /**
  1590. * 获取秒
  1591. * @returns {Number}
  1592. */
  1593. second () {
  1594. return this.date.getSeconds()
  1595. }
  1596. /**
  1597. * 获取毫秒
  1598. * @returns {Number}
  1599. */
  1600. milliSecond () {
  1601. return this.date.getMilliseconds()
  1602. }
  1603. }
  1604.  
  1605. /**
  1606. * 获取一个增强的日期
  1607. * @param {Date} date 要增强的日期
  1608. * @returns {DateEnhance} 增强日期
  1609. */
  1610. function dateEnhance (date) {
  1611. return new DateEnhance(date)
  1612. }
  1613.  
  1614. /**
  1615. * 时间日期间隔
  1616. * @class DateBetween
  1617. */
  1618. class DateBetween {
  1619. /**
  1620. * 构造函数
  1621. * @param {Date} start 开始时间
  1622. * @param {Date} end 结束时间
  1623. */
  1624. constructor (start, end) {
  1625. /**
  1626. * @field start 开始时间
  1627. */
  1628. this.start = start;
  1629. /**
  1630. * @field end 结束时间
  1631. */
  1632. this.end = end;
  1633. }
  1634. /**
  1635. * 获取毫秒差值
  1636. * @returns {Number} 毫秒差值
  1637. */
  1638. milliSecond () {
  1639. return this.end.getTime() - this.start.getTime()
  1640. }
  1641. /**
  1642. * 获取秒差值
  1643. * @returns {Number} 秒差值
  1644. */
  1645. second () {
  1646. return Math.floor(this.milliSecond() / 1000)
  1647. }
  1648. /**
  1649. * 获取分钟差值
  1650. * @returns {Number} 分钟差值
  1651. */
  1652. minute () {
  1653. return Math.floor(this.second() / 60)
  1654. }
  1655. /**
  1656. * 获取小时差值
  1657. * @returns {Number} 小时差值
  1658. */
  1659. hour () {
  1660. return Math.floor(this.minute() / 60)
  1661. }
  1662. /**
  1663. * 获取天数差值
  1664. * @returns {Number} 天数差值
  1665. */
  1666. day () {
  1667. return Math.floor(this.hour() / 24)
  1668. }
  1669. /**
  1670. * 获取月份差值
  1671. * 注: 此处获取的差值是按月计算的,即 2018-12-31 => 2019-01-01 也被认为相差一个月
  1672. * @returns {Number} 月份差值
  1673. */
  1674. month () {
  1675. const year = this.year();
  1676. const month = this.end.getMonth() - this.start.getMonth();
  1677. return year * 12 + month
  1678. }
  1679. /**
  1680. * 获取年份差值
  1681. * 注: 此处获取的差值是按年计算的,即 2018-12-31 => 2019-01-01 也被认为相差一年
  1682. * @returns {Number} 年份差值
  1683. */
  1684. year () {
  1685. return this.end.getFullYear() - this.start.getFullYear()
  1686. }
  1687. }
  1688.  
  1689. /**
  1690. * 获取两个时间的差值
  1691. * @param {Date} start 开始时间
  1692. * @param {Date} end 结束时间
  1693. * @returns {DateBetween} 差值对象
  1694. */
  1695. function dateBetween (start, end) {
  1696. return new DateBetween(start, end)
  1697. }
  1698.  
  1699. /**
  1700. * 将指定函数包装为只调用一次
  1701. * @param {Function} fn 需要包装的函数
  1702. * @returns {Function} 包装后的函数
  1703. */
  1704. const onec = fn => {
  1705. let flag = true;
  1706. let res;
  1707. return function (...args) {
  1708. if (flag === false) {
  1709. return res
  1710. }
  1711. flag = false;
  1712. return (res = fn.call(this, ...args))
  1713. }
  1714. };
  1715.  
  1716. /**
  1717. * 包装一个函数为指定参数只执行一次的函数
  1718. * @param {Function} fn 需要包装的函数
  1719. * @param {Function} paramConverter 参数转换的函数,参数为需要包装函数的参数
  1720. * @returns {Function} 需要被包装的函数
  1721. */
  1722. const onecOfSameParam = (
  1723. fn,
  1724. paramConverter = (...args) => JSON.stringify(args)
  1725. ) => {
  1726. const paramMap = new Map();
  1727. return function (...args) {
  1728. const key = paramConverter(...args);
  1729. const old = paramMap.get(key);
  1730. if (old !== undefined) {
  1731. return old
  1732. }
  1733. const res = fn.call(this, ...args);
  1734. if (res instanceof Promise) {
  1735. return res.then(res => {
  1736. paramMap.set(key, res);
  1737. return res
  1738. })
  1739. }
  1740. paramMap.set(key, res);
  1741. return res
  1742. }
  1743. };
  1744.  
  1745. /**
  1746. * 返回合理参数本身的函数
  1747. * 1. 如果没有参数则返回 undefined
  1748. * 2. 如果只有一个参数则返回参数本身
  1749. * 3. 如果有两个以上的参数则返回参数列表
  1750. * @param {...Object} args 任何对象
  1751. * @returns {undefined|Object|Array.<Object>} 传入的参数
  1752. */
  1753. function returnReasonableItself (...args) {
  1754. const len = args.length;
  1755. if (len === 0) {
  1756. return
  1757. }
  1758. if (len === 1) {
  1759. return args[0]
  1760. }
  1761. return args
  1762. }
  1763.  
  1764. /**
  1765. * 从数组中移除指定的元素
  1766. * 注: 时间复杂度为 1~3On
  1767. * @param {Array} arr 需要被过滤的数组
  1768. * @param {Array} deleteItems 要过滤的元素数组
  1769. * @param {Function} [kFn=returnItself] 每个元素的唯一键函数
  1770. */
  1771. function filterItems (arr, deleteItems, kFn = returnItself) {
  1772. // @ts-ignore
  1773. const kSet = new Set(deleteItems.map(kFn));
  1774. return arr.filter(v => !kSet.has(kFn(v)))
  1775. }
  1776.  
  1777. /**
  1778. * 数组之间的差异结果类
  1779. * @class ArrayDiff
  1780. */
  1781. class ArrayDiff {
  1782. /**
  1783. * 构造函数
  1784. * @param {Array} left 第一个数组独有的元素列表
  1785. * @param {Array} right 第二个数组独有的元素列表
  1786. * @param {Array} common 两个数组共有的元素列表
  1787. */
  1788. constructor (left, right, common) {
  1789. /**
  1790. * @field 第一个数组独有的元素列表
  1791. */
  1792. this.left = left;
  1793. /**
  1794. * @field 第二个数组独有的元素列表
  1795. */
  1796. this.right = right;
  1797. /**
  1798. * @field 两个数组共有的元素列表
  1799. */
  1800. this.common = common;
  1801. }
  1802. }
  1803.  
  1804. /**
  1805. * 比较两个数组的差异
  1806. * @param {Array} thanArr 第一个数组
  1807. * @param {Array} thatArr 第二个数组
  1808. * @param {Function} [kFn=returnItself] 每个元素的唯一键函数
  1809. * @returns {ArrayDiff} 比较的差异结果
  1810. */
  1811. function arrayDiffBy (thanArr, thatArr, kFn = returnItself) {
  1812. // @ts-ignore
  1813. const kThanSet = new Set(thanArr.map(kFn));
  1814. // @ts-ignore
  1815. const kThatSet = new Set(thatArr.map(kFn));
  1816. const left = thanArr.filter(v => !kThatSet.has(kFn(v)));
  1817. const right = thatArr.filter(v => !kThanSet.has(kFn(v)));
  1818. // @ts-ignore
  1819. const kLeftSet = new Set(left.map(kFn));
  1820. const common = thanArr.filter(v => !kLeftSet.has(kFn(v)));
  1821. return new ArrayDiff(left, right, common)
  1822. }
  1823.  
  1824. /**
  1825. * 使用 Generator 实现一个从 0 开始的自增序列
  1826. */
  1827. function * autoIncrementGenerator () {
  1828. for (let i = 0; ; i++) {
  1829. /**
  1830. * @returns {Number} 每次获取都返回循环中的当前迭代变量,然后暂停于此处
  1831. */
  1832. yield i;
  1833. }
  1834. }
  1835. /**
  1836. * 包装 {@link autoIncrementGenerator} 为只能调用一次的函数
  1837. */
  1838. const generator = onec(autoIncrementGenerator);
  1839.  
  1840. /**
  1841. * 获取自增长序列的最新值
  1842. * @returns {Number} 最新值
  1843. */
  1844. function autoIncrement () {
  1845. return generator().next().value
  1846. }
  1847.  
  1848. /**
  1849. * 转换基类
  1850. */
  1851. class IConverter {
  1852. /**
  1853. * 将字符串解析为字符串列表
  1854. *
  1855. * @param {String} str 字符串
  1856. * @return {Array.<String>} 字符串列表
  1857. * @abstract
  1858. */
  1859. from (str) {
  1860. throw new Error('子类必须重写 from 函数')
  1861. }
  1862.  
  1863. /**
  1864. * 将字符串列表构造为字符串
  1865. *
  1866. * @param {Array.<String>} list 字符串列表
  1867. * @return {String} 字符串
  1868. * @abstract
  1869. */
  1870. to (list) {
  1871. throw new Error('子类必须重写 to 函数')
  1872. }
  1873. }
  1874.  
  1875. /**
  1876. * 驼峰风格解析
  1877. */
  1878. class CamelOrPascalFrom extends IConverter {
  1879. /**
  1880. * 将字符串解析为字符串列表
  1881. *
  1882. * @param {String} str 字符串
  1883. * @return {Array.<String>} 字符串列表
  1884. * @override
  1885. */
  1886. from (str) {
  1887. const result = [];
  1888. let len = str.length;
  1889. let old = 0;
  1890. for (let i = 0; i < len; i++) {
  1891. const c = str.charAt(i);
  1892. if (c >= 'A' && c <= 'Z') {
  1893. if (i !== 0) {
  1894. result.push(str.substring(old, i));
  1895. }
  1896. old = i;
  1897. }
  1898. }
  1899. if (old !== str.length) {
  1900. result.push(str.substring(old, str.length));
  1901. }
  1902. return result
  1903. }
  1904. }
  1905.  
  1906. /**
  1907. * 小写开头的驼峰转换器
  1908. *
  1909. */
  1910. class CamelConverter extends CamelOrPascalFrom {
  1911. /**
  1912. * 将字符串列表构造为字符串
  1913. *
  1914. * @param {Array.<String>} list 字符串列表
  1915. * @return {String} 字符串
  1916. * @override
  1917. */
  1918. to (list) {
  1919. const str = list
  1920. .map(s => s.substring(0, 1).toUpperCase() + s.substring(1))
  1921. .join();
  1922. return str.substring(0, 1).toLowerCase() + str.substring(1)
  1923. }
  1924. }
  1925.  
  1926. /**
  1927. * 大写开头的驼峰转换器
  1928. */
  1929. class PascalConverter extends CamelOrPascalFrom {
  1930. /**
  1931. * 将字符串列表构造为字符串
  1932. *
  1933. * @param {Array.<String>} list 字符串列表
  1934. * @return {String} 字符串
  1935. * @override
  1936. */
  1937. to (list) {
  1938. return list
  1939. .map(s => s.substring(0, 1).toUpperCase() + s.substring(1))
  1940. .join()
  1941. }
  1942. }
  1943. /**
  1944. * 下划线风格解析
  1945. */
  1946. class SnakeOrScreamingSnakeFrom extends IConverter {
  1947. /**
  1948. * 将字符串解析为字符串列表
  1949. *
  1950. * @param {String} str 字符串
  1951. * @return {Array.<String>} 字符串列表
  1952. * @override
  1953. */
  1954. from (str) {
  1955. return str.split('_')
  1956. }
  1957. }
  1958. /**
  1959. * 小写下划线的转换器
  1960. */
  1961. class SnakeConverter extends SnakeOrScreamingSnakeFrom {
  1962. /**
  1963. * 将字符串列表构造为字符串
  1964. *
  1965. * @param {Array.<String>} list 字符串列表
  1966. * @return {String} 字符串
  1967. * @override
  1968. */
  1969. to (list) {
  1970. return list.map(s => s.toLowerCase()).join('_')
  1971. }
  1972. }
  1973. /**
  1974. * 大写下划线的转换器
  1975. */
  1976. class ScreamingSnakeConverter extends SnakeOrScreamingSnakeFrom {
  1977. /**
  1978. * 将字符串列表构造为字符串
  1979. *
  1980. * @param {Array.<String>} list 字符串列表
  1981. * @return {String} 字符串
  1982. * @override
  1983. */
  1984. to (list) {
  1985. return list.map(s => s.toUpperCase()).join('_')
  1986. }
  1987. }
  1988. /**
  1989. * @enum {Symbol} 字符串风格常量对象
  1990. */
  1991. const stringStyleType = {
  1992. /**
  1993. * 小写驼峰
  1994. */
  1995. Camel: Symbol(1),
  1996. /**
  1997. * 大写驼峰
  1998. */
  1999. Pascal: Symbol(2),
  2000. /**
  2001. * 小写下划线
  2002. */
  2003. Snake: Symbol(3),
  2004. /**
  2005. * 大写下划线
  2006. */
  2007. ScreamingSnake: Symbol(4)
  2008. };
  2009.  
  2010. /**
  2011. * 转换器工厂
  2012. */
  2013. class ConverterFactory {
  2014. /**
  2015. * 获取一个转换器实例
  2016. *
  2017. * @param {Symbol} styleType 转换风格,使用了 {@link stringStyleType} 定义的常量对象
  2018. * @return {IConverter} 转换器对象
  2019. * @throws 如果获取未定义过的转换器,则会抛出异常
  2020. */
  2021. static getInstance (styleType) {
  2022. switch (styleType) {
  2023. case stringStyleType.Camel:
  2024. return new CamelConverter()
  2025. case stringStyleType.Pascal:
  2026. return new PascalConverter()
  2027. case stringStyleType.Snake:
  2028. return new SnakeConverter()
  2029. case stringStyleType.ScreamingSnake:
  2030. return new ScreamingSnakeConverter()
  2031. default:
  2032. throw new Error('No corresponding converter found')
  2033. }
  2034. }
  2035. }
  2036.  
  2037. /**
  2038. * 字符串风格转换器
  2039. * 请不要直接使用构造函数创建,而是用 {@link StringStyleUtil.getConverter} 来获得一个转换器
  2040. * @private
  2041. */
  2042. class StringStyleConverter {
  2043. /**
  2044. * 构造一个字符串任意风格转换器
  2045. * @param {Symbol} from 转换字符串的风格
  2046. * @param {Symbol} to 需要转换的风格
  2047. * @private
  2048. */
  2049. constructor (from, to) {
  2050. /**
  2051. * @field 解析字符串风格的转换器
  2052. * @type {IConverter}
  2053. * @private
  2054. */
  2055. this.fromConverter = ConverterFactory.getInstance(from);
  2056. /**
  2057. * @field 构造字符串风格的转换器
  2058. * @type {IConverter}
  2059. * @private
  2060. */
  2061. this.toConverter = ConverterFactory.getInstance(to);
  2062. }
  2063.  
  2064. /**
  2065. * 转换字符串的风格
  2066. *
  2067. * @param {String} str 要转换的字符串
  2068. * @return {String} 转换得到的字符串
  2069. */
  2070. convert (str) {
  2071. if (str === undefined || str === null || str.length === 0) {
  2072. return str
  2073. }
  2074. return this.toConverter.to(this.fromConverter.from(str))
  2075. }
  2076. }
  2077.  
  2078. /**
  2079. * 包装获取字符串风格转换器
  2080. * 此处采用了单例模式,每种转换器只会有一个
  2081. *
  2082. * @param {stringStyleType} from 解析风格
  2083. * @param {stringStyleType} to 转换风格
  2084. * @return {StringStyleConverter} 转换器的实例
  2085. */
  2086. const _getConverter = onecOfSameParam(
  2087. /**
  2088. * @param {stringStyleType} from 解析风格
  2089. * @param {stringStyleType} to 转换风格
  2090. * @return {StringStyleConverter} 转换器的实例
  2091. */
  2092. (from, to) => new StringStyleConverter(from, to),
  2093. /**
  2094. * 根据参数生成唯一标识
  2095. * @param {stringStyleType} from 解析风格
  2096. * @param {stringStyleType} to 转换风格
  2097. * @return {String} 唯一参数标识字符串
  2098. */
  2099. (from, to) => from.toString() + to.toString()
  2100. );
  2101.  
  2102. /**
  2103. * 字符串风格转换工具类
  2104. */
  2105. class StringStyleUtil {
  2106. /**
  2107. * 获取一个转换器的实例
  2108. * 该函数获取的转换器可以任意复用,请优先使用函数
  2109. * @param {stringStyleType} from 解析风格
  2110. * @param {stringStyleType} to 转换风格
  2111. * @return {StringStyleConverter} 转换器的实例
  2112. */
  2113. static getConverter (from, to) {
  2114. return _getConverter(from, to)
  2115. }
  2116. /**
  2117. * 直接转换字符串的风格
  2118. * 请优先使用可以复用的 {@link StringStyleUtil.getConverter} 函数
  2119. * @param {stringStyleType} from 解析风格
  2120. * @param {stringStyleType} to 转换风格
  2121. * @param {String} str 要转换的字符串
  2122. * @return {String} 转换得到的字符串
  2123. */
  2124. static convert (from, to, str) {
  2125. return StringStyleUtil.getConverter(from, to).convert(str)
  2126. }
  2127. }
  2128.  
  2129. exports.FetchLimiting = FetchLimiting;
  2130. exports.StateMachine = StateMachine;
  2131. exports.StringStyleUtil = StringStyleUtil;
  2132. exports.appends = appends;
  2133. exports.arrayDiffBy = arrayDiffBy;
  2134. exports.arrayToMap = arrayToMap;
  2135. exports.asIterator = asIterator;
  2136. exports.asyncFlatMap = asyncFlatMap;
  2137. exports.autoIncrement = autoIncrement;
  2138. exports.blankToNull = blankToNull;
  2139. exports.blankToNullField = blankToNullField;
  2140. exports.copyText = copyText;
  2141. exports.createElByString = createElByString;
  2142. exports.dateBetween = dateBetween;
  2143. exports.dateConstants = dateConstants;
  2144. exports.dateEnhance = dateEnhance;
  2145. exports.dateFormat = dateFormat;
  2146. exports.dateParse = dateParse;
  2147. exports.debounce = debounce;
  2148. exports.deletes = deletes;
  2149. exports.download = download;
  2150. exports.downloadString = downloadString;
  2151. exports.downloadUrl = downloadUrl;
  2152. exports.emptyAllField = emptyAllField;
  2153. exports.excludeFields = excludeFields;
  2154. exports.fetchTimeout = fetchTimeout;
  2155. exports.fill = fill;
  2156. exports.filterItems = filterItems;
  2157. exports.flatMap = flatMap;
  2158. exports.formDataToArray = formDataToArray;
  2159. exports.format = format;
  2160. exports.getCookies = getCookies;
  2161. exports.getCusorPostion = getCusorPostion;
  2162. exports.getYearWeek = getYearWeek;
  2163. exports.groupBy = groupBy;
  2164. exports.insertText = insertText;
  2165. exports.isEditable = isEditable;
  2166. exports.isFloat = isFloat;
  2167. exports.isNumber = isNumber;
  2168. exports.isRange = isRange;
  2169. exports.lastFocus = lastFocus;
  2170. exports.loadResource = loadResource;
  2171. exports.mapToObject = mapToObject;
  2172. exports.objToFormData = objToFormData;
  2173. exports.onec = onec;
  2174. exports.onecOfSameParam = onecOfSameParam;
  2175. exports.parseUrl = parseUrl;
  2176. exports.randomInt = randomInt;
  2177. exports.range = range;
  2178. exports.readLocal = readLocal;
  2179. exports.removeEl = removeEl;
  2180. exports.removeText = removeText;
  2181. exports.returnItself = returnItself;
  2182. exports.returnReasonableItself = returnReasonableItself;
  2183. exports.safeExec = safeExec;
  2184. exports.setCusorPostion = setCusorPostion;
  2185. exports.sets = sets;
  2186. exports.singleModel = singleModel;
  2187. exports.spliceParams = spliceParams;
  2188. exports.strToArrayBuffer = strToArrayBuffer;
  2189. exports.strToDate = strToDate;
  2190. exports.stringStyleType = stringStyleType;
  2191. exports.throttle = throttle;
  2192. exports.timing = timing;
  2193. exports.toLowerCase = toLowerCase;
  2194. exports.toObject = toObject;
  2195. exports.toUpperCase = toUpperCase;
  2196. exports.uniqueBy = uniqueBy;
  2197. exports.wait = wait;
  2198. exports.waitResource = waitResource;
  2199. exports.watch = watch;
  2200. exports.watchEventListener = watchEventListener;
  2201. exports.watchObject = watchObject;
  2202.  
  2203. Object.defineProperty(exports, '__esModule', { value: true });
  2204.  
  2205. }));
  2206. //# sourceMappingURL=rx-util.js.map