现代项目优先用 div + display: grid 或 flex;因 table 在筛选、排序、响应式折叠、动态高亮等场景需重建 dom,而 div 仅需切换 class 或 css 变量,数据驱动渲染更高效。

航班列表用 table 还是 div + CSS Grid?
直接说结论:现代项目优先用 div + display: grid 或 flex,不是因为 table 不能用,而是它在筛选、排序、响应式折叠列、动态高亮等场景下会卡死——你得重写整张表的 DOM 结构,而 div 只需改 class 或 CSS 变量。
常见错误现象:table 里嵌套 tbody 动态渲染后,colspan 错位、筛选后分页错乱、移动端横向滚动卡顿。这些不是“写法问题”,是语义和操作粒度不匹配导致的。
- 筛选时只需对每个
div.flight-item切换hidden属性,不用重建 DOM - 想让“出发时间”列在手机上显示为顶部标签+右侧值?用
grid-template-areas一行 CSS 就能重排,table得靠 JS 搬运 HTML - 需要点击列头排序?
Array.sort()后只刷新数据绑定,UI 层完全不动
筛选条件怎么和 DOM 同步而不手动 querySelectorAll?
别写 document.querySelectorAll('.flight-item') 再遍历比对——这是最慢也最容易漏状态的写法。核心原则:筛选逻辑只作用于数据源(数组),DOM 渲染完全由数据驱动。
使用场景:用户选了“起飞城市 = 上海”,又勾了“仅显示直飞”,再输入“价格 ≤ ¥1200”。这三个条件不是独立判断,而是组合成一个过滤函数。
- 把所有航班存为
const flights = [...]数组,每项含departureCity、isDirect、price等字段 - 筛选时只调用
flights.filter(f => f.departureCity === 'SHA' && f.isDirect && f.price - 渲染函数接收这个结果数组,统一生成
div.flight-item,不关心“谁被筛掉了” - 如果用了
localStorage记住上次筛选项,恢复时直接重跑filter,不操作 DOM
input[type="range"] 控制价格区间时,为什么拖动卡顿?
卡顿不是浏览器性能问题,是监听了 input 事件却没做节流,每次像素级拖动都触发一次全量 filter + 重渲染。尤其航班超 50 条时,页面直接假死。
性能影响:未节流时,1 秒内可能触发 60+ 次筛选;加了 requestIdleCallback 或简单 setTimeout 防抖后,稳定在 2–3 次/秒,肉眼无感知延迟。
- 用
let priceTimer+clearTimeout做防抖,延迟 200ms 执行筛选 - 把价格范围显示同步到旁边两个
input[type="number"],但它们只负责展示,不参与逻辑——避免双向绑定引发循环更新 - 注意
range的min/max值必须和真实航班价格范围一致,否则拖动条“空跑”或卡死在端点
移动端折叠详情展开收起,用 details 标签行不行?
行,但仅限静态内容。一旦详情里要放实时票价浮动提示、余票倒计时、或“立即预订”按钮(需绑定事件),details 就暴露短板:无法精确控制动画、不能监听展开完成、CSS 自定义程度低。
容易踩的坑:details[open] 是布尔属性,JS 修改它不会触发动画;想加淡入/高度过渡?得自己用 max-height + transition 模拟,而 details 内部高度是自动计算的,没法设具体数值。
- 用
div.flight-details+aria-expanded+height: 0 / auto+overflow: hidden组合更可控 - 展开时先设
height为元素实际scrollHeight,再加 class 触发 transition;收起时反向操作 - 务必加
role="region"和aria-labelledby,否则屏幕阅读器无法关联标题与内容
复杂点在于动画结束后的清理:比如展开后要 focus 到第一个可操作按钮,这个时机必须等 transitionend 之后,而不是靠 setTimeout 猜。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











