Wavescroll是一款基于GSAP的响应式全屏背景图片jQuery幻灯片插件。该幻灯片插件支持鼠标拖动、鼠标滚动和移动触摸事件,可以制作出炫酷的波浪滚动切换效果。
该幻灯片插件主要使用的技术有:jQuery, CSS3, requestAnimationFrame 和 GSAP的TweenMax.js。
使用方法
HTML结构
该jQuery幻灯片的HTML结构如下:
<div class="ws-pages"> <div class="ws-bgs"> <div class="ws-bg"></div> <div class="ws-bg"></div> <div class="ws-bg"></div> <div class="ws-bg"></div> <div class="ws-bg"></div> </div> <div class="ws-text"> <h2 class="ws-text__heading"> <span>This is Slide 1</span> </h2> <h2 class="ws-text__heading"> <span>This is Slide 2</span> </h2> <h2 class="ws-text__heading"> <span>This is Slide 3</span> </h2> <h2 class="ws-text__heading"> <span>This is Slide 4</span> </h2> <h2 class="ws-text__heading"> <span>This is Slide 5</span> <span>The end</span> </h2> </div> </div>
CSS样式
该幻灯片的主要CSS样式如下:所有幻灯片都通过background-size: cover;
来设置为全屏模式。.ws-bg__part
是制作百叶窗效果的每一个窗叶。每个幻灯片slide分为24个窗叶,分别使用使用ws-bg__part-n:after
伪元素来制作。
.ws-pages { overflow: hidden; position: relative; height: 100%; } .ws-bgs { position: relative; height: 100%; } .ws-bg { height: 100%; background-size: cover; background-position: center center; } .ws-pages.s--ready .ws-bg { background: none !important; } .ws-bg:after { content: ""; display: table; clear: both; } .ws-bg__part { overflow: hidden; position: relative; float: left; width: 4.16667%; height: 100%; background-size: cover; background-position: center center; cursor: -webkit-grab; cursor: grab; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .ws-bg__part:after { content: ""; position: absolute; top: 0; width: 100vw; height: 100%; background: inherit; } .ws-bg__part-1:after { left: 0vw; } .ws-bg__part-2:after { left: -4.16667vw; } .ws-bg__part-3:after { left: -8.33333vw; } .ws-bg__part-4:after { left: -12.5vw; } .ws-bg__part-5:after { left: -16.66667vw; } .ws-bg__part-6:after { left: -20.83333vw; } .ws-bg__part-7:after { left: -25vw; } .ws-bg__part-8:after { left: -29.16667vw; } .ws-bg__part-9:after { left: -33.33333vw; } .ws-bg__part-10:after { left: -37.5vw; } .ws-bg__part-11:after { left: -41.66667vw; } .ws-bg__part-12:after { left: -45.83333vw; } .ws-bg__part-13:after { left: -50vw; } .ws-bg__part-14:after { left: -54.16667vw; } .ws-bg__part-15:after { left: -58.33333vw; } .ws-bg__part-16:after { left: -62.5vw; } .ws-bg__part-17:after { left: -66.66667vw; } .ws-bg__part-18:after { left: -70.83333vw; } .ws-bg__part-19:after { left: -75vw; } .ws-bg__part-20:after { left: -79.16667vw; } .ws-bg__part-21:after { left: -83.33333vw; } .ws-bg__part-22:after { left: -87.5vw; } .ws-bg__part-23:after { left: -91.66667vw; } .ws-bg__part-24:after { left: -95.83333vw; }
幻灯片的图片使用背景图片来制作。
.ws-bg:nth-child(1) { background-image: url(1.jpg); } .ws-bg:nth-child(1) .ws-bg__part { 1.jpg); } .ws-bg:nth-child(2) { background-image: url(2.jpg); } .ws-bg:nth-child(2) .ws-bg__part { background-image: url(2.jpg); } .ws-bg:nth-child(3) { background-image: url(3.jpg); } .ws-bg:nth-child(3) .ws-bg__part { background-image: url(3.jpg); } .ws-bg:nth-child(4) { background-image: url(4.jpg); } .ws-bg:nth-child(4) .ws-bg__part { background-image: url(4.jpg); } .ws-bg:nth-child(5) { background-image: url(5.jpg); } .ws-bg:nth-child(5) .ws-bg__part { background-image: url(5.jpg); }
初始化插件
Wavescroll是基于GSAP来制作的,所以在使用时要在页面中引入jQuery和TweenMax.js文件。
<script src="/path/to/jquery.min.js"></script> <script src="/path/to/TweenMax.min.js"></script>
Wavescroll幻灯片的核心js代码如下:
window.requestAnimFrame = (function() { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback){ window.setTimeout(callback, 1000 / 60); }; })(); function rafThrottle(fn) { var busy = false; return function() { if (busy) return; busy = true; fn.apply(this, arguments); requestAnimFrame(function() { busy = false; }); }; }; $(document).ready(function() { var $wsPages = $(".ws-pages"); var $headings = $(".ws-text__heading"); var bgParts = 24; var staggerVal = 65; var staggerStep = 4; var textH = $(".ws-text").height(); var winW = $(window).width(); var winH = $(window).height(); var curPage = 1; var numOfPages = $(".ws-bg").length; var changeAT = 0.5; var waveStartDelay = 0.2; var waveStagger = 0.013; var waveBlocked = false; var index = 1; var startY = 0; var deltaY = 0; var headingsY = 0; var $parts; function initBgs() { var arr = []; for (var i = 1; i <= bgParts; i++) { var $part = $('<div class="ws-bg__part">'); $part.addClass("ws-bg__part-" + i); arr.push($part); } $(".ws-bg").append(arr); $wsPages.addClass("s--ready"); $parts = $(".ws-bg__part"); changePages(); }; initBgs(); function changePages() { var y = (curPage - 1) * winH * -1; var textY = textH * (curPage - 1) * -1; var leftMax = index - 1; var rightMin = index + 1; TweenMax.to($(".ws-bg__part-" + index), changeAT, {y: y}); for (var i = leftMax; i > 0; i--) { var d = (index - i) * waveStagger; TweenMax.to($(".ws-bg__part-" + i), changeAT - d, {y: y, delay: d}); } for (var j = rightMin; j <= bgParts; j++) { var d = (j - index) * waveStagger; TweenMax.to($(".ws-bg__part-" + j), changeAT - d, {y: y, delay: d}); } TweenMax.to($headings, changeAT, {y: textY}); }; function waveChange() { waveBlocked = true; var y = (curPage - 1) * winH * -1; var textY = textH * (curPage - 1) * -1; for (var i = 1; i <= bgParts; i++) { var $part = $(".ws-bg__part-" + i); var d = (i - 1) * waveStagger + waveStartDelay; TweenMax.to($part, changeAT, {y: y, delay: d}); } TweenMax.to($headings, changeAT, {y: textY, delay: d}); var delay = (changeAT + waveStagger * (bgParts - 1)) * 1000; setTimeout(function() { waveBlocked = false; }, delay); }; function navigateUp() { if (curPage > 1) curPage--; }; function navigateDown() { if (curPage < numOfPages) curPage++; }; function navigateWaveUp() { if (curPage === 1) return; curPage--; waveChange(); }; function navigateWaveDown() { if (curPage === numOfPages) return; curPage++; waveChange(); }; function movePart($part, y) { var y = y - (curPage - 1) * winH; var headY = headingsY - (curPage - 1) * textH; TweenMax.to($part, changeAT, {y: y, ease: Back.easeOut.config(4)}); TweenMax.to($headings, changeAT, {y: headY}); }; function moveParts(y, index) { var leftMax = index - 1; var rightMin = index + 1; var stagLeft = 0; var stagRight = 0; var stagStepL = -staggerStep; var stagStepR = -staggerStep; var sign = (y > 0) ? -1 : 1; movePart($(".ws-bg__part-" + index), y); for (var i = leftMax; i > 0; i--) { var step = index - i; stagStepL += (step <= 15) ? staggerStep : 1; var sVal = staggerVal - stagStepL; if (sVal < 0) sVal = 0; stagLeft += sVal; var nextY = y + stagLeft * sign; if (Math.abs(y) < Math.abs(stagLeft)) nextY = 0; movePart($(".ws-bg__part-" + i), nextY); } for (var j = rightMin; j <= bgParts; j++) { var step = j - index; stagStepR += (step <= 15) ? staggerStep : 1; var sVal = staggerVal - stagStepR; if (sVal < 0) sVal = 0; stagRight += sVal; var nextY = y + stagRight * sign; if (Math.abs(y) < Math.abs(stagRight)) nextY = 0; movePart($(".ws-bg__part-" + j), nextY); } }; var mousemoveHandler = rafThrottle(function(e) { var y = e.pageY; var x = e.pageX; index = Math.ceil(x / winW * bgParts); deltaY = y - startY; headingsY = textH * deltaY / winH; moveParts(deltaY, index); }); var touchmoveHandler = rafThrottle(function(e) { e.preventDefault(); var y = e.originalEvent.touches[0].pageY; var x = e.originalEvent.touches[0].pageX; index = Math.ceil(x / winW * bgParts); deltaY = y - startY; headingsY = textH * deltaY / winH; moveParts(deltaY, index); }); var swipeEndHandler = function() { $(document).off("mousemove", mousemoveHandler); $(document).off("touchmove", touchmoveHandler); $(document).off("mouseup touchend", swipeEndHandler); if (!deltaY) return; if (deltaY / winH >= 0.5) navigateUp(); if (deltaY / winH <= -0.5) navigateDown(); changePages(); }; $(document).on("mousedown touchstart", ".ws-bg__part", function(e) { startY = e.pageY || e.originalEvent.touches[0].pageY; deltaY = 0; $(document).on("mousemove", mousemoveHandler); $(document).on("touchmove", touchmoveHandler); $(document).on("mouseup touchend", swipeEndHandler); }); $(document).on("mousewheel DOMMouseScroll", function(e) { if (waveBlocked) return; if (e.originalEvent.wheelDelta > 0 || e.originalEvent.detail < 0) { navigateWaveUp(); } else { navigateWaveDown(); } }); $(document).on("keydown", function(e) { if (waveBlocked) return; if (e.which === 38) { navigateWaveUp(); } else if (e.which === 40) { navigateWaveDown(); } }); $(window).on("resize", function() { winW = $(window).width(); winH = $(window).height(); changePages(); }); });