bootstrapTable转DataTables,并给有着tfoot的DataTables加滚动条

前言

  • 最近需要bootstrapTable转化为DataTables,这两个难道都算老框架了吗,都没多少文讲这个,尤其是DataTablestfoot后加滚动条,使用scrollX属性没有效果
  • 本文主要说下bootstrapTableDataTables的区别,怎么去转换,还有如何给有着tfootDataTables加滚动条

一、关于bootstrapTableDataTables的区别(注释用AI润色过,不对的地方请提出)

1.bootstrapTable初始化

直接上一个例子,

javascript 复制代码
var TableInit = function() {
	var oTableInit = new Object();
	//初始化Table
	oTableInit.Init = function() {
		$('#table1').bootstrapTable({
			toolbar: '#toolbar', //工具按钮用哪个容器
			striped: true, //是否显示行间隔色
			cache: false, //是否使用缓存,默认为true,所以一般情况下需要设置一下这个属性(*)
			pagination: true, //是否显示分页(*)
			sortable: true, //是否启用排序
			sortOrder: "asc", //排序方式
			sortName: "n", //初始化时排序的列名
			queryParams: oTableInit.queryParams, //传递参数(*)
			sidePagination: "client", //分页方式:client客户端分页,server服务端分页(*)
			pageNumber: 1, //初始化加载第一页,默认第一页
			pageSize: 20, //每页的记录行数(*)
			pageList: [20, 50, 100], //可供选择的每页的行数(*)
			search: false, //是否显示表格搜索,此搜索是客户端搜索,不会进服务端,所以,个人感觉意义不大
			strictSearch: true, //决定搜索时是进行 严格匹配(搜索词必须完全匹配字段值(区分大小写)) 还是 模糊匹配(搜索词可以是字段值的一部分(不区分大小写)),用于search属性产生的搜索框
			showColumns: false, //是否显示所有的列
			showRefresh: false, //是否显示刷新按钮
			minimumCountColumns: 2, //最少允许的列数
			clickToSelect: false, //是否启用点击选中行
			//   height: 565,                        //行高,如果没有设置height属性,表格自动根据记录条数觉得表格高度
			uniqueId: "i", //每一行的唯一标识,一般为主键列
			showToggle: false, //是否显示详细视图和列表视图的切换按钮
			cardView: false, //是否显示详细视图
			detailView: true, //是否显示父子表

			/*
			        exportDataType可以取以下值:
			        'basic':导出当前页的数据(即页面中当前显示的数据)

			        'all':导出所有数据(包括所有分页的数据)

			        'selected':导出选中的数据(需要开启复选框选择功能)
			*/
			exportDataType: 'all',
			showExport: true, //是否显示导出按钮
			buttonsAlign: "right", //按钮位置
			exportTypes: ['excel'], //导出文件类型
			Icons: 'glyphicon-export',
			exportOptions: {
				ignoreColumn: [0, 1, 9], //忽略某一列的索引
				fileName: '列表', //文件名称设置
				worksheetName: 'sheet1', //表格工作区名称
				tableName: '列表',
				excelstyles: ['background-color', 'color', 'font-size', 'font-weight'],
				//onMsoNumberFormat: DoOnMsoNumberFormat
			},

			//注册加载子表的事件。 
			/**
			 * 在 Bootstrap Table 中,当启用 detailView 时,点击行前面的展开按钮会触发 onExpandRow 事件。该事件会传入三个参数:
			 * @param {*} index 当前展开行的索引
			 * @param {*} row 当前展开行的数据对象
			 * @param {*} $detail 一个 jQuery 对象,指向用于展示子表格的容器元素
			 */
			onExpandRow: function(index, row, $detail) {
				oTableInit.InitSubTable(index, row, $detail);
			},
			columns: [{
				checkbox: true //显示复选框
			}, {
				field: 'index', //field是列的字段名
				title: '序号', //title是列的标题,也就是表头
				/**
				 * formatter: 用于格式化列的显示内容的函数
				 * @param {*} value 对应字段(field)的值
				 * @param {*} row 当前行的数据对象
				 * @param {*} index 当前行的索引
				 * @returns 
				 */
				formatter: function(value, row, index) {
					return index + 1;
				}
			}, {
				field: 'n',
				title: '表名称',
				sortable: true, //是否启用排序
			}, {
				field: 'i',
				title: '表号',
				sortable: true,
			}, {
				field: 'groupN',
				title: '分组 ',
				sortable: true,
				/**
				 * sorter: 用于自定义排序逻辑的函数
				 * @param {*} a 第一行在 groupN 字段的显示值
				 * @param {*} b 第二行在 groupN 字段的显示值
				 * @param {*} ra 第一行的数据对象
				 * @param {*} rb 第二行的数据对象
				 * @returns 
				 */
				sorter: function(a, b, ra, rb) {
					return groups[ra.d] - groups[rb.d];
				},
				formatter: function(value, row, index) {
					if (row.d == 0)
						return "未分组 ";
					else return groups[row.d];
				}
			}, {
				field: 'chaozuo',
				title: '操作',
				//align属性用于设置列内容的对齐方式
				align: 'center',
				//formatter: 用于格式化列的显示内容的函数
				formatter: operateOther
			}, {
				field: 'd',
				title: 'd ',

				cellStyle: { //自定义单元格样式
					css: {
						"display": "none"
					}
				}
			}, ]
		});
	};

	//初始化子表格(无线循环)
	oTableInit.InitSubTable = function(index, row, $detail) {
		var cur_table = $detail.html('<table ></table>').find('table');
		$(cur_table).bootstrapTable({
			clickToSelect: false, // 点击行不选中
			detailView: false, // 子表格不能再展开(避免无限循环)
			uniqueId: "i",
			pageSize: 50,
			pageList: [10, 50, 100],
			columns: [{
				field: 'n',
				title: '表名称 ',
				sortable: true,
			}, {
				field: 'i',
				title: '表号 ',
				sortable: true,
			}, {
				field: 'e',
				title: '剩余',
				sortable: true,
				formatter: function(value, row, index) {
					if (row.m == "1") return '-';
					else {
						return row.e;
					}
				},
				cellStyle: function(value, row, index) {
					if (row.m == "1") return {
						css: {}
					};
					if (value <= 0) return {
						css: {
							"background-color": "red"
						}
					};
					else if (row.w > value) return {
						css: {
							"background-color": "#ffd9ec"
						}
					};
					else return {
						css: {}
					};
				},
			}, {
				field: 'chaozuo',
				title: '操作',
				align: 'center',
			}, ],
		});

		/**
		 * 加载子表格数据
		 * 'load':Bootstrap Table 的方法名,表示加载数据
		 * @param {*} cld[row.i] 传递给 load 方法的数据参数
		 */
		$(cur_table).bootstrapTable('load', cld[row.i]);

	};

	return oTableInit;
};

2.DataTables初始化

  • domDataTables 中用于控制表格布局结构的配置项:
字符 组件 说明 默认位置
l length changing 每页显示条数选择框 左上
f filtering 搜索过滤框 右上
t table 表格主体 中间
i info 表格信息(显示条数) 左下
p pagination 分页控件 右下
r processing 加载处理提示 表格上方
B buttons 按钮区域 左上
R ColReorder 列重新排序 -
S Scroller 滚动组件 -
P serchPanes 搜索面板 -
Q searchBuilder 搜索构建器 -

如果未写dom的配置,默认为

javascript 复制代码
dom: 'lfrtip'
javascript 复制代码
var TableInit = function () {
    var oTableInit = new Object();
    //初始化Table
    oTableInit.Init = function () {
        $('#table1').DataTable({
            //引入中文文本版本
            language: {
                url: 'datetables-zh_cn.json',
            },
            //DataTables:使用 dom 字符串控制布局
            //一个靠左的容器div用于放置表格信息说明il
            dom: 'rt<"float-left"il>p',
            pageLength: 20,   //默认每页显示20条记录
            lengthMenu: [20, 50, 100],   //每页显示记录数选项
            order: [], // 不设置默认排序
            autoWidth: false,   //禁用自动列宽计算

            initComplete: function () {   //表格初始化完成后执行,将按钮添加到自定义位置
                var btnContainer = this.api().buttons().containers()[0]; //获取按钮容器buttons的第一个元素
                $(btnContainer).addClass('float-right');   //添加浮动类使按钮靠右显示
                $(btnContainer).appendTo('#toolbar');      //将按钮容器添加到自定义的div中

            },
            buttons: [    //定义导出按钮
                {
                    extend: 'csvHtml5',
                    text: '<div class="export"><img src="res/Export.png" alt="导出Excel"/> <span class="export-text">导出</span></div>',
                    className: 'btn custom_export_btn',
                    bom: true,   //解决中文导出乱码问题
                    filename: '列表',
                    title: '列表',
                    sheetName: 'sheet1',
                    exportOptions: {
                        columns: [2, 3, 4] // 要导出的序列
                    },
                    customize: function (xlsx) {   //可以添加自定义导出内容的操作
                        return xlsx;
                    }
                }
            ],

            //DataTables:也通过columns数组定义,但使用data属性指定字段,render函数进行格式化
            //DataTables: 没有内置的详细视图,但可以通过在每行添加一个按钮,点击时展开一个行来模拟
            columns: [
                {   //子表格控制列,点击展开子表格
                    data: null,
                    orderable: false,   //是否启用排序
                    title: '',
                    render: function (data, type, row, meta) {
                        return '<a class="detail-icon" href="#"> <i class="glyphicon glyphicon-plus icon-plus"></i> </a>';
                    },
                    className: 'details-control text-center',

                },
                {    //checkbox列
                    data: null,
                    orderable: false,
                    title: '<div class="custom-control custom-checkbox"><input type="checkbox" class="custom-control-input" id="customCheck"><label class="custom-control-label" for="customCheck">&nbsp;</label></div>',
                    render: function (data, type, row, meta) {
                        return '<div class="custom-control custom-checkbox"><input type="checkbox" class="custom-control-input ccall" id="customCheck' + meta.row + '"><label class="custom-control-label" for="customCheck' + meta.row + '">&nbsp;</label></div>';
                    },

                },
                {
                    data: null,
                    title: '序号',
                    orderable: false,
                    render: function (data, type, row, meta) {
                        return meta.row + 1;
                    }
                },
                {
                    data: 'n',
                    title: '表名称',
                    orderable: true,
                },
                {
                    data: 'i',
                    title: '表号',
                    orderable: true,
                },
                {
                    data: 't',
                    title: '备注',
                    orderable: true,
                },
                {
                    data: null,
                    title: '分组',
                    orderable: true,
                    render: function (data, type, row) {
                        if (type === 'sort') {      //dataTables不支持直接比较两行数据的函数格式
                            // 排序时使用 groups 中的数值
                            return groups[row.gid] || 0;
                        } else {
                            // 显示时使用文本
                            if (row.gid == 0) return '未分组';
                            else return groups[row.gid] || '';
                        }
                    }
                },
                {
                    data: null,
                    title: '操作',
                    orderable: false,
                    render: function (data, type, row, meta) {
                        return operateOther(null, row, meta.row);
                    },

                },
                {
                    data: null,
                    title: 'd',
                    visible: false,   //隐藏列
                    render: function (data, type, row) {
                        return row.d || '';
                    }
                }
            ]
        });
        $('#table1 th:gt(9)').css("display", "none");
    };

    //初始化子表格(无线循环)
    oTableInit.InitSubTable = function (index, row, $detail) {
        var subData = cld[row.i] || [];   //根据父表的表号i获取对应的子表数据
        var cur_table = $detail.html('<table class="table table-hover w-100"></table>').find('table');
        $(cur_table).DataTable({
            dom: 't',
            data: subData,
            language: {
                url: 'datetables-zh_cn.json',
            },
            pageLength: 50,
            lengthMenu: [10, 50, 100],
            columns: [
                {
                    data: 'n',
                    title: '表名称 ',
                    orderable: true
                },
                {
                    data: 'i',
                    title: '表号 ',
                    orderable: true
                },
                {
                    data: 'e',
                    title: '剩余',
                    orderable: true,
                    render: function (data, type, row) {
                        if (row.m == "1" || row.e == null) return '-';
                        else return row.e;
                    },
                    createdCell: function (td, cellData, rowData, row, col) {
                        if (rowData.m != "1") {
                            if (cellData <= 0) {
                                $(td).css('background-color', '#ffd9ec');
                            } else if (rowData.w > cellData) {
                                $(td).css('background-color', '#ffd9ec');
                            }
                        }
                    }
                },
                {
                    data: 's',
                    title: '状态 ',
                    orderable: true,
                    render: function (data, type, row) {
                        return editStatus(data, row, index);
                    }
                },
                {
                    data: null,
                    title: '操作',
                    orderable: false,
                    className: 'text-center',
                }
            ]
        });

    };

    return oTableInit;
};

