SlickGrid的行高是否可以动态调整?

11

我们正在实现用户偏好设置,用于在网格上“即时”显示“更多”或“更少”数据。 “更多”应增加行高(每行具有相同的增加高度)。

当用户切换时,我们会更新 DataView,并使用更新后的 rowHeight 值调用 grid 上的 setOptions。然后调用 invalidate() 和 render()。

但是,行高并没有更新。 :(

请问是否有解决方案?我们应该直接通过 CSS 修改高度吗?如果可以,请提供如何进行此操作的任何提示?

3个回答

17

的确,根据用户交互动态更新行高是可能的。Slickgrid API提供了我们所需的一切。

因为:

  1. 我们可以动态添加/删除行;
  2. 我们可以在行和单元格级别上动态应用自定义CSS。


这里有一个简单的演示来开始:

////////////////////////////////////////////////////////////////////////////////
//example codez re trying to create a grid with rows of dynamic height to
//cater for folks that wanna bung loads of stuff in a field & see it all...
//by violet313@gmail.com ~ visit: www.violet313.org/slickgrids
//have all the fun with it  ;) vxx.
////////////////////////////////////////////////////////////////////////////////
modSlickgridSimple=(
function()
{
    var _dataView=null;
    var _grid=null;
    var _data=[];


    //////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////
    var getPaddingItem=function(parent , offset)
    {
        var item={};

        for (var prop in _data[0]) item[prop]=null;
        item.id=parent.id+"."+offset;

        //additional hidden padding metadata fields
        item._collapsed=     true;
        item._isPadding=     true;

        return item;
    }

    //////////////////////////////////////////////////////////////
    //this just builds our expand collapse button
    //////////////////////////////////////////////////////////////
    var onRenderIDCell=function(row, cell, value, columnDef, item)
    {
        if (item._isPadding==true); //render nothing
        else if (item._collapsed) return "<div class='toggle expand'></div>";
        else
        {
            var html=[];
            var rowHeight=_grid.getOptions().rowHeight;

            //V313HAX:
            //putting in an extra closing div after the closing toggle div and ommiting a
            //final closing div for the detail ctr div causes the slickgrid renderer to
            //insert our detail div as a new column ;) ~since it wraps whatever we provide
            //in a generic div column container. so our detail becomes a child directly of
            //the row not the cell. nice =)  ~no need to apply a css change to the parent
            //slick-cell to escape the cell overflow clipping.

            //sneaky extra </div> inserted here-----------------v
            html.push("<div class='toggle collapse'></div></div>");

            html.push("<div class='dynamic-cell-detail' ");   //apply custom css to detail
            html.push("style='height:", item._height, "px;"); //set total height of padding
            html.push("top:", rowHeight, "px'>");             //shift detail below 1st row
            html.push("<div>",item._detailContent,"</div>");  //sub ctr for custom styling
            //&omit a final closing detail container </div> that would come next

            return html.join("");
        }
    }

    //////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////
    var onRowClick=function(e, args)
    {
        _dataView.beginUpdate();

        if ($(e.target).hasClass("toggle"))
        {
            var item=_dataView.getItem(args.row);

            if (item)
            {
                if (!item._collapsed)
                {
                    item._collapsed=true;
                    for (var idx=1; idx<=item._sizePadding; idx++)
                        _dataView.deleteItem(item.id+"."+idx);
                    item._sizePadding=0;
                }
                else
                {
                    item._collapsed=false;
                    kookupDynamicContent(item);
                    var idxParent=_dataView.getIdxById(item.id);
                    for (var idx=1; idx<=item._sizePadding; idx++)
                        _dataView.insertItem(idxParent+idx, getPaddingItem(item,idx));
                }
                _dataView.updateItem(item.id, item);
            }
            e.stopImmediatePropagation();
        }

        _dataView.endUpdate();
    }

    //////////////////////////////////////////////////////////////
    var gridOptions={ enableColumnReorder:  true };

    //////////////////////////////////////////////////////////////
    var _gridColumns=
    [
        {
            id:         "id",
            name:       "",
            field:      "id",
            resizable:  false,
            width:      20,
            formatter:  onRenderIDCell,
        },
        {id: "title",        name: "Title",         field: "title",        resizable: true},
        {id: "duration",     name: "Duration",      field: "duration",     resizable: true},
        {id: "pcComplete",   name: "% Complete",    field: "pcComplete",   resizable: true},
        {id: "start",        name: "Start",         field: "start",        resizable: true},
        {id: "finish",       name: "Finish",        field: "finish",       resizable: true},
        {id: "effortDriven", name: "Effort Driven", field: "effortDriven", resizable: true},
    ];

    //////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////
    var kookupTestData=(function()
    {
        for (var i = 0; i < 100; i++)
            _data[i] =
            {
                id:               i,
                title:            "Task " + i,
                duration:         "5 days",
                pcComplete:       Math.round(Math.random() * 100),
                start:            "01/01/2009",
                finish:           "01/05/2009",
                effortDriven:     (i % 5 == 0),

                //additional hidden metadata fields
                _collapsed:       true,
                _sizePadding:     0,     //the required number of pading rows
                _height:          0,     //the actual height in pixels of the detail field
                _isPadding:       false,
            };
    })();

    //////////////////////////////////////////////////////////////
    //create the detail ctr node. this belongs to the dev & can be custom-styled as per
    //////////////////////////////////////////////////////////////
    var kookupDynamicContent=function(item)
    {
        //add some random oooks as fake detail content
        var oookContent=[];
        var oookCount=Math.round(Math.random() * 12)+1;
        for (var next=0; next<oookCount; next++)
            oookContent.push("<div><span>oook</span></div>");
        item._detailContent=oookContent.join("");

        //calculate padding requirements based on detail-content..
        //ie. worst-case: create an invisible dom node now &find it's height.
        var lineHeight=13; //we know cuz we wrote the custom css innit ;)
        item._sizePadding=Math.ceil((oookCount*lineHeight) / _grid.getOptions().rowHeight);
        item._height=(item._sizePadding * _grid.getOptions().rowHeight);
    }

    //////////////////////////////////////////////////////////////
    //jquery onDocumentLoad
    //////////////////////////////////////////////////////////////
    $(function()
    {
        //initialise the data-model
        _dataView=new Slick.Data.DataView();
        _dataView.beginUpdate();
        _dataView.setItems(_data);
        _dataView.endUpdate();

        //initialise the grid
        _grid=new Slick.Grid("#grid-simple", _dataView, _gridColumns);
        _grid.onClick.subscribe(onRowClick);

        //wire up model events to drive the grid per DataView requirements
        _dataView.onRowCountChanged.subscribe
            (function(){ _grid.updateRowCount();_grid.render(); });

        _dataView.onRowsChanged.subscribe
            (function(e, a){ _grid.invalidateRows(a.rows);_grid.render(); });

        $(window).resize(function() {_grid.resizeCanvas()});
    });
}
)();
//////////////////////////////////////////////////////////////
//done ;)
::-webkit-scrollbar       
{ 
    width:              12px; 
    background-color:   #B9BACC; 
}
::-webkit-scrollbar-track 
{ 
    color:              #fff; 
    -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); 
    border-radius:      10px;  
}
::-webkit-scrollbar-thumb 
{ 
    color:              #96A9BB; 
    border-radius:      10px;  
    -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.5); 
}

