Posted at

メニューが横幅に収まらない時に右上に収納されるやつ

あまりサンプルが見つからなかったのでやってみた。

こういう動きを何て言うのか分からないので、自分が見つけられなかっただけの可能性は否めないです・・・。


デモ


See the Pen
navbar with menu storage
by Yoshiaki Itakura (@negibouze)
on CodePen.


ちょっと解説

せっかくなので、Intersection Observerを使ってみました。

ポイントはroot#menuにするところくらいです。

const setIntersectionObserver = () => {

const observerOptions = {
root: document.querySelector("#menu"), // menuをroot要素にする
rootMargin: "0px",
threshold: [0.8]
};

const items = document.querySelectorAll(".menu-item");
observer = new IntersectionObserver(
intersectionCallback,
observerOptions
);
// menu-itemを監視対象にする
for (const item of items) {
observer.observe(item);
}
}

entry.isIntersectingで処理を分岐します。

true: 見えるようになった

false: 見えなくなった

const intersectionCallback = (entries) => {

entries.forEach(entry => {
const target = entry.target;
const storage = document.querySelector(".storage");
if (entry.isIntersecting) {
// navbarのメニューを表示する
target.classList.remove("invisible");
const len = overflowMenuItems.length;
if (1 <= len) {
if (len === 1) {
// 最後の要素が表示された時は、more(縦の「・・・」)を非表示にする
storage.classList.add("hide");
}
// 収納していたメニューの先頭を削除する
overflowMenuItems.shift();
}
} else {
// あふれメニューの末尾に要素のクローンを追加する
overflowMenuItems.unshift(target.cloneNode(true));
// navbarのメニューを非表示にする
target.classList.add("invisible");
// more(縦の「・・・」)を表示する
storage.classList.remove("hide");
}
});
sortOverflowItems();
createOverflowMenu();
}

並び順を保証するために、data属性のorderでsortします。

※これをやらないと、初回表示時に横幅が足りない時に並び順が保証されない

const sortOverflowItems = () => {

overflowMenuItems.sort((a, b) => {
return a.dataset.order < b.dataset.order ? -1 : 1;
})
}

#overflowMenuの子要素にあふれた分のメニューを追加します。

差分更新にした方が良いと思いますが、ひとまず毎回、既存の子要素を全削除してから、再度追加しています。

const createOverflowMenu = () => {

const menu = document.querySelector("#overflowMenu");
// 一回全部消す
while (menu.firstChild) {
menu.removeChild(menu.firstChild);
}
for (const item of overflowMenuItems) {
menu.appendChild(item);
}
}

おまけ: ドラッグで横幅を変えるやつ(動作確認用)

/* 動作確認用 */

const wrapper = document.querySelector(".wrapper");

const addResizeEvent = () => {
const rightEdge = document.querySelector(".right-edge");

rightEdge.addEventListener("mousedown", initResize, false);
}

const initResize = (e) => {
window.addEventListener("mousemove", Resize, false);
window.addEventListener("mouseup", stopResize, false);
}

const Resize = (e) => {
wrapper.style.width = `${e.clientX - wrapper.offsetLeft}px`;
}

const stopResize = (e) => {
window.removeEventListener("mousemove", Resize, false);
window.removeEventListener("mouseup", stopResize, false);
}