Создание многуровненого списка (или по сути дерева) хорошо подходит для визализации сложных объектов.
Например отображения папок на сервере.
Пример данной реализации подразумевает предварительную загрузку дерева и потом только перерисовку нод.
index.html
tree.js
style.css
Результат:
Для добаваления динамической загрузки достачно немного переписать метод render.
Нужно добавить запрос на сервер c путём к текущей папке
Что-то вроде такого:
Спасибо за внимание.
1 2 3 | <div id="tree"></div><script src="tree.js" /><link rel="stylesheet" href="style.css" /> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | //Функция создаётся и сразу вызывается(function initTree (treeNode) { const FOLDER = 'FOLDER'; const FILE = 'FILE'; const clickFolder = folder => render(folder); //Создание DOM элемента function initChild(child) { const entity = document.createElement('li'); entity.innerHTML = (child.type === FOLDER ? './' : '') + child.name; entity.setAttribute('class', child.type); entity.addEventListener( 'click', () => child.type === FOLDER && clickFolder(child) ); return entity; } //Создание всех DOM-элементов в папке function initFolder(parent) { const entity = document.createElement('ul'); parent.children .sort(child => child.type !== FOLDER) .forEach(child => entity.appendChild(initChild(child))); return entity; } //Функция создающая возврающая дерево списка с "родителями" function getRoot() { const withParents = (child, parent) => { child.parent = parent; if (child && child.children) { child.children = child.children.map( subchild => withParents(subchild, child) ); } return child; }; return withParents(getMockFolderData()); } //Генерируем дерево списка для примера function getMockFolderData() { const rootFolder = { type: FOLDER, children: [] }; let currentFolder = rootFolder; for (let size= 0; size < 25; size++) { currentFolder = ( [ currentFolder.parent || currentFolder, ...currentFolder.children.filter(f => f.type === FOLDER) ] .sort(() => 0.5 - Math.random()) .pop() ); const FILE_NAMES = ["Фотки", "Любимая папка", "Разное"]; const FOLDER_NAMES = ["photo1.png", "backup.zip", "42.jpg"]; currentFolder.children.push( Math.random() < 0.5 ? { type: FOLDER, name: FILE_NAMES.sort(() => Math.random() - 0.5).pop() children: [] } : { name: FOLDER_NAMES.sort(() => Math.random() - 0.5).pop(), type: FILE } ); } return rootFolder; } //Рекурсивно по родителям получаем путь к папке function getBreadcrumbs(child, arr = []) { return ( child.parent ? getBreadcrumbs(child.parent, [child, ...arr]) : [child, ...arr] ); } //Перерисовываем текущую папку function render(root) { const folder = initFolder(root); const breadcrumbs = document.createElement('span'); getBreadcrumbs(root).forEach(child => { const breadcrumb = document.createElement('a'); breadcrumb.href = "javascript:void(0)"; breadcrumb.innerHTML = `${child.name || ""} ${child.type === FOLDER ? "/" : ""}`; breadcrumb.addEventListener( 'click', () => child.type === FOLDER && render(child) ); breadcrumbs.appendChild(breadcrumb); }); treeNode.innerHTML = ""; treeNode.appendChild(breadcrumbs); treeNode.appendChild(folder); } render(getRoot());})(document.getElementById('tree')); |
1 2 3 4 5 6 7 8 9 | #tree { background: #003 }#tree > span { margin-left: 16px; display: block;}#tree > span > a { color: #aaf; }#tree > span > a:hover { color: #aaf; background: rgba(255, 255, 255, 0.3); }#tree > ul > li { color: #fff; padding: 4px; display: block; }#tree > ul > li.FOLDER:hover { cursor: pointer; background: rgba(255, 255, 255, 0.3);} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | function render(root) { const breadcrumbs = document.createElement('span'); const breadcrumbsArray = getBreadcrumbs(root); breadcrumbsArray .forEach(child => { const breadcrumb = document.createElement('a'); breadcrumb.href = "javascript:void(0)"; breadcrumb.innerHTML = (child.name || "") + (child.type === FOLDER ? "/" : ""); breadcrumb.addEventListener('click', () => child.type === FOLDER && render(child)); breadcrumbs.appendChild(breadcrumb); }); treeNode.innerHTML = ""; treeNode.appendChild(breadcrumbs); $.getJSON( "/get-folder-content?uri=" + breadcrumbsArray.map(child => child.name).join('/'), rootData => treeNode.appendChild(initFolder(rootData)) );} |