veloxi实现曲线左右拖动的导航条放大选择效果代码

代码语言:html

所属分类:拖放

代码描述:veloxi实现曲线左右拖动的导航条放大选择效果代码

代码标签: veloxi 曲线 左右 拖动 导航条 放大 选择

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  

  
  
<style>
* {
  box-sizing: border-box;
}
body {
  margin: 0;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100vh;
  background: whitesmoke;
  font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
    Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
  overflow: hidden;
  max-width: 100%;
}

.curved-nav {
  width: 100%;
  height: 100%;
  position: relative;
  will-change: transform, opacity;
}

.curved-nav::before {
  position: absolute;
  content: '';
  width: 100%;
  aspect-ratio: 1;
  border-radius: 20rem;
  background: radial-gradient(
      63.62% 69.52% at 100% 0%,
      rgba(247, 214, 98, 0.8) 0%,
      rgba(247, 214, 98, 0.168) 52.08%,
      rgba(247, 214, 98, 0) 100%
    ),
    linear-gradient(
      208.42deg,
      #f0422a 7.46%,
      rgba(240, 88, 42, 0.18) 42.58%,
      rgba(240, 101, 42, 0) 64.13%
    ),
    radial-gradient(
      114.51% 122.83% at 0% -15.36%,
      #e74f6a 0%,
      rgba(231, 79, 106, 0.22) 66.72%,
      rgba(231, 79, 106, 0) 100%
    ),
    linear-gradient(
      333.95deg,
      rgba(83, 208, 236, 0.85) -7.76%,
      rgba(83, 208, 236, 0.204) 19.67%,
      rgba(138, 137, 190, 0) 35.42%
    ),
    radial-gradient(
      109.15% 148.57% at 4.46% 98.44%,
      #1b3180 0%,
      rgba(27, 49, 128, 0) 100%
    ),
    linear-gradient(141.57deg, #4eadeb 19.08%, rgba(78, 173, 235, 0) 98.72%);
  background-blend-mode: normal, normal, normal, normal, multiply, normal;
  filter: blur(84px);
  will-change: transform;
  backface-visibility: hidden;
  transform: translate3d(0, 0, 0);
}

.nav-container {
  display: flex;
  width: 100%;
  max-width: 375px;
  touch-action: none;
  will-change: transform, opacity;
}

.nav-container-wrapper {
  overflow: hidden;
  padding: 40px 50px;
}

.nav-items {
  display: flex;
  width: 100%;
  --item-size: calc(375px / 5);
}

.nav-item {
  width: var(--item-size);
  height: var(--item-size);
  border-radius: 10px;
  background: white;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24px;
  cursor: pointer;
  color: #222;
  user-select: none;
  -webkit-user-select: none;
  flex-shrink: 0;
  will-change: transform, opacity;
  touch-action: none;
}

.curved-nav {
  width: 100%;
  max-width: 375px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.content-wrapper {
  border: 1px solid rgba(0, 0, 0, 0.1);
  border-radius: 10px;
  width: 250px;
  height: 250px;
  display: flex;
  align-items: center;
  justify-content: center;
  will-change: transform, opacity;
}

.content-item {
  color: white;
  font-size: 300px;
  line-height: 0.7;
  position: absolute;
  will-change: opacity;
}

@media (max-width: 500px) {
  .nav-items {
    --item-size: calc(375px / 6);
  }
  .curved-nav {
    overflow: hidden;
  }
}
</style>


  
  
</head>

<body translate="no">
  <div class="curved-nav">
  <div class="content-wrapper">
    <div
      class="content-item"
      data-vel-plugin="CurvedNavPlugin"
      data-vel-view="contentItem"
    >
      A
    </div>
    <div
      class="content-item"
      data-vel-plugin="CurvedNavPlugin"
      data-vel-view="contentItem"
    >
      B
    </div>
    <div
      class="content-item"
      data-vel-plugin="CurvedNavPlugin"
      data-vel-view="contentItem"
    >
      C
    </div>
    <div
      class="content-item"
      data-vel-plugin="CurvedNavPlugin"
      data-vel-view="contentItem"
    >
      D
    </div>
    <div
      class="content-item"
      data-vel-plugin="CurvedNavPlugin"
      data-vel-view="contentItem"
    >
      E
    </div>
    <div
      class="content-item"
      data-vel-plugin="CurvedNavPlugin"
      data-vel-view="contentItem"
    >
      F
    </div>
    <div
      class="content-item"
      data-vel-plugin="CurvedNavPlugin"
      data-vel-view="contentItem"
    >
      G
    </div>
    <div
      class="content-item"
      data-vel-plugin="CurvedNavPlugin"
      data-vel-view="contentItem"
    >
      H
    </div>
    <div
      class="content-item"
      data-vel-plugin="CurvedNavPlugin"
      data-vel-view="contentItem"
    >
      I
    </div>
    <div
      class="content-item"
      data-vel-plugin="CurvedNavPlugin"
      data-vel-view="contentItem"
    >
      J
    </div>
  </div>
  <div class="nav-container-wrapper">
    <div class="nav-container">
      <div
        class="nav-items"
        data-vel-plugin="CurvedNavPlugin"
        data-vel-view="itemsContainer"
        data-vel-data-active-index="0"
      >
        <div
          class="nav-item"
          data-vel-plugin="CurvedNavPlugin"
          data-vel-view="item"
        >
          A
        </div>
        <div
          class="nav-item"
          data-vel-plugin="CurvedNavPlugin"
          data-vel-view="item"
        >
          B
        </div>
        <div
          class="nav-item"
          data-vel-plugin="CurvedNavPlugin"
          data-vel-view="item"
        >
          C
        </div>
        <div
          class="nav-item"
          data-vel-plugin="CurvedNavPlugin"
          data-vel-view="item"
        >
          D
        </div>
        <div
          class="nav-item"
          data-vel-plugin="CurvedNavPlugin"
          data-vel-view="item"
        >
          E
        </div>
        <div
          class="nav-item"
          data-vel-plugin="CurvedNavPlugin"
          data-vel-view="item"
        >
          F
        </div>
        <div
          class="nav-item"
          data-vel-plugin="CurvedNavPlugin"
          data-vel-view="item"
        >
          G
        </div>
        <div
          class="nav-item"
          data-vel-plugin="CurvedNavPlugin"
          data-vel-view="item"
        >
          H
        </div>
        <div
          class="nav-item"
          data-vel-plugin="CurvedNavPlugin"
          data-vel-view="item"
        >
          I
        </div>
        <div
          class="nav-item"
          data-vel-plugin="CurvedNavPlugin"
          data-vel-view="item"
        >
          J
        </div>
      </div>
    </div>
  </div>
</div>
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/veloxi.min.js"></script>
      <script  >

const {
    EventBus,
    Events,
    Plugin,
    createApp,
    DragEventPlugin,
    DragEvent
  } = Veloxi

const OFFSET = 10

class SetActiveIndexEvent {
  index
  constructor({ index }) {
    this.index = index
  }
}

class NavItem {
  view
  index
  container
  initialized = false

  constructor(view, index, container) {
    this.view = view
    this.index = index
    this.container = container
    this.view.position.animator.set('dynamic', { speed: 5 })
    this.view.scale.animator.set('dynamic', { speed: 5 })
  }

  init() {
    requestAnimationFrame(() => {
      this.enableTransition()
    })
    this.initialized = true
  }

  enableTransition() {
    this.view.styles.transition = '0.2s opacity linear'
  }

  update() {
    this.updatePosition()
    this.updateOpacity()
    this.updateScale()
  }

  updateWithOffset(offset) {
    const targetSlot = offset > 0 ? this.nextSlot : this.previousSlot
    const percentage = Math.abs(offset / this.container.stepSize)
    this.updatePositionWithOffset(offset, targetSlot, percentage)
    this.updateOpacityWithPercentage(targetSlot, percentage)
    this.updateScaleWithPercentage(targetSlot, percentage)
  }

  updatePositionWithOffset(offset, targetSlot, percentage) {
    const x = this.currentPosition.x
    let y = this.currentPosition.y
    switch (targetSlot) {
      case slotIndex.ACTIVE:
        y -= 10 * percentage
        break
      case slotIndex.FIRST_NEXT:
      case slotIndex.FIRST_PREVIOUS:
        const fromActive = this.slotIndex === slotIndex.ACTIVE
        y += 25 * (fromActive ? 1 : -1) * percentage
        break
      case slotIndex.SECOND_NEXT:
      case slotIndex.SECOND_PREVIOUS:
        const fromFirst = [
          slotIndex.FIRST_NEXT,
          slotIndex.FIRST_PREVIOUS
        ].includes(this.slotIndex)
        y += 40 * percentage * (fromFirst ? 1 : -1)
        break
      default:
        const fromSecond = [
          slotIndex.SECOND_NEXT,
          slotIndex.SECOND_PREVIOUS
        ].includes(this.slotIndex)
        y += 40 * percentage * (fromSecond ? 1 : -1)
    }
    this.view.position.set({ x: x + offset, y })
  }

  updateScaleWithPercentage(targetSlot, percentage) {
    let scale = this.currentScale

    switch (targetSlot) {
      case slotIndex.ACTIVE:
        scale += 0.1 * percentage
        break
      case slotIndex.FIRST_NEXT:
      case slotIndex.FIRST_PREVIOUS:
        const fromActive = this.slotIndex === slotIndex.ACTIVE
        if (fromActive) {
          scale -= 0.1 * percentage
        }
        break
    }
    this.view.scale.set({ x: scale, y: scale })
  }

  updateOpacityWithPercentage(targetSlot, percentage) {
    let opacity = this.currentOpacity
    switch (targetSlot) {
      case slotIndex.ACTIVE:
        opacity += 0.2 * percentage
        break
      case slotIndex.FIRST_PREVIOUS:
      case slotIndex.FIRST_NEXT:
        const fromActive = this.slotIndex === slotIndex.ACTIVE
        opacity += 0.2 * percentage * (fromActive ? -1 : 1)
        break
      case slotIndex.SECOND_PREVIOUS:
      case slotIndex.SECOND_NEXT:
        const fromFirst = [
          slotIndex.FIRST_NEXT,
          slotIndex.FIRST_PREVIOUS
        ].includes(this.slotIndex)
        if (!fromFirst) {
          if (
            this.firstItemIndexInStart === this.index ||
            this.firstItemIndexInEnd === this.index
          ) {
            opacity += 0.2 * percentage * (fromFirst ? -1 : 1)
          } else {
            opacity = 0
          }
        } else {
          opacity += 0.2 * percentage * (fromFirst ? -1 : 1)
        }
        break
      default:
        const fromSecond = [
          slotIndex.SECOND_NEXT,
          slotIndex.SECOND_PREVIOUS
        ].includes(this.slotIndex)
        if (fromSecond) {
          opacity += 0.4 * percentage * (fromSecond ? -1 : 1)
        } else {
          opacity = 0
        }
    }
    this.view.styles.opacity = `${opacity}`
  }

  updatePosition() {
    const shouldAnimate = this.container.shouldAnimateMap.get(this.index)
    const x = this.slotPosition.x
    let y = this.slotPosition.y
    switch (this.slotIndex) {
      case slotIndex.ACTIVE:
        break
      case slotIndex.FIRST_NEXT:
      case slotIndex.FIRST_PREVIOUS:
        y += 10
        break
      case slotIndex.SECOND_NEXT:
      case slotIndex.SECOND_PREVIOUS:
        y += 40
        break
      default:
        y += 100
    }
    this.view.position.set({ x, y }, shouldAnimate)
  }

  get currentPosition() {
    const x = this.slotPosition.x
    let y = this.slotPosition.y
    switch (this.slotIndex) {
      case slotIndex.ACTIVE:
        break
      case slotIndex.FIRST_NEXT:
      case slotIndex.FIRST_PREVIOUS:
        y += 10
        break
      case slotIndex.SECOND_NEXT:
      case slotIndex.SECOND_PREVIOUS:
        y += 40
        break
      default:
   .........完整代码请登录后点击上方下载按钮下载查看

网友评论0