Vue3 customizes a simple Swiper sliding component – touchpad sliding & mouse sliding & left and right arrow sliding – demo

The code implements a basic sliding function, and monitors sliding operations through mouse press, mouse release and mouse move events.

The specific implementation logic is as follows:

  • In the onMounted hook function, we add three event listeners to the scroll container:
  • mousedown event: when the mouse is pressed, set control.isDown to true, and record the mouse start position control.startX and scrollbar position control.scrollLeft.
  • mouseup event: When the mouse is released, set control.isDown to false, indicating that the mouse has been lifted.
  • mousemove event: when the mouse moves, if control.isDown is true, calculate the mouse sliding distance walk , and set the scroll container’s scrollLeft property to control.scrollLeft - walk.

Through these event monitoring, we can realize the scrolling effect of scrolling the container when the mouse slides.

In addition, the code also includes the sliding function when the left and right arrow buttons are clicked. In the onPageLeft method, by modifying the scrollLeft property of the scrolling container, slide to the left by a container width distance; in the onPageRight method, by Modify the scrollLeft property of the scrolling container to slide to the right by a container width.

Structure code

<template>
  <div class="swiper">
    <div class="watch-list-arrow watch-list-arrow--left" @click="onPageLeft">
      <div class="watch-list-arrow-btn">←</div>
    </div>
    <div ref="currencyItemsRef" class="currency-items">
      <div class="currency-item" v-for="(item, index) in symbols" :key="index">
        {<!-- -->{ item }}
      </div>
    </div>
    <div class="watch-list-arrow watch-list-arrow--right" @click="onPageRight">
      <div class="watch-list-arrow-btn">→</div>
    </div>
  </div>
</template>

Business logic

<script setup>
import { ref, reactive, onMounted } from 'vue';
const symbols = ref([
  'BTC111',
  'ETH',
  'XRP',
  'LTC',
  'BCH',
  'ADA',
  'DOGE',
  'DOT',
  'LINK',
  'UNI1',
  'UNI2',
  'UNI3',
  'UNI4',
  'UNI5',
  'UNI6',
  'UNI999'
]);

const currencyItemsRef = ref(null);

// Left and right arrows slide
const onPageLeft = () => {
  // version one
  // currencyItemsRef.value.scrollLeft -= currencyItemsRef.value.offsetWidth;
  // version two
  // const containerWidth = currencyItemsRef.value.clientWidth;
  // const currentScrollLeft = currencyItemsRef.value.scrollLeft;

  // const nextScrollLeft = currentScrollLeft - containerWidth;

  // if (nextScrollLeft >= 0) {
  // currencyItemsRef.value.scrollTo({
  // left: nextScrollLeft,
  // behavior: 'smooth'
  // });
  // } else {
  // currencyItemsRef.value.scrollTo({
  // left: 0,
  // behavior: 'smooth'
  // });
  // }
  // version three
  currencyItemsRef.value.scroll({
    left:
      currencyItemsRef.value.scrollLeft - currencyItemsRef.value.offsetWidth,
    behavior: 'smooth'
  });
};

const onPageRight = () => {
  // version one
  // currencyItemsRef.value.scrollLeft += currencyItemsRef.value.offsetWidth;
  // version two
  // const containerWidth = currencyItemsRef.value.clientWidth;
  // const maxScrollLeft = currencyItemsRef.value.scrollWidth - containerWidth;
  // const currentScrollLeft = currencyItemsRef.value.scrollLeft;

  // const nextScrollLeft = currentScrollLeft + containerWidth;

  // if (nextScrollLeft <= maxScrollLeft) {
  // currencyItemsRef.value.scrollTo({
  // left: nextScrollLeft,
  // behavior: 'smooth'
  // });
  // } else {
  // currencyItemsRef.value.scrollTo({
  // left: maxScrollLeft,
  // behavior: 'smooth'
  // });
  // }
  // version three
  currencyItemsRef.value.scroll({
    left:
      currencyItemsRef.value.scrollLeft + currencyItemsRef.value.offsetWidth,
    behavior: 'smooth'
  });
};

// mouse scroll
const control = reactive({
  isDown: false, // Whether to press the mouse
  startX: 0, // mouse start position
  scrollLeft: 0 // scroll bar position
});

const move = (e) => {
  if (!control. isDown) return;
  e.preventDefault();
  const x = e.pageX - currencyItemsRef.value.offsetLeft;
  const walk = (x - control.startX) * 2; // sliding distance
  currencyItemsRef.value.scrollLeft = control.scrollLeft - walk;
  // control. scrollLeft = control. scrollLeft - walk;
  // requestAnimationFrame(() => {
  // currencyItemsRef.value.scrollLeft = control.scrollLeft;
  // });
};

onMounted(() => {
  console.log('dom', currencyItemsRef.value);
  // Summarize the realization of sliding on the web side, which is to monitor the mouse press, mouse release, and mouse movement events
  currencyItemsRef.value.addEventListener('mousedown', (e) => {
    control.isDown = true;
    control.startX = e.pageX - currencyItemsRef.value.offsetLeft;
    control.scrollLeft = currencyItemsRef.value.scrollLeft;
  });

  currencyItemsRef.value.addEventListener('mouseup', (e) => {
    control.isDown = false;
  });

  currencyItemsRef.value.addEventListener('mousemove', move);
});
</script>
<!--

In this example, we use vue's ref function to create a currencyItemsRef reference, which points to the div element of the scroll container. We also define the onPageLeft and onPageRight methods to handle the sliding events when the left and right arrows are clicked.

In the onPageLeft method, we slide to the left by a distance of one container width by subtracting the width of the scrolling container.

Similarly, in the onPageRight method, we slide to the right by a distance of one container width by adding the width of the scrolling container.

By clicking the left and right arrow buttons, you can see that the scroll container will slide accordingly to display different items.

 -->

style

<style lang="scss" scoped>
.swiper {
  display: flex;
  align-items: center;
  width: 800px;
  overflow: hidden;
}

.watch-list-arrow {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  background-color: lightgray;
  cursor: pointer;
}

.watch-list-arrow-btn {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
}

.currency-items {
  display: flex;
  gap: 10px;
  overflow-x: scroll;
  scroll-behavior: smooth;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  /* &::-webkit-scrollbar {
    display: none;
  } */
}

.currency-item {
  flex: 0 0 auto;
  width: 100px;
  height: 100px;
  background-color: lightblue;
}
</style>

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge Vue entry skill tree Vue componentsGlobal and local components