寒假到來又是讀書的好季節,因此作了一本小冊來補充知識效果以下: css
咱們須要將兩張圖合成一張有正反兩面。這裏須要將反面沿着 y 軸反轉一下就能夠正確的顯示了。使用 transform:scale(-1,1)
本來左側這張圖是正面看時的視角,右側圖是反面看的視角 bash
想法dom
<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 是前後致使的用戶看到的層級關係,因此反轉的時候後面的圖片就會被翻轉到前面。動畫
多頁翻轉時會遇到層級問題,仍是會出現只會顯示最後一組圖片,由於它的層級最高。 this
解決方式
首先要清楚右側的第一張圖片(即將翻頁的那張圖)必須顯示在最上面,而左側的圖片(已翻轉的圖片)顯示最後一張圖片就達到咱們的想要的效果了。spa
// 經過 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>
}
複製代碼
發現問題
當子項直接爲圖片是須要給圖片設置 background
或 border
才能是 3d 改變層級的效果生效。而圖標外層包一層div並不會出現該問題。我將div設置爲 inline / inline-block 也不會出現該問題。目前還沒搞清楚啥緣由?3d
上文中實現了📖翻頁效果,試想下一本書若是有幾百頁,那麼咱們須要建立一個頁的dom,能不能嘗試用最少的dom結構完成這些操做。 嘗試用3頁來模擬整本書的翻閱效果。
想法待解決的問題
transform:rotateY(deg)
來控制,經過控制整個角度來實現翻頁效果方案
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>
}
複製代碼
constructor(){
super()
this.state = {
// 全部頁面列表
list:[],
// 實際展現頁面的列表
displayList:[],
// 管理位置列表
positionList:['middle','right','right'],
}
}
複製代碼
// 找到須要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 須要替換圖片,由於至關於最開始的第一頁又回到開始,咱們須要將第一頁到數據更新就產生了新到頁面。
經過手動實現翻頁📖的效果,又能夠開心的學習,對css瞭解更多一些。一開始想作這個效果思路有點亂,發如今開發前用文檔記錄下本身的思路,一個個解決進一步梳理比較有效果。下圖是在實現過程當中梳理的想法,有助於本身一步步解決問題。
關於動畫效果若是有好的實現方式歡迎在評論區留下意見。