Skip to content

Commit e14b7d9

Browse files
committed
🎈 perf: 优化模糊搜索
1 parent 403367e commit e14b7d9

3 files changed

Lines changed: 37 additions & 86 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
"electron-updater": "^6.6.2",
6060
"file-saver": "^2.0.5",
6161
"font-list": "^2.0.1",
62+
"fuse.js": "^7.1.0",
6263
"get-port": "^7.1.0",
6364
"github-markdown-css": "^5.8.1",
6465
"js-cookie": "^3.0.5",

pnpm-lock.yaml

Lines changed: 12 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/utils/helper.ts

Lines changed: 24 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ import { isEmpty } from "lodash-es";
88
import { convertToLocalTime } from "./time";
99
import { useSettingStore } from "@/stores";
1010
import { marked } from "marked";
11-
import SvgIcon from "@/components/Global/SvgIcon.vue";
1211
import { isElectron } from "./env";
12+
import SvgIcon from "@/components/Global/SvgIcon.vue";
13+
import Fuse from "fuse.js";
1314

1415
type AnyObject = { [key: string]: any };
1516

@@ -75,50 +76,24 @@ export const renderOption = ({ node, option }: { node: VNode; option: SelectOpti
7576
*/
7677
export const fuzzySearch = (keyword: string, data: SongType[]): SongType[] => {
7778
try {
78-
const result: SongType[] = [];
79-
const regex = new RegExp(keyword, "i");
80-
81-
/**
82-
* 递归函数:遍历对象及其嵌套属性,过滤包含关键词的对象
83-
* @param {Object} obj - 要检查的对象
84-
* @returns {boolean} - 如果找到匹配的属性值,返回 true;否则返回 false
85-
*/
86-
const searchInObject = (obj: AnyObject): boolean => {
87-
for (const key in obj) {
88-
if (Object.prototype.hasOwnProperty.call(obj, key)) {
89-
const value = obj[key];
90-
// 如果属性值是对象,则递归调用
91-
if (typeof value === "object" && value !== null) {
92-
if (searchInObject(value)) {
93-
return true;
94-
}
95-
}
96-
// 检查属性值是否是字符串并包含关键词
97-
if (value && typeof value === "string" && regex.test(value)) {
98-
return true;
99-
}
100-
}
101-
}
102-
return false;
103-
};
104-
105-
if (!data) return [];
79+
if (!keyword || !data || !Array.isArray(data)) return [];
10680

107-
// 如果传入的是数组,遍历数组
108-
if (Array.isArray(data)) {
109-
for (const item of data) {
110-
if (searchInObject(item)) {
111-
result.push(item);
112-
}
113-
}
114-
} else {
115-
// 如果传入的是对象,直接调用递归函数
116-
if (searchInObject(data)) {
117-
result.push(data);
118-
}
119-
}
81+
const fuse = new Fuse(data, {
82+
// 针对歌曲可读字段进行索引
83+
keys: [
84+
{ name: "name", weight: 0.5 },
85+
{ name: "alia", weight: 0.2 },
86+
{ name: "artists", weight: 0.15 },
87+
{ name: "artists.name", weight: 0.15 },
88+
{ name: "album", weight: 0.1 },
89+
{ name: "album.name", weight: 0.1 },
90+
{ name: "dj.name", weight: 0.05 },
91+
],
92+
threshold: 0.35, // 0 精确匹配 ~ 1 完全模糊
93+
ignoreLocation: true, // 不要求关键词位置接近
94+
});
12095

121-
return result;
96+
return fuse.search(keyword).map((result) => result.item);
12297
} catch (error) {
12398
console.error("模糊搜索出现错误:", error);
12499
return [];
@@ -385,41 +360,6 @@ export const shuffleArray = <T>(arr: T[]): T[] => {
385360
return copy;
386361
};
387362

388-
/**
389-
* 在浏览器空闲时执行任务
390-
* @param task 要执行的任务
391-
*/
392-
export const runIdle = (task: () => void) => {
393-
try {
394-
const ric = window?.requestIdleCallback as ((cb: () => void) => number) | undefined;
395-
if (typeof ric === "function") {
396-
ric(() => {
397-
try {
398-
task();
399-
} catch {
400-
/* empty */
401-
}
402-
});
403-
} else {
404-
setTimeout(() => {
405-
try {
406-
task();
407-
} catch {
408-
/* empty */
409-
}
410-
}, 0);
411-
}
412-
} catch {
413-
setTimeout(() => {
414-
try {
415-
task();
416-
} catch {
417-
/* empty */
418-
}
419-
}, 0);
420-
}
421-
};
422-
423363
/**
424364
* 处理歌曲音质
425365
* @param song 歌曲数据
@@ -438,12 +378,12 @@ export const handleSongQuality = (
438378
return QualityType.LQ;
439379
}
440380
// 含有 level 特殊处理
441-
if( typeof song === "object" && "level" in song){
442-
if(song.level === "hires") return QualityType.HiRes;
443-
if(song.level === "lossless") return QualityType.SQ;
444-
if(song.level === "exhigh") return QualityType.HQ;
445-
if(song.level === "higher") return QualityType.MQ;
446-
if(song.level === "standard") return QualityType.LQ;
381+
if (typeof song === "object" && "level" in song) {
382+
if (song.level === "hires") return QualityType.HiRes;
383+
if (song.level === "lossless") return QualityType.SQ;
384+
if (song.level === "exhigh") return QualityType.HQ;
385+
if (song.level === "higher") return QualityType.MQ;
386+
if (song.level === "standard") return QualityType.LQ;
447387
return undefined;
448388
}
449389
const order = [

0 commit comments

Comments
 (0)