V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Harldwell
V2EX  ›  推广

玩转 3D Swiper 性感秀之思路分析总结

  •  
  •   Harldwell · 2018-11-05 21:56:58 +08:00 · 961 次点击
    这是一个创建于 2194 天前的主题,其中的信息可能已经有所发展或是发生改变。

    解析:

    创建列 DIV:

    • 从上图中我们能看出,每次旋转的动画是由多列小卡片组成的;
    • 每列根据它的下标,对背景进行位移,做到拼接的效果,整体看起来就成了一张图
    • 一起来看一下真像是啥样的:

    旋转的动画是由多列小卡片组成

    colNode(){ //生成列的节点 for (var i=0;i<this.colLen;i++){ let iDivCol = document.createElement('div'); //列 iDivCol.className = "div-col"; iDivCol.style.width = this.colW+'px'; iDivCol.style.height = this.cubeH+'px'; iDivCol.style.zIndex = (i>this.colLen/2?this.colLen-i:i); this.swiperEle.appendChild(iDivCol); } }

    立体感的构成 :

    • 旋转的立体感是如何构成的呢?
    • 原理其实很简单,可以理解成每列都是一个 立体魔方 ,它们都是相互独立的,
    • 每列 backgroundPosition:index*xcolW,进行一个位移,
    • 简单来说,即每列内部都有 6 个面组成,每个面都以父级为目标进行 position、transform 等设置,
    • 一张图,让你看懂全世界:—— 图五为完成输出

    单列的构成之四个面的展示

    //——[正、上、左、右] for(var i = 0;i<4;i++){ let dividingLine = i<2; let span = document.createElement('span'); span.className = ${dividingLine?'bg-img':'pure-color'} i${i}; span.style.width = ${dividingLine? this.colW:this.cubeH}px; span.style.height = this.cubeH+'px'; if(dividingLine){ span.style.backgroundPosition = -${index*this.colW}px 0; }; iDivCol.appendChild(span); };

    单列的布局结构 :

    zIndex

    Zindex 的重要性

    transform 等角投影

    /四个面的样式/ ...省略 N 行 .div-col span.i1{ /top/ transform-origin:top; transform:translateZ(-360px) rotateX(90deg); } .div-col span.i2{ /left/ transform-origin: left; transform: rotateY(90deg); } .div-col span.i3{ /right/ transform-origin:left; transform:translateX(25px) rotateY(90deg); }

    单列的 html 布局及重点样式

    切换 :

    div-col transform-origin:50% 50% -180px

    单列的鼠标经过

    • 鼠标经过都实现了,上下页切换还远吗?
    • 之前创建结构的时候,我们已知 div 的列数,
    • 为了更好的装 B,我们在旋转的时候,给每列都要添加一定延时 setTimeout ,得以达到缓冲的视差,
    • 然后 requestAnimationFrame 就该它出场了, setInterval 已经成为过去式,
    • 同时旋转前,还要设置下一页,要显示的图片,
    • 当然记得旋转完成,后要重置角度哦。

    单次旋转展示

    3D 旋转缓冲效果

    ...省略 N 行 swiperAnimate(){ const requestAnimationFrame = window.requestAnimationFrame||window.WebkitRequestAnimationFrame; const iDivCol = this.swiperEle.querySelectorAll(".div-col"); for(var i=0;i<iDivCol.length;i++){ //让动画更逼真,给个过渡,当然也可以调整,requestAnimationFrame 每次递增的值, iDivCol[i].style.WebkitTransition=.8s -webkit-transform ease; iDivCol[i].style.WebkitTransformOrigin=iDivCol[i].style.transformOrigin = "50% 50% -180px"; this.animateMove(iDivCol[i],i,requestAnimationFrame); } } animateMove(Col,index,animationFrame){

    let ColNum =0;
    let spanSurface =  Col.querySelectorAll("span");
    //即将旋转到的面,展示的图片
    spanSurface[1].style.backgroundImage="url(./2.jpg)";
    setTimeout(()=>{
        //每列进行一个延时,以达到缓冲效果
        this.rotate(Col,0,spanSurface,animationFrame);
    
    },index*this.delayMilli);
    

    } ...省略 N 行

    上下翻页 :

    • 上面基本已实现了旋转的效果,再加一些修饰,
    • 上下点击切换的功能,注意的地方在于,防止重复点击,当前旋转中时不能点:

    pageDown(){ if(this.status){ console.log("下翻,不能点击") return ; }; this.status = 1; this.pageNum = this.pageNum>=this.imageList.length ? 1 :++this.pageNum; this.swiperAnimate(); }

    上下点击切换 3D 旋转示例

    预加载 :

    • 因轮播图图片较多,且此示例的图片每次只加载了两张,故要对图片进行一个预加载,
    • 以及图片加载出错后的过滤,避免影响后续效果的呈现:

    preloadingImage(){ this.imageList.map((k,v)=>{ let imgNode = new Image(); imgNode.onerror=err=>{ this.imageList.splice(v,1); } imgNode.src = k; }); }

    图片加载出错后的过滤

    总结:

    一个效果实现的方式有很多种,比如我们可以设置 6 个面,每设置一次,都是展示一张图,这样就不用每次旋转完后又去重置图片、角度等问题,包括 requestAnimationFrame 动画切换的过渡过程,也应该有更好的方式,欢迎各位大佬指点。以上就是今天为您带来的分享,你 GET 到了吗?如果觉得不错,记得给个赞哦 enter image description here

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2413 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 16:03 · PVG 00:03 · LAX 08:03 · JFK 11:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.