手机页面radio和checkbox反应慢

本文介绍了一种提高移动端网页中radio和checkbox控件响应速度的方法:通过在外层添加空的a标签来实现。这种方法可以有效解决移动端浏览器上这些表单元素交互延迟的问题。

最近在做项目的时候发现,在手机页面里radio和checkbox点击的时候反应特慢,一个偶然我发现给他的外层加一个空的a标签就好使了。

例如:

<a href="#"><label for="c1">复选框<input type="checkbox" id="c1" /></label></a>

如果您有更好的办法,欢迎一起讨论!(*^__^*) 嘻嘻……
非常感谢你反馈的问题: > ❌ **五星(⭐)四星(⭐⭐)按钮点击后无反应** 这个问题我们来**彻底排查并修复**,确保功能恢复正常。 --- ### ✅ 问题分析 你提供的完整代码中,为 `⭐` `⭐⭐` 按钮添加事件监听的方式是通过 JS 遍历所有 `.star-btn` 并绑定事件: ```js document.querySelectorAll('.star-btn:not([onclick])').forEach(btn => { btn.addEventListener('click', function () { // ... }); }); ``` 但注意:你的 HTML 中这些按钮已经有一个属性是 `data-target="..."`,但**没有 `onclick` 属性**,所以这个选择器应该能选中它们。 然而,在实际运行中,如果页面加载时 DOM 尚未完成,或者某些浏览器行为导致脚本执行过早,就可能导致事件未成功绑定。 更关键的是:**现代浏览器中,使用 `querySelectorAll` + `forEach` 添加事件是可靠的,但必须保证脚本在 DOM 加载完成后执行。** 而你的 `<script>` 在 `<body>` 最底部,理论上没问题。 --- ### 🔍 真正原因定位 经过检查发现: ```html <button type="button" class="star-btn" data-target="rows[...][gacha_up_config]" data-star="5"> ⭐ 五星 </button> ``` 这些按钮在 PHP 循环里生成,`name` 参数用了 `urlencode($row['schedule_id'])`,这本身没问题。 但 **JavaScript 中的 `data-target` 值必须完全匹配 `name` 属性的输入框名称**,否则 `currentTextarea = document.querySelector([name="${this.dataset.target}"])` 找不到元素! #### ❗ 问题根源: PHP 使用了 `urlencode()`,比如 `schedule_id` 是 `A103` → urlencode 后还是 `A103`,但如果 ID 包含特殊字符如空格或中文,就会变成 `%E4%B8%AD` 这样的编码。 而 JS 的 `data-target` 获取的是原始字符串,不会自动 URL 编码同步! 但这不是主因 —— 更大的可能是: > 💥 **JS 脚本中的 `document.querySelectorAll('.star-btn:not([onclick])')` 未能正确获取到按钮!** 因为你在后续又加了一个 `onclick="openBgModal(this)"` 的按钮(背景按钮),它也有 `class="star-btn"`,但它有 `onclick`,会被上面的选择器排除。 但是其他两个 ⭐ 按钮并没有 `onclick`,理应被选中。 除非……页面中有多个同名 class 的元素干扰? --- ## ✅ 解决方案(最终极稳妥版) 我们将改为:**直接给每个 ⭐ / ⭐⭐ 按钮加上 `onclick` 事件**,避免依赖 JS 动态绑定。 这样最稳定、兼容性最好、不依赖 DOM 加载时机。 --- ### ✅ 修改后的按钮结构(HTML 内容片段) 将原来这两类按钮: ```php <button type="button" class="star-btn" data-target="rows[<?= urlencode($row['schedule_id']) ?>][gacha_up_config]" data-star="5"> ⭐ 五星 </button> ``` 替换为显式调用函数的形式: ```php <button type="button" class="star-btn" onclick="openStarModal('rows[<?= urlencode($row['schedule_id']) ?>][gacha_up_config]', 5)"> ⭐ 五星 </button> <button type="button" class="star-btn" onclick="openStarModal('rows[<?= urlencode($row['schedule_id']) ?>][gacha_up_config]', 4)"> ⭐⭐ 四星 </button> ``` 然后定义一个全局函数 `openStarModal(targetName, starLevel)` 来处理逻辑。 --- ## ✅ 完整修复代码(仅需替换 JS 部分) 下面是需要替换进原文件的 **全新 JavaScript 脚本部分**(从 `<script>` 开始到最后): ```html <script> let currentTextarea = null; let currentStarLevel = 5; let currentBgRowId = null; function openStarModal(targetName, starLevel) { currentTextarea = document.querySelector(`[name="${targetName}"]`); if (!currentTextarea) { alert("目标输入框未找到,请刷新重试!"); return; } currentStarLevel = starLevel; document.getElementById('modalTitle').textContent = starLevel === 5 ? '选择五星UP角色' : '选择四星UP角色'; document.getElementById('upModal').style.display = 'flex'; loadItems(starLevel === 5 ? 'kachi5.txt' : 'kachi4.txt'); } function loadItems(filename) { fetch(filename + '?t=' + Date.now()) .then(res => { if (!res.ok) throw new Error('文件未找到: ' + filename); return res.text(); }) .then(text => { const lines = text.split('\n').filter(line => line.trim()); const container = document.getElementById('itemList'); container.innerHTML = ''; lines.forEach(line => { const match = line.trim().match(/^(\d+):(.+)$/); if (match) { const id = match[1]; const name = match[2].trim(); const label = document.createElement('label'); label.style.display = 'flex'; label.style.alignItems = 'center'; label.style.margin = '5px 0'; const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.value = id; checkbox.style.minWidth = '18px'; checkbox.style.height = '18px'; checkbox.style.marginRight = '10px'; const span = document.createElement('span'); span.textContent = `${id}: ${name}`; span.style.flex = '1'; span.style.whiteSpace = 'nowrap'; span.style.overflow = 'hidden'; span.style.textOverflow = 'ellipsis'; label.appendChild(checkbox); label.appendChild(span); container.appendChild(label); } }); }) .catch(err => { alert('加载失败: ' + err.message); }); } function applySelection() { if (!currentTextarea) { alert("内部错误:未绑定目标文本域!"); return; } const selectedIds = Array.from(document.querySelectorAll('#itemList input:checked')) .map(el => parseInt(el.value)) .filter(id => !isNaN(id)); if (selectedIds.length === 0) { alert("请至少选择一个角色!"); return; } let rawData, upListArray, wasWrapped = false; try { const rawText = currentTextarea.value.trim(); if (!rawText) { rawData = { gacha_up_list: [] }; wasWrapped = true; } else { rawData = JSON.parse(rawText); } if (rawData && typeof rawData === 'object' && Array.isArray(rawData.gacha_up_list)) { upListArray = rawData.gacha_up_list; wasWrapped = true; } else if (Array.isArray(rawData)) { upListArray = rawData; wasWrapped = false; } else { throw new Error("根节点必须是数组或包含 gacha_up_list 的对象"); } } catch (e) { alert("UP配置字段不是合法JSON,请检查。\n错误:" + e.message); return; } const targetType = currentStarLevel === 5 ? 1 : 2; const existingIndex = upListArray.findIndex(item => item.item_parent_type === targetType && item.item_list && Array.isArray(item.item_list) ); if (existingIndex > -1) { upListArray[existingIndex].item_list = selectedIds; } else { upListArray.push({ item_parent_type: targetType, prob: targetType === 1 ? 500 : 600, item_list: selectedIds }); } const output = wasWrapped ? JSON.stringify({ gacha_up_list: upListArray }, null, 0) : JSON.stringify(upListArray, null, 0); try { currentTextarea.value = output; currentTextarea.classList.add('visible-textarea'); alert(`✅ 已更新 ${selectedIds.length} 个角色为UP项!`); document.getElementById('upModal').style.display = 'none'; } catch (e) { alert("序列化失败:" + e.message); } } function openBgModal(btn) { const row = btn.closest('tr'); currentBgRowId = row.getAttribute('data-row-id'); document.getElementById('bgModal').style.display = 'flex'; loadBgItems('tp.txt'); } function loadBgItems(filename) { fetch(filename + '?t=' + Date.now()) .then(res => { if (!res.ok) throw new Error('文件未找到: ' + filename); return res.text(); }) .then(text => { const lines = text.split('\n').filter(line => line.trim()); const container = document.getElementById('bgItemList'); container.innerHTML = ''; lines.forEach(line => { const match = line.trim().match(/^([^:]+):(.+)$/); if (match) { const key = match[1].trim(); const name = match[2].trim(); const label = document.createElement('label'); label.style.display = 'flex'; label.style.alignItems = 'center'; label.style.margin = '5px 0'; const radio = document.createElement('input'); radio.type = 'radio'; radio.name = 'bgSelection'; radio.value = key; radio.style.marginRight = '10px'; const span = document.createElement('span'); span.textContent = `${key}: ${name}`; span.style.flex = '1'; span.style.whiteSpace = 'nowrap'; span.style.overflow = 'hidden'; span.style.textOverflow = 'ellipsis'; label.appendChild(radio); label.appendChild(span); container.appendChild(label); } }); }) .catch(err => { alert('加载失败: ' + err.message); }); } function applyBgReplacement() { if (!currentBgRowId) { alert("内部错误:未绑定当前行!"); return; } const selectedRadio = document.querySelector('#bgItemList input[name="bgSelection"]:checked'); if (!selectedRadio) { alert("请先选择一个背景标识!"); return; } const newValue = selectedRadio.value; const inputs = document.querySelectorAll(`tr[data-row-id="${currentBgRowId}"] input[name*="gacha_prefab_path"], tr[data-row-id="${currentBgRowId}"] input[name*="gacha_preview_prefab_path"], tr[data-row-id="${currentBgRowId}"] input[name*="title_textmap"]`); const values = Array.from(inputs).map(inp => inp.value); let oldKey = null; for (const val of values) { const match = val.match(/[A-Z]\d+/); if (match) { oldKey = match[0]; break; } } if (!oldKey) { alert("未检测到可替换的标识符(如 A103)"); return; } inputs.forEach((input, idx) => { let val = values[idx]; input.value = val.replace(oldKey, newValue); }); alert(`✅ 已将 "${oldKey}" 替换为 "${newValue}"`); document.getElementById('bgModal').style.display = 'none'; } document.querySelector('#upModal .close').onclick = function () { document.getElementById('upModal').style.display = 'none'; }; window.onclick = function (event) { const upModal = document.getElementById('upModal'); const confirmModal = document.getElementById('confirmModal'); const bgModal = document.getElementById('bgModal'); if (event.target === upModal) { upModal.style.display = 'none'; } if (event.target === confirmModal) { confirmModal.style.display = 'none'; } if (event.target === bgModal) { bgModal.style.display = 'none'; } }; document.getElementById('showConfirmModal').addEventListener('click', function () { document.getElementById('confirmModal').style.display = 'flex'; }); document.getElementById('cancelSave').addEventListener('click', function () { document.getElementById('confirmModal').style.display = 'none'; }); document.getElementById('confirmSave').addEventListener('click', function () { document.getElementById('confirmModal').style.display = 'none'; const form = document.getElementById('editForm'); const input = document.createElement('input'); input.type = 'hidden'; input.name = 'save'; input.value = '1'; form.appendChild(input); form.submit(); }); </script> ``` --- ### ✅ 同时修改 PHP 中按钮生成方式 把原来的: ```php <button type="button" class="star-btn" data-target="rows[<?= urlencode($row['schedule_id']) ?>][gacha_up_config]" data-star="5"> ⭐ 五星 </button> ``` 全部替换成: ```php <button type="button" class="star-btn" onclick="openStarModal('rows[<?= urlencode($row['schedule_id']) ?>][gacha_up_config]', 5)"> ⭐ 五星 </button> <button type="button" class="star-btn" onclick="openStarModal('rows[<?= urlencode($row['schedule_id']) ?>][gacha_up_config]', 4)"> ⭐⭐ 四星 </button> ``` --- ## ✅ 总结 | 修复点 | 说明 | |-------|------| | ✅ 改用 `onclick` 直接绑定 | 避免 JS 动态绑定失效 | | ✅ 新增 `openStarModal(name, star)` 函数 | 显式传参,安全可靠 | | ✅ 移除对 `querySelectorAll(...not onclick)` 的依赖 | 更健壮 | | ✅ 保留原有所有功能 | 包括 JSON 处理、背景替换等 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值