本教程详细指导如何将现有的图片触摸滑动组件改造为支持视频内容的滑动播放器。通过调整HTML结构、适配CSS样式和优化JavaScript事件处理,特别是阻止视频元素的默认拖拽行为,确保滑动功能流畅运行,解决滑动器可能出现的“冻结”问题,实现响应式、交互友好的视频展示。
引言:从图片到视频的滑动体验
在现代web应用中,触摸滑动组件因其直观的用户体验而广受欢迎。最初,这类组件多用于展示图片画廊。然而,随着富媒体内容的兴起,将图片滑动器升级为视频滑动器成为一个常见的需求。将静态图片替换为动态视频并非简单的标签替换,视频元素自带的交互行为(如拖拽、播放控制)可能会与滑动组件的自定义javascript逻辑产生冲突,导致滑动功能“冻结”或失效。本教程将深入探讨如何解决这些挑战,实现一个功能完善的触摸滑动视频播放器。
HTML结构重构:引入视频元素
将图片滑动器改造为视频滑动器,最核心的步骤是替换HTML中的 <img> 标签为 <video> 标签。为了确保视频能够正确加载、显示并提供用户控制,需要注意以下几点:
- 替换标签: 将每个 <div class=”slide”> 内部的 <img> 标签替换为 <video> 标签。
- 视频源: 使用 <source> 标签指定视频文件的URL。为了更好的兼容性,可以提供多种格式的视频源。
- 控制条: 添加 controls 属性,为用户提供播放、暂停、音量等基本控制。
- 尺寸: 可以通过 width 和 height 属性设置视频的初始尺寸,但通常更推荐通过CSS进行响应式控制。
以下是改造后的HTML结构示例:
<div class="slider-container"> <div class="slide"> <h2>Airpods</h2> <h4>$199</h4> <video width="320" height="240" controls> <source src="https://player.vimeo.com/external/367564948.sd.mp4?s=d969af3ae466e775628a8d281105fd03a8df12ae&profile_id=165&oauth2_token_id=57447761" type="video/mp4"/> 您的浏览器不支持视频播放。 </video> <a href="#" class="btn">Buy Now</a> </div> <div class="slide"> <h2>iPhone 12</h2> <h4>$799</h4> <video width="320" height="240" controls> <source src="https://player.vimeo.com/external/334344435.sd.mp4?s=d367341a941ffa97781ade70e4f4a28f4a1a5fc8&profile_id=165&oauth2_token_id=57447761" type="video/mp4"/> 您的浏览器不支持视频播放。 </video> <a href="#" class="btn">Buy Now</a> </div> <div class="slide"> <h2>iPad</h2> <h4>$599</h4> <video width="320" height="240" controls> <source src="https://player.vimeo.com/external/369639344.sd.mp4?s=b892fce959245aa4ae7ab08bc4b1af2766acdf4e&profile_id=165&oauth2_token_id=57447761" type="video/mp4"/> 您的浏览器不支持视频播放。 </video> <a href="#" class="btn">Buy Now</a> </div> </div>
CSS样式适配:确保视频显示正常
将 <img> 替换为 <video> 后,需要相应地调整CSS样式,以确保视频在滑动器中能够正确地布局和响应。关键在于将原来针对 img 元素的样式规则应用到 video 元素上。
- 视频尺寸与布局: 确保视频能够在其父容器 (.slide) 内正确缩放,并保持居中。
- 替换选择器: 将 .slide img 相关的样式选择器更改为 .slide video。
以下是适配后的CSS样式:
立即学习“Java免费学习笔记(深入)”;
@import url('https://fonts.googleapis.com/css2?family=Open+Sans&display=swap'); * { box-sizing: border-box; margin: 0; padding: 0; } html, body { font-family: 'Open Sans', sans-serif; height: 100%; width: 100%; overflow: hidden; background-color: #333; color: #fff; line-height: 1.7; } .slider-container { height: 100vh; display: inline-flex; overflow: hidden; transform: translateX(0); transition: transform 0.3s ease-out; cursor: grab; } .slide { max-height: 100vh; width: 100vw; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 1rem; user-select: none; } /* 将此处 img 选择器改为 video */ .slide video { max-width: 100%; max-height: 60%; transition: transform 0.3s ease-in-out; } .slide h2 { font-size: 2.5rem; margin-bottom: 0.5rem; } .slide h4 { font-size: 1.3rem; } .btn { background-color: #444; color: #fff; text-decoration: none; padding: 1rem 1.5rem; } .grabbing { cursor: grabbing; } .grabbing .slide video { /* 同样将此处 img 选择器改为 video */ transform: scale(0.9); }
JavaScript逻辑优化:解决滑动“冻结”问题
JavaScript是实现滑动逻辑的核心。将图片替换为视频后,最常遇到的问题是滑动器在第一次操作后“冻结”。这通常是因为视频元素具有其自身的默认拖拽行为,与自定义的触摸或鼠标拖拽事件冲突。解决此问题的关键在于阻止视频元素的默认 dragstart 事件。
- 选择视频元素: 确保JavaScript正确地选择了每个 slide 中的 <video> 元素,而不是 <img>。代码中 const slideImage = slide.querySelector(‘video’) 已经正确实现。
- 阻止默认拖拽: 为每个视频元素添加 dragstart 事件监听器,并调用 e.preventDefault()。这会阻止浏览器处理视频元素的默认拖拽行为,从而允许自定义的滑动逻辑正常工作。
以下是完整的JavaScript代码,其中已包含了对视频元素 dragstart 事件的处理:
/* This JS code is from the following project: https://github.com/bushblade/Full-Screen-Touch-Slider */ const slider = document.querySelector('.slider-container'), slides = Array.from(document.querySelectorAll('.slide')) let isDragging = false, startPos = 0, currentTranslate = 0, prevTranslate = 0, animationID = 0, currentIndex = 0 slides.forEach((slide, index) => { // 确保这里选择的是 video 元素 const slideImage = slide.querySelector('video') // 阻止视频元素的默认 dragstart 行为,这是解决“冻结”问题的关键 slideImage.addEventListener('dragstart', (e) => e.preventDefault()) // Touch events slide.addEventListener('touchstart', touchStart(index)) slide.addEventListener('touchend', touchEnd) slide.addEventListener('touchmove', touchMove) // Mouse events slide.addEventListener('mousedown', touchStart(index)) slide.addEventListener('mouseup', touchEnd) slide.addEventListener('mouseleave', touchEnd) slide.addEventListener('mousemove', touchMove) }) // Disable context menu window.oncontextmenu = function (event) { event.preventDefault() event.stopPropagation() return false } function touchStart(index) { return function (event) { currentIndex = index startPos = getPositionX(event) isDragging = true // https://css-tricks.com/using-requestanimationframe/ animationID = requestAnimationFrame(animation) slider.classList.add('grabbing') } } function touchEnd() { isDragging = false cancelAnimationFrame(animationID) const movedBy = currentTranslate - prevTranslate // 根据移动距离判断是否切换到上一个或下一个幻灯片 if (movedBy < -100 && currentIndex < slides.length - 1) currentIndex += 1 if (movedBy > 100 && currentIndex > 0) currentIndex -= 1 setPositionByIndex() slider.classList.remove('grabbing') } function touchMove(event) { if (isDragging) { const currentPosition = getPositionX(event) currentTranslate = prevTranslate + currentPosition - startPos } } function getPositionX(event) { return event.type.includes('mouse') ? event.pageX : event.touches[0].clientX } function animation() { setSliderPosition() if (isDragging) requestAnimationFrame(animation) } function setSliderPosition() { slider.style.transform = `translateX(${currentTranslate}px)` } function setPositionByIndex() { currentTranslate = currentIndex * -window.innerWidth prevTranslate = currentTranslate setSliderPosition() }
完整示例:整合代码
为了方便读者实践,以下提供一个包含上述HTML、CSS和JavaScript的完整页面结构。您可以将其保存为 .html 文件并在浏览器中打开。
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>触摸滑动视频播放器</title> <style> @import url('https://fonts.googleapis.com/css2?family=Open+Sans&display=swap'); * { box-sizing: border-box; margin: 0; padding: 0; } html, body { font-family: 'Open Sans', sans-serif; height: 100%; width: 100%; overflow: hidden; background-color: #333; color: #fff; line-height: 1.7; } .slider-container { height: 100vh; display: inline-flex; overflow: hidden; transform: translateX(0); transition: transform 0.3s ease-out; cursor: grab; } .slide { max-height: 100vh; width: 100vw; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 1rem; user-select: none; } .slide video { /* 注意这里是 video 选择器 */ max-width: 100%; max-height: 60%; transition: transform 0.3s ease-in-out; } .slide h2 { font-size: 2.5rem; margin-bottom: 0.5rem; } .slide h4 { font-size: 1.3rem; } .btn { background-color: #444; color: #fff; text-decoration: none; padding: 1rem 1.5rem; margin-top: 1rem; border-radius: 5px; } .grabbing { cursor: grabbing; } .grabbing .slide video { /* 注意这里是 video 选择器 */ transform: scale(0.9); } </style> </head> <body> <div class="slider-container"> <div class="slide"> <h2>Airpods</h2> <h4>$199</h4> <video width="320" height="240" controls> <source src="https://player.vimeo.com/external/367564948.sd.mp4?s=d969af3ae466e775628a8d281105fd03a8df12ae&profile_id=165&oauth2_token_id=57447761" type="video/mp4"/> 您的浏览器不支持视频播放。 </video> <a href="#" class="btn">Buy Now</a> </div> <div class="slide"> <h2>iPhone 12</h2> <h4>$799</h4> <video width="320" height="240" controls> <source src="https://player.vimeo.com/external/334344435.sd.mp4?s=d367341a941ffa97781ade70e4f4a28f4a1a5fc8&profile_id=165&oauth2_token_id=57
css javascript java html js git go github 浏览器 iphone ipad JavaScript css html const class 事件 选择器 重构