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