零JS筆記 | javascript運動 | 匀速 | 缓冲
運動基礎:勻速運動
運動框架實現: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; } }