interface Obj { [x: string]: any; } type Func any> = F extends (...args: infer A) => infer R ? ((...args: A) => R) & T : never; type TimeoutId = ReturnType; type Falsy = null | undefined | false | '' | 0 | 0n; type Truthy = T extends Falsy ? never : T; type Join = K extends string | number ? P extends string | number ? P extends '' ? `${K}` : `${K}.${P}` : `${K}` : never; type KeyPath = T extends object ? { [K in keyof T]-?: K extends string | number ? K extends Array ? never : K | Join ? number | Join> : KeyPath> : never; }[keyof T] : ''; /** * 检测传入对象自身的可用key路径,搭配泛型如 `(path: SelfKeyPath)` 慎用! * @example * type MyData = { * a: { * b: { * c: Array<{ * g: number * h: boolean * }> * } * } * } * // "a" | "a.b" | "a.b.c" | `a.b.c.${number}` | `a.b.c.${number}.g` | `a.b.c.${number}.h` * type MyDataPaths = SelfKeyPath; */ type SelfKeyPath = Exclude, '' | never>; interface DebounceFirstWrap { (...args: Parameters): ReturnType | void; _tid?: number; flag?: true | null; } /** * the next call will be triggerd after `timeout` the last call went by * @param callback function to invoke only once till `timeout` * @param timeout milliseconds * @returns function * @example * // not click for at least 1s and to be triggered * onclick = debounceFirst(() => console.log('1'), 1000) */ declare function debounceFirst(callback: T, timeout: number): DebounceFirstWrap; interface DebounceLastWrap { (...args: Parameters): void; _tid?: number; } /** * each call will be **async** triggerd always after `timeout` * @param callback function to invoke only once after `timeout` * @param timeout milliseconds * @returns function * @example * // resize window and callback triggered only after 1s when stop resizing * onresize = debounceLast(() => console.log('only happens after 1s when stop'), 1000) * * // use clearTimeout to stop the next trigger if necessary * addEventListener('resize', debounceLast(() => { * clearTimeout(onresize._tid); * console.log('cleared') * }, 999)) */ declare function debounceLast(callback: T, timeout: number): DebounceLastWrap; interface Evt { [x: string]: ((...args: any[]) => any)[]; } interface Emitter { evts: T; on(name: K, func: T[K][number]): this; once(name: K, func: T[K][number]): this; off(name: K, func?: T[K][number]): this; emit(name: keyof T, ...args: any[]): this; } /** * event emitter * * @example * const emitter = Emitter() * emitter.on('some', (arg) => {console.log(arg)}) * .emit('some', 123).off('some') * * const emitter = Emitter<{ * hi: [(m: string) => void] * tell: ((t: boolean) => boolean)[] * }>() * emitter * .once('hi', (s) => alert(s)) * .on('tell', (s) => !!s) * .emit('hi') * .emit('tell') * .off('tell') */ declare function Emitter(): { evts: T; /** * add listener for given name * @param name listener type * @param func listener * @returns this * @example * Emitter().on('hi', (s) => { alert(s) }).emit('hi') * // with type * Emitter<{ * hi: [(m:string) => void] * }>().on('hi', (s) => { alert(s) }).emit('hi', 'hiii') */ on(name: K, func: T[K][number]): Emitter; /** * add listener only running once for given name * @param name listener type * @param func listener * @returns this * @example * Emitter().once('hi', (s) => { alert(s) }).emit('hi') * // with type * Emitter<{ * hi: [(m:string) => void] * }>().once('hi', (s) => { alert(s) }).emit('hi', 'hiii') */ once(name: K, func: T[K][number]): Emitter; /** * remove listener for given name * @param name listener type * @param func listener * @returns this * @example * const emitter = Emitter(), * tell = (s) => alert(s) * emitter.on('hi', tell) * .on('hi', (s) => alert('1: ' + s)) * .on('hi', (s) => alert('2: ' + s)) * // remove the "tell" * .off('hi', tell) * // remove all of the type 'hi' * .off('hi') */ off(name: K, func?: T[K][number]): Emitter; /** * call the listener for given name * @param name listener type * @param args arguments passed to listener * @returns this * @example * const say = (m: string) => console.log(m) * Emitter().once('runOnce', say) * .emit('runOnce', 'called once only') * .on('run', say) * .emit('run', '1st run') * .emit('run', '2st run') */ emit(name: keyof T, ...args: any[]): Emitter; }; /** * 获取给定对象的某属性值,路径以 . 形式,如 a.b.c.d,也适用于数组 * @param obj * @param keyPath 键路径,如 home.head.title * @param check 检验 keyPath 是否有效。如对象{one:1},keyPath为one.two,由于one上找不到属性“two”,故返回值里的 isValidKeys 是false * @returns any | { isValidKeys: boolean; validKeys: string; value: any; } * @example getPathValue({a: [ 1, { b: {0: [ 3 ] } } ]}, 'a.1.b.0.0') === 3 * getPathValue<123>({a: {b: 123} }, 'a.b') === 123 * getPathValue({a: {b: null}}, 'a.b', true) => {isValidKeys: true, validKeys: 'a.b', value: null} * getPathValue({a: {b: null}}, 'a.b', true) => {isValidKeys: true, validKeys: 'a.b', value: null} * * 特殊情况:某层key本身是点连接的字符串,如 { a: { 'b.c': [ { d: 1 } ] } } * getPathValue({ a: { 'b.c': [ { d: 1 } ] } }, 'a.[b.c].0.d') === 1 */ declare function getPathValue(obj: Obj, keyPath: string): T; declare function getPathValue(obj: Obj, keyPath: string, check: false | undefined): T; declare function getPathValue(obj: Obj, keyPath: string, check: true): { isValidKeys: boolean; validKeys: string; value: T; }; /** * 按给定key路径及末端值生成对应格式对象 * @param keyPath e.g.: a.b.c.d * @param value * @returns object * @example makeObjectByPath('one.two.three', 0) * 返回结果 { one: { two: { three: 0 } } } * * 特殊情况:某层key本身是点连接的字符串,如 { a: { 'b.c': { d: 1 } } } * makeObjectByPath('a.[b.c].d', 1) * 返回结果 { a: { 'b.c': { d: 1 } } } */ declare function makeObjectByPath(keyPath: string, value?: any): Obj; /** * 返回不含指定自有属性及不可枚举属性的新对象,或剔除给定对象的指定自有属性并返回该对象 * * @param obj 源对象 * @param excludes 忽略的`key[]` * @param inSelf 是否直接更改源对象 * @returns 默认返回新对象 * @example const tmp1 = omitOwnKeys({ a: 1, b: 2 }, ['b']); const tmp2 = omitOwnKeys({ a: 1, b: 2 } as const, ['b'] as const); const tmp3 = omitOwnKeys<{ a: 1; b: 2 }, ['a']>({ a: 1, b: 2 }, ['a']); // in vue sfc */ declare function omitOwnKeys>(obj: T, excludes: K, inSelf?: boolean): Omit; /** * deduplication for source array * @param source array to be deduplicated * @param compare compare function, return truthy for pushing the "only" * @returns deduplicated array * @example const arr = [{ id: 1 }, { id: 2 }, { id: 1, num: 3 }]; * // get an array within only id: [{ id: 1 }, { id: 2 }] * onlyify(arr, (res, from) => res.every((e) => e.id !== from.id)); * * // get an array within only id at last: [{ id: 2 }, { id: 1, num: 3 }] * onlyify(arr, (res, from) => arr.findLast((e) => e.id === from.id) === from && res.every((e) => e.id !== from.id)); */ declare function onlyify(source: T[], compare: (result: T[], sourceItem: T) => boolean | void): T[]; /** * 轮询传入的函数,仅在当次函数调用后才继续下次轮询 * * @param callback function to be called periodically * @param interval milliseconds between each call * @param args arguments passed to callback * @returns poller with `run` and `stop` methods * @example * const poller = polling((arg1, arg2) => { console.log('polling', arg1, arg2); }, 2000, 'arg1', 'arg2'); * poller.run(); * * // pass custom callback, interval and args when calling `run`, which override the corresponding params from `polling(...args)` * const poller = polling(); * poller.run((arg1, arg2) => { console.log('custom polling', arg1, arg2); }, 1000, 'arg1', 'arg2'); */ declare function polling(callback?: Func, interval?: number, ...args: any[]): { tid: TimeoutId | null; run(handle?: Func, handleInterval?: number, ...handleArgs: any[]): void; stop(): void; }; /** * @example animate( 500, (progress) => { box.style.transform = "translateX(" + progress * 300 + "px)"; }, easeOut, ); */ type timingTypes = 'linear' | 'easeIn' | 'easeOut' | 'easeInOut'; /** * 滚动元素内容至指定位置。未指定有效duration与type时尝试调用原生scroll({behavior:'smooth'}) * @param el html element,未指定则使用根元素:html * @param duration 过渡持续时间,单位ms * @param top 滚动到指定的scrollTop * @param left 滚动到指定的scrollLeft * @param type 过渡曲线 * @example * scroller({ * top: 0, * // duration: 500, * // type: 'easeOut' * }) */ declare function scroller({ el, duration, top, left, type }: { el?: Element; duration?: number; top?: number; left?: number; type?: timingTypes; }): void; /** * 将对象转为url param * @param obj * @returns string */ declare function serialize(obj: Obj): string; /** * 通过给定键路径为传入对象设置值 * @param obj 需要通过keyPath设置value的对象 * @param keyPath 以.分隔的键路径,如 a.b.c * @param value 设置的值 * @returns 赋值成功则返回 true * @example const a = { one: { two: [ 3, {} ] } } * setPathValue(a, 'one.two.1.four', 1) === true * a.one.two[1].four === 1 * * 特殊情况:某层key本身是点连接的字符串,如 { a: { 'b.c': { d: 1 } } } * const p = { a: { 'b.c': { d: 1 } } } * setPathValue(p, 'a.[b.c].d', 2) * p.a['b.c'].d === 2 */ declare function setPathValue(obj: Obj, keyPath: string, value?: any): true | undefined; interface ThrottleWrap { (...args: Parameters): ReturnType | void; _last?: number; onEnd?: Func<{ _tid?: TimeoutId | null; }>; } /** * get a throttled function, only to be called after `interval`. an `onEnd` listener could be added to the returned function * @param callback function to invoke every `interval` ms * @param interval milliseconds between each call * @returns function * @example * const o = { * click: throttle(() => {console.log(this); return 1}, 1000), * move: throttle(function () {console.log(this); return ''}, 500) * } * * o.click() === 1 // the logged 'this' is not o * o.move() === '' // the logged 'this' is o itself * * // add an end listener if need, maybe unnecessary in some events like 'mousemove'. and `onEnd` is in task queue * click.onEnd = () => console.log('the end call maybe unnecessary') */ declare function throttle(callback: T, interval: number): ThrottleWrap; /** * 滚动元素内容至顶部或底部,未指定duration与type则尝试调用原生scroll({behavior:'smooth'}) * @param el html element,未指定则使用根元素:html * @param dir 'top' | 'bottom' * @param duration 过渡时间,单位ms * @param type 过渡曲线 * @example toTopOrBottom() * toTopOrBottom(null, 'bottom') */ declare function toTopOrBottom(el?: Element, dir?: 'top' | 'bottom', type?: timingTypes, duration?: number): void; /** * 异步复制到剪贴板 * @param val * @returns Promise | Promise * * @example * const res = await asyncCopy('1') */ declare function asyncCopy(val: string): Promise | Promise; /** * 深度合并对象与数组。仅检测对象自身的可枚举属性,忽略继承而来的 * @param target 待合并的目标对象或数组 * @param source 深度合并至target的对象或数组 * @param skipHandle 单独处理合并过程中的每一项,返回Truthy则不进行深度合并 * @returns target */ declare function deepMerge(target: Obj, source: Obj, skipHandle?: (key: string, target: Obj, from: any) => boolean | void): Obj; /** * 根据给定索引删除源数组对应项 * @param arr any[] * @param indexes 包含待删除索引的数组 * @returns 包含被删除项的数组 * @example delArrItem([null, 5, 'as', {}, false], [3,1,7]) => [5, {}] */ declare function delArrItem(arr: any[], indexes: number[]): any[]; /** * 从arr中删除items里的元素 * @param arr 需要删除指定项的数组 * @param items 要从arr中移除掉的项 * @returns 删除了给定项的源数组arr * @example delArrItemByVal([2, '', alert, console, false, NaN], ['', alert, console, NaN]) => [2, false] */ declare function delArrItemByVal(arr: any[], items: any[]): any[]; /** * 使用给定string结合随机数生成唯一id * @param prefix id前缀,默认无前缀 * @param level 调用Math.random时的取值范围,默认 100 * @param step 取到重复值时会将 step 加到 level 上重新计算随机值,默认 50 * @returns prefix + random uid */ declare function genUID(prefix?: string, level?: number, step?: number): string; /** * 获取滚动条尺寸 * @param force 是否重新计算一次 * @returns 滚动条尺寸 */ declare function getScrollBarSize(force?: boolean): number; declare function isObject(obj: any): boolean; /** * 移动数组某项 * @param arr 数组 * @param from 移动前的index * @param to 移动后的index */ declare function moveArrItem(arr: any[], from: number, to: number): any[]; /** * 保存文件到本地 * * @param content 待保存内容,二进制或字符串 * @param fileName 文件名 * @param ext 文件后缀 * @param isUrl `content`是否为url地址。若url跨域则`download`属性会失效,浏览器会尝试直接打开文件 * @param type 下载的文件类型,默认 `application/octet-stream` */ declare function saveFile(content: Blob | string, fileName: string, ext?: string, isUrl?: boolean, type?: string): void; /** * 滚动容器,即可滚动的元素自身,其overflow应为auto/scroll */ type Scroller = HTMLElement & { _scrollAt: number | null; _scrollTid: number | null; _scrollbars?: { barX: HTMLElement; barY: HTMLElement; } | null; }; /** * 滚动条滑块 */ type Thumb = HTMLElement & { _ratio: number; }; /** * 自定义滚动条对象 */ type CustomBar = { /** * 是否禁用自定义滚动条。默认在移动端上停用 * * 可按需修改生效条件如 Scrollbar.disabled = Scrollbar.disabled && /Firefox|Linux|Macintosh/.test(navigator.userAgent) */ disabled: boolean; /** * 是否在使用滚动条时清除页面已选项,默认禁用 */ clearSelection: boolean | null; /** * 是否在使用滚动条时阻止(chromium)默认的selectstart事件,默认禁用 */ stopSelect: boolean | null; /** * 是否监听body&html的样式变化从而切换window的滚动条,默认禁用 * * 如需要展示modal时,通常组件会将body的overflow改为hidden从而隐藏滚动条以及避免scroll chaining */ watchPageStyle: boolean | null; /** * @description * 更新滚动条尺寸后是否同步位置 */ syncPos: boolean | null; _stylingPage: boolean | null; stylingPage: boolean | null; pageWatcher?: MutationObserver | null; sizeWatcher?: ResizeObserver | null; scrollerWatcher?: ResizeObserver; getBar: (el: HTMLElement) => { isPage: boolean; barX?: HTMLElement; barY?: HTMLElement; thumbX?: Thumb; thumbY?: Thumb; scrollTarget: Scroller; }; /** * 移除滚动条,无需手动调用 * * @param el 使用Scrollbar.attach附加过滚动条的元素 */ remove: (el: Scroller) => void; /** * 对指定元素附加自定义滚动条 * * @param el html元素 * @returns this * * @example * // 只给窗口本身使用时仅需为html添加scroller类并调用attach,无需传参 * & Scrollbar.attach() * @example * // 给局部元素使用,为便于监测滚动容器&内容区域的尺寸变化,应符合类似下列结构 * *
* *
* *
*
*
* * Scrollbar.attach(document.getElementById('list')) * * // attach支持链式调用 * Scrollbar.attach().attach(document.querySelector('.list')) */ attach: (el?: HTMLElement | null) => CustomBar; init?: () => void; updateBar: (container: HTMLElement) => void; updatePos: (thumbX: Thumb, thumbY: Thumb, scrollTarget: HTMLElement) => void; getDownData: (dir: 'X' | 'Y', bar: HTMLElement, thumb: Thumb, scrollTarget: HTMLElement) => { distance: number; lastScroll: number; }; mouseMove: (dir: 'X' | 'Y', type: 'scrollTop' | 'scrollLeft', pos: number, distance: number, thumb: Thumb, scrollTarget: HTMLElement) => void; addMouseUp: (onmousemove: (e: MouseEvent) => void, listenOn: Scroller | Window, scrollTarget: Scroller, onScroll: () => void) => void; showBar: (this: Scroller) => void; hideBar: (obj: Scroller) => void; }; /** * 自定义滚动条对象 * * @example * // 只给窗口本身使用时仅需为html添加scroller类并调用attach,无需传参 * & Scrollbar.attach() * @example * // 给局部元素使用,为便于监测滚动容器&内容区域的尺寸变化,应符合类似下列结构 * *
* *
* *
*
*
* * Scrollbar.attach(document.getElementById('list')) * * // attach支持链式调用 * Scrollbar.attach().attach(document.querySelector('.list')) */ declare const Scrollbar: CustomBar; /** * 复制到剪贴板 * @param val * @returns boolean */ declare function setClipboard(val: string): boolean | undefined; /** * 替换字符串中的 "%s" * * 当第二个参数是对象时,以相应的属性值替换字符串中的“{}”插值部分 * * @returns string * @example sprintf('hel %s %s', 'l', 'o'); * sprintf('he{a} {b.c}', {a: 'l', b: {c: 'lo'}}) */ declare function sprintf(str: string, ...args: (string | number)[] | [object]): string; /** * 简单持久化存储,以对象形式存储至 localStorage[id],id 默认值为空字符 '',适用于(全局)配置只需一层的场景 * * @example * const ini = new StoreSimply('app', {theme: 0}) * ini.getVal('theme') === 0 * ini.setVal('theme', 1).getVal('theme') === 1 * ini.setVal('login.accnt', {id:3}).getVal('login.accnt').id === 3 */ declare class StoreSimply { id: string; data: T; private _tid; constructor(id?: string | null, data?: T); getVal(key: keyof T): T[keyof T]; /** * 更改键值,支持链式调用 * @param key 要求为实例化时所传data自身的key * @param value any * @returns this * @example * new StoreSimply('app', {num: 1, more: false}) * .setVal('num',null) * .setVal('more') */ setVal(key: keyof T, value?: any): this; } /** * 按唯一id进行本地设置,数据存至localStorage,不传 id 则使用默认的空字符 '' * @example * 保存在本地后的对象格式be like * { * 未提供id时则使用 '' 作为唯一标识 * '': { * theme: 0, * login: { * remember: false, * agree: { * read: false, * check: false, * } * } * }, * 给定的id,例如 Admin。如在同域下存在多个应用(项目),需要同时按账号及应用区分时,可将id设为应用+账号,避免过多嵌套 * Admin: { * theme: 1, * login: { * remember: true, * agree: { * read: true, * check: true, * } * } * } * } * * 使用示例,设置一次 * setVal('login.agree.read', true) * or * save({ * login: { * // _flush: true, // 任意属性赋予这个值则表示直接替换,而不是尝试针对对象的深度合并 * agree: { * read: true * } * } * }) 或者链式调用,一次设置多个值 * new StoreById('app', { * theme: 0, * head: { * show: false * } * }).setVal('head.show', true).save({theme: 1}) * .setVal('foot.show', false).save({head: {title: 0}}) * .save({ * foot: { * tip: 'xxx' * } * }).setVal('one.two.three.four', null) * * 在读写时检测路径并获得路径提示 * type Config = { * user: { * id: string; * pwd: string; * }; * app: { * theme: string; * }; * }; * new StoreById>() */ declare class StoreById { id: string; data: T; private _tid; constructor(id?: string | null, data?: T); /** * 以点语法获取对应配置 * @param keyPath e.g. login.agree * @param target 查询keyPath值的目标对象,不存在时从this.data上查询 * @returns any * @example getVal('login.agree') * getVal('login.remember') */ getVal(keyPath: K, target?: Obj): V; /** * 以点语法修改配置,支持链式调用 * @param keyPath 键路径,如 one.two.three * @param value 赋予的值 * @param deep 当value是对象时是否深度合并,默认不进行深度合并 * @param target 进行赋值的目标对象,存在target则赋值行为都是在target上进行,而不是this.data * @param skipHandle 用于处理合并过程中每一项的函数,返回Truthy则跳过该次的深度合并 * @example * setVal('login.agree.read', true) * 若不存在 {login: {agree: {read: any}}},也可保存成功,且保存后的对象为 {login: {agree: {read: true}}} */ setVal(keyPath: K, value?: any, { deep, target, skipHandle }?: { deep?: boolean; target?: Obj; skipHandle?: (key: string, target: Obj, fromValue: any) => boolean; }): this; /** * 以对象形式修改配置,支持链式调用,默认进行深度合并 * @param value * @param targetOrReplace 若为true,则直接将this.data替换为value;若为对象,则合并行为都是在该对象上进行,而不是this.data * @param skipHandle 用于处理合并过程中每一项的函数,返回Truthy则跳过该次的深度合并 * @example * // 只修改 login 中 agree 的 read * save({ * login: { * // _flush: true, // 任意属性赋予这个值则表示直接替换,而不是尝试默认的深度合并 * agree: { * read: true * } * } * }) */ save(value: Obj, targetOrReplace?: boolean | Obj | null, skipHandle?: (key: string, target: Obj, fromValue: any) => boolean | void): this; } /** * 类似StoreById的api,但将数据存至indexedDB。由于indexedDB的操作属于异步,故需在实例的onsuccess事件中获取数据库的数据 * @param id 数据库名称,不传使用 '-' * @param table 数据库中的仓库(表)名称,不传使用数据库名 * @param data 初始化的数据 * @example * const d = new StoreByIDB() * d.onsuccess = () => { * console.log(d.data) * d.setVal('APP.ui.theme', 'auto').setVal('login.agree.read', true).getVal('login.agree.read') * } * * 在读写时检测路径并获得路径提示 * type Config = { * user: { * id: string; * pwd: string; * }; * app: { * theme: string; * }; * }; * const d = new StoreByIDB>() */ declare class StoreByIDB { id: string; table: string; data: T; onsuccess?: () => void; onerror: (e: Event) => void; private _tid; private _idb; constructor(id?: string, table?: string | null, data?: T); /** * 以点语法获取对应配置 * @param keyPath * @param target 查询keyPath值的目标对象,不存在时从this.data上查询 * @returns any * @example getVal('login.agree') * getVal('login.remember') */ getVal(keyPath: K, target?: Obj): V; /** * 以点语法修改配置,支持链式调用 * @param keyPath 键路径,如 one.two.three * @param value 赋予的值 * @param deep 当value是对象时是否深度合并,默认不进行深度合并 * @param useJSON 将数据修改至数据库时是否使用JSON.parse(JSON.stringify(this.data)),对于无法进行结构化克隆的数据(如Proxy)可以采用该方式 * @param target 进行赋值的目标对象,存在target则赋值行为都是在target上进行,而不是this.data * @param skipHandle 用于处理合并过程中每一项的函数,返回Truthy则跳过该次的深度合并 * @example * setVal('login.agree.read', true) * 若不存在 {login: {agree: {read: any}}},也可保存成功,且保存后的对象为 {login: {agree: {read: true}}} * * // 移除键 * setVal('login.agree.read', undefined, {useJSON: true}) * // 将值设为undefined但不移除该键 * setVal('login.agree.read') */ setVal(keyPath: K, value?: any, { deep, useJSON, target, skipHandle }?: { deep?: boolean; useJSON?: boolean; target?: Obj; skipHandle?: (key: string, target: Obj, fromValue: any) => boolean; }): this; /** * 以对象形式修改配置,支持链式调用,默认进行深度合并 * @param value * @param targetOrReplace 若为true,则直接将this.data替换为value;若为对象,则合并行为都是在该对象上进行,而不是this.data * @param useJSON 将数据修改至数据库时是否使用JSON.parse(JSON.stringify(this.data)),对于无法进行结构化克隆的数据(如Proxy)可以采用该方式 * @param skipHandle 用于处理合并过程中每一项的函数,返回Truthy则跳过该次的深度合并 * @example * // 只修改 login 中 agree 的 read * save({ * login: { * // _flush: true, // 任意属性赋予这个值则表示直接替换,而不是尝试默认的深度合并 * agree: { * read: true * } * } * }) */ save(value: Obj, targetOrReplace?: boolean | Obj | null, useJSON?: boolean | null, skipHandle?: (key: string, target: Obj, fromValue: any) => boolean | void): this; } type ymdhms = { year: number; month: number; day: number; week: number; hour: number; minute: number; second: number; }; type onUpdate = (rest: ymdhms, date: Date) => void; /** * 用于生成时钟 */ declare class Clock { /** * 用于配合visibilitychange事件批量处理计时的开始&暂停 */ private static task; private static pauseAt; /** * 相当于 new Clock(begin, step, runOnVisible, onUpdate) * @param begin 开始时间,若是一个Date则从此时开始计时,若是falsy则始终以当前时间为准 * @param step 计时的间隔,单位:秒,默认为 1 * @param runOnVisible 是否仅在页面可见时运行。以当前时间为基准时才可启用! * @param onUpdate 更新回调,可在此处获取当前的具体时间,包含年月日周时分秒 * @returns */ static genInstance(begin?: Date | null, step?: number, runOnVisible?: boolean, onUpdate?: onUpdate): Clock; /** * 清理task中已停止的实例 */ static clean(): void; static onPageToggle(): void; /** * 批量开始或暂停task中的时钟 */ static toggleTask(pause?: boolean): void; begin?: Date | null; date: Date; step: number; runOnVisible?: boolean; onUpdate?: onUpdate; private _tid?; private _prev; /** * 生成时钟,实例化即自动开始运行,实例化后立即调用stop可暂停 * * @param begin 开始时间,若是一个Date则从此时开始计时,若是falsy则始终以当前时间为准 * @param step 计时的间隔,单位:秒,默认为 1 * @param runOnVisible 是否仅在页面可见时运行。以当前时间为基准时才可启用! * @param onUpdate 更新回调,可在此处获取当前的具体时间,包含年月日周时分秒 * @example * 生成一个每1秒更新当前时间的实例 * const padZero = num => (num + '').padStart(2, '0') * new Clock(null, null or 1, false, ({year, month, day, week, hour, minute, second}, date) => { * console.log(`now: ${year}-${month}-${padZero(day)} ${padZero(hour)}:${padZero(minute)}:${padZero(second)}`) * }) * * 从2000-01-01 00:00:00起,每5秒更新时间,但暂停以待手动启用 * const clock = new Clock(new Date(2000, 0,1,0,0,0), 5) * clock.stop() * * 3秒后开始,若调用的是clock.start(true),则会变成从当前时刻开始 * setTimeout(() => clock.start(), 3000) */ constructor(begin?: Date | null, step?: number, runOnVisible?: boolean, onUpdate?: onUpdate); getNow(): { year: number; monthIndex: number; month: number; day: number; week: number; hour: number; minute: number; second: number; }; process(skip?: boolean): void; /** * (重新)开始,实例化后自动调用 * @param when 若为true则从当前时间开始 */ start(when?: boolean | number): void; /** * 停止运行 */ stop(): void; /** * 终止并将实例从Clock.tasks中移除 */ remove(): void; } type dhms = { day: number; hour: number; minute: number; second: number; }; /** * @param rest 包含day、hour、minute、second的对象 * @param leftTime 剩余计时的秒数 */ type onCount = (rest: dhms, leftTime: number) => void; /** * 用于生成倒计时 */ declare class Countdown { /** * 用于配合visibilitychange事件批量处理计时的开始&暂停 */ private static task; /** * 相当于 new Countdown(to, runOnVisible, onCount) * @param to 计时终止时间,可以是一个Date,也可以是包含day、hour、minute、second属性的对象 * @param runOnVisible 是否仅在页面可见时进行计时。建议仅在以当前时间为基准时启用。一般情况下浏览器会对定时器进行节流,故可能需要通过visibilitychange刷新当前剩余计时 * @param onCount 处于倒计时中的回调,可在此方法中获取剩余的day、hour、minute、second * @returns */ static genInstance(to: Date | Partial, runOnVisible?: boolean, onCount?: onCount): Countdown; /** * 清理task中已停止计时的实例 */ static clean(): void; static onPageToggle(): void; /** * 批量开始或暂停task中的计时 */ static toggleTask(pause?: boolean): void; from: number; to: Date; runOnVisible?: boolean; onCount?: onCount | null; /** * 在计时终止并移除后触发,返回Truthy可阻止置空onCount */ onEnd?: (leftTime: number) => boolean | void; private _tid?; private _last; /** * 生成倒计时,实例化即自动开始计时,实例化后立即调用stop可暂停计时 * * @param to 计时终止时间,可以是一个Date,也可以是包含day、hour、minute、second属性的对象 * @param runOnVisible 是否仅在页面可见时进行计时。建议仅在以当前时间为基准时启用。一般情况下浏览器会对定时器进行节流,故可能需要通过visibilitychange刷新当前剩余计时 * @param onCount 处于倒计时中的回调,可在此方法中获取剩余的day、hour、minute、second * @example * 开始一个1分20秒的倒计时 * new Countdown({minute: 1, second: 20}, false, ({minute, second}) => {}) * * 开始一个距当前时间剩余1小时的倒计时,但暂停以待手动开始计时 * const countdown = new Countdown(new Date(Date.now() + 3600000), false, ({minute, second}) => {}) * countdown.stop() * * 3秒后开始计时,若调用start(true),则会以当前时刻为计时终止时间 * setTimeout(() => countdown.start(), 3000) */ constructor(to: Date | Partial, runOnVisible?: boolean, onCount?: onCount); getRest(): { day: number; hour: number; minute: number; second: number; }; /** * 保持计时直到结束 */ process(): void; /** * (重新)开始计时,实例化后自动调用 * @param fromNow 若为Truthy则始终以当前时间为计时终止时刻 */ start(fromNow?: boolean): void; /** * 暂停或终止计时 * @param end 是否终止计时 */ stop(end?: boolean): void; /** * 终止计时,并将实例从CountDown.tasks中移除,当倒计时结束后会自动调用 */ remove(): void; } export { Clock, Countdown, Emitter, Scrollbar, StoreByIDB, StoreById, StoreSimply, asyncCopy, debounceFirst, debounceLast, deepMerge, delArrItem, delArrItemByVal, genUID, getPathValue, getScrollBarSize, isObject, makeObjectByPath, moveArrItem, omitOwnKeys, onlyify, polling, saveFile, scroller, serialize, setClipboard, setPathValue, sprintf, throttle, toTopOrBottom }; export type { Falsy, Func, SelfKeyPath, Truthy };