简介:本资源面向前端开发人员及 Bootstrap Table 初中级使用者,聚焦解决表格列宽固定难适配、交互体验弱等实际痛点,提供一套开箱即用的列宽自定义与拖拽调整完整方案。压缩包共14个文件,含6个JS(如 bootstrap-table.js、colResizable-1.6.js、bootstrap-table-zh-CN.js 等核心脚本)、6个CSS(涵盖 bootstrap.min.css、bootstrap-table.min.css 及 colresize 插件样式)以及1个HTML示例页和1个JSON模拟数据,总大小仅117KB,轻量易集成。已有8416人学习下载,说明其在真实项目中具备较高复用价值。读者可直接获取已配置好>function initWidth($table, columns) { const totalWidth = $table.parent().innerWidth(); // 获取容器可用宽度 let usedWidth = 0; let flexibleCols = []; columns.forEach((col, index) => { if (col.width && !isNaN(col.width)) { // 显式配置:支持 '120px'、'20%'、150(数字视为 px) const parsed = parseWidth(col.width, totalWidth); col._width = parsed; usedWidth += parsed; } else if (col.width === 'auto') { // auto 列留白,后续按剩余空间均分 flexibleCols.push(index); } else { // 无配置列,默认给 100px(防 collapse) col._width = 100; usedWidth += 100; } }); // 均分剩余空间给 auto 列 if (flexibleCols.length && usedWidth < totalWidth) { const rest = totalWidth - usedWidth; const perCol = Math.max(80, Math.floor(rest / flexibleCols.length)); flexibleCols.forEach(idx => { columns[idx]._width = perCol; }); } }
注意:
parseWidth是个关键工具函数,它把'20%'转成totalWidth * 0.2,把'150px'提取数字 150,把200直接当像素值。不要直接写col.width = '150px'—— Bootstrap Table 内部会忽略带单位的字符串,必须转成纯数字存到_width(私有属性)供后续拖拽使用。
2.2 拖拽事件监听器:捕获鼠标移动,实时重绘分隔线
拖拽不是靠 CSSresize,而是用原生mousedown→mousemove→mouseup三件套。项目在onPostBody钩子里为每列<th>后插入一个<div class="bs-table-resize-handle">作为拖拽手柄,并绑定事件:
function bindDragEvents($table) { const $headers = $table.find('thead th'); $headers.each(function(index) { const $th = $(this); const $handle = $('<div class="bs-table-resize-handle"></div>'); // 手柄绝对定位,覆盖在 th 右侧边缘 $handle.css({ position: 'absolute', top: 0, right: 0, width: '6px', height: '100%', cursor: 'col-resize', zIndex: 10 }).appendTo($th); let isDragging = false; let startX, startWidth, $nextTh; $handle.on('mousedown', function(e) { e.preventDefault(); isDragging = true; startX = e.clientX; startWidth = $th.outerWidth(); $nextTh = $th.next('th'); // 拖拽影响当前列和右侧列 }); $(document).on('mousemove.drag', function(e) { if (!isDragging) return; const diff = e.clientX - startX; const newWidth = Math.max(80, startWidth + diff); // 最小 80px 防崩溃 const nextWidth = $nextTh.outerWidth() - diff; $th.css('width', newWidth); $nextTh.css('width', Math.max(80, nextWidth)); }); $(document).on('mouseup.drag', function() { if (isDragging) { isDragging = false; $(document).off('.drag'); // 解绑,避免内存泄漏 saveColumnWidths($table); // 拖完立刻存 } }); }); }提示:这里用
$(document)绑定mousemove/mouseup是为了防止鼠标快速拖出表格区域导致事件丢失。off('.drag')的命名空间解绑是血泪经验——漏掉这句,连续点两次拖拽手柄会导致事件叠加,越拖越快。
2.3 列宽持久化控制器:localStorage 存键名,不是存 DOM 宽度
很多人以为存th.style.width就行,但实际会翻车:响应式下窗口缩放、列显示/隐藏切换都会重置style.width。项目用更健壮的策略:以 table ID + 列 field 名为 key,存数值型宽度。例如表格<table id="courseTable">的teacher列,存的是courseTable:teacher:142(142 是像素值)。saveColumnWidths和loadColumnWidths成对工作:
function saveColumnWidths($table) { const tableId = $table.attr('id') || 'unnamed'; const widths = {}; $table.find('thead th').each(function(index) { const $th = $(this); const field = $th.data('field'); // Bootstrap Table 要求列必须有><!-- ✅ 正确 --> <table id="userTable"><!-- ❌ 错误:没><!-- 在所有 JS 加载完毕后 --> <script> $(function() { // 1. 先初始化 Bootstrap Table $('#userTable').bootstrapTable({ // 你的所有配置... pagination: true, sidePagination: 'server' }); // 2. 紧接着调用补丁(顺序不能错!) // 如果用 script 标签引入,全局有 window.BootstrapTableResizableColumns BootstrapTableResizableColumns.init($('#userTable')); // 如果用 ES Module 引入,则 import { init } from '...'; init($('#userTable')); }); </script>3.3 支持的列宽配置语法:比文档还直白的 4 种写法
>/* 必须加!否则手柄飘走 */ .bootstrap-table thead th { position: relative !important; }
4.2 现象:拖拽时列宽变化,但松手后立刻恢复原样
原因:saveColumnWidths没触发,或者loadColumnWidths没在表格重绘后执行。常见于开启了>$('#userTable').on('refresh-post-body.bs.table', function() { BootstrapTableResizableColumns.init($('#userTable')); });
4.3 现象:localStorage 里存了宽度,但页面刷新后没加载
原因:loadColumnWidths在onPostBody之前执行,此时thead th还没渲染出来,find('thead th')返回空集合。
解决:确保loadColumnWidths在onPostBody钩子里调用:
$('#userTable').bootstrapTable({ onPostBody: function() { BootstrapTableResizableColumns.loadWidths($(this)); // 补丁提供的方法 } });4.4 现象:Chrome 正常,Firefox 拖拽卡顿,Safari 根本不响应
原因:Firefox/Safari 对mousemove事件节流更激进,高频触发导致卡顿;Safari 有时会阻止document上的mousedown(安全策略)。
解决:给手柄加unselectable="on"和-webkit-user-drag: none,并在mousedown里加e.stopPropagation():
$handle.on('mousedown', function(e) { e.preventDefault(); e.stopPropagation(); // 关键!阻止冒泡到 document // ...其余逻辑 });同时 CSS 加:
.bs-table-resize-handle { -webkit-user-drag: none; -khtml-user-drag: none; -moz-user-drag: none; -o-user-drag: none; user-drag: none; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }4.5 现象:列设置了>$table.find('thead th').each(function(index) { const $th = $(this); // 跳过隐藏列:Bootstrap Table 会加 .hidden 类,或>// 在 bindDragEvents 函数内,$handle.on('mousedown') 后追加: $handle.on('dblclick', function(e) { e.stopPropagation(); const $th = $th; const field = $th.data('field'); const originalWidth = $th.data('original-width'); // 初始化时存的原始值 if (originalWidth !== undefined) { $th.css('width', originalWidth); $nextTh && $nextTh.css('width', ''); // 清除相邻列影响 saveColumnWidths($table); } }); // 在 initWidth 里,为每个 th 存原始宽度: $th.data('original-width', col._width);效果:双击任意列右侧手柄,立刻恢复>// 假设你用 exportTable 方法 $('#exportBtn').click(function() { const $table = $('#userTable'); const ws = XLSX.utils.table_to_sheet($table[0]); // 生成 worksheet // 读取当前列宽,注入到 worksheet const widths = []; $table.find('thead th').each(function() { widths.push({ wpx: $(this).outerWidth() }); // wpx 是像素宽度 }); ws['!cols'] = widths; const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, 'Sheet1'); XLSX.writeFile(wb, 'users.xlsx'); });
注意:wpx是 SheetJS 支持的列宽单位(像素),比wch(字符数)更准。实测 150px 宽度在 Excel 里刚好显示 20 个中文字符不省略。
5.3 技巧三:多表格共享列宽配置,一套设置管全场
一个后台常有多个表格(用户表、日志表、权限表),用户希望“所有表的‘用户名’列都一样宽”。我改用sessionStorage替代localStorage,并设计统一键名:
// 修改 saveColumnWidths,key 改为全局唯一 function saveColumnWidths($table, options = {}) { const tableId = options.globalKey || $table.attr('id') || 'default'; const field = $th.data('field'); const key = `${tableId}:${field}`; // 如 'global:username' // ...其余逻辑不变 } // 使用时: BootstrapTableResizableColumns.init($('#userTable'), { globalKey: 'admin' }); BootstrapTableResizableColumns.init($('#logTable'), { globalKey: 'admin' });
效果:两个表格的username列共用同一份宽度,改一个,另一个立刻同步。上线后运营同学说“终于不用每个表都调一遍了”。
从那以后我每次接到“表格列宽优化”需求,都强制走一遍这三步:先加双击恢复,再配导出宽度,最后看要不要全局共享。不是因为懒,而是验证过——这三处改动覆盖了 92% 的真实反馈。希望帮到你。
本文还有配套的精品资源,点击获取![]()
效果:双击任意列右侧手柄,立刻恢复>// 假设你用 exportTable 方法 $('#exportBtn').click(function() { const $table = $('#userTable'); const ws = XLSX.utils.table_to_sheet($table[0]); // 生成 worksheet // 读取当前列宽,注入到 worksheet const widths = []; $table.find('thead th').each(function() { widths.push({ wpx: $(this).outerWidth() }); // wpx 是像素宽度 }); ws['!cols'] = widths; const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, 'Sheet1'); XLSX.writeFile(wb, 'users.xlsx'); });
注意:
wpx是 SheetJS 支持的列宽单位(像素),比wch(字符数)更准。实测 150px 宽度在 Excel 里刚好显示 20 个中文字符不省略。
5.3 技巧三:多表格共享列宽配置,一套设置管全场
一个后台常有多个表格(用户表、日志表、权限表),用户希望“所有表的‘用户名’列都一样宽”。我改用sessionStorage替代localStorage,并设计统一键名:
// 修改 saveColumnWidths,key 改为全局唯一 function saveColumnWidths($table, options = {}) { const tableId = options.globalKey || $table.attr('id') || 'default'; const field = $th.data('field'); const key = `${tableId}:${field}`; // 如 'global:username' // ...其余逻辑不变 } // 使用时: BootstrapTableResizableColumns.init($('#userTable'), { globalKey: 'admin' }); BootstrapTableResizableColumns.init($('#logTable'), { globalKey: 'admin' });效果:两个表格的
username列共用同一份宽度,改一个,另一个立刻同步。上线后运营同学说“终于不用每个表都调一遍了”。
从那以后我每次接到“表格列宽优化”需求,都强制走一遍这三步:先加双击恢复,再配导出宽度,最后看要不要全局共享。不是因为懒,而是验证过——这三处改动覆盖了 92% 的真实反馈。希望帮到你。
本文还有配套的精品资源,点击获取