先上效果
https://rencoo.github.io/webproject/images/3DchangImg/index.html
完成目标
- 轮播图片的组件化
- API 和 控制流 分开
- 设计了较高级的API用于收集回调函数
- CSS的 transform 和 transform-origin 元素的转换(缩放、移动等)功能
- CSS的 transition 平滑过渡样式功能的使用
- 通过两个 <span> 来达到 UI需要的显示效果与鼠标点击事件兼顾
CODE部分
<!DOCTYPE html><html lang="en" dir="ltr"> ???<head> ???????<meta charset="utf-8"> ???????<title>3D图片轮播图</title> ???????<link rel="stylesheet" href="change.css"> ???</head> ???<body> ???????<div id="my-slider"> ???????????<!-- 轮播图结构 --> ???????????<div class="slider-list"> ???????????????<ul> ???????????????????<li class="p1"><img src="img/1.png" alt="" /></li> ???????????????????<li class="p2"><img src="img/2.png" alt="" /></li> ???????????????????<li class="p3-selected"><img src="img/3.jpg" alt="" /></li> ???????????????????<li class="p4"><img src="img/4.png" alt="" /></li> ???????????????????<li class="p5"><img src="img/5.jpg" alt="" /></li> ???????????????????<li class="p6"><img src="img/6.jpg" alt="" /></li> ???????????????????<li class="p7"><img src="img/7.jpg" alt="" /></li> ???????????????</ul> ???????????</div> ???????????<!-- 控制流 UI --> ???????????<div class="slider-control"> ???????????<!-- 使用两个<span>的说明:由于里面按钮ui效果厚度需要很小,在窗口里不好点击到(触发事件);因此在外面套了一个<span>,用于绑定鼠标点击事件--> ???????????????<span><span></span></span> ???????????????<span><span></span></span> ???????????????<span class="btn-selected"><span></span></span> ???????????????<span><span></span></span> ???????????????<span><span></span></span> ???????????????<span><span></span></span> ???????????????<span><span></span></span> ???????????</div> ???????????<span class="prev btn"><</span> ???????????<span class="next btn">></span> ???????</div> ???????????????<!-- 在组件外,也能灵活调用 API --> ???????<div id="sliderState"><p>当前第 3 页</p></div> ???</body> ???<script src="change.js"></script></html>
* { ???margin: 0; ???padding: 0;}#my-slider { ???position: relative; ???width: 100%; ???height: 340px; ???margin-top: 100px;}#my-slider>.slider-list{ ???position: absolute; ???left: 50%; ???width: 1200px; ???height: 300px; ???margin-left: -600px; ???overflow: hidden;}li { ???position: absolute; ???top: 0; ???left: 0; ???width: 750px; ???height: 300px; ???list-style: none; ???opacity: 0; ???transition: all 0.3s ease-in-out; }li>img { ???position: absolute; ???top: 0; ???left: 0; ???width: 100%; ???height: 100%; ???cursor: pointer;}.p1 { ???transform:translate3d(-224px,0,0) scale(0.81);}.p2 { ???transform:translate3d(0px,0,0) scale(0.81); ???transform-origin:0 50%; ???z-index: 2; ???opacity: 0.8;}.p3-selected { ???transform:translate3d(224px,0,0) scale(1); ???z-index: 3; ???opacity: 1;}.p4 { ???transform:translate3d(448px,0,0) scale(0.81); ???transform-origin:100% 50%; ???z-index: 2; ???opacity: 0.8;}.p5 { ???transform:translate3d(672px,0,0) scale(0.81);}.p6 { ???transform:translate3d(896px,0,0) scale(0.81);}.p7 { ???transform:translate3d(1120px,0,0) scale(0.81);} ??.btn { ???position: absolute; ???top: 50%; ????width: 60px; ???height: 100px; ???margin-top: -50px; ???background: black; ???opacity: 0.2; ???line-height: 100px; ???font-size: 30px; ???color: white; ???text-decoration: none; ???text-align: center; ???cursor: pointer;}.next{ ???right: 0;}.slider-control { ???position: absolute; ???bottom: 0; ???left: 50%; ???width: 1200px; ???height: 30px; ???margin-left: -600px; ???text-align: center; ???padding-top: 10px;}.slider-control>span { ???display: inline-block; ???width: 35px; ???height: 100%; ???cursor: pointer;}.slider-control>span>span { ???position: relative; ???top: 30%; ???display: block; ???width: 100%; ???height: 1px; ???background: red;}.slider-control>.btn-selected>span { ???background: blue;}#sliderState { ???position: absolute; ???top: 440px; ???width: 100%; ???text-align: center;}
class Slider { ???constructor(id, cycle=3000){ ???????this.container = document.getElementById(id); ???????this.items= this.container.querySelectorAll(‘.slider-list li‘); ???????this.cycle = cycle; ???????// 回调函数队列; ???????this.slideHandlers = []; ????????// UI 控制流部分 ???????// 鼠标移入组件时清除定时器 ???????this.container.addEventListener(‘mouseover‘, ()=>{ ???????????this.stop(); ???????}) ???????????????// 鼠标移出组件时开始定时器 ???????this.container.addEventListener(‘mouseout‘, ()=>{ ???????????this.start(); ???????}) ???????// 鼠标点击图片,触发上一张和下一张 ???????this.container.addEventListener(‘click‘, evt=>{ ???????????console.log(‘picclicked‘); ???????????console.log(evt.target.parentElement); ???????????if (evt.target.parentElement.className != ‘p2‘ && evt.target.parentElement.className != ‘p4‘ ) return; ???????????else if (evt.target.parentElement.className == ‘p2‘) { ???????????????console.log(‘前一张‘); ???????????????this.prevImg(); ???????????} ????????????else { ???????????????console.log(‘下一张‘); ???????????????this.nextImg(); ???????????} ???????}) ???????????????// 鼠标点击上一张 和 下一张 按钮进行触发 上一张和下一张 ???????let nextBtn = this.container.querySelector(‘.next‘); ???????if(nextBtn) { ???????????nextBtn.addEventListener(‘click‘, () => this.nextImg()); ???????} ???????let prevBtn = this.container.querySelector(‘.prev‘); ???????if(prevBtn) { ???????????prevBtn.addEventListener(‘click‘, () => this.prevImg()); ???????} ???????// 鼠标点击底下slider控制按钮进行图片切换 ???????let controller = this.container.querySelector(‘.slider-control‘); ???????if (controller) { ???????????// 加了这个判断之后,整体删除组件的控制部分,程序也能正常运行 ???????????let btns = this.container.querySelectorAll(‘.slider-control>span‘); ???????????controller.addEventListener(‘click‘, evt=>{ ???????????????var idx = Array.from(btns).indexOf(evt.target); ???????????????????????????????if(idx >= 0) this.slideTo(idx); ???????????}); ???????????// 往回调函数队列中增加 "改变底下当前选中按钮的背景色" 的回调函数 ???????????this.addSlideListener(function(idx) { ???????????????let selected = controller.querySelector(‘.btn-selected‘); ???????????????if(selected) selected.className = ‘‘; ???????????????btns[idx].className = ‘btn-selected‘; // 次数 褚className 不用加点 ???????????}); ???????} ???} ???// API 部分 ???// 获取照片CSS布局定位的 class ???// ["p1", "p2", "p3-selected", "p4", "p5", "p6", "p7"]; ???getLiClasses(){ ???????let liClasses = []; ???????Array.from(this.items).forEach(li=>{ ???????????liClasses.push(li.className); ???????}) ???????return liClasses; ???} ???// 获取当前展示的图片 ???getSelectedItem() { ???????let selected = this.container.querySelector(‘.p3-selected‘); ???????return selected; ???} ???// 获取当前展示的图片的编号 ???getSelectedItemIndex() { ???????return Array.from(this.items).indexOf(this.getSelectedItem()); ???} ???// 跳到要展示的目标图片(核心API) ???slideTo(idx) { ???????let currentIdx = this.getSelectedItemIndex(); ????????let liClasses = this.getLiClasses(); ???????????????let item = this.items[idx]; ???????if(item){ ???????????if(idx == currentIdx) { ???????????????return; ???????????} ???????????else if(idx < currentIdx){ ???????????????Array.from(this.items).forEach((item, i) => { ???????????????????item.className = ‘‘; ???????????????????item.className = liClasses[(i + (currentIdx - idx)) % liClasses.length]; ???????????????}) ???????????} ???????????else if(idx > currentIdx){ ???????????????Array.from(this.items).forEach((item, i)=>{ ???????????????????item.className = ‘‘; ????????????????????item.className = liClasses[(i + liClasses.length -(idx - currentIdx)) % liClasses.length]; ???????????????}) ???????????} ???????} ???????????????// 执行回调函数队列里的函数: ???????// 1. 改变底下按钮中当前选中按钮的背景色 ???????// 2. 显示当前第几页 ???????this.slideHandlers.forEach(handler=>{ ???????????handler(idx); ???????}); ???} ???????// 下一张图片 ???nextImg() { ???????let currentIdx = this.getSelectedItemIndex(); ???????let nextIdx = (currentIdx + 1) % this.items.length; ???????this.slideTo(nextIdx); ???} ???// 上一张图片 ???prevImg() { ???????let currentIdx = this.getSelectedItemIndex(); ???????let prevIdx = (currentIdx + this.items.length - 1) % this.items.length; ???????this.slideTo(prevIdx); ???} ???// 启动计时器 ???start() { ???????this.stop(); ???????this._sliderTimer = setInterval(() => { ???????????this.nextImg(); ???????}, this.cycle); ???} ???// 清除计时器 ???stop() { ???????clearInterval(this._sliderTimer); ???} ???// 高级API; 用于收集回调函数 ???addSlideListener(handler) { ???????this.slideHandlers.push(handler); ???}}// 调用const slider = new Slider(‘my-slider‘);// 启动定时器slider.start();// 在组件外部往 回调函数队列 添加函数slider.addSlideListener(function(idx){ ???sliderState.textContent = `当前第 ${idx + 1} 页`;});
webProject demo-2 Images/3DchangeImg
原文地址:https://www.cnblogs.com/rencoo/p/9381499.html