还有处理checkbox在表头的全选功能和关闭展开子表的按钮的功能:

javascript 复制代码
// 添加表头复选框全选/取消全选功能

// 1. 监听表头复选框的点击事件
// 目标:ID为"customCheck"的表头复选框
// 事件:点击事件
$("#table1").on("click", "#customCheck", function () {

    // 2. 判断表头复选框当前是否被选中
    // prop("checked")返回布尔值:true表示选中,false表示未选中
    if ($("#customCheck").prop("checked")) {

        // 3. 如果表头复选框被选中,选中所有行的复选框
        // 找到表格中所有类名为"ccall"的复选框(即每行前面的复选框)
        // 设置它们的checked属性为"checked"(选中状态)
        $("#table1").find(".ccall").prop("checked", "checked");

    } else {

        // 4. 如果表头复选框取消选中,取消选中所有行的复选框
        // 将表格中所有类名为"ccall"的复选框的checked属性设置为false
        $("#table1").find(".ccall").prop("checked", false);
    }
});

// 监听表格中展开/折叠按钮的点击事件
// 目标:表格中类名为"details-control"的单元格(包含展开图标)
// 事件:点击事件
$('#table1').on('click', 'td.details-control', function () {

    // 1. 获取当前点击行和行数据
    // tr: 获取包含当前点击单元格的整行元素
    var tr = $(this).closest('tr');

    // 2. 获取DataTable行对象
    // row: 通过DataTable API获取当前行的数据对象和操作方法
    var row = $('#table1').DataTable().row(tr);

    // 3. 获取当前行的完整数据
    // data: 包含该行所有字段值的对象(如n、i、gid等)
    var data = row.data();

    // 4. 判断子表格当前是否已展开
    // isShown(): DataTable API方法,返回布尔值,表示子行是否已显示
    if (row.child.isShown()) {

        // 5. 如果子表格已展开,执行折叠操作

        // a. 隐藏子表格(移除子行DOM)
        row.child.hide();

        // b. 从当前行移除"shown"类(用于CSS样式控制)
        tr.removeClass('shown');

        // c. 切换展开图标:从"-"(减号)变为"+"(加号)
        // 表示现在可以再次展开
        $(this).find('i').removeClass('glyphicon-minus').addClass('glyphicon-plus');

    } else {

        // 6. 如果子表格未展开,执行展开操作

        // a. 创建子表格容器
        // 创建一个div元素,用于放置子表格
        var childContainer = $('<div class="child-table-container"></div>');

        // b. 显示子表格(添加子行DOM)
        // child(): 创建子行内容并显示
        row.child(childContainer).show();

        // c. 调用子表格初始化函数
        // 参数1: row.index() - 当前行在DataTable中的索引
        // 参数2: data - 当前行的完整数据
        // 参数3: childContainer - 子表格容器(相当于Bootstrap Table中的$detail)
        oTable.InitSubTable(row.index(), data, childContainer);

        // d. 为当前行添加"shown"类(用于CSS样式控制)
        tr.addClass('shown');

        // e. 切换展开图标:从"+"(加号)变为"-"(减号)
        // 表示现在可以折叠
        $(this).find('i').removeClass('glyphicon-plus').addClass('glyphicon-minus');
    }
});

