Действительно, можно динамически обновлять высоту строки в зависимости от взаимодействия с пользователем. Slickgrid API
предоставляет все, что нам нужно.
Так как:
- мы можем динамически добавлять/удалять строки;
- мы можем динамически применять пользовательские
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 [email protected] ~ 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; что я утверждаю, что это возможно.
Чтобы сделать динамическую высоту строки на ячейку, мы используем аналогичный трюк, но мы также должны иметь дело с несколькими побочными эффектами:~
удаление разделения строк
Мы должны:
- избежать отсечения переполнения per-cell
- удалить нежелательную стеснительность строк
- удалить границы строк
Slickgrid API
обеспечивает стиль на основе строк через Grid. .getItemMetadata интерфейс обратного вызова. В следующей скрипке в строке 107 см. onRenderRow
реализацию этого интерфейса:
возиться с этим!
Обратите также внимание на строки 148-150, я вызываю Slickgrid
Grid.setCellCssStyles API для добавления пользовательского класса dynamic-cell
css
, который задает для overflow
значение visible
, чтобы убрать отсечение переполнения на ячейку.
изменение размера столбца
Если содержание сведений является статическим, изменение размера столбца не представляет сложности.
Детальное содержание, которое отвечает на изменение ширины столбца (текущий текст или wotnot), требует некоторой доработки. Строки заполнения должны динамически добавляться и удаляться соответствующим образом. См. (со строки 66) функции addPadding
и trimPadding
в следующей скрипте:
возиться с этим!
сортировка
Здесь тоже есть над чем поработать. нам нужно убедиться, что независимо от того, сортируем ли мы вверх или вниз, заполнение остается непрерывным под родителем. См. comparer
в строке 136 в следующей скрипке:
поиграйте с ней !
фильтрация
В значительной степени однострочный: если это заполнение, то делегируйте сравнение родителю. Работа выполнена. См. pcFilter
в строке 192 в следующей скрипке:
поиграйте с ней !
Ура! это изменение размера, сортировка и фильтрация в менее чем 500 строк довольно разборчивых, щедро прокомментированных пользовательских javascripts.. я действительно видел некоторые причудливые input-range-slider
pollyfills с большим количеством строк кода;)
Предостережения
Я рассмотрел только основы. В Slickgrid
есть целый аспект выбираемого/редактируемого, который выходит за рамки моих текущих требований (извините).
Также:
- только пример кода; не готов к производству. вы были предупреждены и т. д. и т. д. =)
- примеры работают в большинстве современных браузеров; я /не/ пробовал с iE; версии >= 11 могут быть в порядке..
Дополнительная информация
Об этом можно сказать больше, чем можно разумно втиснуть в SO
ответ, несмотря на правила политики без ссылок. Любой, кто хочет узнать больше обо всем этом, может перейти здесь, где я расскажу подробнее.
Последний пример
Вот последний забавный пример. он использует все вышеперечисленные функции, но, как видно, я отказался от расширяемых строк и теперь есть два поля динамического содержимого. Кроме того, к сведению, в этом примере используются MutationObservers для создания onPostRender
в качестве альтернативы Slickgrid
родному asyncPostRender
параметру столбца обратный вызов:
поиграйте с этим!
И вот оно. - часть пути к DataView-like Slickgrid extension-mod
; и все это без необходимости прибегать к ужасному хакерству с прекрасными кодами Slickgrid. ура ;)
Оооок! Этому посту несколько лет; и теперь я вижу, что есть несколько ответвлений исходного проекта, который в настоящее время не поддерживается. например: https://github.com/6pac/SlickGrid
person
violet313
schedule
01.04.2015