调整页面上的下拉列表选项顺序,保留原本的默认值,并按首字母排序,并且使用懒加载功能
// ==UserScript== // @name Replace Dropdown Lists for Bangumi // @name:zh-CN bangumi下拉列表排序 // @namespace https://github.com/Adachi-Git/ReplaceDropdownListsForBangumi // @version 0.6 // @description 调整页面上的下拉列表选项顺序,保留原本的默认值,并按首字母排序,并且使用懒加载功能 // @author Adachi // @match *://bangumi.tv/subject/* // @match *://bgm.tv/subject/* // @match *://chii.in/subject/* // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; var delay = 2000; // 设置延迟执行时间,单位是毫秒 // 汉字拼音首字母映射表 var pinyinMap = { '原': 'Y', '总': 'Z', '导': 'D', '副': 'F', '脚': 'J', '分': 'F', '主': 'Z', '演': 'Y', '音': 'Y', '人': 'R', '构': 'G', '系': 'X', '美': 'M', '色': 'S', '机': 'J', '道': 'D', '作': 'Z', '动': 'D', '摄': 'S', 'C': 'C', '3': '3', '监': 'J', '第': 'D', 'O': 'O', '制': 'Z', '背': 'B', '数': 'S', '剪': 'J', '插': 'C', '企': 'Q', '宣': 'X', '录': 'L', '製': 'Z', '设': 'S', '特': 'T', '配': 'P', '联': 'L', '补': 'B', '执': 'Z', '助': 'Z', '台': 'T', '后': 'H', '协': 'X', '连': 'L', '译': 'Y', '客': 'K', '文': 'W', '出': 'C', '改': 'G', '前': 'Q', '续': 'X', '全': 'Q', '番': 'F', '相': 'X', '不': 'B', '衍': 'Y', '角': 'J', '其': 'Q', '开': 'K', '发': 'F', '游': 'Y', '剧': 'J', 'S': 'S', '程': 'C', 'Q': 'Q', '关': 'G', '创': 'C', '编': 'B', '共': 'G', '故': 'G', '艺': 'Y', '厂': 'C', '片': 'P', '印': 'Y', '广': 'G', }; // 定义一个函数来处理下拉列表的逻辑 function adjustSelectOptions(select) { // 保存原本的默认值 var defaultValue = select.value; // 获取所有选项并转换为数组 var optionsArray = Array.from(select.options); // 移除所有选项 optionsArray.forEach(function(option) { select.remove(option.index); }); // 按汉字的拼音首字母排序选项数组 optionsArray.sort(function(a, b) { var pinyinA = pinyinMap[a.textContent[0]]; var pinyinB = pinyinMap[b.textContent[0]]; // 如果拼音首字母不存在,则将其视为 -Infinity,确保空值被放到列表的最上面 pinyinA = pinyinA ? pinyinA : -Infinity; pinyinB = pinyinB ? pinyinB : -Infinity; // 排序时忽略空值 if (pinyinA === -Infinity && pinyinB === -Infinity) { return 0; } else if (pinyinA === -Infinity) { return -1; } else if (pinyinB === -Infinity) { return 1; } else { return pinyinA.localeCompare(pinyinB); } }); // 将重新排序后的选项重新添加到下拉列表中,并在选项文本前添加拼音首字母 optionsArray.forEach(function(option) { var originalText = option.textContent; var pinyin = pinyinMap[originalText[0]]; // 如果拼音首字母存在,则在文本前添加拼音首字母;否则只保留原始文本 option.textContent = (pinyin ? pinyin + ' - ' : '') + originalText; select.add(option); }); // 保留原本的默认值 select.value = defaultValue; } // 延迟执行处理函数 setTimeout(function() { // 查找可见的下拉列表并处理它们 var selects = document.querySelectorAll('select[name^="infoArr"]:not([data-adjusted])'); selects.forEach(function(select) { if (isElementInViewport(select)) { adjustSelectOptions(select); select.setAttribute('data-adjusted', 'true'); } }); }, delay); // 添加 DOM 变化的监听器 var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { // 查找新增的下拉列表并处理 var newSelects = mutation.target.querySelectorAll('select[name^="infoArr"]:not([data-adjusted])'); newSelects.forEach(function(newSelect) { if (isElementInViewport(newSelect)) { adjustSelectOptions(newSelect); newSelect.setAttribute('data-adjusted', 'true'); } }); }); }); // 监听整个文档的变化 observer.observe(document.documentElement, { childList: true, subtree: true }); // 添加滚动事件监听器 window.addEventListener('scroll', function() { // 查找尚未处理的下拉列表 var selects = document.querySelectorAll('select[name^="infoArr"]:not([data-adjusted])'); selects.forEach(function(select) { // 如果该下拉列表在视图内,进行处理并标记为已处理 if (isElementInViewport(select)) { adjustSelectOptions(select); select.setAttribute('data-adjusted', 'true'); } }); }); // 检查元素是否在视图内 function isElementInViewport(element) { var rect = element.getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); } })();