基本上转换应该就好了,如果有缺漏,希望各位佬告知我补充下去<(^-^)>

二、给DataTables加滚动条

  • 方法比较粗暴,用一个div容器包住表格,自定义滚动条,滚动条轨道宽度与表格宽度一致,容器宽度 ≥ \ge ≥ 表格宽度 → 隐藏滚动条(空间足够),容器宽度 < < < 表格宽度 → 显示滚动条(需要滚动)
  • 仍旧使用前面使用的例子,虽然没有tfoot,但做法是一样的
  • 这一段可通用,建议放在initComplete中
javascript 复制代码
					                const tableElement=$('#table1');

					                const tableDiv = $('<div id="tableDiv" class="w-100"></div>').insertAfter(tableElement);

					               tableElement.appendTo(tableDiv);

					               // 设置表格最小宽度,防止收缩过度
					               tableElement.css('min-width', 900+'px');

					               const tableWidth=tableElement.innerWidth();





					                // 创建滚动条结构并放在tableDiv之下,与表格底部对齐
					                const scrollbar = $('<div class="sticky-scrollbar" id="fakeScrollbar"><div class="scrollbar-track"></div></div>');
					                scrollbar.insertAfter(tableDiv);


					                // 使用表格的可见宽度设置滚动条宽度
					                $('.scrollbar-track',scrollbar).css('width', tableWidth);



					                // 空间足够时隐藏滚动条,使用容器宽度与表格宽度比较
					                const containerWidth = tableDiv.innerWidth();
					                const currentTableWidth = tableWidth;


					                if (containerWidth >= currentTableWidth) {
					                    scrollbar.attr('hidden', 'hidden');
					                } else {
					                    scrollbar.removeAttr('hidden');
					                }



					                // 6. 实现滚动同步
					                const fakeScrollbar = scrollbar[0];
					                const realContent = tableDiv[0];

					                // 监听真实内容的滚动,同步到假滚动条
					                realContent.addEventListener('scroll', function() {
					                    // 使用百分比计算进行滚动同步
					                    const scrollPercent = (this.scrollLeft / (this.scrollWidth - this.clientWidth)) * 100;
					                    fakeScrollbar.scrollLeft = (scrollPercent / 100) * (fakeScrollbar.scrollWidth - fakeScrollbar.clientWidth);
					                });

					                // 监听假滚动条的滚动,同步到真实内容
					                fakeScrollbar.addEventListener('scroll', function() {
					                    const scrollPercent = (this.scrollLeft / (this.scrollWidth - this.clientWidth)) * 100;
					                    realContent.scrollLeft = (scrollPercent / 100) * (realContent.scrollWidth - realContent.clientWidth);
					                });

					                // 7. 使用Intersection Observer检测可见性,但尊重空间足够时隐藏的条件
					                const observer = new IntersectionObserver((entries) => {
					                    entries.forEach(entry => {
					                        if (entry.isIntersecting) {
					                            // 可见时,根据空间是否足够决定是否显示滚动条
					                            updateScrollbarVisibility();
					                        } else {
					                            // 不可见时隐藏滚动条
					                            fakeScrollbar.style.visibility = 'hidden';
					                            fakeScrollbar.style.opacity = '0';
					                        }
					                    });
					                }, {
					                    threshold: [0, 0.1, 1], //多点检测
					                });
					                observer.observe(realContent);

					                // 添加窗口大小变化监听,在窗口大小变化时重新检查滚动条显示条件
					                window.addEventListener('resize', updateScrollbarVisibility);

					                // 滚动条显示控制逻辑
					                function updateScrollbarVisibility() {
					                    const containerWidth = tableDiv.innerWidth();
					                    const currentTableWidth = tableElement.innerWidth();

					                    // 更新滚动条宽度
					                    $('.scrollbar-track', scrollbar).css('width', currentTableWidth);

					                    if (containerWidth >= currentTableWidth) {
					                        // 空间足够,隐藏滚动条
					                        scrollbar.attr('hidden', 'hidden');
					                    } else {
					                        // 空间不足,显示滚动条
					                        scrollbar.removeAttr('hidden');
					                        fakeScrollbar.style.visibility = 'visible';
					                        fakeScrollbar.style.opacity = '1';
					                    }
					                }

