如何用变量优化document.getElementById,减少RPG骰子工具重复代码?
简化RPG骰子工具的下拉菜单处理代码
我用JavaScript写了一款桌面RPG骰子工具,现在想在添加新功能前简化代码、移除冗余内容。目前工具通过下拉菜单修改掷骰设置,每个菜单都对应独立函数,用document.getElementById把选中值存到全局变量里,现在已经有8个这类菜单,之后还要新增更多,同时要适配同系统的其他游戏(菜单ID和变量名会变更)。
我不想给每个菜单都写新函数,能不能把菜单ID存到变量里,插入到document.getElementById中?比如把MoonSettingSelected = document.getElementById("MoonPhaseMenu");改成类似let SelectedSetting = document.getElementById(SelectedMenu);的形式。我试过用QuerySelectorAll获取菜单数据,但觉得getElementById更好用,我是JavaScript新手。
示例HTML代码
<div class="centre RageOptions"> <select id="MoonPhaseMenu" onclick="SetMoonPhase()" class="menu shadow"> <option value="9999" selected>Moon phase</option> <option value="1">Full</option> <option value="2">Crescent</option> <option value="3">Half</option> <option value="4">Gibbous</option> <option value="5">New</option> </select> </div> <p> </p> <div> <div class="centre RageOptions"> <select id="AuspiceMenu" onclick="SetAuspice()" class="menu shadow"> <option value="9999" selected>Auspice</option> <option value="1">Ahroun</option> <option value="2">Theurge</option> <option value="3">Philodox</option> <option value="4">Galliard</option> <option value="5">Ragabash</option> </select> </div> <p> </p> <div class="centre RageOptions"> <select id="RankMenu" onclick="SetRank()" class="menu shadow"> <option value="9999" selected>Rank</option> <option value="0">Cub (0)</option> <option value="1">Cliath (1)</option> <option value="2">Fostern (2)</option> <option value="3">Adren (3)</option> <option value="4">Athro (4)</option> <option value="5">Elder (5)</option> <option value="6">Legend (6)</option> </select> </div> </div>
示例JavaScript代码
// CHANGE GLOBAL VARIABLES ON MENU SELECT var MoonSetting = "9999"; var AuspiceSetting = "9999"; var GarouRank = Number(0); function SetMoonPhase() { let MoonSettingSelected = document.getElementById("MoonPhaseMenu"); MoonSettingSelected.addEventListener("change", function handleChange(event) { MoonSetting = Number(event.target.value); }); } function SetAuspice() { AuspiceSettingSelected = document.getElementById("AuspiceMenu"); AuspiceSettingSelected.addEventListener( "change", function handleChange(event) { AuspiceSetting = Number(event.target.value); } ); } function SetRank() { // Set GarouRank global variable on menu change GarouRankSelected = document.getElementById("GarouRankMenu"); GarouRankSelected.addEventListener("change", function handleChange(event) { GarouRank = Number(event.target.value); }); } // …and repeat for 5 (and counting) functions, each of which is identical except for the ID in getElementById("…")
优化方案
1. 统一管理菜单与全局变量的映射
先创建一个配置对象,把每个菜单ID和对应的全局变量关联起来,彻底摆脱重复函数:
// 用对象封装所有设置,避免零散全局变量污染作用域 const settings = { MoonSetting: "9999", AuspiceSetting: "9999", GarouRank: 0 }; // 菜单ID与对应设置字段的映射表,新增菜单只需要加一条 const menuMappings = [ { menuId: "MoonPhaseMenu", settingKey: "MoonSetting" }, { menuId: "AuspiceMenu", settingKey: "AuspiceSetting" }, { menuId: "RankMenu", settingKey: "GarouRank" } ];
2. 编写通用事件绑定函数
写一个通用函数遍历映射表,自动给每个菜单绑定change事件,更新对应设置:
function setupMenuHandlers() { menuMappings.forEach(mapping => { const menu = document.getElementById(mapping.menuId); if (!menu) return; // 避免找不到元素报错 menu.addEventListener("change", (event) => { // 根据字段类型转换值,比如GarouRank需要转数字 const value = mapping.settingKey === "GarouRank" ? Number(event.target.value) : event.target.value; settings[mapping.settingKey] = value; }); }); } // 页面加载完成后初始化所有菜单 document.addEventListener("DOMContentLoaded", setupMenuHandlers);
3. 简化HTML,移除冗余属性
原来的onclick属性可以直接删掉,因为初始化函数会自动完成事件绑定:
<div class="centre RageOptions"> <select id="MoonPhaseMenu" class="menu shadow"> <option value="9999" selected>Moon phase</option> <option value="1">Full</option> <option value="2">Crescent</option> <option value="3">Half</option> <option value="4">Gibbous</option> <option value="5">New</option> </select> </div> <p> </p> <div> <div class="centre RageOptions"> <select id="AuspiceMenu" class="menu shadow"> <option value="9999" selected>Auspice</option> <option value="1">Ahroun</option> <option value="2">Theurge</option> <option value="3">Philodox</option> <option value="4">Galliard</option> <option value="5">Ragabash</option> </select> </div> <p> </p> <div class="centre RageOptions"> <select id="RankMenu" class="menu shadow"> <option value="9999" selected>Rank</option> <option value="0">Cub (0)</option> <option value="1">Cliath (1)</option> <option value="2">Fostern (2)</option> <option value="3">Adren (3)</option> <option value="4">Athro (4)</option> <option value="5">Elder (5)</option> <option value="6">Legend (6)</option> </select> </div> </div>
优化优势
- 新增菜单时,只需要在
menuMappings里加一条映射,不用写新函数 - 代码冗余度大幅降低,维护和扩展更轻松
- 用
DOMContentLoaded确保页面元素加载完成后再绑定事件,避免找不到元素的问题 - 保留了你偏好的
getElementById,逻辑清晰直观 - 适配其他游戏时,只需要修改
settings对象和menuMappings数组即可
内容的提问来源于stack exchange,提问作者Richard Cosgrove
相关产品推荐
相关产品推荐

