4

我正在尝试确定固定宽度的 HTML 表格单元格中最宽的内容。目前我正在使用外部sizer 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 的 Infragistics WebHierarchicalDataGrid 控件中实现“列自动调整大小”功能 - 列需要采用最宽的宽度Max(Header Width, Data Width),同时保持固定的页眉/寻呼机位置)。

谢谢!

4

2 回答 2

2

重写 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);

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

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

于 2012-12-13T18:30:43.933 回答
0

默认情况下,当列和网格本身没有指定宽度时,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 和_adjustGridLayout 之间的网格初始化函数期间调用resizeGrid。为此,您可以修改 WebDataGrid 的原型,将 _adjustGridLayout 替换为另一个调用 resizeGrid 并调用原始 _adjustGridLayout 的原型:

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

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

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>

如果您使用的是行选择器,则需要在我提供的逻辑中更新计算以考虑行选择器。

于 2013-02-20T19:14:26.503 回答