《月熊志》技术解析——沉浸式的翻阅体验
发表于 2013-12-25 13:08:33

《月熊志》为大家提供了一个沉浸式的翻阅体验,用户可以在页面切换时体验到真实的3D翻书效果,非常的酷炫。而要实现这个效果,需要用到CSS3 3D transform和JavaScript,同时为了实现跨浏览器和跨设备的统一体验,用到hammer.js库去处理滑动操作。

示例效果:

网页的结构十分简单,整个杂志是一个ID为magazine的div,子元素. page即页面元素,其中还需要包含一层.page-content层。

css:

  1. .page { 
  2.     positionabsolute
  3.     top: 0
  4.     left: 0
  5.     width100%
  6.     height100%
  7.     overflowhidden
  8.     displaynone
  9. .page-content { 
  10.     positionabsolute
  11.     top: 0
  12.     left: 0
  13.     width100%
  14.     height100%

当用户拖拽页面时,我们会复制一份当前页和下一页,作为3D翻页的元素存在,层之间的关系如下:

$currentPage -> 当前页

$newPage -> 新的一页(上一页/下一页)

$pageBack -> 克隆的$newPage

$pageFront -> 克隆的$currentPage

除了当前页的其他页面,为了只显示页面一半,需要将外层div的宽度设置为50%,同时将.page-content设为200%。

CSS:

  1. .page.front, 
  2. .page.back, 
  3. .page.prev, 
  4. .page.next { 
  5.     width50%
  6. .page.front .page-content, 
  7. .page.back .page-content, 
  8. .page.prev .page-content, 
  9. .page.next .page-content { 
  10.     width200%

当开始拖拽时,通过鼠标位置在屏幕的左边或者右边判断翻页的方向并复制页面。然后在拖拽时,根据移动距离计算翻页进度并转换为角度应用到元素上。最后使用css transition完成余下动画。

JS代码关键部分:

  1. $("#magazine").hammer({prevent_default: true}).on("dragstart"function(event) { 
  2.     //开始拖拽 
  3.  
  4.     //根据指针的位置判断新的一页是上一页还是下一页 
  5.     var pageX = event.gesture.center.pageX; 
  6.     _.$newPage = pageX > centerX ? _.$currentPage.next(".page").addClass("next") : _.$currentPage.prev(".page").addClass("prev"); 
  7.  
  8.     //复制当前页和新的一页 
  9.     _.$pageFront = $("<div class='page front' />").append(_.$currentPage.children().clone()); 
  10.     _.$pageBack = $("<div class='page back/>").append(_.$newPage.children().clone()); 
  11.  
  12.     $(this).on("drag"function(event) { 
  13.         //拖拽中 
  14.  
  15.         //获得手势方向 
  16.         var direction = event.gesture.direction; 
  17.  
  18.         //如果是左右滑动才继续 
  19.         if (direction != "left" && direction != "right"return
  20.  
  21.         //获得鼠标x坐标,和窗口宽度相除获得百分比和角度 
  22.         var deltaX = Math.max((_.direction == "left" ? -1 : 1) * event.gesture.deltaX, 0), 
  23.             progress = deltaX / winWidth, 
  24.             angle = (direction == "left" ? -180 : 180) * progress; 
  25.  
  26.         //使用transform翻转页面 
  27.         _.$pageFront.css("transform""perspective(2200px) rotateY(" + angle + "deg)"); 
  28.         _.$pageBack.css("transform""perspective(2200px) rotateY(" + (angle - 180) + "deg)"); 
  29.  
  30.     }).on("dragend"function(event) { 
  31.         //拖拽结束 
  32.  
  33.         var deltaX = Math.max((direction == "left" ? -1 : 1) * event.gesture.deltaX, 0), 
  34.             time = event.gesture.deltaTime, 
  35.             progress = deltaX / winWidth, 
  36.             flipped = progress > 0.5 || deltaX / time > 0.5, //如果滑动距离超过屏幕的一半或者速度大于0.5就认为页面被翻过去了 
  37.             duration = !flipped ? 1 - progress : progress, 
  38.             angle = !flipped ? 0 : _.direction == "left" ? -180 : 180; 
  39.  
  40.         //通过css3 transition完成余下动画 
  41.         _.$pageFront.css({ 
  42.             "transition""all " + duration + "s ease-out"
  43.             "transform""perspective(2200px) rotateY(" + angel + "deg)" 
  44.         }); 
  45.         _.$pageBack.css({ 
  46.             "transition""all " + duration + "s ease-out"
  47.             "transform""perspective(2200px) rotateY(" + (angel - 180) + "deg)" 
  48.         }); 
  49.     }); 
  50. }); 

如果你的页面包含视频或者Canvas等元素,那还需要再做一些额外的工作,因为这些元素并不能以同样的状态被直接复制。

最后如果你需要兼容不支持CSS3浏览器。可以借助Modernizr判断,以水平滑动的方式切换页面。

  1. if (Modernizr.csstransforms3d && Modernizr.csstransitions) { 
  2.     //支持 
  3. } else { 
  4.     //不支持 
  5. }; 
CSDN官方微信
扫描二维码,向CSDN吐槽
微信号:CSDNnews
微博关注
【免责声明:CSDN本栏目发布信息,目的在于传播更多信息,丰富网络文化,稿件仅代表作者个人观点,与CSDN无关。其原创性以及文中陈述文字和文字内容未经本网证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本网不做任何保证或者承诺,请读者仅作参考,并请自行核实相关内容。您若对该稿件有任何怀疑或质疑,请立即与CSDN联系,我们将迅速给您回应并做处理。】