移动端筛选抽屉必须用 fixed + transform 实现,禁用 left/right;遮罩层需 preventDefault 且 z-index 低于抽屉;表单须用 form+fieldset+name 语义化结构,读取值统一用 FormData.entries()。

移动端筛选抽屉必须用 fixed + transform,别碰 left/right
直接改 left 或 right 会触发重排,在 iOS Safari 和部分 Android WebView 中动画卡顿、收不回去,甚至导致页面滚动异常。真实项目里更稳的做法是:抽屉容器设 position: fixed,动画只走 transform: translateX()。
常见错误现象:
• 抽屉滑到一半突然跳回原位
• 键盘弹出后抽屉位置偏移
• 横屏切换时抽屉宽度错乱
- 宽度和偏移量统一用
px(如width: 280px,关着时transform: translateX(280px)),别用%或vw - 加
will-change: transform,尤其在 iOS 上能防闪屏 - 关闭时务必清空
transform内联样式,不能只靠 class 切换——残留值会干扰下一次打开
遮罩层和 body 滚动控制是移动端必填项
不处理这两点,iOS 会卡死、Android 会点透、键盘收起后页面错位。这不是“可选优化”,是功能可用的底线。
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
- 抽屉打开时执行
document.body.style.overflow = 'hidden';关闭时恢复为'auto',别漏掉 - 遮罩层(
overlay)必须绑定touchstart并调用event.preventDefault(),否则手指滑动会滚动背景页 -
overlay的z-index要比抽屉低(如抽屉z-index: 1000,遮罩z-index: 999),否则 iOS 点击穿透到下层 - 关闭逻辑建议用
setTimeout(() => { closeDrawer(); }, 0),绕过 iOS 的 click 延迟陷阱
筛选表单结构必须用 form + fieldset + name 语义化组织
不用 form 标签,就等于放弃 FormData、自动重置、无障碍聚焦、键盘导航这些原生能力。手写一堆 div + data- 属性,后期维护成本翻倍。
立即学习“前端免费学习笔记(深入)”;
- 整个面板用
<form id="filter-form"></form>包裹,哪怕你不用 submit 提交 - 每个筛选维度(品牌、价格、评分)用
<fieldset></fieldset>隔开,标题用<legend></legend> - 多选用
<input type="checkbox" name="brand" value="apple">,别用自定义span+ JS 模拟 - 价格区间拆成两个
<input type="number" name="price_min">和<input type="number" name="price_max">,别塞进一个range - 重置按钮直接绑
form.reset(),前提是它在form内且没被移除
读取筛选值别遍历 DOM,用 FormData.entries() 最可靠
手动查 querySelectorAll('[name]') 或拼字符串容易漏掉未选中的 checkbox、忽略空值、搞混同名多值逻辑。FormData 天然支持多选、自动过滤空值、返回标准键值对。
- 获取值统一用:
const formData = new FormData(document.getElementById('filter-form')); - 转成数组方便处理:
Array.from(formData.entries())→[["brand", "apple"], ["brand", "xiaomi"], ["rating", "4"]] - 价格字段要显式判断是否为空:
if (minVal !== "" && maxVal !== "") { ... },否则""传给后端可能被当 0 - 多选字段(如
brand)被选中多个时,formData.getAll('brand')比get()更安全
data-level 标记层级,每次只渲染当前级,fetch 成功后再替换下一级容器,且每个选项带 data-id 和 data-parent-id,别依赖 DOM 层级找父级。


















