Frontend Development 12 min read

Responsive Full‑Page Scroll Implementation with Vue 3

This article explains how to create a responsive full‑screen scrolling effect using Vue 3, detailing the concept, requirements, underlying principles, and providing complete HTML, JavaScript, and CSS code to handle mouse wheel, touch events, dynamic height calculation, and indicator navigation.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Responsive Full‑Page Scroll Implementation with Vue 3

The article introduces a full‑screen scrolling feature where each mouse‑wheel or touch swipe moves the page by one full viewport height, requiring the layout to adapt to window size changes.

Requirements include responsive behavior that does not break when the window is resized and clickable indicators for manual page switching.

The core principle is to hide overflow on the outer container, place scrollable content inside an inner container, calculate the viewport height dynamically, and translate the inner container based on the current page index.

HTML implementation provides the outer box, inner box, scroll elements generated with v-for , and an indicator list:

<!-- 最外层容器 -->
<div class="outer-box" ref="fullPage">
  <!-- 内层容器 -->
  <div ref="element" :class="{ activeTranstion: isCloseTranstion }" class="inner-box"
       @mousewheel="mousewheel" @touchstart="handleTouchStart" @touchend="handleTouchEnd" @touchmove="handleTouchMove">
    <!-- 滚动显示的元素 -->
    <div v-for="item in ysImage" :style="{ backgroundImage: `url(${item.backgroundImage})`, height: windowHeight + 'px' }" class="scroll-element"></div>
  </div>
  <!-- 指示器 -->
  <ul class="aside">
    <li v-for="(item, index) in asideData" @click="changeBac(index)">
      <span :class="{ active: index === $index }"></span>
      <div v-show="index === $index" class="show-dec">{{ item.title }}</div>
    </li>
  </ul>
</div>

JavaScript implementation uses Vue's composition API to manage state, throttle mouse‑wheel events, calculate scroll distance, and handle touch gestures for mobile devices. Key functions include mousewheel (with throttling), goScroll (determines next or previous page), next , last , changeBac , and touch handlers handleTouchStart , handleTouchMove , handleTouchEnd . Dynamic window height is obtained via useWindowSize() and applied through computed properties windowHeight , transformScroll , and a watchEffect that updates the element's transform style.

function mousewheel(e) {
  isCloseTranstion.value = false;
  if (canRun.value) {
    canRun.value = false;
    goScroll(e);
    setTimeout(() => { canRun.value = true; }, 1100);
  }
}

function goScroll(e) {
  // e.wheelDelta < 0 means next page, > 0 means previous page
  if (e.wheelDelta < 0) { next(); } else { last(); }
}

const $index = ref(0);
function next() { if ($index.value < 4) $index.value++; }
function last() { if ($index.value > 1 || $index.value === 1) $index.value--; }

function changeBac(index) { isCloseTranstion.value = false; $index.value = index; }

// Touch handling (mobile)
function handleTouchStart(e) { startY.value = e.touches[0].pageY || e.changedTouches[0].pageY; }
function handleTouchMove(e) {
  e.preventDefault();
  isCloseTranstion.value = true;
  moveDistance.value = (e.changedTouches[0].pageY || e.touches[0].pageY) - startY.value;
  const isCriticalPoint = ($index.value === 4 && moveDistance.value < 0) || ($index.value === 0 && moveDistance.value > 0);
  if (isCriticalPoint) return;
  element.value.style.transform = `translateY(-${$index.value * windowHeight.value + moveDistance.value * -1}px)`;
}
function handleTouchEnd(e) {
  isCloseTranstion.value = false;
  endY.value = e.changedTouches[0].pageY || e.touches[0].pageY;
  moveDistance.value = endY.value - startY.value;
  if (Math.abs(moveDistance.value) >= 60) {
    if ($index.value < 4 && moveDistance.value < 0) $index.value++;
    if ($index.value > 0 && moveDistance.value > 0) $index.value--;
  } else {
    element.value.style.transform = `translateY(-${$index.value * windowHeight.value}px)`;
  }
}

CSS implementation defines the layout, hides overflow, sets transitions, and styles the indicator dots and description boxes. The .activeTranstion class disables transition during touch moves, while the .active class styles the indicator dots.

.activeTranstion { transition: all 0ms ease 0s !important; }
.active { display: inline-block; width: 12px !important; height: 12px !important; }
.outer-box { width: 100%; height: 100%; overflow: hidden; position: relative; }
.inner-box { width: 100%; transition: all ease-in-out 0.5s; }
.scroll-element { background-size: cover !important; background-position: center; background-repeat: no-repeat; }
.aside { list-style: none; position: fixed; right: 20px; top: 50%; transform: translateY(-50%); }
.aside li { height: 14px; width: 14px; margin: 7px; display: flex; align-items: center; justify-content: center; position: relative; }
.aside li .show-dec { text-align: right; position: absolute; width: 70px; right: 20px; padding: 1px; color: #000; transition: all linear 0.1s; font-size: 12px; background-color: #fff; }
.aside li span { border-radius: 100%; border: #fff solid 1px; width: 4px; height: 4px; display: inline-block; background-color: #fff; transition: all ease-in-out 0.2s; }
.aside li:hover span { width: 10px; height: 10px; background-color: #fff; cursor: pointer; }

The final effect can be viewed at the provided demo URL, and the complete source code is available on GitHub.

In summary, the full‑screen scroll works by detecting scroll direction, dynamically computing viewport height, translating the inner container accordingly, and handling both mouse wheel and touch events to ensure a smooth, responsive experience across desktop and mobile devices.

JavaScriptCSSHTMLresponsiveFullPageScroll
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.