Как правило, вы должны определить отдельные компоненты для каждого уровня, назначить шаблон для каждого из ваших компонентов и реализовать что-то вроде expand()
/ collapse()
методов. Если компонент изначально свернут (ваш случай), ему не нужно отображать дочерние элементы при инициализации, он будет отображать их только при развертывании (будут использоваться соответствующие шаблоны дочерних компонентов).
Пожалуйста, предоставьте основной код, который вы пытаетесь заставить работать, вам будет проще помочь таким образом.
Вот быстрый прототип системы Widget с простым потоком рендеринга, использующим шаблоны. Я думаю, вы хотите что-то подобное в вашем приложении. Он неоптимизирован, это просто представление о том, как может выглядеть ваша структура.
/**
* Widget constructor
*/
var Widget = function(config) {
// apply config
$.extend(this, config);
// attempt to render
this.render();
};
/**
* Widget prototype
*/
$.extend(Widget.prototype, {
// render target
renderTo: null,
// template
tpl: '<div class="container-panel">' +
'<p>${txt}</p>' +
'<div class="items-container"></div>' +
'</div>',
// template data
tplData: null,
// child items array
children: null,
// initial collapsed state
collapsed: false,
// widget's root element
el: null,
// default render target selector for child items
renderTarget: '.items-container',
render: function() {
var me = this,
renderDom
// render the widget
if(!this.rendered && this.renderTo && this.tpl) {
renderDom = $.tmpl(this.tpl, this.tplData);
// assume that first element is widget's root element
this.el = renderDom[0];
$(this.renderTo).append(renderDom);
// clear the reference
renderDom = undefined;
// THIS IS JUST EXAMPLE CODE! Bind click handler...
$(this.el).find('p').first().click(function() {
me.collapsed ? me.expand() : me.collapse();
});
// find render target for children
this.renderTarget = $(this.el).find(this.renderTarget).first();
// render children if not collapsed
this.renderChildren();
// set rendered flag
this.rendered = true;
}
},
renderChildren: function() {
var children = this.children;
if(!this.collapsed && children && children.length) {
for(var i = 0, len = children.length; i < len; i++) {
// render children inside
children[i].renderTo = this.renderTarget;
children[i].render();
}
}
},
/**
* Expand template method. Override it.
*/
expand: function() {
this.collapsed = false;
this.renderChildren();
this.renderTarget.show();
},
/**
* Collapse template method. Override it.
*/
collapse: function() {
this.collapsed = true;
this.renderTarget.hide();
}
});
Здесь я предварительно определил шаблоны и жестко запрограммировал логику расширения / свертывания, которая происходит при щелчке внутри первого элемента абзаца виджета.
Вот как бы вы использовали виджеты:
// Using our widgets
var containerPanel = new Widget({
tplData: {txt: 'Hello world!'},
renderTo: $('body'),
collapsed: true,
children: [
new Widget({
tplData: {txt: ' Child 1'},
collapsed: true,
children: [
new Widget({
tplData: {txt: ' Child 1.1'}
}),
new Widget({
tplData: {txt: ' Child 1.2'}
}),
new Widget({
tplData: {txt: ' Child 1.3'}
})
]
}),
new Widget({
tplData: {txt: ' Child 2'}
})
]
});
Вы можете увидеть живой пример на jsFiddle: http://jsfiddle.net/dipish/XDmWq/
Просто нажмите на элементы и посмотрите на динамически генерируемую разметку.
Я думаю, что код не требует пояснений, но не стесняйтесь задавать любые вопросы. Обратите внимание, что в коде используется плагин jQuery Templates , но это только для удобства.
Если в вашем веб-приложении много сложных компонентов, вы можете использовать что-то более серьезное, чем простой jQuery, например ExtJS или Dojo Toolkit . Такие структуры обычно предоставляют вам удобную систему классов и базовую логику виджетов / компонентов для построения, помимо множества других вещей.
Удачи!