Статьи

Конструктор нижнего меню (HTML5)

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

 

результат загрузки