運動基礎:勻速運動
運動框架實現:1、開始前,關閉已有定時器;2、檢測停止條件與執行運動對立;(if/else)

btn.onclick =function(){
    sMove()
}
function sMove(){
    clearInterval(_t)
    _t = setInterval(function () {
        if(div1.offsetLeft >= 500){
            clearInterval(_t)
        }
        else{
            div1.style.left = div1.offsetLeft+10+'px'
        }
    },30)
}

分享到:

See the Pen MavJVv by elmok (@elmok) on CodePen.


<script async src="//assets.codepen.io/assets/embed/ei.js"></script>

透明變化的問題 小數點精度問題:alert(0.1+0.2) //0.3000000000004 所以,操作須用整數; 透明度處理分IE及標準 ; 獲取透明度的值,不能直接使用obj.style.opacity,須使用
function css(obj,attr){
    return obj.currentStyle ? obj.currentStyle[attr] : getComputedStyle(obj) [attr]
}

之後通過css()獲取透明度值再*100四舍五入轉整數;,所以是:

function sMove2(obj, _target, _speed) {
  clearInterval(_t)
  _t = setInterval(function () {
    var iCur = Math.round(css(obj, 'opacity') * 100)
    if (iCur == _target) {
      clearInterval(_t)
    } 
    else {
      obj.style.opacity = (iCur + _speed) / 100  //標準
      obj.style.filter = 'alpha(opacity=' + iCur + _speed + ')' //IE
    }
  }, 30)
}

使多物體能同時運動,技巧是更改定時器命名:obj._t 整合是:

function sMove2(obj, attr, _target, _speed) {
  clearInterval(obj._t)
  var iCur = 0;
  obj._t = setInterval(function () {
    if (attr == 'opacity') {                   //判斷是否透明
      iCur = Math.round(css(obj, attr) * 100)
    } 
    else {
      iCur = parseInt(css(obj, attr));
    }
    if (iCur == _target) {                    //判斷是否到結束點
      clearInterval(obj._t)
    } 
    else {                                   //未到結束點時
      if (attr == 'opacity') {                          //透明操作
        obj.style.opacity = (iCur + _speed) / 100
        obj.style.filter = 'alpha(opacity=' + iCur + _speed + ')'
      } 
      else {                                        //其他操作                
        obj.style[attr] = iCur + _speed + 'px'
      }
    }
  }, 30)
}
function css(obj, attr) {
  return obj.currentStyle ? obj.currentStyle[attr] : getComputedStyle(obj) [attr]
}

使用多個值同時運動,比如,走width:200同時height:300; 所以獲取參數使用json,for in來操作

function sMove2(obj, json, _speed) {
  clearInterval(obj._t)
  var iCur = 0;
  obj._t = setInterval(function () {
    var on = true;
    //定時器每走一下,把要運動的屬性推進一次;
    for (var attr in json) {
      var _target = json[attr]
      if (attr == 'opacity') {
        iCur = Math.round(css(obj, attr) * 100)
      } 
      else {
        iCur = parseInt(css(obj, attr));
      }
      if (iCur !== _target) { //如果其中有一個屬性沒到,則on=false
        //什麼時候停定時器,所有屬性都運動到了
        on = false //記住這是寶時器,所有on的值在不斷改變,不存在駐內在需要變回true的情況,因為一開頭定義就是true;
        if (attr == 'opacity') {
          obj.style.opacity = (iCur + _speed) / 100
          obj.style.filter = 'alpha(opacity=' + iCur + _speed + ')'
        } 
        else {
          obj.style[attr] = iCur + _speed + 'px'
        }
      }
    }
    //注意要在for in外面看是否所有屬性都運動到了。

    if (on) {
      clearInterval(obj._t)
    }
  }, 30)
}

把運動使用.call()回調加上,即可在回調裏使用this

if (on) {
  clearInterval(obj._t)
  fn && fn.call(obj) //this指向,默認是window,所以指向調用的obj
}



缓冲运动,關鍵,速度怎麼算?

缓冲运动 与摩擦力的区别:可以精确的停到指定目标点 距离越远速度越大 速度由距离决定 速度=(目标值-当前值)/缩放系数 Bug:速度取整 值取整
//當速度小於0.5時,掛了。
console.log(div1.offsetLeft);
_speed = (500 - div1.offsetLeft) * 0.2

//所以需要的_speed小於0.5時,向上取整為1; 
_speed = _speed > 0 ? Math.ceil(_speed)  : Math.floor(_speed)

注意: css可以解析小數點,js會把當前值四舍五入運算;

所以整合是,速度參數不需要,因為算出來即可;

function sMove2(obj, json, fn) {
    clearInterval(obj._t);
    var iCur = 0;
    var _speed = 0;
    obj._t = setInterval(function() {
        var on = true;
        for ( var attr in json ) {
            var _target = json[attr];
            if (attr == 'opacity') { //opacity属性传值为0 - 100
                iCur = Math.round(css( obj, 'opacity' ) * 100);
            } else {
                iCur = parseInt(css(obj, attr));
            }
            _speed = ( _target - iCur ) / 8;
            _speed = _speed > 0 ? Math.ceil(_speed) : Math.floor(_speed);
            if (iCur != _target) {
                on = false;
                if (attr == 'opacity') {
                    obj.style.opacity = (iCur + _speed) / 100;
                    obj.style.filter = 'alpha(opacity='+ (iCur + _speed) +')';
                } else {
                    obj.style[attr] = iCur + _speed + 'px';
                }
            }
        }
        if (on) {
            clearInterval(obj._t);
            fn && fn.call(obj);
        }
    }, 30);
}

