扒皮下GitHub 404的圖片層次軸動特效

今天要克隆的前端特效很是有意思,能夠參見GitHub404頁面 https://github.com/vajoy/master/index.html css

記得以前華爲在站酷發佈EMUI設計大賽的主頁也用了這種特效。說簡單點,就是鼠標在頁面移動時,banner上的圖片呈現有層次的空間軸動特效,效果圖以下:html

我們先仿造GitHub 404頁面來寫一下banner原型——前景有「魷魚」和「對話框」,遠景有倆小屋子:前端

代碼以下git

<!doctype html>
<html>
<head>
<style>
body,heml{margin:0; padding:0;}
.bannerWrap{ position:relative; margin:0 auto;width:1000px; height:350px; background-color:#F0E262; overflow:hidden;}
.bannerWrap img{ display:block; position:absolute;}
</style>
<script src="jq.js"></script>
<meta charset="utf-8">
<title>層級圖片軸動效果</title>
</head>

<body>

<div class="bannerWrap" id="bannerWrap">
    <img src="house2.png" class="small_house" id="small_house" />
    <img src="house1.png" class="house" id="house" />
    <img src="fish.png" class="fish" id="fish" />
    <img src="404.png" class="info" id="info" />
</div><!--bannerWrap結束-->
</body>
</html>
View Code

接着寫腳本前先分析一下,如何作到讓鼠標在屏幕上的位置,能夠映射爲圖片在banner上的位置呢?好比鼠標在屏幕最右上角的位置時,前景的圖片也在banner裏所能移動到的最右上角的位置(遠景圖片爲相反的方位,即左下角)。github

又如何讓每一個圖片移動的距離和方位都各不相同?好比遠景的兩個小屋子圖片,最遠的屋子移動的速度比近一點的屋子的速度要快。且近景和遠景圖片所移動的方位是相反的。ide

⑴ 首先第一個問題,咱們能夠聯想到數位板,一塊長方形的數位板能夠匹配各類型號的電腦屏幕,不管你的數控筆移動到數位板的哪一個位置,它都能控制鼠標移動到對應比例的屏幕位置。是的,咱們提到了「比例」這東西,它遵循:spa

鼠標x座標 / 屏幕寬度 = 數控筆在數位板上的x座標 / 數位板寬度   ;設計

鼠標y座標 / 屏幕高度 = 數控筆在數位板上的y座標 / 數位板高度   ;3d

咱們引伸到如今的例子來,不外乎是把數控筆換成banner上的圖片,把數位板換成banner罷了。咱們能夠很輕易地獲取屏幕寬度、banner寬度、鼠標移動時的x、y座標,那麼天然能夠依據上面的公式來反推出圖片所應在banner上的x、y座標,哦,不對,應該說是相對banner而言的left、top偏移。指針

 

⑵ 至於第二個問題,咱們能夠給每張圖片設置一個Boolean參數判斷其是否前景圖片,若是是,則依循鼠標移動位置移動,若是不是則以相反方向移動。

咱們也能夠給每張圖片設置一個scale比例參數,參數越大者則移動的位置越大,從而控制其移動速度。

 

⑶ 另有一個須要考慮的問題是,在頁面剛加載好(假設鼠標還沒作任何移動)的時候,各圖片所在banner的位置應當是與鼠標移動到屏幕正中點的時候所在位置一致的。這要求咱們在初始化各圖片的時候,就先模擬出鼠標指針在屏幕正中的效果。

咱們能夠寫出初步的腳本代碼:

$(function(){
  var win_w, win_h,b_w, b_h,
  small_house, house, fish, info, pToW_w, pToW_h, $img,
  temp_p_l, temp_p_t;
  
   
  var $banner = $("#bannerWrap");
  var picArray = "small_house,house,fish,info".split(",");
  small_house = { l: 800, t: -140, s: 0.09, isFront: false },  //smallhouse的參數
  house = { l: 130, t: -130, s: 0.05, isFront: false },  //house的參數
  fish = { l: -100, t: -90, s: 0.02, isFront: true },  //fish的參數
  info = { l: -350, t: -110, s: 0.03, isFront: true };  //info的參數
  

  win_w = $(window).width();     //初始化獲取屏幕寬度
  win_h = $(window).height();     //初始化獲取屏幕高度
  pToW_w = $banner.width()/win_w;     //初始化獲取banner寬度和屏幕寬度的比例
  pToW_h = $banner.height()/win_h;     //初始化獲取banner高度和屏幕高度的比例
 

  $.each( picArray, function(i ,id){      //初始化各圖片的位置(至關於鼠標移到屏幕中間時圖片的位置)
      $img = $("#"+ id);
      temp_p_l = pToW_w * eval(id+".s") * win_w/2 ;     //這裏使用win_w/2是爲了模擬鼠標移到屏幕水平中點的效果
      temp_p_t = pToW_h * eval(id+".s") * win_h/2 ;     //這裏使用win_h/2是爲了模擬鼠標移到屏幕垂直中點的效果
      if(eval(id +".isFront")){
          $img.css({"left": eval(id +".l") + temp_p_l , "top": eval(id +".t") + temp_p_t }); 
      }else{
          $img.css({"left": eval(id +".l") - temp_p_l , "top": eval(id +".t") - temp_p_t }); 
      }
  })
  
  var changePst = function( pageX, pageY ){
      $.each( picArray, function(i ,id){   
          $img = $("#"+ id);
          temp_p_l = pToW_w *  eval(id +".s") * pageX ; 
          temp_p_t = pToW_h *  eval(id +".s") * pageY ; 
          if(eval(id +".isFront")){
              $img.css({"left": eval(id +".l") + temp_p_l , "top": eval(id +".t") + temp_p_t });
          }else{
              $img.css({"left": eval(id +".l") - temp_p_l , "top": eval(id +".t") - temp_p_t });
          }
      })
  }
  

  $("body,html").mousemove(function(e){  //鼠標在屏幕移動時觸發changePst事件
      changePst(e.pageX, e.pageY);
  })

})

每一個圖片都有 l、t、s、isFront 這四個參數。

其中 l 和 t 表示圖片相對banner的初步偏移位置(後面還要再加上或減去temp_p_*來獲得最終偏移位置);s表示縮放級別,數值越大則該圖片移動的距離越大;isFront則是判斷是否前景圖片。

雖然上方腳本初步實現咱們想要的功能,卻沒考慮到一個問題,即屏幕被縮放時,圖片的位置、應偏移的距離都會出錯,由於可能banner的寬度已經再也不是原來的寬度(banner寬度爲百分比)、屏幕的寬高也再也不是原來的寬高(計算圖片偏移距離涉及到屏幕寬高)。

因此咱們把初始化事件封裝起來,供屏幕縮放時調用。同時動態獲取banner寬度,而不是生硬地寫入到各圖片初始化的l參數中:

$(function(){
  var win_w, win_h,b_w, b_h,
  small_house, house, fish, info, pToW_w, pToW_h, $img,
  temp_p_l, temp_p_t;
  
   
  var $banner = $("#bannerWrap");
  var picArray = "small_house,house,fish,info".split(",");
  small_house = { l: 200, t: -140, s: 0.09, isFront: false },
  house = { l: 70, t: -130, s: 0.05, isFront: false },  
  fish = { l: -160, t: -90, s: 0.02, isFront: true },  
  info = { l: -410, t: -110, s: 0.03, isFront: true }; 
  
  var resetImg = function(){ 
      b_w = $banner.width();      //初始化獲取banner寬度
      b_h = $banner.height();     //初始化獲取banner高度
      win_w = $(window).width();    
      win_h = $(window).height();    
      pToW_w = $banner.width()/win_w;    
      pToW_h = $banner.height()/win_h;    
     

      $.each( picArray, function(i ,id){      //初始化各圖片的位置(至關於鼠標移到屏幕中間時圖片的位置)
            $img = $("#"+ id);
          temp_p_l = pToW_w * eval(id+".s") * win_w/2 ;    
          temp_p_t = pToW_h * eval(id+".s") * win_h/2 ;  
          if(eval(id +".isFront")){
              $img.css({"left": b_w/2 + eval(id +".l") + temp_p_l , "top": b_h/2 + eval(id +".t") + temp_p_t });   //動態加上banner寬高
          }else{
              $img.css({"left": b_w/2 + eval(id +".l") - temp_p_l , "top": b_h/2 + eval(id +".t") - temp_p_t }); 
          }
      })
  }
  
  resetImg();
  $(window).on("resize",resetImg);      //屏幕縮放時從新初始化數據
  
  var changePst = function( pageX, pageY ){
      $.each( picArray, function(i ,id){   
          $img = $("#"+ id);
          temp_p_l = pToW_w *  eval(id +".s") * pageX ; 
          temp_p_t = pToW_h *  eval(id +".s") * pageY ; 
          if(eval(id +".isFront")){
              $img.css({"left": b_w/2 + eval(id +".l") + temp_p_l , "top": b_h/2 + eval(id +".t") + temp_p_t });
          }else{
              $img.css({"left": b_w/2 + eval(id +".l") - temp_p_l , "top": b_h/2 + eval(id +".t") - temp_p_t });
          }
      })
  }
  

  $("body,html").mousemove(function(e){
      changePst(e.pageX, e.pageY);
  })

})

至此咱們完成了咱們所預期的功能。

眼尖的同窗會發現,resetImg事件裏的.each方法跟changePst事件裏的很是類似。咱們能夠把它們整合起來提升複用、減小代碼量:

$(function(){
  var win_w, win_h,b_w, b_h,
  small_house, house, fish, info, pToW_w, pToW_h, $img,
  temp_p_l, temp_p_t;
  
  var $banner = $("#bannerWrap");
  var picArray = "small_house,house,fish,info".split(",");
  small_house = { l: 200, t: -140, s: 0.09, isFront: false },  //smallhouse的參數
  house = { l: 70, t: -130, s: 0.05, isFront: false },  //house的參數
  fish = { l: -160, t: -90, s: 0.02, isFront: true },  //fish的參數
  info = { l: -410, t: -110, s: 0.03, isFront: true };  //info的參數
  
  var setPst = function(x, y){
      x = x||win_w/2;
      y = y||win_h/2;
      $.each( picArray, function(i ,id){    
            $img = $("#"+ id);
          temp_p_l = pToW_w * eval(id+".s") * x ;   
          temp_p_t = pToW_h * eval(id+".s") * y ;    
          if(eval(id +".isFront")){     //判斷是否前景元素
              $img.css({"left": b_w/2 + eval(id +".l") + temp_p_l , "top": b_h/2 + eval(id +".t") + temp_p_t });  //這裏的b_w/2和b_h/2是爲了保證窗口縮放時還能在相對位置
          }else{
              $img.css({"left": b_w/2 + eval(id +".l") - temp_p_l , "top": b_h/2 + eval(id +".t") - temp_p_t }); 
          }
      })
  }
    
  var resetImg = function(){ 
      b_w = $banner.width();      //初始化獲取banner寬度
      b_h = $banner.height();     //初始化獲取banner高度
      win_w = $(window).width();     //初始化獲取屏幕寬度
      win_h = $(window).height();     //初始化獲取屏幕高度
      pToW_w = $banner.width()/win_w;     //初始化獲取banner寬度和屏幕寬度的比例
      pToW_h = $banner.height()/win_h;     //初始化獲取banner高度和屏幕高度的比例
     
      setPst();  
  }
  
  resetImg();
  $(window).on("resize",resetImg);      //屏幕縮放時從新初始化數據
  
  $("body,html").mousemove(function(e){
      setPst(e.pageX, e.pageY);
  })

})
View Code

最後仍是爲你們提供本案例的Demo,請到GitHub上下載:https://github.com/VaJoy/BlogDemo/tree/master/140809祝週末愉快,共勉~

相關文章
相關標籤/搜索