表格行列中DIV拆分问题:时间表第5-7行首列布局求解
解决时间表布局与拖拽问题的方案
你遇到的核心问题是跨时段课程在起始时间不同时无法在同一单元格横向并排,以及依赖rowspan合并单元格带来的布局局限性。下面是针对你的场景的具体解决方案,包含代码修改和逻辑调整:
一、核心思路调整
放弃通过rowspan合并多行单元格的方式,改为在每个小时对应的单元格中渲染所有覆盖该小时的课程条目。这样不管课程起始时间是否相同,只要覆盖当前小时,就会出现在同一单元格内,自然支持横向并排展示。
二、代码修改
1. 更新表格生成函数 GuiXeduleWeekList
调整数据处理逻辑,提前按「小时-星期」维度整理所有课程条目,确保每个单元格能获取到覆盖当前时段的所有内容:
public function GuiXeduleWeekList($p_aSubArray) { echo("<table border='1' class='table' width='100%' style='background-color:white'>"); echo("<tr><th class='text-center'>RE</th>"); foreach($_SESSION['aWeekdays'] as $sDay){ echo("<th class='text-center'>".$sDay."</th>"); } echo("</tr>"); // 预整理数据:按[小时][星期]存储所有覆盖该时段的课程条目 $aHourDayEntries = []; foreach($p_aSubArray as $aEntry){ $iStartHour = $aEntry[6]; $iEndHour = $aEntry[7]; $iDay = $aEntry[5]; // 遍历课程覆盖的所有小时,将条目存入对应维度 for($h = $iStartHour; $h <= $iEndHour; $h++){ $aHourDayEntries[$h][$iDay][] = $aEntry; } } for($iWeekHour = 1; $iWeekHour <= 17; $iWeekHour++){ echo("<tr>"); echo("<th>".$iWeekHour." ".$_SESSION['aREUnits'][$iWeekHour-1]."</th>"); for($iDayOfTheWeek = 1;$iDayOfTheWeek<=5;$iDayOfTheWeek++){ $aCellEntries = $aHourDayEntries[$iWeekHour][$iDayOfTheWeek] ?? []; if(!empty($aCellEntries)){ // 去重避免同一课程在多个小时单元格重复渲染 $uniqueEntries = array_unique($aCellEntries, SORT_REGULAR); $this->cellContent($uniqueEntries); } else { echo("<td class='empty'><div id='drop_zone' ondragenter='drag_enter(event)' ondrop='drag_drop(event)' ondragover='return false' ondragleave='drag_leave(event)'></div></td>"); } } echo("</tr>"); } echo("</table>"); }
2. 重构内容生成函数 cellContent
移除rowspan相关逻辑,专注于渲染单个单元格内的所有课程条目,支持横向并排:
protected function cellContent($p_aCellContent){ echo("<td class='filled back_blue'><div class='entry-container'>"); foreach($p_aCellContent as $aCellContent){ $sLesson = $this->fetchLessonName($aCellContent[2]); $sClassname = $this->fetchClassName($aCellContent[4]); $sTeacher = $this->fetchTeacher($aCellContent[3]); $sClassroom = $this->fetchClassroom($aCellContent[1]); // 给每个课程添加唯一ID,方便拖拽时识别 $entryId = $aCellContent[0]; // 假设数组第一个元素是数据库主键ID echo("<div draggable='true' ondragstart='drag_start(event, ".$entryId.")' ondragend='drag_end(event)' class='schedule-entry'>"); echo("<form method='post'>"); echo("<input type='hidden' name='entry_id' value='".$entryId."'>"); echo("<input type='hidden' name='iClass' value='".$aCellContent[4]."'>"); echo("<input type='hidden' name='iTeacher' value='".$aCellContent[3]."'>"); echo("<input type='hidden' name='iClassroom' value='".$aCellContent[1]."'>"); echo($sLesson."<br>"); echo("<button type='submit' class='btn btn-sm btn-light'>".$sClassname."</button><br>"); echo("<button type='submit' class='btn btn-sm btn-light'>".$sTeacher."</button><br>"); echo("<button type='submit' class='btn btn-sm btn-light'>".$sClassroom."</button>"); echo("</form>"); echo("</div>"); } echo("</div></td>"); return; }
3. 优化CSS布局
使用Flexbox实现条目横向并排,替换容易引发布局冲突的float:
.entry-container { display: flex; gap: 8px; /* 条目之间的间距 */ padding: 4px; flex-wrap: wrap; /* 条目过多时自动换行 */ } .schedule-entry { border: #cccccc solid 2px; border-radius: 4px; padding: 6px; background-color: #f8f9fa; min-width: 120px; } .schedule-entry form { margin: 0; } .schedule-entry .btn { margin: 2px 0; width: 100%; }
三、拖拽功能补充建议
为实现拖拽后同步数据库,你需要完善以下逻辑:
- 在
drag_start中携带课程ID、原时间范围等信息,通过event.dataTransfer.setData()传递 - 在
drag_drop中获取目标单元格对应的小时和星期数,发送AJAX请求更新数据库 - 更新成功后重新渲染时间表,确保布局同步
示例拖拽逻辑(JavaScript):
function drag_start(event, entryId) { // 获取当前课程所在的小时和星期 const hour = event.target.closest('tr').querySelector('th').textContent.split(' ')[0]; const day = event.target.closest('td').cellIndex; event.dataTransfer.setData('entryId', entryId); event.dataTransfer.setData('originalHour', hour); event.dataTransfer.setData('originalDay', day); } function drag_drop(event) { event.preventDefault(); const entryId = event.dataTransfer.getData('entryId'); // 获取目标单元格对应的小时和星期 const targetHour = event.target.closest('tr').querySelector('th').textContent.split(' ')[0]; const targetDay = event.target.closest('td').cellIndex; // 发送AJAX请求更新数据库 fetch('update_schedule.php', { method: 'POST', headers: {'Content-Type': 'application/x-www-form-urlencoded'}, body: `entry_id=${entryId}&target_hour=${targetHour}&target_day=${targetDay}` }) .then(response => response.json()) .then(data => { if(data.success) { // 重新渲染时间表 location.reload(); // 或调用你的表格渲染函数 } }); }
四、方案优势说明
- 摆脱
rowspan限制:每个小时单元格独立负责自身内容,避免合并单元格导致的布局冲突 - 数据精准匹配:提前按时段整理课程,确保每个单元格能展示所有覆盖该时段的内容
- 稳定的横向布局:Flexbox原生支持横向并排,自动处理换行,比
float更可靠 - 拖拽逻辑解耦:每个课程携带唯一标识,拖拽后可精准更新数据库
内容的提问来源于stack exchange,提问作者Johan de Klijn
相关产品推荐
相关产品推荐