function css(obj, attr) {
    return obj.currentStyle ? obj.currentStyle[attr] : getComputedStyle(obj) [attr]
}

下面是實例,多圖片殿開收縮:1、元素居中放大,寬高、定位都要改變,圖片放大1倍,則位移放大寬高的一半;

2、用js設置css樣式時,須注意問題,在同一個代碼塊中,有些css樣式的設置的權限要高於其他的樣式;解決:可放在不同代碼塊裏;

See the Pen PPKWLZ by elmok (@elmok) on CodePen.


<script async src="//assets.codepen.io/assets/embed/ei.js"></script>

帶運動的留言本、注意ul及li加overflow:hidden;否則運動會有問題;

_li.style.height = 0;
_li.style.opacity = 0; //因為要運動。所以先初始化為0;

See the Pen RWZKmw by elmok (@elmok) on CodePen.


<script async src="//assets.codepen.io/assets/embed/ei.js"></script>

返回頂部:如果是fixed定位則不需要算setTop值;使用absolute固定在右下角,須一直改變top值
setTop()方法,當前的style.top = 當前視口高度 + 滾動條 - 元素本身高度
iCur表示當前變化的值:Math.floor((0 - iCur) / 8);當前變化的值到頂部0 來計算出speed
iCur== 0,到頂部了,清除,未到頂部,則滾動條高度:document.documentElement.scrollTop = document.body.scrollTop = iCur + _speed;

var div = document.getElementById('div1')
var _t = null;
var b = 1;
setTop();
window.onscroll = function () {
  if (b != 1) { //如果==1,那麼當前scroll事件是被定時器所觸發的,所果不等於1,即非定時器的其他任何一個操作觸發
    clearInterval(_t)
  }
  b = 2;
  setTop();
}
div.onclick = function () {
  clearInterval(_t)
  var iCur = _speed = 0;
  _t = setInterval(function () {
    iCur = document.documentElement.scrollTop || document.body.scrollTop
    _speed = Math.floor((0 - iCur) / 8); //其實還是算speed
    if (iCur == 0) {
      clearInterval(_t)
    } else {
      document.documentElement.scrollTop = document.body.scrollTop = iCur + _speed;
    }
    b = 1;
  }, 30)
}
function setTop() {
  var scrollTop = document.documentElement.scrollTop || document.body.scrollTop
  div.style.top = scrollTop + document.documentElement.clientHeight - div.offsetHeight + 'px'
}

圖片預加載


當給Image()對象的src屬性一個url時,則對象去加載,加載完成保存在瀏覽器的cache裏,下次若再用,則直接從cache文件讀取;所以速度很快 ,並且節約資源;使用Image()對像,把需要的圖片地址處理後預加載到瀏覽器中;在頁面上再調用相同地址時,瀏覽器會自動先從cache裏讀取;

兩個事件:onload 當資源加載完成時,onerror,當資源加載失敗時

var oImage = new Image()  //對象
var img = document.getElementById('img')  //頁面元素
oImage.src = 'http://i1.download.fd.pchome.net/1.jpg'  //對象加載
oImage.onload = function () {
  document.onclick = function () {
    img.src = 'http://i1.download.fd.pchome.net/1.jpg'   //頁面請求
  }
}
function xl() {
  oimg.src = arr[icur]  //頁面上的圖片用數組先存起
  oimg.onload = function () {
    icur++
    if (icur < arr.length) { //如果小於,證明未下載完,則再次調用xl()
      xl() //遞歸
    }
    document.title = icur + '/' + arr.length;
  }
}

按需加載


初始化時:

 <img _src="t5.JPG" src="white.png" alt=""/>

當obj的top值 < 滾動條 + 視口高度;把_src的值附給src;
避免重覆加載,可以在賦值後的img上加自定義屬性 _img[i].isload = true; 如果isload =false則加載,=true則不重覆加載

window.onload = function () {
  var _ul = document.getElementById('ul1')
  var _img = _ul.getElementsByTagName('img')
  showImage()
  window.onscroll = function () {
    showImage()
  }
  function showImage() {
    var scrollTop = document.documentElement.scrollTop || document.body.scrollTop
    for (var i = 0; i < _img.length; i++) {
    //注意前後順序
      if (!_img[i].isload && getTop(_img[i]) < scrollTop + document.documentElement.clientHeight) {
        _img[i].src = _img[i].getAttribute('_src')
        _img[i].isload = true; //這種方法並非最優,for循環還要跑
      }
    }
  }
  function getTop(obj) {
    var itop = 0;
    while (obj) {
      itop += obj.offsetTop;
      obj = obj.offsetParent;
    }
    return itop;
  }
}