Поговорим про нижнюю навигацию сайтов. Я уверен, что вы видели её много раз (на различных сайтах). Как правило, это три-четыре колонны меню с различными ссылками. Сегодня я хотел бы показать вам, разработку, которую можно использовать для создания, нижнего меню. Главная цель этой разработки – приготовить статический код HTML (как кэш-файл) для встраивания в нижнюю часть сайта. Если вы заинтересованы в такой теме, то я расскажу вам о создании хорошего, удобного меню. Это руководство разделено на 2 части, сегодня я расскажу вам о первой части: пользовательский интерфейс с возможностью перетаскивания блоков.
Для начала, я хотел бы предложить вам загрузить исходные файлы и запустить демо в новой вкладке для лучшего понимания.
Итак, давайте приступим к разработке
Шаг 1. HTML
intex.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;
}
Шаг 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();
Здесь мы использовали много обработчиков событий. В начале, скрипта обновляем различные обработчики для всех перетаскивании и dropable объектов. При перемещении между блоками (с нижней области), мы должны воссоздать объекты в верхней области и обновить обработчики событий. В случае, когда нам нужно удалить колонку, мы должны передвинуть объект назад в нижнюю неактивную область, в которой содержится список всех возможных элементов.
Заключение
Вот и все, сегодня мы реализовали первую половину нашей постройки меню с функциями перетаскивания. Надеюсь, что наше руководство помогло вам. Не стесняйтесь поделиться своими знаниями с друзьями. Удачи!
Автор: Lecaw