零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;
  }
}

零JS筆記 | 正則基礎

部分常用正則:

//QQ驗證:
var re = /^[1-9]\d{4,11}$/

//去空格:
var re = /^\s+|\s+$/g;

//匹配中文:
[\u4e00-\u9fa5]

//行首行尾空格
^\s*|\s*$

//Email:
^\w+@[a-z0-9]+(\.[a-z]+){1,3}$

//网址:
[a-zA-z]+://[^\s]*

//QQ号:
[1-9][0-9]{4,9}

//邮政编码:
[1-9]\d{5}

//身份证:
[1-9]\d{14}|[1-9]\d{17}|[1-9]\d{16}x

ver re = {
    qq:[1-9][0-9]{4,9},
    email:^\w+@[a-z0-9]+(\.[a-z]+){1,3}$,
    number:/\d+/,
    url:[a-zA-z]+://[^\s]*,
    nospace:^\s*|\s*$,
    postalcode:[1-9]\d{5},
    icard:[1-9]\d{14}|[1-9]\d{17}|[1-9]\d{16}x
}

re.email




例如分析:

abcd12@163qq.com

^w+@[a-z0-9]+(.[a-z]+){1,3}$

^w+ :可出現多位字符

@:匹配@

[a-z0-9]+ :可出現多次字符

(.[a-z]+) :分組,.匹配真正的. [a-z]:出現net com 一個整體;

{1,3}$: 再+量詞表示如.com.cn .cn.net等等


普通查看字符串裏的數字

str = 'weirup123skjdlj890lkjd12kldk899'
console.log(findNum(str));
function findNum(str) {
  var arr = [
  ]
  var tmp = ''
  for (var i = 0; i < str.length; i++) {
    if (str.charAt(i) <= '9' && str.charAt(i) >= '0') {
      //  arr.push(str.charAt(i))
      tmp += str.charAt(i)
    } 
    else {
      if (tmp) {
        arr.push(tmp);
        tmp = '';
      }
    }
  }
  if (tmp) {
    arr.push(tmp)
    tmp = '';
  }
  return arr;
}
var re = /\d+/g; //找出數字;
var re = /\D+/g; //找出字母;
console.log(str.match(re));

