Skip to content

Instantly share code, notes, and snippets.

@alasomlira
Created November 12, 2019 17:37
Show Gist options
  • Save alasomlira/977829e430e6c3158ed18fbc746b6d9f to your computer and use it in GitHub Desktop.
Save alasomlira/977829e430e6c3158ed18fbc746b6d9f to your computer and use it in GitHub Desktop.
Menu responsive es6 [pure js]
<header class="demo-header">
<h1 class="logo">Logo</h1>
<nav class="nav">
<ul class="nav-list">
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Services</a></li>
<li><a href="#">Contact</a></li>
<li><a href="#">Blog</a></li>
<li><a href="#">Event</a></li>
<li>
<a href="#">+ Portfolio</a>
<ul class="sub-menu">
<li><a href="#">Portfolio 1</a></li>
<li><a href="#">Portfolio 2</a></li>
</ul>
</li>
<li><a href="#">Shop</a></li>
</ul>
</nav>
</header>
// Menu responsive
// By NguyenLong
class wilMenu {
constructor(el, opt) {
const optDefault = {
moreButton: '<a href="#">+ More</a>',
classMore: 'item-menu-more',
classMoreChild: 'sub-menu-more sub-menu'
}
this.opts = wilExtend(optDefault, opt);
this.els = document.querySelectorAll(el);
this.create(this.els);
}
create(els) {
wilEach(els, (el) => {
el.style.display = 'inline-block';
this.addMore(el);
this.responsive(el);
});
}
addMore(el) {
const {opts} = this;
let moreHTML = `
<li class="${opts.classMore}">
${opts.moreButton}
<ul class="${opts.classMoreChild}"></ul>
</li>
`;
if (el.innerHTML.indexOf(opts.moreButton) === -1) {
el.insertAdjacentHTML('beforeend', moreHTML);
}
}
responsive(el) {
const itemMore = el.children[el.children.length-1];
const subMore = itemMore.lastElementChild;
let elWidthBegin = el.offsetWidth;
let itemMoreWidth = itemMore.offsetWidth;
let lastResize = 0;
const cst = 100;
itemMore.style.display = 'none';
itemMore.firstElementChild.addEventListener('click', event => {
event.stopPropagation();
event.preventDefault();
})
const eventResize = document.createEvent('Event');
eventResize.initEvent('eventResize', true, true);
el.addEventListener('eventResize', () => {
let ww = window.innerWidth;
let elWidth = el.offsetWidth;
let parentWidth = el.parentNode.offsetWidth;
if (ww > lastResize) {
if (elWidth + cst <= parentWidth) {
if (subMore.innerHTML !== '') {
el.insertBefore(
subMore.firstChild,
el.childNodes[el.childNodes.length-2]
);
}
}
if (elWidthBegin + cst + 10 <= parentWidth + itemMoreWidth) {
itemMore.style.display = 'none';
}
} else {
let listItemLast = el.children[el.children.length-2];
if (elWidth + cst > parentWidth) {
if (listItemLast !== undefined) {
subMore.insertBefore(
listItemLast,
subMore.firstChild
);
}
}
if (elWidthBegin + cst + 10 > parentWidth + itemMoreWidth) {
itemMore.style.display = 'inline-block';
}
}
lastResize = ww;
});
const update = setInterval(() => {
let elWidth = el.offsetWidth;
let parentWidth = el.parentNode.offsetWidth;
if (elWidth + cst > parentWidth) {
el.dispatchEvent(eventResize);
} else {
clearTimeout(update);
}
}, 5);
window.addEventListener('resize', () => {
el.dispatchEvent(eventResize);
});
}
}
function wilEach(els, cb) {
for(var i = 0, len = els.length; i < len; i++) {
if (i === len) break;
cb(els[i], i);
}
}
function wilExtend(obj, src) {
if (typeof src === 'object') {
wilEach(Object.keys(src), (key) => {
obj[key] = src[key];
});
}
return obj;
}
// Menu responsive
// By NguyenLong
// moreButton: string ( tag html )
// classMore: string
// classMoreChild: string
const menu = new wilMenu('.nav-list', {
moreButton: '<a href="#">+ More</a>',
classMore: 'item-menu-more',
classMoreChild: 'sub-menu-more sub-menu'
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
%clear-fix {
&:after {
content: '';
display: table;
clear: both;
}
}
.demo-header {
background-color: #252c41;
font-family: 'Poppins', sans-serif;
font-weight: 500;
padding: 0 15px;
@extend %clear-fix;
}
.logo {
display: inline-block;
float: left;
width: 100px;
color: #fff;
margin-top: 10px;
}
.nav {
float: right;
width: calc(100% - 100px);
white-space: nowrap;
@extend %clear-fix;
ul {
list-style: none;
margin: 0;
padding: 0;
}
}
.nav-list {
float: right;
> li {
display: inline-block;
}
li {
position: relative;
}
a {
display: block;
padding: 25px 20px;
color: #9ea6ba;
font-size: 16px;
text-decoration: none;
}
.sub-menu {
position: absolute;
background-color: #222;
width: 200px;
right: 0;
top: 100%;
display: none;
a {
padding: 15px;
border-bottom: 1px solid rgba(#fff, 0.1);
}
.sub-menu {
top: 0;
right: 100%;
}
}
li:hover {
> .sub-menu {
display: block;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment