创意的气泡滑块拖动vue特效

基于vue制作手机端气泡滑块拖动ui交互,线条上滑块拖动气泡提示ui特效。

Html代码:

<!DOCTYPE html>
<html lang="en" >
<head>
  <meta charset="UTF-8">
  <title>创意的气泡滑块拖动vue特效</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<main>
  <div class="sliderContainer">
    <div class="ballon" ref="ballonEl">
      <span class="ballon__text" ref="ballonTextEl">{{ percent }}</span>
    </div>
    <div v-on:mousedown="dragStart" v-on:touchstart="dragStart" ref="thumbEl" class="sliderContainer__thumb"></div>
    <div class="sliderContainer__input" ref="inputEl"></div>
  </div>
</main>
<script src='js/vue.min.js'></script>
<script src='js/hammer.min.js'></script>
<script src='js/TweenMax.min.js'></script>
<script src="js/script.js"></script>
</body>
</html>

css代码:

:root {
  --color-primary: #5626e8;
  --color-secondary: #d2daef;
  --color-bg: #f4f6fe;
}

* {
  box-sizing: border-box;padding:0;margin:0;
}

body {
  background-color: var(--color-bg);
}

main {
   100%;
  min-height: 100vh;
  display: -webkit-box;
  display: flex;
  -webkit-box-pack: center;
          justify-content: center;
  -webkit-box-align: center;
          align-items: center;
}

.sliderContainer {
  position: relative;
   100%;
  display: -webkit-box;
  display: flex;
  -webkit-box-orient: vertical;
  -webkit-box-direction: normal;
          flex-direction: column;
  -webkit-box-align: center;
          align-items: center;
  padding: 3em;
}

.sliderContainer .sliderContainer__input {
   100%;
  -webkit-appearance: none;
  -moz-appearance: none;
       appearance: none;
  outline: none;
  height: 0.2em;
  background-image: -webkit-gradient(
    linear,
    left top,
    right top,
    color-stop(50%, var(--color-primary)),
    color-stop(50%, var(--color-secondary))
  );
  border-radius: 1em;
  margin: 0;
}

.sliderContainer .sliderContainer__thumb {
  cursor: pointer;
   1.5em;
  height: 1.5em;
  border: 0.5em solid var(--color-primary);
  border-radius: 100%;
  background-color: white;
  position: absolute;
  top: 50%;
  -webkit-transform: translateY(-50%);
          transform: translateY(-50%);
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
}

.ballon {
  --size: 4em;

   var(--size);
  height: var(--size);
  display: -webkit-box;
  display: flex;
  -webkit-box-pack: center;
          justify-content: center;
  -webkit-box-align: center;
          align-items: center;
  background-color: var(--color-primary);
  border-bottom-left-radius: 50%;
  position: absolute;
  border-top-left-radius: 50%;
  border-top-right-radius: 50%;
  top: -1.2em;
  opacity: 0;
}

.ballon .ballon__text {
  color: white;
  -webkit-transform: rotate(-45deg);
          transform: rotate(-45deg);
  font-family: Arial, Helvetica, sans-serif;
}

.ballon::after {
  content: "";
  position: absolute;
   0;
  height: 0;
  border-left: 0.25em solid transparent;
  border-right: 0.25em solid transparent;
  -webkit-transform: rotate(-45deg);
          transform: rotate(-45deg);
  border-bottom: 0.25em solid var(--color-primary);
  top: 98%;
  left: 94%;
}

@media (max- 768px) {
  .sliderContainer {
    min- 95%;
  }
}
let currentDeltaX = 0;

//Utils
const getElementOffset = el => el.getBoundingClientRect();

const getPercentInBetween = ({ value, min, max }) => {
  return (value - min) / (max - min) * 100;
};

const getValueInBetween = (value, { min, max }) => {
  if (value < min) return min;
  if (value > max) return max;
  return value;
};

const getSliderValue = () => {
  const getRef = ref => app.$refs[ref];
  const { left: thumbElLeft,  thumbElWidth } = getElementOffset(
  getRef("thumbEl"));

  const { left: inputElLeft, right: inputElRight } = getElementOffset(
  getRef("inputEl"));

  const thumbCenterPoint = thumbElLeft + thumbElWidth / 2;

  const rangeValue = getPercentInBetween({
    value: thumbCenterPoint,
    min: inputElLeft,
    max: inputElRight });


  const percent = Math.round(
  getValueInBetween(rangeValue, { min: 0, max: 100 }));


  return percent;
};

const getBallonScaleValue = () =>
1 + getValueInBetween(getSliderValue(), { min: 1, max: 99 }) / 480;

//-------------------

const app = new Vue({
  el: "main",
  data: {
    isDragging: false,
    percent: 50,
    initialThumbElClientRect: null },

  mounted: function () {
    const getRef = ref => this.$refs[ref];

    TweenLite.set(getRef("thumbEl"), {
      y: "-50%" });


    TweenLite.set(getRef("ballonEl"), {
      rotation: 45 });


    this.initialThumbElClientRect = getElementOffset(getRef("thumbEl"));
  },
  methods: {
    getRef: function (ref) {
      return this.$refs[ref];
    },
    dragStart: function () {
      this.isDragging = true;
      TweenLite.set(this.getRef("ballonEl"), {
        rotation: 45 });

      this.percent = getSliderValue();
      this.toggleSliderAnimation();
    },
    dragEnd: function () {
      this.isDragging = false;
      this.toggleSliderAnimation();
    },
    drag: function (event) {
      if (this.isDragging) {
        const { deltaX: newDeltaX, velocityX } = event;
        const {
          left: thumbElInitialOffsetLeft,
          right: thumbElInitialOffsetRight,
           thumbElWidth } =
        this.initialThumbElClientRect;
        const {
          left: inputElOffsetLeft,
          right: inputElOffsetRight } =
        getElementOffset(this.getRef("inputEl"));

        const xMovement = newDeltaX + currentDeltaX;

        const hasGoneTooLeft =
        thumbElInitialOffsetLeft + xMovement <
        inputElOffsetLeft - thumbElWidth / 2;
        const hasGoneTooRight =
        thumbElInitialOffsetRight + xMovement >
        inputElOffsetRight + thumbElWidth / 2;

        if (hasGoneTooLeft || hasGoneTooRight) return;

        this.moveThumb({ x: xMovement, velocityX });
      }
    },
    moveThumb: function ({ x, velocityX }) {
      const sliderValue = getSliderValue();
      const tl = new TimelineLite();

      const scaleValue = getBallonScaleValue();

      tl.
      to(this.getRef("thumbEl"), 0.001, {
        x,
        ease: Power4.ease }).

      to(this.getRef("ballonEl"), 0.2, {
        x,
        scale: scaleValue,
        rotation:
        45 + getValueInBetween(velocityX, { min: -7, max: 7 }) * -15,
        ease: Power4.ease });


      this.getRef("inputEl").style.backgroundImage = `-webkit-gradient(
        linear,
        left top,
        right top,
        color-stop(${sliderValue}%, var(--color-primary)),
        color-stop(${sliderValue}%, var(--color-secondary))
      )`;

      this.percent = sliderValue;
    },

    toggleSliderAnimation: function () {
      const that = this;
      const tl = new TimelineLite();

      const sliderValue = getSliderValue();
      const scaleValue = this.isDragging ? getBallonScaleValue() : 0.8;
      const shouldFlyBalloon = sliderValue >= 80 && sliderValue <= 100;

      const toggleThumbAnim = () => {
        tl.to(that.getRef("thumbEl"), 0.23, {
           that.isDragging ? "2.6em" : "1.5em",
          height: that.isDragging ? "2.6em" : "1.5em",
          borderWidth: that.isDragging ? "2px" : "0.5em",
          ease: Power4.easeOut });

      };

      const toggleBallonAnim = () => {
        tl.to(
        that.getRef("ballonEl"),
        0.5,
        {
          opacity: that.isDragging ? 1 : 0,
          scale: scaleValue,
          y: that.isDragging ? "-75%" : "5%",
          ease: that.isDragging ? Power1.easeOut : Power1.easeIn },

        "-0.23");

      };

      if (this.isDragging) {
        toggleThumbAnim();
        toggleBallonAnim();
      } else {
        toggleThumbAnim();
        if (shouldFlyBalloon) {
          tl.to(this.getRef("ballonEl"), 1.7, {
            y: -window.innerHeight / 2,
            opacity: 0,
            ease: Power1.easeOut,
            onComplete: () => {
              TweenLite.set(this.getRef("ballonEl"), {
                y: "5%" });

            } });

        } else {
          toggleBallonAnim();
        }
      }
    } } });



const getRef = ref => app.$refs[ref];

const appHammer = new Hammer.Manager(getRef("thumbEl"));
appHammer.add(new Hammer.Pan({ threshold: 0 }));
appHammer.on("pan", app.drag);
appHammer.on("panend", ({ deltaX }) => {
  currentDeltaX += deltaX;
});

window.addEventListener("mouseup", app.dragEnd, false);
window.addEventListener("touchend", app.dragEnd, false);
原文地址:https://www.cnblogs.com/ZXH-null/p/13139697.html