Я уверен, что вы видели это раньше (на разных сайтах). Как обычно, это меню из трех-четырех колонок с разными ссылками. Сегодня я хотел бы показать вам конструктор, который вы можете использовать для создания этого нижнего меню. Основная цель этого компоновщика — подготовить статический HTML-код (в виде файла кэша) для встраивания в нижнюю часть вашего сайта. Если вам понравилась эта идея, вы можете поиграть с ней, и я расскажу вам о создании хорошего удобного в использовании конструктора меню. Этот урок разделен на 2 части: сегодня я расскажу вам о первой стороне, которая является пользовательским интерфейсом с возможностью перетаскивания.
В качестве первого я предлагаю вам скачать исходные файлы и держать демонстрацию открытой во вкладке для лучшего понимания.
Live Demo
результат загрузки
Итак, начнем
Шаг 1. HTML
index.html
<div class="actions"> Actions: <button id="preview" disabled>Preview</button> <button id="add_col">Add Column</button> </div> <div class="actions">Columns (with active elements)</div> <div class="columns"> <div class="column" id="drop_1" droppable="true"><img src="images/delete.png" onclick="removeColumn(this)" /></div> <div class="column" id="drop_2" droppable="true"><img src="images/delete.png" onclick="removeColumn(this)" /></div> <div class="column" id="drop_3" droppable="true"><img src="images/delete.png" onclick="removeColumn(this)" /></div> </div> <div style="clear:both"></div> <div class="actions">All (inactive) elements. You can drag these elements into columns.</div> <div class="inactive" droppable="true"> <a id="1" draggable="true">Link 1</a> <a id="2" draggable="true">Link 2</a> <a id="3" draggable="true">Link 3</a> <a id="4" draggable="true">Link 4</a> <a id="5" draggable="true">Link 5</a> <a id="6" draggable="true">Link 6</a> <a id="7" draggable="true">Link 7</a> <a id="8" draggable="true">Link 8</a> <a id="9" draggable="true">Link 9</a> <a id="10" draggable="true">Link 10</a> <a id="11" draggable="true">Link 11</a> <a id="12" draggable="true">Link 12</a> </div> <script src="js/main.js"></script>
Есть три основных раздела: блок с действиями, блок с активными столбцами и блок с неактивными элементами. Все элементы мы можем перетаскивать между столбцами. Также мы можем добавлять и удалять наши столбцы.
Шаг 2. CSS
/* menu builder styles */ .actions { border: 1px solid #CCCCCC; font-size: 24px; margin: 20px auto 5px; overflow: hidden; padding: 10px; width: 900px; /* CSS3 Box sizing property */ -moz-box-sizing: border-box; -webkit-box-sizing: border-box; -o-box-sizing: border-box; box-sizing: border-box; } .actions button { cursor: pointer; font-size: 20px; padding: 5px; } .actions #add_col { float: right; } .inactive { border: 1px dashed #ccc; margin: 0 auto; width: 900px; } .inactive a { border-color: #FFFFFF; border-style: solid; border-width: 8px 8px 20px; cursor: pointer; display: inline-block; font-size: 20px; height: 20px; margin: 10px; opacity: 1; position: relative; text-align: center; width: 180px; -khtml-user-drag: element; /* CSS3 Prevent selections */ -moz-user-select: none; -webkit-user-select: none; -khtml-user-select: none; user-select: none; /* CSS3 Box Shadow */ -webkit-box-shadow: 2px 2px 4px #444; -o-box-shadow: 2px 2px 4px #444; box-shadow: 2px 2px 4px #444; } .inactive a.hidden { height: 0; margin: 0; opacity: 0; width: 0; } .columns { margin: 0 auto; overflow: hidden; width: 900px; } .column { border: 2px dashed #ccc; float: left; min-height: 100px; padding: 10px; position: relative; width: 33.3%; /* CSS3 Box sizing property */ -moz-box-sizing: border-box; -webkit-box-sizing: border-box; -o-box-sizing: border-box; box-sizing: border-box; } .column a { border-color: #FFFFFF; border-style: solid; border-width: 4px 4px 10px; cursor: pointer; display: block; font-size: 16px; height: 30px; margin-bottom: 15px; opacity: 1; position: relative; text-align: center; -khtml-user-drag: element; -webkit-user-drag: element; /* CSS3 Prevent selections */ -moz-user-select: none; -webkit-user-select: none; -khtml-user-select: none; user-select: none; /* CSS3 Box Shadow */ -webkit-box-shadow: 2px 2px 4px #444; -o-box-shadow: 2px 2px 4px #444; box-shadow: 2px 2px 4px #444; /* CSS3 Box sizing property */ -moz-box-sizing: border-box; -webkit-box-sizing: border-box; -o-box-sizing: border-box; box-sizing: border-box; } .column img { cursor: pointer; position: absolute; right: 2px; top: 2px; z-index: 5; }
Теперь пришло время стилизовать нашу страницу конструктора меню:
CSS / main.css
Шаг 3. JS
JS / main.js
// add event handler realization var addEvent = (function () { if (document.addEventListener) { return function (el, type, fn) { if (el && el.nodeName || el === window) { el.addEventListener(type, fn, false); } else if (el && el.length) { for (var i = 0; i < el.length; i++) { addEvent(el[i], type, fn); } } }; } else { return function (el, type, fn) { if (el && el.nodeName || el === window) { el.attachEvent('on' + type, function () { return fn.call(el, window.event); }); } else if (el && el.length) { for (var i = 0; i < el.length; i++) { addEvent(el[i], type, fn); } } }; } })(); // update handlers for draggable objects function updateHandlerDrag() { var dragItems = document.querySelectorAll('[draggable=true]'); for (var i = 0; i < dragItems.length; i++) { // dragstart event handler addEvent(dragItems[i], 'dragstart', function (event) { event.dataTransfer.setData('obj_id', this.id); return false; }); } } // update handlers for droppable objects function updateHandlerDrop() { var dropAreas = document.querySelectorAll('[droppable=true]'); // dragover event handler addEvent(dropAreas, 'dragover', function (event) { if (event.preventDefault) event.preventDefault(); this.style.borderColor = "#000"; return false; }); // dragleave event handler addEvent(dropAreas, 'dragleave', function (event) { if (event.preventDefault) event.preventDefault(); this.style.borderColor = "#ccc"; return false; }); // dragenter event handler addEvent(dropAreas, 'dragenter', function (event) { if (event.preventDefault) event.preventDefault(); return false; }); // drop event handler addEvent(dropAreas, 'drop', function (event) { if (event.preventDefault) event.preventDefault(); // get dropped object var iObj = event.dataTransfer.getData('obj_id'); var oldObj = document.getElementById(iObj); // get inner text var linkText = oldObj.innerHTML; oldObj.className += 'hidden'; // remove object from DOM oldObj.parentNode.removeChild(oldObj); // add similar object in another place this.innerHTML += '<a id="'+iObj+'" draggable="true">'+linkText+'</a>'; // and update event handlers updateHandlerDrag(); this.style.borderColor = "#ccc"; return false; }); } // add column button var addColBtn = document.querySelectorAll('#add_col'); addEvent(addColBtn, 'click', function (event) { if (event.preventDefault) event.preventDefault(); // recalculate widths for columns var oCols = document.querySelector('div.columns'); var iChilds = oCols.childElementCount + 1; var dWidth = 100 / iChilds; // add single column oCols.innerHTML += '<div class="column" id="drop_'+(iChilds+1)+'" droppable="true"><img src="images/delete.png" onclick="removeColumn(this)" /></div>'; // set new widths for (var i = 0; i < iChilds; i++) { oCols.children[i].style.width = dWidth + '%'; } // update handlers updateHandlerDrop(); return false; }); // remove columns function removeColumn(obj) { var oParent = obj.parentNode; // move object to inactive area var oInactive = document.querySelector('div.inactive'); for (var i = 0; i < oParent.childNodes.length; i++) { if (oParent.childNodes[i].nodeType == document.ELEMENT_NODE && oParent.childNodes[i].tagName == 'A') { oInactive.innerHTML += '<a id="'+oParent.childNodes[i].id+'" draggable="true">'+oParent.childNodes[i].innerHTML+'</a>'; } } // remove column oParent.parentElement.removeChild(oParent); // recalculate widths for columns var oCols = document.querySelector('div.columns'); var iChilds = oCols.childElementCount; var dWidth = 100 / iChilds; // set new widths for (var i = 0; i < iChilds; i++) { oCols.children[i].id = 'drop_' + (i + 1); oCols.children[i].style.width = dWidth + '%'; } // update handlers updateHandlerDrop(); updateHandlerDrag(); } // update handlers updateHandlerDrag(); updateHandlerDrop();
Есть много обработчиков событий (для того, чтобы сделать это html5 drag and drop). В начале сценарий обновляет различные обработчики для всех перетаскиваемых и перетаскиваемых объектов. При перетаскивании между блоками (областями перетаскивания) мы должны воссоздавать объекты и обновлять обработчики. В случае, когда нам нужно удалить столбец, мы должны переместить весь объект активного столбца обратно в неактивную область (со списком всех возможных элементов). Завтра мы научим нашего строителя генерировать результаты.
Live Demo
результат загрузки