还有要加上的css:

css 复制代码
#tableDiv {
  overflow: auto;
  scrollbar-width: none;
}

/* 滚动条样式 */
.sticky-scrollbar {
  position: sticky;
  bottom: 0;
  height: 15px;
  background: #e0e0e0;
  z-index: 10;
  overflow-x: auto;
  overflow-y: hidden;
}

.scrollbar-track {
  height: 10px;
  background: #888;
  border-radius: 7px;
}
相关推荐
刘一说2 小时前
TypeScript 与 JavaScript:现代前端开发的双子星
javascript·ubuntu·typescript
EndingCoder3 小时前
类的继承和多态
linux·运维·前端·javascript·ubuntu·typescript
用户47949283569153 小时前
React 终于出手了:彻底终结 useEffect 的"闭包陷阱"
前端·javascript·react.js
木头程序员3 小时前
前端(包含HTML/JavaScript/DOM/BOM/jQuery)基础-暴力复习篇
开发语言·前端·javascript·ecmascript·es6·jquery·html5
哈__3 小时前
React Native 鸿蒙跨平台开发:PixelRatio 实现鸿蒙端图片的高清显示
javascript·react native·react.js
wszy18094 小时前
外部链接跳转:从 App 打开浏览器的正确姿势
java·javascript·react native·react.js·harmonyos
pas1364 小时前
31-mini-vue 更新element的children
前端·javascript·vue.js
码界奇点4 小时前
基于Vue3与TypeScript的后台管理系统设计与实现
前端·javascript·typescript·vue·毕业设计·源代码管理
ashcn20015 小时前
水滴按钮解析
前端·javascript·css