console
class DualScroll {
constructor(container) {
this.container = document.querySelector(container);
this.rows = Array.from(this.container.querySelectorAll('.section-row'));
console.log("@@@@", this.rows)
this.currentIndex = { row: 0, col: 0 };
this.initScrollSnap();
this.setupObservers();
this.bindEvents();
}
initScrollSnap() {
this.container.style.scrollBehavior = 'smooth';
}
setupObservers() {
this.observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const row = this.rows.indexOf(entry.target.parentElement);
const col = Array.from(entry.target.parentElement.children)
.indexOf(entry.target);
this.currentIndex = { row, col };
}
});
}, { threshold: 0.7 });
this.rows.forEach(row => {
Array.from(row.children).forEach(section => {
this.observer.observe(section);
});
});
}
bindEvents() {
let startX, startY;
this.container.addEventListener('wheel', (e) => {
e.preventDefault();
const { deltaX, deltaY } = e;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
this.scrollTo(0, deltaX > 0 ? 1 : -1);
} else {
this.scrollTo(deltaY > 0 ? 1 : -1, 0);
}
}, { passive: false });
this.container.addEventListener('touchstart', (e) => {
startX = e.touches[0].clientX;
startY = e.touches[0].clientY;
});
this.container.addEventListener('touchend', (e) => {
const endX = e.changedTouches[0].clientX;
const endY = e.changedTouches[0].clientY;
const diffX = startX - endX;
const diffY = startY - endY;
if (Math.abs(diffX) > Math.abs(diffY)) {
this.scrollTo(0, diffX > 0 ? 1 : -1);
} else {
this.scrollTo(diffY > 0 ? 1 : -1, 0);
}
});
}
scrollTo(rowDelta, colDelta) {
const newRow = Math.max(0,
Math.min(this.rows.length - 1, this.currentIndex.row + rowDelta));
const newCol = Math.max(0,
Math.min(this.rows[newRow].children.length - 1,
this.currentIndex.col + colDelta));
this.rows[newRow].children[newCol].scrollIntoView({
behavior: 'smooth',
block: 'nearest',
inline: 'center'
});
}
}
new DualScroll('#scroller');
<div class="scroll-container" id="scroller">
<div class="section-row">
<div class="section">1-1</div>
<div class="section">1-2</div>
<div class="section">1-3</div>
</div>
<div class="section-row">
<div class="section">2-1</div>
<div class="section">2-2</div>
<div class="section">2-3</div>
</div>
</div>
<script src="script.js"></script>
body { margin: 0; overflow: hidden; }
.scroll-container {
width: 100vw;
height: 100vh;
overflow: auto;
scroll-snap-type: both mandatory;
}
.section-row {
display: flex;
width: 300vw;
height: 100vh;
}
.section {
flex: 0 0 100vw;
height: 100vh;
scroll-snap-align: start;
}
.section-row:nth-child(odd) .section { background: #f5f5f5; }
.section-row:nth-child(even) .section { background: #e5e5e5; }