GSAP+Swiper+Svg实现六等分平面圆形进度条关联文本图片手动自动切换的效果
圆形使用svg代码实现,一个svg背景圆,一个svg进度条圆;进度条使用GSAP的动画操作svg的stroke-dasharray和stroke-dashoffset属性实现,实现思路是一个间隔为一个圆的周长;图片自动轮播切换使用swiper.js插件实现,因为它方法参数多,可以省去不少时间。
实现代码
插件文件:
<link rel="stylesheet" type="text/css" href="js/swiper-bundle.css" media="screen"/> <script src="js/swiper-bundle.min.js"></script> <script src="js/gsap.min.js"></script> <script src="js/ScrollTrigger.min.js"></script>
HTML代码:
<div class="process"> <div class="box"> <div class="circle"> <!--svg圆形,建议使用js插入--> <div class="process-circle" id="process-circle"> <svg viewBox="0 0 700 700"> <!-- 适配大半径 --> <!-- 背景圆 --> <circle class="bg" cx="350" cy="350" r="346"/> <!-- 进度圆 --> <circle class="ring" cx="350" cy="350" r="346"/> </svg> </div> </div> <div class="dots"> <ul class="ul"> <!--圆的六等分点,建议使用js插入--> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> </ul> </div> <div class="pic"> <!--swiper轮播图插件html代码--> <div class="swiper"> <div class="swiper-wrapper"> <figure class="swiper-slide"> <img class="img" src="upload/process_01.jpg" alt="图1"/> </figure> <figure class="swiper-slide"> <img class="img" src="upload/process_02.jpg" alt="图2"/> </figure> <figure class="swiper-slide"> <img class="img" src="upload/process_03.jpg" alt="图3"/> </figure> <figure class="swiper-slide"> <img class="img" src="upload/process_04.jpg" alt="图4"/> </figure> <figure class="swiper-slide"> <img class="img" src="upload/process_05.jpg" alt="图5"/> </figure> <figure class="swiper-slide"> <img class="img" src="upload/process_06.jpg" alt="图6"/> </div> </div> </div> </div> </div> <div class="text"> <div class="swiper"> <div class="swiper-wrapper"> <div class="swiper-slide item">Step 1</div> <div class="swiper-slide item">Step 2</div> <div class="swiper-slide item">Step 3</div> <div class="swiper-slide item">Step 4</div> <div class="swiper-slide item">Step 5</div> <div class="swiper-slide item">Step 6</div> </div> </div> </div> </div>
CSS代码:
/*oprocess*/ .oprocess { font-size:0.16rem; max-width: (700em/16); width: 85%; margin:0 auto; position: relative; .text { opacity: 0.2; .cur { opacity: 1; } } .box { position: relative; } .pic { width:(600em/16); margin:0 auto; position: absolute; left:50%; top:50%; transform: translate3d(-50%,-50%,0); .swiper { border-radius: 50%; } img { display:block; width:100%; height:auto; } } /*遮罩镂空*/ .circle { mask:url(images/circle_mask.png) no-repeat center center; -webkit-mask:url(images/circle_mask.png) no-repeat center center; mask-size:100% 100%; -webkit-mask-size:100% 100%; .bg { fill:none; stroke:#696969; stroke-width: (4em/16); } .ring { fill:none; stroke: @color; stroke-width: (4em/16); stroke-linecap:round; stroke-dasharray:2174; stroke-dashoffset:2174; } } .dots { li { position: absolute; width: 10%; border-radius: 50%; border:(4em/16) solid transparent; z-index: 6; cursor: pointer; &:before { display: block; content: ''; padding-bottom: 100%; } &:after { .w(62,12); .pb(62,9); background: url(images/square_01.svg) no-repeat center center; background-size: contain; .after; left:50%; top:50%; transform: translate(-50%,-50%); } &:nth-child(1){ right: (140/700*100%); top:(10/700*100%); } &:nth-child(2){ right: (2/700*100%); transform: translate(50%,-50%); top:50%; } &:nth-child(3){ right: (140/700*100%); bottom:(15/700*100%); } &:nth-child(4){ left: (140/700*100%); bottom:(15/700*100%); } &:nth-child(5){ left: (2/700*100%); transform: translate(-50%,-50%); top:50%; } &:nth-child(6){ left: (138/700*100%); top:(10/700*100%); } } .cur { border-color:@color; } } .process-circle { transform: rotate(-54.9deg); padding-bottom: 100%; position: relative; svg { position: absolute; left:0; top:0; width: 100%; height: 100%; } } } @media only screen and (min-width:1025px) { .process { .text { .swiper { position: absolute; left:0; top:0; width: 100%; height: 100%; overflow: visible; } .swiper-slide { height: auto; } .item { cursor: pointer; position: absolute; top:0; width: (420em/16)!important; &:nth-child(-n+3){ left:100%; .ml(700,40); } &:nth-child(1), &:nth-child(6){ .mt(700,15); } &:nth-child(2), &:nth-child(5){ .mt(700,290); } &:nth-child(3), &:nth-child(4){ .mt(700,540); } &:nth-child(n+4){ right:100%; .mr(700,40); text-align: right; } &:nth-child(3), &:nth-child(5){ .num, .title { color:#fff; } } } } } }
js代码:
function seteq(eq){ $('.process .text .item').eq(eq).addClass('cur').siblings('.item').removeClass('cur'); $('.process .dots li').eq(eq).addClass('cur').siblings('li').removeClass('cur'); $('.process .pic .swiper-slide').eq(eq).stop().fadeIn('fast').siblings().hide(); } $(function(){ var process = $('.process'); var processCircle = document.getElementById('process-circle'); var progressRing = processCircle.querySelector('.ring'); // 计算周长(2πr)stroke-Dashoffset间隔为一个圆周长 var circumference = 2 * Math.PI * 346 + 1; // ≈ 2174 // 初始化进度圆(完全隐藏) progressRing.style.strokeDasharray = Math.ceil(circumference); progressRing.style.strokeDashoffset =Math.ceil(circumference); var _eq = 0; //记录当前index var _clickl = gsap.timeline(); //创建点击的动画对象 var processtext = new Swiper('.process .text .swiper',{ slidesPerView:1, loop:false, simulateTouch:false, allowTouchMove:false, virtualTranslate:true, speed:1000, autoplay: { delay: 1000, stopOnLastSlide: false, disableOnInteraction: false, }, breakpoints: { 0:{ virtualTranslate:false, }, 1025: { virtualTranslate:true, } }, on:{ init:function(){ var _index = this.realIndex; seteq(_index); }, transitionStart:function(swiper){ var _index = this.realIndex; console.log(_index); var _step = 362*_index - 65; swiper.autoplay.stop(); if(!_clickl.isActive()){ if(_eq==5 && _index==0){ console.log(_eq); _clickl.to(progressRing,{ strokeDashoffset:68, duration:0.2, onComplete: (self) => { swiper.slideTo(_index); seteq(_index); _clickl.to(progressRing,{ strokeDashoffset:0, duration:0.2, onComplete: (self) => { _clickl.to(progressRing,{ strokeDashoffset:-circumference, duration:1, ease: "power3.out", onComplete: (self) => { gsap.set(progressRing,{ strokeDashoffset:circumference }); swiper.update(); swiper.slideTo(1); swiper.autoplay.start(); _eq=0; } }); } }); } }) }else{ var _offset = circumference - _step; _clickl.to(progressRing,{ strokeDashoffset:_offset, duration:0.2, ease:'linear', onComplete: (self) => { processtext.slideTo(_index); seteq(_index); processtext.autoplay.start(); } }); _eq = _index; } } } } }); process.find('.text .item').click(function(){ var _index = $(this).index(); processtext.slideTo(_index); }); process.find('.dots li').click(function(){ var _index = $(this).index(); processtext.slideTo(_index); }); });
swiper中文网:https://www.swiper.com.cn/
gsap官网:https://gsap.com/docs/v3/GSAP/
PS:代码很粗糙,但基本实现了预期的动画效果,算是积累思路。