题库列表必须用语义化HTML表格结构:<thead>仅含列名,<tbody>每行一道题;单选/多选题选项须用<fieldset>+<label>包裹并严格绑定id;筛选时应动态重建<tbody>而非隐藏行;导出Excel需符合SheetJS标准解析规则。

表格结构必须用 <thead> 和 <tbody> 明确分离
题库列表本质是数据表格,不是装饰性布局。如果直接用 <tr> 堆叠所有行,会导致排序、筛选、分页等后续功能难以绑定到正确区域。浏览器和辅助技术也依赖语义化结构识别表头。
常见错误是把题干、选项、答案全塞进一个 <tr> 里,结果 <th> 没包裹在 <thead> 中,或者漏掉 <tbody> —— 这会让 JS 操作 document.querySelector('tbody tr') 返回空列表。
-
<thead>只放列名:题目编号、题干、类型、难度、操作 -
<tbody>每道题一行:<tr>内用<td>对齐对应列,不要嵌套表格 - 题干过长时用
title属性或 CSStext-overflow: ellipsis,别靠<br>换行破坏表格流
单选/多选题的选项必须用 <fieldset> + <label> 包裹,不能只靠 <input type="radio">
题库表格里每道题要能直接预览交互效果,但很多人把 <input> 直接丢进 <td>,导致点击文字无法选中、无障碍阅读器读不出关联关系。
真实场景下,用户需要点“B. 跳跃”就选中对应 radio,而不是只点小圆圈——这要求每个选项必须是独立 <label>,且 for 属性匹配 id;多个选项还要用 <fieldset> 归组,否则键盘 Tab 会跨题跳转。
立即学习“前端免费学习笔记(深入)”;
- 每个选项
<input>必须有唯一id,<label>的for值与之严格一致 -
<fieldset>加role="radiogroup"或aria-labelledby提升可访问性 - 禁用状态(如已阅卷)用
disabled属性,不要仅靠 CSS 灰掉
题型切换时,<tbody> 行内容需动态替换而非隐藏显示
用户筛选“判断题”时,如果只是给非判断题行加 style="display:none",会导致 getBoundingClientRect() 计算错位、打印时仍输出、屏幕阅读器未同步状态。
真正干净的做法是清空 <tbody> 后重新 appendChild() 符合条件的 <tr>。尤其当题库超 200 行时,DOM diff 比样式切换更稳定。
- 提前把每道题数据存为数组对象,含
type、stem、options等字段 - 筛选函数返回新
tr元素,而非复用旧 DOM 节点 - 避免在循环中反复调用
innerHTML += ...,改用DocumentFragment批量插入
导出 Excel 时,<table> 必须兼容 SheetJS 的解析规则
很多团队用 xlsx.full.min.js 导出题库,但发现公式乱码、合并单元格丢失、中文列宽异常——根本原因是 HTML 表格用了不被支持的写法。
SheetJS 默认只读取标准 <table> 结构,遇到 <div> 伪装表格、<span> 套 <td>、内联 style="mso-number-format:'@'" 等写法会静默失败。
- 确保
<table>下直接是<thead>/<tbody>,中间无其他标签 - 避免用
colspan/rowspan合并题干单元格,改用服务端生成时处理 - 数字类字段(如难度值)用
<td data-t="n">3</td>显式声明类型,防止被转成文本
表格不是万能容器,题库排列的核心约束其实是“可筛选、可导出、可聚焦导航”。把 <table> 当作数据载体而非样式工具,比追求视觉花哨重要得多。



















