jsly 3.0.6 → 3.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +101 -0
- package/dist/index.cjs.js +193 -0
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +191 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.umd.js +3 -3
- package/dist/index.umd.js.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -7626,5 +7626,195 @@ class EventBus {
|
|
|
7626
7626
|
// 导出单例
|
|
7627
7627
|
const $bus = new EventBus();
|
|
7628
7628
|
|
|
7629
|
-
|
|
7629
|
+
/**
|
|
7630
|
+
* 转义正则表达式中的特殊字符。
|
|
7631
|
+
*
|
|
7632
|
+
* @private
|
|
7633
|
+
* @function escapeRegExp
|
|
7634
|
+
* @description
|
|
7635
|
+
* 将字符串中的正则表达式特殊字符(如 `. * + ? ^ $ { } ( ) | [ ] \\`)全部转义,
|
|
7636
|
+
* 以便安全地用于构建正则表达式。通常用于用户输入的关键字过滤,避免因
|
|
7637
|
+
* 正则表达式语法导致的匹配异常。
|
|
7638
|
+
*
|
|
7639
|
+
* @param {string} str - 需要进行转义的原始字符串。
|
|
7640
|
+
* @returns {string} 已转义、可安全用于 RegExp 的字符串。
|
|
7641
|
+
*
|
|
7642
|
+
* @example
|
|
7643
|
+
* escapeRegExp("a+b*c") // => "a\\+b\\*c"
|
|
7644
|
+
*/
|
|
7645
|
+
function escapeRegExp(str) {
|
|
7646
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7647
|
+
}
|
|
7648
|
+
|
|
7649
|
+
/**
|
|
7650
|
+
* 高亮文本中的关键词。
|
|
7651
|
+
*
|
|
7652
|
+
* @function highlightKeyword
|
|
7653
|
+
* @description
|
|
7654
|
+
* 在给定的文本中查找所有匹配的关键词(不区分大小写),并使用带样式的
|
|
7655
|
+
* HTML 标签(默认 `<span>`)包裹,使其以高亮方式显示。该方法适用于搜索
|
|
7656
|
+
* 结果展示、文本匹配提示等场景。
|
|
7657
|
+
*
|
|
7658
|
+
* @param {string} text - 原始完整文本。
|
|
7659
|
+
* @param {string} keyword - 需要高亮显示的关键词。如果为空,则直接返回原文本。
|
|
7660
|
+
* @param {Object} [config] - 配置对象,用于自定义高亮标签和样式。
|
|
7661
|
+
* @param {string} [config.tag="span"] - 包裹关键词的 HTML 标签名。
|
|
7662
|
+
* @param {string} [config.bgColor="#ff0"] - 高亮背景颜色。
|
|
7663
|
+
* @param {string} [config.color="#001"] - 关键词文字颜色。
|
|
7664
|
+
*
|
|
7665
|
+
* @returns {string} 返回插入带样式标签后的 HTML 字符串。
|
|
7666
|
+
*
|
|
7667
|
+
* @example
|
|
7668
|
+
* highlightKeyword(
|
|
7669
|
+
* "泡泡音乐是一款好用的播放器",
|
|
7670
|
+
* "音乐"
|
|
7671
|
+
* )
|
|
7672
|
+
* // => '泡泡<span style="background-color: #ff0;color: #001;">音乐</span>是一款好用的播放器'
|
|
7673
|
+
*/
|
|
7674
|
+
function highlightKeyword(text, keyword, config = {
|
|
7675
|
+
tag: "span",
|
|
7676
|
+
bgColor: "#ff0",
|
|
7677
|
+
color: "#001"
|
|
7678
|
+
}) {
|
|
7679
|
+
if (!keyword) return text;
|
|
7680
|
+
const {
|
|
7681
|
+
tag,
|
|
7682
|
+
bgColor,
|
|
7683
|
+
color
|
|
7684
|
+
} = config;
|
|
7685
|
+
const pattern = new RegExp(escapeRegExp(keyword), "gi");
|
|
7686
|
+
const style = `background-color: ${bgColor};color: ${color};`;
|
|
7687
|
+
return text.replace(pattern, match => `<${tag} style="${style}">${match}</${tag}>`);
|
|
7688
|
+
}
|
|
7689
|
+
|
|
7690
|
+
/**
|
|
7691
|
+
* 基于 requestAnimationFrame 实现的定时器(RAF Interval)
|
|
7692
|
+
*
|
|
7693
|
+
* 功能类似于 setInterval,但内部使用 requestAnimationFrame 驱动。
|
|
7694
|
+
* 相比 setInterval:
|
|
7695
|
+
* - 与浏览器刷新率同步,更平滑
|
|
7696
|
+
* - 页面不可见时会自动暂停(节省性能)
|
|
7697
|
+
* - 不易出现掉帧或时间漂移问题
|
|
7698
|
+
*
|
|
7699
|
+
* 适用于动画、轮播、游戏循环等需要与渲染帧同步的场景。
|
|
7700
|
+
*
|
|
7701
|
+
* @template {(...args: any[]) => any} F
|
|
7702
|
+
* @param {F} callback - 每次间隔触发时执行的函数。
|
|
7703
|
+
* @param {number} delay - 执行间隔时间(毫秒)。
|
|
7704
|
+
* @returns {() => void} 返回一个停止函数,用于取消循环。
|
|
7705
|
+
*
|
|
7706
|
+
* @example
|
|
7707
|
+
* const stop = rafInterval(() => {
|
|
7708
|
+
* console.log('每秒执行一次')
|
|
7709
|
+
* }, 1000)
|
|
7710
|
+
*
|
|
7711
|
+
* // 停止
|
|
7712
|
+
* stop()
|
|
7713
|
+
*
|
|
7714
|
+
* @example
|
|
7715
|
+
* // 在 Vue 中使用
|
|
7716
|
+
* let stop
|
|
7717
|
+
* onMounted(() => {
|
|
7718
|
+
* stop = rafInterval(() => {
|
|
7719
|
+
* rotate.value += 1
|
|
7720
|
+
* }, 16)
|
|
7721
|
+
* })
|
|
7722
|
+
*
|
|
7723
|
+
* onUnmounted(() => {
|
|
7724
|
+
* stop()
|
|
7725
|
+
* })
|
|
7726
|
+
*/
|
|
7727
|
+
function rafInterval(callback, delay) {
|
|
7728
|
+
if (typeof callback !== 'function') {
|
|
7729
|
+
throw new TypeError('rafInterval expected a function as the first argument');
|
|
7730
|
+
}
|
|
7731
|
+
let start = performance.now();
|
|
7732
|
+
let frameId = null;
|
|
7733
|
+
let stopped = false;
|
|
7734
|
+
function loop(now) {
|
|
7735
|
+
if (stopped) return;
|
|
7736
|
+
const delta = now - start;
|
|
7737
|
+
if (delta >= delay) {
|
|
7738
|
+
callback();
|
|
7739
|
+
// 使用 += 防止时间漂移
|
|
7740
|
+
start += delay;
|
|
7741
|
+
}
|
|
7742
|
+
frameId = requestAnimationFrame(loop);
|
|
7743
|
+
}
|
|
7744
|
+
frameId = requestAnimationFrame(loop);
|
|
7745
|
+
return function stop() {
|
|
7746
|
+
stopped = true;
|
|
7747
|
+
if (frameId) cancelAnimationFrame(frameId);
|
|
7748
|
+
};
|
|
7749
|
+
}
|
|
7750
|
+
|
|
7751
|
+
/**
|
|
7752
|
+
* 轮询函数(Polling)
|
|
7753
|
+
*
|
|
7754
|
+
* 按指定间隔重复执行异步任务,直到:
|
|
7755
|
+
* 1. 任务返回 truthy 值(成功)
|
|
7756
|
+
* 2. 超时
|
|
7757
|
+
* 3. 被手动停止
|
|
7758
|
+
*
|
|
7759
|
+
* 常用于:
|
|
7760
|
+
* - 接口状态查询
|
|
7761
|
+
* - 等待资源加载完成
|
|
7762
|
+
* - 检测条件成立
|
|
7763
|
+
*
|
|
7764
|
+
* @template T
|
|
7765
|
+
* @param {() => Promise<T> | T} task - 需要轮询执行的函数(支持同步或异步)。
|
|
7766
|
+
* @param {Object} [options]
|
|
7767
|
+
* @param {number} [options.interval=1000] - 每次轮询间隔时间(毫秒)。
|
|
7768
|
+
* @param {number} [options.timeout=0] - 超时时间(毫秒),0 表示不限制。
|
|
7769
|
+
* @returns {{ promise: Promise<T>, stop: () => void }}
|
|
7770
|
+
*
|
|
7771
|
+
* @example
|
|
7772
|
+
* const { promise, stop } = poll(
|
|
7773
|
+
* () => fetch('/api/status').then(r => r.json()),
|
|
7774
|
+
* { interval: 2000, timeout: 10000 }
|
|
7775
|
+
* )
|
|
7776
|
+
*
|
|
7777
|
+
* promise.then(res => console.log('成功:', res))
|
|
7778
|
+
*/
|
|
7779
|
+
function poll(task, {
|
|
7780
|
+
interval = 1000,
|
|
7781
|
+
timeout = 0
|
|
7782
|
+
} = {}) {
|
|
7783
|
+
if (typeof task !== 'function') {
|
|
7784
|
+
throw new TypeError('poll expected a function as the first argument');
|
|
7785
|
+
}
|
|
7786
|
+
let stopped = false;
|
|
7787
|
+
let startTime = Date.now();
|
|
7788
|
+
let timer = null;
|
|
7789
|
+
const promise = new Promise((resolve, reject) => {
|
|
7790
|
+
async function execute() {
|
|
7791
|
+
if (stopped) return;
|
|
7792
|
+
try {
|
|
7793
|
+
const result = await task();
|
|
7794
|
+
if (result) {
|
|
7795
|
+
resolve(result);
|
|
7796
|
+
return;
|
|
7797
|
+
}
|
|
7798
|
+
if (timeout && Date.now() - startTime >= timeout) {
|
|
7799
|
+
reject(new Error('Polling timeout'));
|
|
7800
|
+
return;
|
|
7801
|
+
}
|
|
7802
|
+
timer = setTimeout(execute, interval);
|
|
7803
|
+
} catch (err) {
|
|
7804
|
+
reject(err);
|
|
7805
|
+
}
|
|
7806
|
+
}
|
|
7807
|
+
execute();
|
|
7808
|
+
});
|
|
7809
|
+
function stop() {
|
|
7810
|
+
stopped = true;
|
|
7811
|
+
if (timer) clearTimeout(timer);
|
|
7812
|
+
}
|
|
7813
|
+
return {
|
|
7814
|
+
promise,
|
|
7815
|
+
stop
|
|
7816
|
+
};
|
|
7817
|
+
}
|
|
7818
|
+
|
|
7819
|
+
export { $bus, buildObjFormData, camelToSnake, convertKeys, copyByClipboardAPI, copyByExecCommand, copyToClipboard, debounce, deepDiff, generateBrowserId, highlightKeyword, poll, rafInterval, randomHash, sha256, shallowDiff, snakeToCamel, throttle, toggleConvertCase };
|
|
7630
7820
|
//# sourceMappingURL=index.esm.js.map
|