Создание многуровненого списка (или по сути дерева) хорошо подходит для визализации сложных объектов.
Например отображения папок на сервере.
Пример данной реализации подразумевает предварительную загрузку дерева и потом только перерисовку нод.
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)) ); } |