Created
July 2, 2025 05:13
-
-
Save JSoon/523dab5ed340bbc093c941496d2aafd3 to your computer and use it in GitHub Desktop.
Flipbook Swipe Example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> | |
| <title>Flipbook Swipe Example</title> | |
| <!-- 引入animate.css --> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"> | |
| <style> | |
| html, | |
| body { | |
| margin: 0; | |
| padding: 0; | |
| height: 100%; | |
| overflow: hidden; | |
| background: #fdf6e3; | |
| font-family: Arial, sans-serif; | |
| } | |
| #flipbook { | |
| width: 100%; | |
| height: 100%; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| #flipbook>div { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| overflow-y: auto; | |
| background: white; | |
| padding: 20px; | |
| box-sizing: border-box; | |
| box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); | |
| transition: transform 0.4s ease, opacity 0.4s ease; | |
| } | |
| /* 初始隐藏所有页 */ | |
| #flipbook>div.hidden { | |
| display: none; | |
| } | |
| /* 动画类 */ | |
| .enter-from-right { | |
| transform: translateX(100%); | |
| } | |
| .enter-from-left { | |
| transform: translateX(-100%); | |
| } | |
| .leave-to-left { | |
| transform: translateX(-100%); | |
| opacity: 0; | |
| } | |
| .leave-to-right { | |
| transform: translateX(100%); | |
| opacity: 0; | |
| } | |
| /* 标题动画样式 */ | |
| .page-title { | |
| animation-duration: 0.8s; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="flipbook"> | |
| <div> | |
| <h2 class="page-title animate__animated animate__backInLeft">Page 1</h2> | |
| <p>这是第一页内容。</p> | |
| </div> | |
| <div> | |
| <h2 class="page-title animate__animated animate__backInLeft">Page 2</h2> | |
| <p>这是第二页内容。上下滚动试试。</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| <p>内容内容内容内容内容</p> | |
| </div> | |
| <div> | |
| <h2 class="page-title animate__animated animate__backInLeft">Page 3</h2> | |
| <p>这是第三页内容。</p> | |
| </div> | |
| <div> | |
| <h2 class="page-title animate__animated animate__backInLeft">Page 4</h2> | |
| <p>这是第四页内容。</p> | |
| </div> | |
| </div> | |
| <script> | |
| const pages = Array.from(document.querySelectorAll('#flipbook > div')); | |
| let currentIndex = 0; | |
| // 初始化:只显示第一页 | |
| pages.forEach((page, index) => { | |
| if (index !== 0) page.classList.add('hidden'); | |
| }); | |
| function showPage(newIndex, direction) { | |
| if (newIndex < 0 || newIndex >= pages.length || newIndex === currentIndex) return; | |
| const current = pages[currentIndex]; | |
| const next = pages[newIndex]; | |
| // 重置标题动画 | |
| const currentTitle = current.querySelector('.page-title'); | |
| const nextTitle = next.querySelector('.page-title'); | |
| // 设置初始进入方向 | |
| next.classList.remove('hidden'); | |
| next.classList.add(direction === 'next' ? 'enter-from-right' : 'enter-from-left'); | |
| // 强制触发一次重绘 | |
| next.offsetHeight; | |
| // 开始动画 | |
| next.classList.remove('enter-from-right', 'enter-from-left'); | |
| current.classList.add(direction === 'next' ? 'leave-to-left' : 'leave-to-right'); | |
| setTimeout(() => { | |
| current.classList.add('hidden'); | |
| current.classList.remove('leave-to-left', 'leave-to-right'); | |
| currentIndex = newIndex; | |
| }, 400); | |
| } | |
| function goNext() { | |
| if (currentIndex < pages.length - 1) { | |
| showPage(currentIndex + 1, 'next'); | |
| } | |
| } | |
| function goPrev() { | |
| if (currentIndex > 0) { | |
| showPage(currentIndex - 1, 'prev'); | |
| } | |
| } | |
| // 手势检测 | |
| let startX = 0, startY = 0, isScrolling; | |
| document.getElementById('flipbook').addEventListener('touchstart', function (e) { | |
| startX = e.touches[0].pageX; | |
| startY = e.touches[0].pageY; | |
| isScrolling = undefined; | |
| }); | |
| document.getElementById('flipbook').addEventListener('touchmove', function (e) { | |
| const dx = e.touches[0].pageX - startX; | |
| const dy = e.touches[0].pageY - startY; | |
| if (typeof isScrolling === 'undefined') { | |
| isScrolling = Math.abs(dy) > Math.abs(dx); | |
| } | |
| // 防止横向滑动时页面跟随左右滚动 | |
| if (!isScrolling) e.preventDefault(); | |
| }, { passive: false }); | |
| document.getElementById('flipbook').addEventListener('touchend', function (e) { | |
| const dx = e.changedTouches[0].pageX - startX; | |
| if (Math.abs(dx) > 50 && isScrolling === false) { | |
| if (dx > 0) { | |
| goPrev(); | |
| } else { | |
| goNext(); | |
| } | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment