文章出處

今天要克隆的前端特效非常有意思,可以參見GitHub404頁面 https://github.com/vajoy/master/index.html 

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

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

代碼如下

<!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里所能移動到的最右上角的位置(遠景圖片為相反的方位,即左下角)。

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

⑴ 首先第一個問題,我們可以聯想到數位板,一塊長方形的數位板可以匹配各種型號的電腦屏幕,無論你的數控筆移動到數位板的哪個位置,它都能控制鼠標移動到對應比例的屏幕位置。是的,我們提到了“比例”這東西,它遵循:

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

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

我們引申到現在的例子來,不外乎是把數控筆換成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
祝周末愉快,共勉~


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()