Разрабатываем нижнее меню на HTML5

в 10:45, , рубрики: bottom menu, drag and drop, html, html5, веб-дизайн, Веб-разработка

image

Поговорим про нижнюю навигацию сайтов. Я уверен, что вы видели её много раз (на различных сайтах). Как правило, это три-четыре колонны меню с различными ссылками. Сегодня я хотел бы показать вам, разработку, которую можно использовать для создания, нижнего меню. Главная цель этой разработки – приготовить статический код 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

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js