<style>
.reg-tb{

width:100%;border-collapse: collapse

}
.reg-tb td{border:1px solid #ccc;padding:5px;}
.reg-tb tr>td:first-child{min-width: 100px;

text-align: center;}

</style>

test 匹配返回真假 寫法:re.test(str)
search 成功返回位置,匹配失败,就返回-1,像indexOf 寫法:str.search(re)
replace 返回替换后的字符串 寫法:str.replace(re,newstr),replace : 第二个参数;可以是字符串,也可以是一个回调函数
match 返回匹配数组 寫法:str.search(re)

轉義字符:

n 換行
r 製表
t 回車
s 空格
S 非空格
d 數字
D 非數字
w 字符 (字母、數字、下劃線_)
W 非字符 (特殊字符、漢字等)
b 独立的部分(起始、结束、空格)
B 非独立的部分

小記錄

i i——ignore 正则中的默认:是区分大小写; 如果不区分大小写的话,在正则的最后加标识 i (不区分大小写)
g 全局匹配:g——global;正则默认:正则匹配成功就会结束,不会继续匹配 如果想全部查找,就要加标识 g(全局匹配)
+ 量詞;匹配不确定的位置 + : 至少出现一次,如d+,即至少匹配多次數字,如果連接數字則為一個整體
{} 量詞;不確定次數:{4,7}:最少出現4次,最多出現7次;{4,}最少出現4次;{4}:剛好出現4次;var re = /ddd/; === /d{3}/;
+ = {1,}
? ? 重複零次或1次;var re = /a?/,表示a只能重複0次或1次
? = {0,1}
* 前边的内容可以重复任意次以使整个表达式得到匹配。因此,.连在一起就意味着任意数量的不包含换行的字符
* = {0,},即可以不出現,但+是一定要出現一次
| “或”的意思,正則內使用,var re = /a|b/;
() 匹配子項,把正则的整体叫parent,左边第一个小括号里面的正则,叫做这个第一个子项...var re = /(a)(b)(c)/;
[] 用中括号表示,中括号的整体代表一个字符; var str = 'abc',var re = /a[dec]c/;,第1位匹配a,第2位匹配[dec]中的一位,第3位匹配c,則返回true
^ 1、排除 : ^ 如果^写在[]里面的话,就代表排除的意思,如var re = /a1c/;,第2位只要不是bde返回true
2、匹配字符串開頭;如var re= /^d/,開頭必須為數字;
$ $匹配结尾; ^和$的意义就变成了匹配行的开始处和结束处。比如填寫QQ號碼必須為5位-12位, var re = /^d{5,12}$/ {5,12}$表示結束的位置必須是數字
- 如果-写在[]里面的话,就代表范围,范围一定是从小到大的,var re = /a[b-k]c/; [a-z] [0-9] [A-Z]、[a-z0-9A-Z];
var str = 'abc'
var re = /a[a-z]c/
console.log(re.test(str))  //,一共3位,對應上所以是true

//如果str = 'abcd',只會對應前3位,對應不是,所以是false
所以,如果需要多個匹配,+表示[a-z]有多位,可以中間一直匹配,當無法匹配時,再找最後一位匹配

var str = 'abcsdfsdfsdfsdfsdfsdfsf'
var re = re = /a[a-z]+c/ 
console.log(re.test(str))   //true

//所以,過濾html標籤正則是:

var re = /<[^>]+>/g; 
str.replace(re, '');  //應用正則替換為空

</td>
</tr>
<tr>

<td>.</td>
<td>正則中 . 表示任意字符,而匹配真正的點:\.   與一般相反</td>

</tr>

<tr>

<td>\1、 \2、\3</td>
<td>重複的第1、2、3個子項[配合()]; 如/(a)(b)(c)\1/===/(a)(b)(c)a/;表示兩個要完全相同,應用比如匹配p標籤配對</td>

</tr>

</table>

test();

var str = 'abcdef';
var re1 = /b/;
var re2 = /w/;
var re3 = /bc/;
var re4 = /bd/;
alert(re1.test(str)); //true
alert(re2.test(str)); //false
alert(re3.test(str)); //true
alert(re4.test(str)); //false
var str = '473t9487306';
var re = /\D/;
if (re.test(str)) {
  alert('不全是数字');
} else {
  alert('全是数字');
}



search :字符串.search(正则)

var str = 'abcdef';
var re1 = /bcd/;
var re2 = /w/;
var re3 = /B/;
var re4 = /B/i;
var re5 = new RegExp('B', 'i'); //这一行的写法与上面一行的写法,意义完全一样
alert(str.search(re1)); //弹出1 弹的是匹配的首字母的位置
alert(str.search(re2)); //弹出-1
alert(str.search(re3)); //弹出-1 //正则默认下是区分大小写的
alert(str.search(re4)); //弹出1
alert(str.search(re5)); //弹出1



match :返回数组
/d+/g; //这里说明前面的反斜杠d至少出现一次,多则不限

var str = 'sdogh3woiehgxfkjb789paf34dj4pgdfhgdorg43';
var re1 = /\d/;
var re2 = /\d/g;
var re3 = /\d\d/g;
var re4 = /\d\d\d/g;
var re5 = /\d\d\d\d/g;
var re6 = /\d+/g; //这里说明前面的反斜杠d至少出现一次,多则不限
alert(str.match(re1)); //[3] 返回的是找到的第一个数字
alert(str.match(re2)); // [3, 7, 8, 9, 3, 4, 4, 4, 3]
alert(str.match(re3)); //[78, 34, 43]
alert(str.match(re4)); //[789]
alert(str.match(re5)); // null
alert(str.match(re6)); //[3, 789, 34, 4, 43]

replace: 替換所有匹配:

返回替换后的字符串

字符串.replace(正则,想替换的)

例子:敏感词过滤

匹配子项

例子:日期格式化

replace的写法 : 字符串.replace(正则, 新的字符串)

var str1 = 'aaa';
var str2 = 'aaa';
var str3 = 'aaa';
var re1 = /a/;
var re2 = /a/g;
var re3 = /a+/g;
str1 = str1.replace(re1, 'b');
alert(str1); //'baa'
str2 = str2.replace(re2, 'b');
alert(str2); //'bbb'
str3 = str3.replace(re3, 'b');
alert(str3); //'b'            特別留意此處;所有匹配到的都換成b,a+表示匹配多個a,如果匹配到,則替換成b

函数的第一个参数:就是匹配成功的字符,每次匹配到的字符不同,不同長度返回不同*號

aT[1].value = aT[0].value.replace(re, function (str) { //函数的第一个参数:就是匹配成功的字符
  //alert(str);
  var result = '';
  for (var i = 0; i < str.length; i++) {
    result += '*';
  }
  return result;
});

匹配子项

// 匹配子项 : 小括号 () (还有另外一个意思:分组操作)
//把正则的整体叫做(母亲)
// 然后把左边第一个小括号里面的正则,叫做这个第一个子项(母亲的第一个孩子)
// 第二个小括号就是第二个孩子
var str1 = '2013-6-7';
var str2 = '2013-6-7';
var str3 = '2013-6-7';
var str4 = '2013-6-7';
var str5 = '2013-6-7';
var re1 = /\d+-/g;  //+匹配d
var re2 = /\d-+/g; //一个数字加至少一个横杠   +匹配d-
var re3 = /(\d-)+/g;
var re4 = /(\d+)(-)/g;
var re5 = /(\d+)(-)/g;
// str1.replace(re1, function($0){
//  alert($0); //2013- 和 6-
// })
// str2.replace(re2, function($0){
//  alert($0); //3- 和 6-
// })
// str3.replace(re3, function($0){
//  alert($0); //3-6-
// })
/*
        str4.replace(re4, function($0, $1, $2){
            // 第一个参数 : $0 (母亲)       /(\d+)(-)/g;
            // 第二个参数 : $1 (第一个孩子)  (\d+)
            // 第三个参数 : $2 (第二个孩子)  (-)
            // 以此类推
            alert($0); //2013- , 6-
            alert($1); //2013 , 6
            alert($2); // - , -
            //运行一次弹出:2013-, 2013, -, 6-, 6, -
        })
        */
str5 = str5.replace(re5, function ($0, $1, $2) {
  // return $0.substring(0, $0.length - 1) + '.';
  return $1 + '.'; //2013.6.7
})
alert(str5); //2013.6.7

match方法中的匹配子项

var str1 = 'abc';
var re1 = /abc/;
var str2 = 'abc';
var re2 = /(a)(b)(c)/;
var str3 = 'abc';
var re3 = /(a)(b)(c)/g;
alert(str1.match(re1)); //[abc]
alert(str2.match(re2)); //[abc, a, b, c](当match不加g的时候才可以获取到匹配子项的集合)
alert(str3.match(re3)); //[abc] //这里因为re里面加个g,就不会获得上面那一句的结果了

正則表達式字符類

[abc]

例子:o[usb]t——obt、ost、out

字符类 : 一组相似的元素或字符

//字符类 : 用中括号表示,中括号的整体代表一个字符

//字符类 : 一组相似的元素或字符
//字符类 : 用中括号表示,中括号的整体代表一个字符

var str1 = 'abc';
var re1 = /a[bde]c/;
alert(re1.test(str1)); //true
var str2 = 'aec';
var re2 = /a[bde]c/;
alert(re2.test(str2)); //true
var str3 = 'abdc';
var re3 = /a[bde]c/;
alert(re3.test(str3)); //false

//排除 : ^ 如果^写在[]里面的话,就代表排除的意思
var str4 = 'abc';
var re4 = /a[^bde]c/;
alert(re4.test(str4)); //false
var str5 = 'awc';
var re5 = /a[^bde]c/;
alert(re5.test(str5)); //true

//范围 : - 如果-写在[]里面的话,就代表范围,范围一定是从小到大的
var str6 = 'abc';
var re6 = /a[e-j]c/;
alert(re6.test(str6)); //false
var str7 = 'afc';
var re7 = /a[e-j]c/;
alert(re7.test(str7)); //true
var str8 = 'a3c';
var re8 = /a[a-z0-9A-Z]c/;
alert(re8.test(str8)); //true
var str9 = 'a3eJ86Xc';

var re9 = /a[a-z0-9A-Z]+c/; //在中括号外面添加了+,代表可以多位
alert(re9.test(str9)); //true

字符类实例,过滤标签

        var str1 = 'a你c';
        var re1 = /a.c/;

        alert(re1.test(str1)); //true

        var str2 = 'a你c';
        var re2 = /a\.c/;
        alert(re2.test(str2)); //false

        // \b : 独立的部分(起始、结束、空格)
        // \B : 非独立的部分

        var str3 = 'onetwo';
        var re3 = /one/;
        alert(re3.test(str3)); //true;

        var str4 = 'onetwo';
        var re4 = /\bone/; //代表字母o前面必须是独立部分,o前面是起始位置
        alert(re4.test(str4)); //true;

        var str5 = 'onetwo';
        var re5 = /one\b/; //e后面是个t,不是个独立部分
        alert(re5.test(str5)); //false; 

        var str6 = 'one two';
        var re6 = /one\b/; //e后面是个空格,是独立部分
        alert(re6.test(str6)); //true;

        var str7 = 'onetwo';
        var re7 = /\bone\b/; //前面满足后面不满足,整体也就不满足
        alert(re7.test(str7)); //false;

当正则需要传参时,一定要用全称的写法,如var re = new RegExp('\b'+sClass+'\b'),這裏也一定要雙\,字符串當中特殊的字符想輸入,必須再加,如輸出單引號'

var str = 'sddfdsfdsfdsfdsfdddddd'
//先排在一起
var arr = str.split('')
str = arr.sort().join('')
var value = ''
var index = 0;
var re = /(\w)\1+/g;
str.replace(re, function (_0,_1) {
    console.log(_0);
console.log('_1'+_1);
if(index<_0.length){
    index = _0.length;
    value = _1;
}
console.log('最多的字符為:' + value + '出現次數為:' + index);
})

前項聲明,反前項聲明

        var s =  'abacad'
        var re = /a(?=b)/g;    //匹配 ab,但只替換匹配到的ab中的a,b不替換;
        s =  s.replace(re,'*')
        console.log(s);  //*bacad
        var s =  'abacad'
        var re = /a(?!b)/g;    //匹配 ab,a後面不能匹配到b,其他可以匹配
        s =  s.replace(re,'*')
        console.log(s);  //ab*c*d

所以,過濾html標籤,但保留li標籤: re = /<2+>/g;


  1. bde
  2. >?!li
© 2025 J.chongj.chong@qq.com 模板由cho制作.