worknova.manus/scripts/fixedThead.js
LAPTOP-V9RRD1TL\Michelle's Computer f8f8fcaf96 first commit
2025-07-21 21:38:17 +08:00

312 lines
8.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* jquery 表头固定插件 v0.1.0fixedThead.js
* @auther wingmeng
* @update: 2017/05/06
*/
;(function($) {
$.fn.fixedThead = function(options) {
var defaults = {
height: 'auto', // 表格最大高度,默认高度占满可视区
vspace: 0, // 垂直预留空间为可视区其他组件空出空间只有当height为auto时生效
top: 0, // 表格距离顶部的距离
bottom: 0, // 表格距离底部的距离
row: 1, // 要固定的行数
col: 0 // 要固定的列数
};
var opts = $.extend(defaults, $.fn.fixedThead.option, options);
return this.each(function() {
var _this = $(this);
opts = verifyOpts(opts, defaults); // 校验参数
if (typeof options == 'string') {
if (options === 'refresh') { // 刷新
refresh(_this, opts);
} else if (options === 'destroy') { // 销毁实例
destroy(_this);
}
return;
}
if (_this.parent().parent('div.fixed-thead').length) {
refresh(_this, opts);
return; // 防止重复创建DOM
}
// 存储、移除自身内嵌样式
if (_this.attr('style')) {
_this.attr('data-style', _this.attr('style'));
_this.removeAttr('style');
}
// 构建HTML结构
var configs = buildHTML(_this, opts);
guideBuild(configs);
configs = null;
});
}
$.fn.fixedThead.option = {};
// 校验并确保自定义参数的合法性
function verifyOpts(opts, defaults) {
var result = defaults;
var ckFun = function(str) {
if (opts[str] == 0 || opts[str]) {
if (!isNaN(opts[str]) && opts[str] >= 0) {
result[str] = opts[str];
}
}
};
for (var key in result) {
ckFun(key);
}
return result;
}
// 刷新数据(动态更新表格)
function refresh(tableObj, opts) {
if (tableObj.parent().parent('div.fixed-thead').length) {
var configs = {
table: tableObj,
bodyWrap: tableObj.parent(),
wrapper: tableObj.parent().parent(),
scrollBarWt: getScrollWidth(),
opts: opts
}
guideBuild(configs, true);
}
}
// 销毁实例
function destroy(tableObj) {
var parent = tableObj.parent().parent('div.fixed-thead'),
oldStyle = tableObj.data('style');
if (oldStyle) {
tableObj.attr('style', oldStyle).removeAttr('data-style'); // 还原之前的style样式
} else {
tableObj.removeAttr('style');
}
parent.before(tableObj);
parent.empty().remove();
}
// 克隆table HTML
function cloneTable(table, flag) {
var tClone = table.clone(), // 是否复制事件?(待完善)
tId = table.attr('id');
if (tId) {
tClone.attr('id', 'clone_' + tId + '_' + flag);
}
tClone.removeAttr('style'); // 移除复制的内嵌样式
return tClone;
}
// 构建HTML向导
function guideBuild(configs, flag) {
var opts = configs.opts,
tableWrap = {};
if (opts.row > 0 && opts.col > 0) {
tableWrap.head = buildHTML_head(configs);
tableWrap.side = buildHTML_side(configs);
tableWrap.corner = buildHTML_coner(configs);
} else {
if (opts.row > 0) {
tableWrap.head = buildHTML_head(configs);
}
if (opts.col > 0) {
tableWrap.side = buildHTML_side(configs);
}
}
calcLayout(configs, tableWrap);
if (!flag) {
configs.bodyWrap.scroll(function() {
if (tableWrap.side) {
tableWrap.side.scrollTop($(this).scrollTop());
}
if (tableWrap.head) {
tableWrap.head.scrollLeft($(this).scrollLeft());
}
});
$(window).resize(function() {
calcLayout(configs, tableWrap);
});
}
}
// 构建HTML结构
function buildHTML(tableObj, opts) {
var wrapper = $('<div class="fixed-thead"></div>'),
bodyWrap = $('<div class="fixed-thead-body"></div>');
tableObj.wrap(wrapper).wrap(bodyWrap);
var configs = {
table: tableObj,
bodyWrap: tableObj.parent(),
wrapper: tableObj.parent().parent(),
scrollBarWt: getScrollWidth(),
opts: opts
};
if (opts.top) {
configs.wrapper.css('margin-top', opts.top);
}
if (opts.bottom) {
configs.wrapper.css('margin-bottom', opts.bottom);
}
return configs;
}
// 构建头部
function buildHTML_head(configs) {
var wrap = configs.wrapper.find('div.fixed-thead-head');
var headTable = cloneTable(configs.table, 'head');
if (wrap.length == 0) {
wrap = $('<div class="fixed-thead-head"></div>');
configs.bodyWrap.before(wrap.append(headTable));
} else {
wrap.empty().append(headTable); // empty()一下释放内存
}
return wrap;
}
// 构建侧边
function buildHTML_side(configs) {
var wrap = configs.wrapper.find('div.fixed-thead-side');
var sideTable = cloneTable(configs.table, 'side');
if (wrap.length == 0) {
wrap = $('<div class="fixed-thead-side"></div>');
configs.bodyWrap.before(wrap.append(sideTable));
} else {
wrap.empty().append(sideTable);
}
return wrap;
}
// 构建左上角
function buildHTML_coner(configs) {
var wrap = configs.wrapper.find('div.fixed-thead-corner');
var cornerTable = cloneTable(configs.table, 'corner');
if (wrap.length == 0) {
wrap = $('<div class="fixed-thead-corner"></div>');
configs.bodyWrap.before(wrap.append(cornerTable));
} else {
wrap.empty().append(cornerTable);
}
return wrap;
}
// 布局计算
function calcLayout(configs, tableWrap) {
// 计算固定的行数高度总和
var maxHt = 0,
headHt = 0,
sideWt = 0;
if (tableWrap.head) {
for (var i = 0; i < configs.opts.row; i++) {
headHt += configs.table.find('tr').eq(i).outerHeight();
}
++headHt; // 让固定head露出1px底边框线
configs.table.css('margin-top', -headHt + 'px');
tableWrap.head.height(headHt);
maxHt = calcLayout_resize_head(configs, tableWrap.head, headHt);
}
if (tableWrap.side) {
for (var i = 0; i < configs.opts.col; i++) {
sideWt += configs.table.find('tr:eq(0)').children().eq(i).outerWidth();
}
++sideWt; // 让固定side露出1px右边框线
// 如果表格未溢出可视区(未出现水平滚动条)
if (configs.table.width() <= configs.bodyWrap.width()) {
sideWt = 0;
}
configs.table.css('margin-left', -sideWt + 'px');
configs.bodyWrap.css('margin-left', sideWt + 'px');
if (tableWrap.head) {
tableWrap.head.css('margin-left', sideWt + 'px')
.children('table').css('margin-left', -sideWt + 'px');
}
tableWrap.side.css({
top: headHt - 1 + 'px',
width: sideWt + 'px',
maxHeight: maxHt - configs.scrollBarWt + 1 + 'px'
}).children('table').css('margin-top', -(headHt - 1) + 'px');
}
if (tableWrap.corner) {
tableWrap.corner.css({
width: sideWt + 'px',
height: headHt + 'px'
});
}
}
// 计算并应用头部固定区域与滚动区域的布局样式
function calcLayout_resize_head(configs, headWrap, headHt) {
var maxHt = 0;
if (configs.opts.height == 'auto') { // 占满可视区
maxHt = $(window).height() - configs.opts.vspace - headHt - configs.opts.top - configs.opts.bottom;
} else {
maxHt = configs.opts.height - headHt;
}
configs.bodyWrap.css('max-height', maxHt + 'px');
var headTable = headWrap.children('table'),
rowfix = headTable.find('.fixed-thead-rowfix');
if (configs.bodyWrap.height() < configs.table.height() - headHt) { // 出现垂直滚动条
if (!rowfix.length) {
calcLayout_fix_head(configs, headWrap, headTable);
}
} else {
rowfix.remove();
}
return maxHt;
}
// 溢出修补
function calcLayout_fix_head(configs, headWrap, headTable) {
var scrollBarWt = configs.scrollBarWt - 1 + 'px'; // 滚动条宽度
// 添加空单元格来修复滚动条占据的宽度
for (var i = 0; i < configs.opts.row; i++) {
var curRow = headTable.find('tr').eq(i),
fixRow = curRow.children().last().clone();
fixRow.empty().addClass('fixed-thead-rowfix');
if (headTable.width() > headWrap.width()) { // 出现水平滚动条的情况
var innerDiv = $('<div style="width:' + scrollBarWt + '"></div>');
fixRow.css({
width: 0,
padding: 0
}).append(innerDiv);
} else {
fixRow.css({
width: scrollBarWt,
padding: 0
});
}
curRow.append(fixRow);
}
}
// 获取浏览器滚动条宽度
function getScrollWidth() {
var noScroll, scroll;
var oDiv = document.createElement('div'),
$oDiv = $(oDiv);
$oDiv.css({
position: 'absolute',
top: '-50px',
zIndex: '-1',
width: '50px',
height: '50px',
overflow: 'hidden'
});
document.body.appendChild(oDiv);
noScroll = oDiv.clientWidth;
oDiv.style.overflowY = 'scroll';
scroll = oDiv.clientWidth;
$oDiv.remove();
return noScroll - scroll;
}
})(jQuery);