书本无限翻页动画

前言

寒假到来又是读书的好季节,因此作了一本小册来补充知识效果以下: css

实现

制做一页

咱们须要将两张图合成一张有正反两面。这里须要将反面沿着 y 轴反转一下就能够正确的显示了。使用 transform:scale(-1,1) 本来左侧这张图是正面看时的视角,右侧图是反面看的视角 bash

想法dom

  1. 将两张图合成一张时经过定位将图重叠在一块儿。
  2. 反转整张图时能够看到一页的两面
<div class='merge'>
          <img src="https://static-zh.wxb.com.cn/karazhan/content/article/2020/1/16f8334cdef.jpg" />
          <img src="https://static-zh.wxb.com.cn/karazhan/content/article/2020/1/16f82fce679.jpg" />
</div>  
复制代码

实际效果
发现旋转时不管转了多少角度都只能看见图二,由于图二的层级永远比图一高。学习

解决办法
使用 3d 视角来实现层级的改变
1.首先将父级设置为3d视角 2. 而后将图一的 Z 方向移动 1px ,z方向表明和用户的距离,原本图一图二的z方向是相同的,可是图二的层级高,因此看到的是图二,如今将图一贯前移动1px,天然看到的是图一了。测试

.merge{
  position: relative;
  transform-style: preserve-3d ;
  transform-origin: left center;
}
img{
  width:200px;
  height: 300px;
  position: absolute;
  top:0;
  left: 0;
  background-color: #fff;
  &:nth-child(1){
    transform: translateZ(1px);
  }
}
复制代码

为何不使用 z-index
使用z-index 来改变层级是,因为两张图片仍是在一个层级上,因此不管图片怎么反转,总有一张图片会始终覆盖另一张图片。因此咱们还得切换它们的z-index的层级,很麻烦。而 translateZ 是前后致使的用户看到的层级关系,因此反转的时候后面的图片就会被翻转到前面。动画

单页demo完整代码ui

制做多页

多页翻转时会遇到层级问题,仍是会出现只会显示最后一组图片,由于它的层级最高。 this

解决方式
首先要清楚右侧的第一张图片(即将翻页的那张图)必须显示在最上面,而左侧的图片(已翻转的图片)显示最后一张图片就达到咱们的想要的效果了。spa

  1. 多张页面的时候,通常咱们使用遍历的方式,只须要把即将翻转的页面的 z-index 提到最高就实现了右侧的翻转的图片层级问题。而左侧的自己最后一张的层级会比以前高,因此咱们不须要设置任何东西。
// 经过 isSelected 来控制层级问题
<div className="page-wrap">
        {
          list.map((item,index)=>{
            return <Merge {...item} isSelected={selectedIndex===index} rotateY={selectedIndex<=index ?0:rotateY}/>
          })
        }
      </div>
      
// merge 组件
render(){
    let {rotateY,left,right,isSelected} = this.props
    return <div className='merge' style={{transform:`rotateY(${rotateY}deg)`,zIndex:isSelected?99:0}}> 
          <img src={left} />
          <img className="image" src={right} />
     </div>   
  }
复制代码

发现问题
当子项直接为图片是须要给图片设置 backgroundborder 才能是 3d 改变层级的效果生效。而图标外层包一层div并不会出现该问题。我将div设置为 inline / inline-block 也不会出现该问题。目前还没搞清楚啥缘由?3d

多页demo完整代码

进阶无限翻页效果

上文中实现了📖翻页效果,试想下一本书若是有几百页,那么咱们须要建立一个页的dom,能不能尝试用最少的dom结构完成这些操做。 尝试用3页来模拟整本书的翻阅效果。

想法

  1. 经过下面这种图来分析翻书整个过程我把它分为 左中右三个部分
  2. 当中间页翻转到左侧时将左侧页回置到右侧,同时右侧翻转到中间页 这样实现了三张图片到循环翻转效果。

待解决的问题

  1. 翻转效果是经过 transform:rotateY(deg) 来控制,经过控制整个角度来实现翻页效果
  2. 从中间件页翻转到左侧是须要过渡效果的,从左侧页翻转到右侧是不须要过渡效果
  3. 层级问题,将中间页到层级设置为三张最高的,之因此选择三张图片来模拟整本书的效果,也是由于三张图片在翻转的时候层级问题解决比较简单些。

方案

  1. 仍是将每页抽离成组件基本代码以下
function Single (props){
    let {position,left,right} = props
    let rotateY = 0
    let zIndex = 0
    let duraction = 0
    // 从中间页翻转到左侧
    let isLeft = position === 'left'
    let isMiddle = position === 'middle'
    let isRight = position === 'right'
    if(isLeft){
        rotateY = 180
    }
    if(isMiddle){
        zIndex = 99
    }
    if(isLeft||isMiddle){
        duraction = 1
    }
    
    return <div className='merge' style={{transform:`rotateY(${rotateY}deg)`,zIndex,transitionDuration:duraction +'s'}}> 
          <img src={left} />
          <img className="image" src={right} />
     </div>   
}
复制代码
  1. 控制书页的位置,初始化数据以下,left / middle / right 分别表明 左侧页面/中间页面/右侧页面
constructor(){
  super()
  this.state = {
    // 全部页面列表
    list:[],
    // 实际展现页面的列表
    displayList:[],
    // 管理位置列表
    positionList:['middle','right','right'],
  }
}
复制代码
  1. 当咱们点击下一页时,须要改变 positionList 中的位置的值 middle->left , left->right , right->middle
// 找到须要middle页的index
    let rightIndex = this.state.positionList.findIndex(item=>item==='right')
    // 找到 left 页的index
    let leftIndex = this.state.positionList.findIndex(item=>item==='left')
    // 找到 middle 页的index
    let middleIndex = this.state.positionList.findIndex(item=>item==='middle')
    let path = ''
    // 将left页进行翻转
    if(leftIndex!==-1){
      this.state.positionList[leftIndex] = 'right'
    }
    // 将中间一页翻转到left
    if(middleIndex!==-1){
      this.state.positionList[middleIndex] = 'left'
    }
    // rgiht 中第一张进行翻转
    this.state.positionList[rightIndex] = 'middle'
复制代码

测试
按照咱们预想的逻辑后测试发现,左侧那页还没等中间页翻转到,已经跑到右侧页面了。咱们须要延迟左侧翻转到动做。
可是翻转是由 rotateY 来控制,是父级 props 传递过来的,子组件不能控制。想了一个办法就是在左侧的位置定位一张图片,该图片的地址和左侧图片的地址保持一致,每次点击下一页都动态修改。
这里咱们只是相同的三张图片进行无限翻转,咱们须要在翻转的时候加入新的图片。

加入新页面
为了便于分析用 0/1/2 分别表明 左侧/中间/右侧 页面。那么初始状态下咱们设置的是 122 也就是 一张中间图两张设置为右侧的图片,来分析下什么时候须要加入新图
122 不须要替换图片 012 不须要替换图片 201 须要替换图片,由于至关于最开始的第一页又回到开始,咱们须要将第一页到数据更新就产生了新到页面。

无限翻页完整demo

最后

经过手动实现翻页📖的效果,又能够开心的学习,对css了解更多一些。一开始想作这个效果思路有点乱,发如今开发前用文档记录下本身的思路,一个个解决进一步梳理比较有效果。下图是在实现过程当中梳理的想法,有助于本身一步步解决问题。

关于动画效果若是有好的实现方式欢迎在评论区留下意见。
相关文章
相关标签/搜索