body
{
    font-family:        Arial, Helvetica, sans-serif;
    background-color:   #131313;
    position:           absolute;
    top:                5px;
    bottom:             5px;
    left:               5px;
    right:              5px;
}

#grid-simple
{
    position:         absolute;
    top:              0px;
    left:             0px;
    right:            0px;    
    bottom:           0px;
    margin:           auto;
    font-size:        12px;
    background-color: #ECEEE9;
}

.toggle
{
    height:           16px;
    width:            16px;
    display:          inline-block;
}
.toggle.expand
{
    background: url(https://violet313.github.io/assets/expand.gif) no-repeat center center;
}

.toggle.collapse
{
    background: url(https://violet313.github.io/assets/collapse.gif) no-repeat center center;
}


/*--- generic slickgrid padding pollyfill  ----------------------*/
 
.dynamic-cell-detail
{
    z-index:            10000;
    position:           absolute;
    background-color:   #F4DFFA;
    margin:             0;
    padding:            0;
    width:              100%;
    display:            table;
}

.dynamic-cell-detail > :first-child
{
    display:            table-cell;
    vertical-align:     middle;
    text-align:         center;
    font-size:          12px;
    line-height:        13px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/Celebio/SlickGrid/master/lib/jquery.event.drag-2.2.js"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/Celebio/SlickGrid/master/slick.core.js"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/Celebio/SlickGrid/master/slick.grid.js"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/Celebio/SlickGrid/master/slick.dataview.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/Celebio/SlickGrid/master/slick.grid.css">
<link rel="stylesheet" type="text/css" href="https://cdn.rawgit.com/Celebio/SlickGrid/master/slick-default-theme.css">
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/themes/base/jquery-ui.css">


<div id="grid-simple"></div>

不到200行代码。
试试吧!

顺便提一下,同样优秀的Datatables通过其API也可以(几乎)本地化提供这种方法。 &imo 这是正确的模式; &我用Slickgrid来实现自己的东西。但它涉及一个小技巧,而且在任何情况下都*不完全符合OP要求;我声称这是可能的。


为了实现动态行高度每个单元格,我们采用类似的技巧,但我们还必须处理一些副作用:~

样式去除行分隔线

我们必须:

  1. 逃避每个单元格溢出剪辑
  2. 删除不需要的行条纹
  3. 删除行边框

Slickgrid API通过Grid.getItemMetadata回调接口提供基于行的样式。在下一个小例子中,在第107行,请看这个接口的onRenderRow实现:
试试吧!

还要注意第148-150行,我调用了SlickgridGrid.setCellCssStyles API添加自定义dynamic-cellcss类,将overflow设置为visible,以便去除每个单元格的溢出裁剪样式。

列调整大小

如果详细内容是静态的,则可以轻松地调整列大小。

对于响应列宽度更改(流动文本或其他内容)的详细内容,需要进行一些工作。填充行需要相应地动态添加和删除。在下一个小例子中,请查看(从第66行开始)中的addPaddingtrimPadding函数:
试试吧!

排序

这里还有一些工作要做。我们需要确保无论是向上还是向下排序,padding都始终连续地位于父元素下面。查看下一个 fiddle 中第136行的 comparer
点此体验!

筛选

几乎只需一行代码:如果是padding,那么将比较委托给父级。完成了。查看下一个 fiddle 中第192行的 pcFilter
点此体验!

太棒了!在不到500行的相当易读的、注释自由的自定义javascript中实现了调整大小、排序和过滤..我事实上看到有些花哨的input-range-slider polyfills的代码行数更多 ;)
<br>acu


注意事项

我只涵盖了基础知识。还有整个可选/可编辑方面的内容,这超出了我的当前需求(抱歉)。
另外:

  • 示例代码仅供参考,不具备生产环境的可用性。 请自行承担风险等问题等等。

  • 示例在大多数现代浏览器中运行良好;我没有在IE上尝试过;版本 >= 11 可能可以使用..

更多信息

关于这个问题还有更多要说的东西,不过不能合理地压缩到一个SO答案中 -不考虑无引用规则。有兴趣了解所有这些内容的人可以去这里,我在那里详细介绍了更多内容

最后一个例子

以下是一个有趣的最终示例,它利用了上述所有功能,但可以看出,我已经放弃了expando-rows,并且有两个动态内容字段。此外,值得一提的是,此示例利用MutationObservers生成onPostRender事件作为Slickgrid原生asyncPostRender 列选项回调的替代方法
试试吧!

这就是我们所拥有的 - 一种类似于DataView的Slickgrid扩展模块;而且所有这些都不需要对可爱的Slickgrid代码进行可怕的黑客攻击。

这篇文章已经过时几年了;现在我看到原始项目有几个分支。即: https://github.com/6pac/SlickGrid


嗨@violet313,我正在尝试您上面的解决方案,但发现很困难...http://violet313.org/slickgrids似乎已经不存在了...尝试通过一些互联网档案馆获取它,但没有成功...您能否在其他地方发布此信息或者它永远消失了?谢谢! - Shorttylad
1
@Shorttylad,是的。抱歉,我一直想修复链接,但还没来得及:/ 我目前没有网络主机,但也许我可以将整个“howto”上传到GitHub :) - 你能忍耐几天吗?还有jsfiddles;它们仍然可以使用。 - violet313
1
谢谢 - 感激不尽。我一直在使用fiddles作为参考框架,并尝试将其实现到我的网格中,但新行不会显示。我可能对它的工作原理没有足够的了解,所以额外的信息将是一个很好的帮助。 - Shorttylad
1
@Shorttylad。好的,完成了。我详细介绍的链接Further Infos下应该再次可用。请注意,rawgit cdn即将停用,因此我正在从https://6pac.github.io/SlickGrid/中获取SlickGrid JavaScript文件-如果有任何重大变更,请告诉我,我会从我的github页面提供服务。叹气。 - violet313
1
哇..这是很多细节..现在没有借口了 :). 我想可能是我在我的网格上使用分组导致了问题,但我会再试一次!谢谢 - Shorttylad

