基于vue实现滑块动画效果

主要实现:通过鼠标移移动、触摸元素、鼠标释放、离开元素事件来进行触发

创建了一个滑动盒子,其中包含一个滑块图片。通过鼠标按下或触摸开始事件,开始跟踪滑块的位置和鼠标/触摸位置之间的偏移量。然后,通过计算偏移量和起始时的位移值,设置滑动盒子的 transform 属性来实现滑动效果。使用 transition 属性,还可以为滑块添加滑动动画。
效果:

运行效果图

html 复制代码
<template>
  <div id="app">
    <div class="slider-container img">
      <div class="slider-track">
        <img class="slider-handle" src="./assets/dot.svg" alt="滑块">
      </div>
    </div>
  </div>
</template>

<script>

export default {
  name: 'App',
  components: {
  },
  data(){
    return {
      sliderContainer:'',
      sliderTrack:'',
      sliderHandle:'',
      isDragging:false,
      startPosY:0,
      startTranslateY:0,
      minTranslateY:0,
      maxTranslateY:0,
    }
  },
  created() {

  },
  mounted() {
    this.sliderContainer = document.querySelector('.slider-container');
    this.sliderTrack = document.querySelector('.slider-track');
    this.sliderHandle = document.querySelector('.slider-handle');

    this.isDragging = false;
    this.startPosY = 0;
    this.startTranslateY = 0;
    this.minTranslateY = 0; // 顶部限制为30px,css样式修改后默认为0
    this.maxTranslateY = this.sliderContainer.clientHeight - this.sliderHandle.offsetHeight - 20; // 底部限制为20px

    this.sliderHandle.addEventListener('mousedown', this.startDrag);
    this.sliderHandle.addEventListener('touchstart', this.startDrag);
  },
  methods: {
    startDrag(event) {
      event.preventDefault();

      if (event.type === 'mousedown') {
        this.startPosY = event.clientY;
      } else if (event.type === 'touchstart') {
        this.startPosY = event.touches[0].clientY;
      }

      this.startTranslateY = this.getTranslateY();
      this.isDragging = true;

      document.addEventListener('mousemove', this.drag);
      document.addEventListener('touchmove', this.drag);
      document.addEventListener('mouseup', this.stopDrag);
      document.addEventListener('touchend', this.stopDrag);
    },
    drag(event) {
      if (!this.isDragging) return;

      var currentPosY = 0;

      if (event.type === 'mousemove') {
        currentPosY = event.clientY;
      } else if (event.type === 'touchmove') {
        currentPosY = event.touches[0].clientY;
      }

      var offsetY = currentPosY - this.startPosY;
      var translateY = this.startTranslateY + offsetY;

      // 边缘限制
      if (translateY < this.minTranslateY) {
        translateY = this.minTranslateY;
      } else if (translateY > this.maxTranslateY) {
        translateY = this.maxTranslateY;
      }

      this.setTranslateY(translateY);
    },
    stopDrag() {
      this.isDragging = false;

      document.removeEventListener('mousemove', this.drag);
      document.removeEventListener('touchmove', this.drag);
      document.removeEventListener('mouseup', this.stopDrag);
      document.removeEventListener('touchend', this.stopDrag);
    },

    getTranslateY() {
      var style = window.getComputedStyle(this.sliderTrack);
      var transform = style.transform || style.webkitTransform;
      var matrix = transform.match(/^matrix\((.+)\)$/);

      if (matrix) {
        return parseFloat(matrix[1].split(', ')[5]); // 获取Y轴位移值
      } else {
        return 0;
      }
    },
    setTranslateY(translateY) {
      let y = translateY
      if (y > 30 && y < 60) {
        console.log("午间");
        y = 60
      } else if (y > 60 && y < 90 ) {
        console.log("午间");
        y = 60
      } else if (y > 90 && y <= 130) {
        console.log("晚间");
        y = 120
      } else if (y < 30) {
        console.log("早间");
        y = 0
      }
      this.sliderTrack.style.transform = 'translate3d(0, ' + y + 'px, 0)'; // 设置Y轴位移值
    }

  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: #2c3e50;
}

.img {
  width: 100px;
  height: 200px;
  background-color: antiquewhite;
  background: url("./assets/TimeOfDay.svg") no-repeat;
  background-size: contain;
  position: relative;
  transition: all 0.5s;
}

.hk_img {
  position: absolute;
  top: 30px;
}

.slider-container {
  width: 100px;
  height: 200px;
  overflow: hidden;
  position: relative;
  background-color: #f0f0f0;
}

.slider-track {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  transition: transform 0.3s ease-out;
  touch-action: none;
  /* 禁用默认的滑动行为 */
}

.slider-handle {
  width: 50px;
  height: 50px;
  position: absolute;
  top: 15px;
  /* 距离顶部30px */
  left: 50%;
  transform: translateX(-50%);
}

.slider-handle:hover {
  cursor: pointer;
}</style>
相关推荐
kyriewen24 分钟前
我让 AI 当面试官面了我一轮:第 3 个追问我就卡住了(附 10 道追问清单)
前端·面试·ai编程
IT_陈寒41 分钟前
Python的GIL把我坑惨了,多线程跑得比单线程还慢
前端·人工智能·后端
前端snow1 小时前
ai agent --- 多agent框架之图编排引擎-langgraph
前端
竹林8181 小时前
OmniPic Studio v3.2.1 核心技术架构与全平台发版解析文档
前端·浏览器
JamesZhang800781 小时前
页面内存只涨不跌? 一次泄漏排查, 牵出 WeakMap 的诞生
前端
Z小明1 小时前
第 6 章 组件进阶
前端·vue.js
江华森1 小时前
HTTP请求的完整过程详解:从DNS解析到TCP挥手的微秒级实战分析
前端
南青1 小时前
Vue 3 中后台实战:我踩过的 10 个坑和最佳实践
前端
江华森1 小时前
HTTPS协议详解——SSL/TLS握手、证书与加密通信
前端
江华森1 小时前
从一个HTTP请求看网络分层原理:基于华为云ECS的真实抓包实战
前端