TEST 1のコーディングです。参考にできます
jsでhamburger.jsの部分
document.addEventListener("DOMContentLoaded", function () {
// header.jsでボタンが移動されている可能性があるため、少し待ってから取得
setTimeout(() => {
const openBtn = document.querySelector(".openbtn");
const openBtnMv = document.querySelector(".openbtn_mv");
const gNav = document.getElementById("g-nav");
const overlay = document.getElementById("overlay");
if (!gNav || !overlay) {
return;
}
// ========================================
// 共通処理
// ========================================
// メニュー開閉処理
function toggleMenu(button) {
if (button) {
button.classList.toggle("active");
}
gNav.classList.toggle("panelactive");
overlay.classList.toggle("active");
document.documentElement.classList.toggle("no-scroll");
}
// メニュー閉じる処理
function closeMenu() {
if (openBtn) openBtn.classList.remove("active");
if (openBtnMv) openBtnMv.classList.remove("active");
gNav.classList.remove("panelactive");
overlay.classList.remove("active");
document.documentElement.classList.remove("no-scroll");
}
// オーバーレイクリックでメニューを閉じる
overlay.addEventListener("click", closeMenu);
// ナビゲーション内リンククリックで閉じる
const navLinks = gNav.querySelectorAll("a");
navLinks.forEach(function (link) {
link.addEventListener("click", closeMenu);
});
// ========================================
// openbtn(header内のハンバーガーボタン)の処理
// ========================================
if (openBtn) {
// クリックでメニュー開閉
openBtn.addEventListener("click", function () {
toggleMenu(openBtn);
});
}
// ========================================
// openbtn_mv(MVヘッダー内のハンバーガーボタン)の処理
// ========================================
if (openBtnMv) {
// クリックでメニュー開閉
openBtnMv.addEventListener("click", function () {
toggleMenu(openBtnMv);
});
// 初期表示設定
openBtnMv.style.display = "block";
// スクロール時の表示/非表示制御
window.addEventListener("scroll", function () {
const currentScrollY = window.scrollY;
if (window.innerWidth <= 768) {
// スクロール位置が5px以上なら非表示、それ以下なら表示
if (currentScrollY > 5) {
openBtnMv.style.display = "none";
// メニューが開いていたら閉じる
if (openBtnMv.classList.contains("active")) {
closeMenu();
}
} else {
openBtnMv.style.display = "block";
}
}
});
}
}, 10);
});
jsでheader.jsの部分
document.addEventListener("DOMContentLoaded", () => {
const header = document.getElementById("header");
const openBtn = document.querySelector(".openbtn");
let lastScrollY = 0;
// ハンバーガーボタンをbody直下に移動してスタッキングコンテキストから独立させる
if (openBtn && window.innerWidth <= 768) {
document.body.appendChild(openBtn);
// 初期状態で非表示にする
openBtn.style.transform = "translateY(-100px)";
openBtn.style.transition = "transform 0.3s ease-in-out";
}
window.addEventListener("scroll", () => {
const currentScrollY = window.scrollY;
if (currentScrollY > 100) {
header.style.transform = "translateY(0)";
header.style.transition = "transform 0.3s ease-in-out";
// ハンバーガーボタンも表示
if (openBtn && window.innerWidth <= 768) {
openBtn.style.transform = "translateY(0)";
}
} else {
header.style.transform = "translateY(-100%)";
// ハンバーガーボタンも非表示
if (openBtn && window.innerWidth <= 768) {
openBtn.style.transform = "translateY(-100px)";
}
}
lastScrollY = currentScrollY;
});
});
jsでのmv-anime.jsの部分
document.addEventListener("DOMContentLoaded", () => {
const images = document.querySelectorAll(".mv_image");
let currentIndex = 0;
// 最初の画像に "active" クラスを追加
if (images.length > 0) {
images[currentIndex].classList.add("active");
}
setInterval(() => {
// 現在の画像を非表示にする
images[currentIndex].classList.remove("active");
// 次の画像を表示する
currentIndex = (currentIndex + 1) % images.length;
images[currentIndex].classList.add("active");
}, 4000); // 4秒ごとに切り替え
});jsでcard_animationの部分
document.addEventListener("DOMContentLoaded", function () {
const toggleBtn = document.getElementById("carouselToggle");
const prevBtn = document.getElementById("prevBtn");
const nextBtn = document.getElementById("nextBtn");
const wrapper = document.querySelector(".product_card_wrapper");
let currentIndex = 0;
let isAutoPlaying = true;
let animationStartTime = Date.now();
let pausedPosition = 0; // 停止時の位置を保存
// スワイプ用の変数
let touchStartX = 0;
let touchEndX = 0;
let touchStartY = 0;
let touchEndY = 0;
let isSwiping = false;
if (wrapper) {
// カードを複製して無限ループを作成
const cards = wrapper.querySelectorAll(".product_card");
const originalCardCount = cards.length;
// 元のカードを2回複製(合計3セット)
for (let i = 0; i < 2; i++) {
cards.forEach((card) => {
const clone = card.cloneNode(true);
wrapper.appendChild(clone);
});
}
// 1枚分の移動距離を計算
function getCardDistance() {
const firstCard = wrapper.querySelector(".product_card");
const cardWidth = firstCard.offsetWidth;
const gap = parseFloat(window.getComputedStyle(wrapper).gap) || 0;
return cardWidth + gap;
}
// 指定インデックスに移動
function moveToIndex(index) {
const distance = getCardDistance();
wrapper.style.transform = `translateX(-${index * distance}px)`;
currentIndex = index;
}
// 次へ
if (nextBtn) {
nextBtn.addEventListener("click", function () {
// 自動再生を停止して手動モードに
if (isAutoPlaying) {
wrapper.classList.add("paused");
wrapper.classList.add("manual-control");
toggleBtn.classList.add("paused");
isAutoPlaying = false;
}
currentIndex++;
// 2セット目の終わり(8枚目)まで行ったら1セット目の最初に戻る
if (currentIndex >= originalCardCount * 2) {
// 瞬時に1セット目の同じ位置に移動
wrapper.style.transition = "none";
currentIndex = currentIndex - originalCardCount;
moveToIndex(currentIndex);
// 次のフレームで通常の遷移を再開
requestAnimationFrame(() => {
wrapper.style.transition = "transform 0.5s ease";
currentIndex++;
moveToIndex(currentIndex);
});
} else {
wrapper.style.transition = "transform 0.5s ease";
moveToIndex(currentIndex);
}
});
}
// 前へ
if (prevBtn) {
prevBtn.addEventListener("click", function () {
// 自動再生を停止して手動モードに
if (isAutoPlaying) {
wrapper.classList.add("paused");
wrapper.classList.add("manual-control");
toggleBtn.classList.add("paused");
isAutoPlaying = false;
}
currentIndex--;
// 最初より前に戻ろうとしたら2セット目の最後に移動
if (currentIndex < 0) {
wrapper.style.transition = "none";
currentIndex = originalCardCount * 2 - 1;
moveToIndex(currentIndex);
requestAnimationFrame(() => {
wrapper.style.transition = "transform 0.5s ease";
currentIndex--;
moveToIndex(currentIndex);
});
} else {
wrapper.style.transition = "transform 0.5s ease";
moveToIndex(currentIndex);
}
});
}
}
if (toggleBtn && wrapper) {
toggleBtn.addEventListener("click", function () {
toggleBtn.classList.toggle("paused");
isAutoPlaying = !isAutoPlaying;
// アニメーションを再開する場合
if (isAutoPlaying) {
wrapper.classList.remove("paused");
wrapper.classList.remove("manual-control");
const distance = getCardDistance();
const oneSetWidth =
(distance * wrapper.querySelectorAll(".product_card").length) / 3;
const animationDuration = 30000;
// 停止位置からの残り距離を計算
const remainingDistance = oneSetWidth + pausedPosition; // pausedPositionは負の値
const remainingProgress = remainingDistance / oneSetWidth;
const remainingTime = remainingProgress * animationDuration;
// 停止位置から最初に戻るまでのカスタムアニメーションを作成
wrapper.style.animation = "none";
wrapper.style.transform = `translateX(${pausedPosition}px)`;
requestAnimationFrame(() => {
wrapper.style.transition = `transform ${remainingTime}ms linear`;
wrapper.style.transform = `translateX(-${oneSetWidth}px)`;
// アニメーション終了後、通常のループアニメーションに戻す
setTimeout(() => {
wrapper.style.transition = "";
wrapper.style.transform = "";
wrapper.style.animation = "";
animationStartTime = Date.now();
pausedPosition = 0;
}, remainingTime);
});
} else {
// 停止時:アニメーションの進行度から現在位置を計算
wrapper.classList.add("manual-control");
const distance = getCardDistance();
const oneSetWidth =
(distance * wrapper.querySelectorAll(".product_card").length) / 3;
const animationDuration = 30000;
// アニメーション開始からの経過時間
const elapsed = (Date.now() - animationStartTime) % animationDuration;
const progress = elapsed / animationDuration;
// 現在の位置を計算
pausedPosition = -oneSetWidth * progress;
wrapper.style.animation = "none";
wrapper.style.transform = `translateX(${pausedPosition}px)`;
wrapper.style.transition = "none";
requestAnimationFrame(() => {
wrapper.classList.add("paused");
});
}
});
// ホバーで一時停止
wrapper.addEventListener("mouseenter", function () {
wrapper.classList.add("paused");
});
wrapper.addEventListener("mouseleave", function () {
if (isAutoPlaying) {
wrapper.classList.remove("paused");
}
});
// スワイプ機能
wrapper.addEventListener(
"touchstart",
function (e) {
touchStartX = e.changedTouches[0].screenX;
touchStartY = e.changedTouches[0].screenY;
isSwiping = false;
},
{ passive: true }
);
wrapper.addEventListener(
"touchmove",
function (e) {
if (!isSwiping) {
const diffX = Math.abs(e.changedTouches[0].screenX - touchStartX);
const diffY = Math.abs(e.changedTouches[0].screenY - touchStartY);
// 横方向のスワイプが縦方向より大きい場合、画面スクロールを防止
if (diffX > diffY && diffX > 10) {
isSwiping = true;
}
}
if (isSwiping) {
e.preventDefault();
}
},
{ passive: false }
);
wrapper.addEventListener(
"touchend",
function (e) {
touchEndX = e.changedTouches[0].screenX;
touchEndY = e.changedTouches[0].screenY;
handleSwipe();
isSwiping = false;
},
{ passive: true }
);
function handleSwipe() {
const diffX = touchStartX - touchEndX;
const diffY = touchStartY - touchEndY;
// 横方向のスワイプが縦方向より大きい場合のみ反応
if (Math.abs(diffX) > Math.abs(diffY) && Math.abs(diffX) > 50) {
// 自動再生を停止して手動モードに
if (isAutoPlaying) {
wrapper.classList.add("paused");
wrapper.classList.add("manual-control");
toggleBtn.classList.add("paused");
isAutoPlaying = false;
}
const originalCardCount =
wrapper.querySelectorAll(".product_card").length / 3;
if (diffX > 0) {
// 左にスワイプ = 次へ
currentIndex++;
if (currentIndex >= originalCardCount * 2) {
wrapper.style.transition = "none";
currentIndex = currentIndex - originalCardCount;
moveToIndex(currentIndex);
requestAnimationFrame(() => {
wrapper.style.transition = "transform 0.5s ease";
currentIndex++;
moveToIndex(currentIndex);
});
} else {
wrapper.style.transition = "transform 0.5s ease";
moveToIndex(currentIndex);
}
} else {
// 右にスワイプ = 前へ
currentIndex--;
if (currentIndex < 0) {
wrapper.style.transition = "none";
currentIndex = originalCardCount * 2 - 1;
moveToIndex(currentIndex);
requestAnimationFrame(() => {
wrapper.style.transition = "transform 0.5s ease";
currentIndex--;
moveToIndex(currentIndex);
});
} else {
wrapper.style.transition = "transform 0.5s ease";
moveToIndex(currentIndex);
}
}
}
}
function moveToIndex(index) {
const distance = getCardDistance();
wrapper.style.transform = `translateX(-${index * distance}px)`;
currentIndex = index;
}
function getCardDistance() {
const firstCard = wrapper.querySelector(".product_card");
const cardWidth = firstCard.offsetWidth;
const gap = parseFloat(window.getComputedStyle(wrapper).gap) || 0;
return cardWidth + gap;
}
}
});
jsでscroll-text-animation.jsの部分
// タイトル → 一文字ずつテキスト → 画像の順でフェードインするアニメーション
document.addEventListener("DOMContentLoaded", function () {
const aboutSection = document.querySelector(".about_shop");
const titleElement = document.querySelector(".about_shop_title");
const textElement = document.querySelector(".about_shop_text");
const imageWrapper = document.querySelector(".about_shop_image_wrapper");
if (!aboutSection || !titleElement || !textElement || !imageWrapper) return;
// 初期状態を非表示に設定
titleElement.style.opacity = "0";
titleElement.style.transform = "translateY(20px)";
titleElement.style.transition = "opacity 0.6s ease, transform 0.6s ease";
imageWrapper.style.opacity = "0";
imageWrapper.style.transform = "translateY(20px)";
imageWrapper.style.transition = "opacity 0.6s ease, transform 0.6s ease";
// 元のテキストを取得してspan要素に分割
const originalText = textElement.innerText;
textElement.innerHTML = ""; // 一度クリア
// テキストを1文字ずつspanで囲む(改行は保持)
const lines = originalText.split("\n");
lines.forEach((line, lineIndex) => {
const chars = line.split("");
chars.forEach((char) => {
const span = document.createElement("span");
span.textContent = char;
span.classList.add("char");
span.style.opacity = "0";
span.style.transform = "translateY(20px)";
span.style.transition = "opacity 0.2s ease, transform 0.2s ease";
textElement.appendChild(span);
});
// 改行を追加(最後の行以外)
if (lineIndex < lines.length - 1) {
textElement.appendChild(document.createElement("br"));
}
});
const chars = textElement.querySelectorAll(".char");
let animationTriggered = false;
// スクロールでセクションが表示されたらアニメーション開始
function checkAndAnimate() {
if (animationTriggered) return;
const rect = aboutSection.getBoundingClientRect();
const windowHeight = window.innerHeight;
// セクションが画面内に入ったら
if (rect.top <= windowHeight * 0.8 && rect.bottom >= 0) {
animationTriggered = true;
// 1. タイトルをフェードイン
titleElement.style.opacity = "1";
titleElement.style.transform = "translateY(0)";
// 2. タイトル表示後、1文字ずつテキストをフェードイン
const titleDelay = 600; // タイトルのアニメーション時間
chars.forEach((char, index) => {
setTimeout(() => {
char.style.opacity = "1";
char.style.transform = "translateY(0)";
}, titleDelay + index * 50); // タイトル後、50msごとに次の文字を表示
});
// 3. 一文字開始から2秒後に画像をフェードイン
setTimeout(() => {
imageWrapper.style.opacity = "1";
imageWrapper.style.transform = "translateY(0)";
}, titleDelay + 2000); // タイトル後 + 2秒
// アニメーション開始後はイベントリスナーを削除
window.removeEventListener("scroll", checkAndAnimate);
}
}
// スクロールイベント
window.addEventListener("scroll", checkAndAnimate);
// 初回チェック
checkAndAnimate();
});
jsのtable_scroll.jsの部分まで
// テーブルのドラッグスクロール機能
document.addEventListener("DOMContentLoaded", function () {
const scrollContainer = document.querySelector(".table-scroll");
if (!scrollContainer) return;
let isDown = false;
let startX;
let scrollLeft;
// マウスカーソルをグラブ(手のひら)に変更
scrollContainer.style.cursor = "grab";
scrollContainer.addEventListener("mousedown", (e) => {
isDown = true;
scrollContainer.style.cursor = "grabbing";
startX = e.pageX - scrollContainer.offsetLeft;
scrollLeft = scrollContainer.scrollLeft;
});
scrollContainer.addEventListener("mouseleave", () => {
isDown = false;
scrollContainer.style.cursor = "grab";
});
scrollContainer.addEventListener("mouseup", () => {
isDown = false;
scrollContainer.style.cursor = "grab";
});
scrollContainer.addEventListener("mousemove", (e) => {
if (!isDown) return;
e.preventDefault();
const x = e.pageX - scrollContainer.offsetLeft;
const walk = (x - startX) * 2; // スクロール速度(数値を大きくすると速くなる)
scrollContainer.scrollLeft = scrollLeft - walk;
});
});
サイトは
こちらから
