测量表列中最长单元格的有效方法



我正在尝试确定固定宽度的HTML表单元格中最宽的内容。目前我正在使用一个外部尺寸测定器DIV:

<div id="xdivSizer" style="position:absolute;display:inline;visibility:hidden">
</div>

在这个代码

var iColWidth = 0;
for (var Y = 0; Y < oDataTable.rows.length; Y++) {
oDivSizer.innerHTML = oDataTable.rows[Y].cells[0].innerHTML;
iColWidth = Math.max(oDivSizer.offsetWidth, iColWidth)
}

它可以工作,但速度非常慢,即使表只有100行左右。看起来主要的罪犯是计算offsetWidth。有没有更有效的方法来实现这一点?

我这样做是因为我需要将该表列的大小调整为最宽数据的大小。如果有其他更好的方法,那也太好了。

(更确切地说,我正试图在用于ASP.NET的Infrastics WebHierarchicalDataGrid控件中实现"列自动大小"功能-列需要采用最宽的Max(Header Width, Data Width)宽度,同时保持固定的标头/分页器位置)

谢谢!

重写div内容将触发大量的重绘、CSS应用程序、DOM操作等。

尝试将列中的所有单元格同时放在DIV,用换行符分隔,或者每个单元格都放在自己的子DIV中。生成的DIV的宽度应为最长单元格的宽度。

var html = [];
for (var Y = 0; Y < oDataTable.rows.length; Y++) {
html.push(oDataTable.rows[Y].cells[0].innerHTML);
}
oDivSizer.innerHTML = html.join("<br />");
var iColWidth = Math.max(oDivSizer.offsetWidth, 1);

另一种可能性是基于每个单元格的innerText的简单启发式。

var iColWidth = 0;
for (var Y = 0; Y < oDataTable.rows.length; Y++) {
var w = Math.floor(oDataTable.rows[Y].cells[0].innerText.length * 11.5);
iColWidth = Math.max(w, iColWidth);
}

还有另一种可能性,正如我在上一条评论中所指出的,是只重新绘制消耗最大区域的列中的TD。

var a = 0;
var n = null;
for (var Y = 0; Y < oDataTable.rows.length; Y++) {
var _a = oDataTable.rows[Y].cells[0].offsetHeight * oDataTable.rows[Y].cells[0].offsetWidth;
if (Number(_a) > a) {
a = _a;
n = oDataTable.rows[Y].cells[0];
}
}
oDivSizer.innerHTML = n.innerHTML;
var iColWidth = Math.max(oDivSizer.offsetWidth, 1);

或者,更进一步,将每个单元格的计算面积除以发现的BR的数量,以解释"有意"的高单元格。

var a = 0;
var n = null;
for (var Y = 0; Y < oDataTable.rows.length; Y++) {
var _a = oDataTable.rows[Y].cells[0].offsetHeight * oDataTable.rows[Y].cells[0].offsetWidth;
var brs = oDataTable.rows[Y].cells[0].getElementsByTagName('br');
_a = Number(_a) / brs.length;
if (_a > a) {
a = _a;
n = oDataTable.rows[Y].cells[0];
}
}
oDivSizer.innerHTML = n.innerHTML;
var iColWidth = Math.max(oDivSizer.offsetWidth, 1);

但是,随着模糊方法的复杂性增加,结果变得更加准确,性能可能会下降。

顺便说一句,如果这种自动调整大小是作为用户交互的结果应用的,我建议在表可供分析后立即执行调整大小计算/处理,而不是等待用户启动调整大小。

默认情况下,当列和网格本身没有指定宽度时,WebDataGrid将根据其内容调整网格的内容区域。然后将头的大小调整为数据部分。无论网格是在容器中还是在容器外,这都能很好地工作。

由于网格的数据部分大小正确,我们所需要做的就是将列的大小调整为较大值,即网格中第一个单元格的宽度或显示完整标题的测量值。以下JavaScript将执行此操作:

function resizeGrid(grid) {
var textWidthChecker = document.getElementById('textWidthChecker');
var columns = grid.get_columns();
var widths = new Array(columns.get_length());
var row = grid.get_rows().get_row(0);
var newGridWidth = 0;
for (var colIdx = 0; colIdx < columns.get_length(); colIdx++) {
var col = columns.get_column(colIdx);
textWidthChecker.innerHTML = col.get_headerText();
var cellElement = row.get_cell(colIdx)._element;
if (!col.get_hidden()) {
if (textWidthChecker.offsetWidth > cellElement.offsetWidth) {
// 8 for padding in header.
newGridWidth += textWidthChecker.offsetWidth + 8;
widths[colIdx] = textWidthChecker.offsetWidth + 8;
} else {
widths[colIdx] = cellElement.offsetWidth;
newGridWidth += cellElement.offsetWidth;
}
}
}
newGridWidth += columns.get_length() * 16; // added for padding on cells
var gridElement = grid.get_element();            
gridElement.style.width = newGridWidth + 'px';
for (var colIdx = 0; colIdx < columns.get_length(); colIdx++) {
var col = columns.get_column(colIdx);
col.set_width(widths[colIdx] + 'px');
}
}

以上要求有一个id为"textWidthChecker"的跨度,以便使用与字体的网格标题相同的CSS类来工作:

<div style="height: 0px;overflow: hidden;" class="igg_HeaderCaption ig_Control">
<span id="textWidthChecker"></span>
</div>

当从客户端Initialize方法调用resizeGrid函数时,只要网格位于一个容器内,容器的宽度足以容纳调整标题时的网格,这种方法就可以很好地工作。

如果网格位于较小的容器中,则此操作将失败,因为WebDataGrid在内部设置其宽度,这会影响列的大小。为了解决这个问题,resizeGrid函数需要提前调用,尽管没有任何事件。

具体来说,在调用_initializeObjects和_ajustGridLayout之间的网格初始化函数期间,需要调用resizeGrid。要做到这一点,您可以修改WebDataGrid的原型,将_ajustGridLayout替换为另一个调用resizeGrid并调用原始_ajustGridlayout:的原型

var adjustGridLayoutFunction = $IG.WebDataGrid.prototype._adjustGridLayout;
$IG.WebDataGrid.prototype._originalAdjustGridLayout = adjustGridLayoutFunction;
$IG.WebDataGrid.prototype._adjustGridLayout = function () {
resizeGrid(this);
this._originalAdjustGridLayout();
}; 

请注意,修改原型会影响页面上的每个网格,因此,如果您想控制应用于哪个网格,则需要在新的_ajustGridLayout函数中添加条件逻辑。例如:

if (this.get_id() == "WebDataGrid1")
resizeGrid(this);

为了防止文本在网格中换行,您还需要对ItemStyle:使用css

.noWrapCellStyle {
white-space: nowrap;
}

为此,应在网格的容器上设置所需的宽度,并且网格宽度应保持为空:

<div style="width:300px;overflow: auto;">
<ig:WebDataGrid ID="WebDataGrid1" runat="server" Height="450px" AutoGenerateColumns="True" ItemCssClass="noWrapCellStyle">
</ig:WebDataGrid>
</div>

如果您使用的是行选择器,那么需要在我提供的逻辑中更新计算,以说明行选择器。

相关内容

  • 没有找到相关文章

最新更新