書本無限翻頁動畫

前言

寒假到來又是讀書的好季節,因此作了一本小冊來補充知識效果以下: 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瞭解更多一些。一開始想作這個效果思路有點亂,發如今開發前用文檔記錄下本身的思路,一個個解決進一步梳理比較有效果。下圖是在實現過程當中梳理的想法,有助於本身一步步解決問題。

關於動畫效果若是有好的實現方式歡迎在評論區留下意見。
相關文章
相關標籤/搜索