7
您可以通过css来做到这一点。 查看 slick.grid.css 文件,并在其中进行所需更改。
查看以下类名: .slick-row.ui-widget-content.slick-row.ui-state-active 或者您可以使用 SlickGrid 的 rowHeight 属性。
请查看网格选项: https://github.com/mleibman/SlickGrid/wiki/Grid-Options

感谢GX的回复。请注意,我正在寻找根据用户交互_动态_更新行高度的方法...更改rowHeight属性似乎无法实现此目的。如果可以的话,我将尝试使用CSS方法-如果这有效,我将把它标记为已接受的答案。再次感谢! - Dave Clausen
感谢@epotter的提问...实际上我还没有机会(或优先级)重新审视这个问题。但我会继续将GX的回答标记为已接受。 - Dave Clausen
14
如果你没尝试过它,为什么要标记为完成?我对行高也有同样的疑问,但现在我不确定这个答案是否有用。 - bradley.ayers
我尝试使用rowHeight,但默认情况下它以px为单位计算。我无法使其自动增加。我尝试将slickGrid.js中的第909行更改为auto。如果有人成功了,请告诉我。 - Viral
由于公众的抗议,我已经取消了这个作为被接受的答案。当时它看起来是可以接受的答案;但是我已经重构了代码,所以不再需要动态修改。而且,那时候我还是一个 Stack Overflow 的新手。非常抱歉。 - Dave Clausen

2
我在网格中添加了一个函数,使我能够扩展行高:
var normalHeight = 25;
var expandedHeight = 100;
var columns = [
    {id: "col1", name: "Column 1", field: "col1", expanded: false},
    {id: "col2", name: "Column 2", field: "col2"}
];
var options = {
    rowHeight: normalHeight
};
var dataView = new Slick.Data.DataView();
var grid = new Slick.Grid(element, dataView, columns, options);
grid.updateOptions = function(expanded){
    var columns = grid.getColumns();
    if(!expanded){
        options['rowHeight'] = normalHeight;
        columns[0]['expanded'] = false;
    }else{
        options['rowHeight'] = expandedHeight;
        columns[0]['expanded'] = true;
    }
    grid.setOptions(options);
    grid.setColumns(columns);
    grid.invalidate();
    grid.render();
}

看起来它工作得很好,希望对某些人有所帮助。


我已经很久没有使用这个了,所以我不是100%确定,但我认为我有一个复选框来切换媒体是展开还是折叠的。每当复选框改变时,我就调用这个函数。 - JstnPwll

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接