分类 JS 下的文章

基礎方法封裝匯總

隨機數生產

function randomNum(alls, now) {
  var arr = []
  var Newarr = []
  for (var i = 1; i <= alls; i++) {
    arr.push(i);
  }
  for (var i = 0; i < now; i++) {
    Newarr.push(arr.splice(Math.floor(Math.random() * arr.length), 1))
  }
  return Newarr;
}
randomNum(49,7)

快速排序

function quickSort(arr) {
  if (arr.length <= 1) { //有可能為0
    return arr;
  }
  var num = Math.floor(arr.length / 2) //向下取整,找到中間數
  var numV = arr.splice(num, 1); //找到基準點的數值
  var left = []; //存小於基准點的值
  var right = []; //存大於基準點的值
  for (var i = 0; i < arr.length; i++) {
    if (arr[i] < numV) {
      left.push(arr[i]);
    } 
    else {
      right.push(arr[i]);
    }
  }
  //以上一次操作,下面再利用遞歸原理
  return quickSort(left).concat([numV], quickSort(right));
  //左邊.concat(基准數,右邊)
}
alert( quickSort([30,12,5,6,9,18,57,2]) )

事件綁定

function on(obj, evt, fn) {
  if (obj.addEventListener) {
    obj.addEventListener(evt, fn, false)
  } 
  else {
    obj.attachEvent('on' + evt, function () {
      fn.call(obj);
    })
  }
}
on(document, 'click', fn1)

元素拖拽

function drag(obj) {
  var cw = document.documentElement.clientWidth;
  var ch = document.documentElement.clientHeight;
  obj.onmousedown = function (e) {
    var e = e || event;
    var disW = e.clientX - this.offsetLeft;
    var disH = e.clientY - this.offsetTop;
    //解決IE文字選中後移動問題:
    if (obj.setCapture) {
      obj.setCapture();
    }
    document.onmousemove = function (e) {
      var e = e || event;
      var cw_w = e.clientX - disW;
      var ch_h = e.clientY - disH
      if (cw_w < 0) {
        cw_w = 0
      } 
      else if (ch_h < 0) {
        ch_h = 0
      } 
      else if (cw_w > cw - obj.offsetWidth) {
        cw_w = cw - obj.offsetWidth
      } 
      else if (ch_h > ch - obj.offsetHeight) {
        ch_h = ch - obj.offsetHeight
      }
      obj.style.left = cw_w + 'px'
      obj.style.top = ch_h + 'px'
    }
    document.onmouseup = function () {
      document.onmousemove = null;
      //解決IE8抬起鼠標,釋放全局捕獲 releaseCapture();
      if (obj.releaseCapture) {
        obj.releaseCapture()
      }
    }
    return false; //down事件觸發時陰止默認行為;
  }
}

獲取className

function getClassName(parent, tagName, className) {
  var aEls = parent.getElementsByTagName(tagName)
  var arr = []
  for (var i = 0; i < aEls.length; i++) {
    var aClassName = aEls[i].className.split(' '); //当前classname拆分成数组
    for (var j = 0; j < aClassName.length; j++) {
      if (aClassName[j] == className) { //如果第j个class == classname
        arr.push(aEls[i]) //则把当前第i个class push进来
        break; //如果class='box box'相同名字,找到一个跳出for
      }
    }
  }
  return arr;
}
getClassName(document, 'li', 'box');

增加class方法

function addClass(obj, className) {
  if (obj.className == '') { //原本无
    obj.className = className;
  } 
  else { //原本有
    var arrClassName = obj.className.split(' ');
    var _index = arrIndexOf(arrClassName, className);
    if (_index == - 1) { //不存在
      obj.className += ' ' + className;
    }
  }
}
//判斷一個數組裏是否存在元素
function arrIndexOf(arr, v) {
  for (var i = 0; i < arr.length; i++) {
    if (arr[i] == v) {
      return i; //当前重複的值出现位置
    }
  }
  return - 1;
}
 
addClass(box, 'box111');

刪除class方法

function removeClass(obj, className) {
  if (obj.className != '') {   //如果有class
    var arrClassName = obj.className.split(' ');
    console.log(arrClassName);
    var _index = arrIndexOf(arrClassName, className);
    if (_index != - 1) {     //如果有需要移除的class
      arrClassName.splice(_index, 1); //删除数组裏需要移除的
      obj.className = arrClassName.join(' ');//再把處理完的數組class給obj
    } 
  }
}
//判斷一個數組裏是否存在元素
function arrIndexOf(arr, v) {
  for (var i = 0; i < arr.length; i++) {
    if (arr[i] == v) {
      return i; //当前重複的值出现位置
    }
  }
  return - 1;
}
 
removeClass(box, 'box3')

選中文字方法

function selectText() {
    if (document.selection) { //IE
        return document.selection.createRange().text;//字符串
    }
    else {
        return window.getSelection().toString(); //getSelection()對象,需轉成字符串
    }
}

阻止冒泡

function (ev) {
    ev = ev || event
    if(ev.stopPropagation){
        ev.stopPropagation();
    }
    else{
        ev.cancelBubble = true;
    }
}

阻止默認事件

function (ev) {
  ev = ev || event
  if (ev.preventDefault) {
    ev.preventDefault();
  } 
  else {
    ev.returnValue = false;
    return false;
  }
}

判斷IE

var ie = !-[1,] //IE9已修復
//推薦
if(!window.VBArray){
    alert('Not IE')
}
else{
    alert('IE')
}

getStyle,startMove方法

function startMove(obj,json,endFn){clearInterval(obj.timer);obj.timer=setInterval(function(){var bBtn=true;for(var attr in json){var iCur=0;if(attr=="opacity"){if(Math.round(parseFloat(getStyle(obj,attr))*100)==0){iCur=Math.round(parseFloat(getStyle(obj,attr))*100)}else{iCur=Math.round(parseFloat(getStyle(obj,attr))*100)||100}}else{iCur=parseInt(getStyle(obj,attr))||0}var iSpeed=(json[attr]-iCur)/8;iSpeed=iSpeed>0?Math.ceil(iSpeed):Math.floor(iSpeed);if(iCur!=json[attr]){bBtn=false}if(attr=="opacity"){obj.style.filter="alpha(opacity="+(iCur+iSpeed)+")";obj.style.opacity=(iCur+iSpeed)/100}else{obj.style[attr]=iCur+iSpeed+"px"}}if(bBtn){clearInterval(obj.timer);if(endFn){endFn.call(obj)}}},30)}function getStyle(obj,attr){if(obj.currentStyle){return obj.currentStyle[attr]}else{return getComputedStyle(obj,false)[attr]}};

getStyle(obj,'left')  //top,opacity,zIndex,width,height....帶px
startMove(img,{left:30;top:100},fn)//left:30;top:100同時進行
startMove(img,{left:30},function(){ startMove(img,{top:100}) },fn) //分步執行

Ajax封裝

function ajax(url,fnSucc,fnFaild){var oAjax=null;if(window.XMLHttpRequest){oAjax=new XMLHttpRequest()}else{oAjax=new ActiveXObject("Microsoft.XMLHTTP")}oAjax.open("GET",url,true);oAjax.send();oAjax.onreadystatechange=function(){if(oAjax.readyState==4){if(oAjax.status==200){fnSucc(oAjax.responseText)}else{if(fnFaild){fnFaild()}}}}};

ajax('date.js',function(){alert('成功')},function(){alert('失敗')})

兼容獲取class對象

function getByClass(oParent, sClass) {
    var aEle = oParent.getElementsByTagName('*');
    var result = [] //最后返回数组
    var re = new RegExp('\\b' + sClass + '\\b', 'i');//正则对象
    for (var i = 0; i < aEle.length; i++) {
        if (re.test(aEle[i].className)) {
            result.push(aEle[i])
        }
    }
    return result;
}

var box = getByClass(document, 'box')

連續觸發兼容寫法

if(ie){
this.inp.onpropertychange = function(){}
}
else{
this.inp.oninput = function(){}
}

doMove前後上下移動

function doMove(obj, attr, dir, target) { //obj,屬性[left,top],速度[每次時間移動多長],目標點
  dir = parseInt(getStyle(obj, attr)) < target ? dir : - dir
  clearInterval(obj.timer)
  obj.timer = setInterval(function () {
    var speed = parseInt(getStyle(obj, attr)) + dir
    if (speed > target && dir > 0 || speed < target && dir < 0) {
      speed = target
    }
    obj.style[attr] = speed + 'px'
    if (speed == target) {
      clearInterval(obj.timer)
    }
  }, 30)
}

doMove(obj,'left',30,10) //移動obj的left到10px的位置,速度為每30ms移動30px
doMove(obj,'left',40,500) //移動obj的left到500px位置,速度為每30ms移動40px
//如果當前left從小到大,則為往前,反之為往後;

WebkitTransitionEnd webkitAnimationEnd方法封装

function addEnd(obj, fn)
{
  obj.addEventListener('WebkitTransitionEnd', fn, false);
  obj.addEventListener('transitionend', fn, false);
}
function removeEnd(obj, fn)
{
  obj.removeEventListener('WebkitTransitionEnd', fn, false);
  obj.removeEventListener('transitionend', fn, false);
}

//同理還有
function addEnd(obj, fn) {
  obj.addEventListener('webkitAnimationEnd', fn, false);
  obj.addEventListener('animationend', fn, false);
}


//end函數如觸發transition行為,即改變width/height/opacity....,則須先removeEnd(obj,fn)
addEnd(obj,end)
function end(){
    removeEnd(obj,end)
    //do something...
}

直角三角形已知斜邊及角度,求另兩邊,方法封裝

function toLT(iR, iDeg) { //斜边[圆弧半径],角度
  return {
    l: Math.round(Math.sin(iDeg / 180 * Math.PI) * iR),
    t: Math.round(Math.cos(iDeg / 180 * Math.PI) * iR)
  }
}
//如已知半徑iR = -150 ; 角度依次增加 var _RH = toLT(-150,90/4*i)
left = _RH.l;top = _RH.t

獲取元素到屏幕的距離 直當於jq的offset()

    function getPos(obj){
        var pos = {left: 0, top:0};
        while (obj) {
            pos.left +=obj.offsetLeft;
            pos.top +=obj.offsetTop;
            obj = obj.offsetParent
        }
        return pos;
    }

抖動

    function shake(obj, attr, endfn) {
        if (obj.door) {
            return
        }
        obj.door = 1;
        var pos = parseInt(css(obj,attr));
        var arr = []; //20 -20 18 -18
        var num = 0;
        for (var i = 20; i > 0; i -= 2) {
            arr.push(i, - i);
        }
        arr.push(0);
        clearTimeout(obj.shake)
        obj.shake = setInterval(function () {
            obj.style[attr] = pos + arr[num] + 'px'
            num++
            if (num == arr.length) {
                clearInterval(obj.shake)
                endfn && endfn()
                obj.door = 0;
            }
        }, 50)
    }

零JS筆記 | 字符串 | 數組 | JSON

字符串方法

  • 下標值找對應的字符: str.charAt(位置)
  • 字符轉編碼: str.charCodeAt(位置)
  • 編碼轉字符: String.fromCharCode(編碼,編碼)
  • 截取一段字符:str.substring()、str.slice()
  • 字符串分割成數組:str.split()
  • 數組連接成字符串: str.join()
var str = '百度一下,你就知道'  //百 = 30334; 度 = 24230

console.log(str.charAt()); //百 str.charAt(位置)默認為0;
console.log(str.charAt(50)); //找不到則返回空白

console.log(str.charCodeAt(1)); //24230 charCodeAt(位置),默認0 返回字符編碼值
console.log(str.charCodeAt(50)); //NaN 找不到則返回NaN

console.log(String.fromCharCode(24230)); //百 根據編碼返回字
console.log(String.fromCharCode(30334, 24230)); //百度
console.log(String.fromCharCode(789745544845647000)); //找不到則返回空白
//inp只允許輸入數字,isNaN無法判斷空格,所以使用str.charCodeAt()
/*
0 - 9之間的編碼為: 48 - 57
a - z 之間的編碼為: 97 - 122
A - Z 之間的編碼為: 65 - 90  
*/
function detectNum(str) {
  var n = 0;
  for (var i = 0; i < str.length; i++) {
    n = str.charCodeAt(i); //每一位的編碼
    if (n < 48 || n > 57) { //有一個非數字,後面不需要檢測
      return false;
    }
  }
  return true;
}
//打印編碼
document.body.innerHTML = String.fromCharCode()
var str = '';
for (var i = 0; i < 1000; i++) {
  str += String.fromCharCode(i) + ' '
}
document.body.innerHTML = str;

//簡漏加密
var inp = document.getElementsByTagName('input')
var box = document.getElementById('box')
inp[1].onclick = function () {
  var str = inp[0].value;
  var strN = '';
  for (var i = 0; i < str.length; i++) {
    strN += String.fromCharCode(str.charCodeAt(i) - 1000); //value每一個轉成編碼
  }
  box.innerHTML = strN;
}

str.indexOf()方法 -- indexOf(字符或字符串) 找到則返回位置,找不到則返回-1,indexOf(字符或字符串,從第幾位開始找),第二個參數為負數,默認0
str.lastIndexOf(),從左 <-- 右

var str = 'what id how goe what miei slfk.mai to zhay zip sib sussuej ahwt haha,id what at miei slfk.mai to zhay'
var s = 'what' //待查找字符
var i = 0;
var nu = 0;
for (; str.indexOf(s, i) != - 1; ) { //重覆執行找不到為止
  alert('找到位置:' + i) //找到3次
  i = str.indexOf(s, i) + s.length //i從找到的位置後加目標長度繼續找、
  nu++;
}
alert('總共:' + nu) //3

//比較
alert('你好'>'我好') //false
console.log('你'.charCodeAt()); //20320
console.log('我'.charCodeAt()); //25105

str.substring()、str.slice() 方法

var str = 'what id how goe what miei slfk.mai'
console.log(str.substring(0, 4)); //what
console.log(str.substring(4, 0)); // what 大的會自動在前面
console.log(str.substring( - 2, 4)); //what  負數當成0處理

console.log(str.slice(0, 4)); //what
console.log(str.slice(4, 0)); //無substring交換位置功能,返回空白
console.log(str.slice( - 3)); //mai 負數 = 尾部找
//展開收縮
_a.onclick = function () {
  if (on) {
    var stra = _span.innerHTML.substring(0, 27);
    _span.innerHTML = stra + '……';
    _a.innerHTML = '展開'
  } 
  else {
    _span.innerHTML = _spani
    _a.innerHTML = '收縮'
  }
  on = !on //每次點擊取反
}

str.toUpperCase()
str.toLowerCase()

str.split()、arr.join()

var strb = 'www.baidu.com'
console.log(strb.split('.')); //["www", "baidu", "com"]

var strT = 'www'
console.log(strT.split()); //["www"]
console.log(strT.split('')); //["w", "w", "w"]

var strM = '去芫存菁'
console.log(strM.split('芫')); //["去", "存菁"]

var strH = '/www.baidu.com/';
console.log(strH.split('/')); //["", "www.baidu.com", ""]

var strD = '2012-08-16-21-14-56'
console.log(strD.split('-')); //["2012", "08", "16", "21", "14", "56"]
console.log(strD.split('-', 3)); //["2012", "08", "16"] 第二個參數表示截取幾組

var arr = [
  'a',
  'b',
  'c'
]
console.log(arr.join()); //a,b,c 不加參數,中間默認有,
console.log(arr.join('')); //abc
console.log(arr.join('-')); //a-b-c
應用一 :
1、獲取值
2、把值轉成數組 str.split('')
3、向數組裏的每一項添加標籤
4、把新數組重新組合成字符串 arr.join('')
應用二 :
1、使用所輸入的內容作為分割可符,分割成數組,[, , , , , ,]
2、再用新的形式作為連接符,連接成字符串
3、所以替換功能也只是把join連接符換成新輸入內容即可
<p id="find">腦殘文段一:站在十六岁,站在青春转弯的地方,站在一段生命与另一段生命的罅隙,我终于泪流满面。<br />
    在黑色的风吹起的日子,在看到霰血鸟破空悲鸣的日子,在红莲绽放樱花伤势的日子里,在你抬头低头的笑容间,在千年万年的时光裂缝与罅隙中,我总是泪流满面。因为我总是意犹未尽地想起你。这是最残酷也是最温柔的囚禁吗? </p>
<input type="text" id="findinp"/>
<input type="button" id="findbtn" value="findbtn"/>
var pfind = document.getElementById('find')
var findinp = document.getElementById('findinp')
var findbtn = document.getElementById('findbtn')
findbtn.onclick = function () {
  var str = findinp.value; //輸入內容作為分割符
  if (!str) return false
  pfind.innerHTML = pfind.innerHTML.split(str).join('<span>' + str + '</span>') //以 關鍵字 分割,以 新關鍵字 組合
}


數組方法
1、截取數組方法:arr.length = n;字符串的lenght無法寫;清空:arr.length = 0; || arr = []
2、添加 push()/unshift(), 返回長度; 刪除 pop()/shift(),返回被刪;
3、數組添加刪除、替換、添加 arr.splice();刪除:返回被刪,替換:返回被刪,添加:返回[]
4、去除重複數組,循環1獲取第一個i,循環2獲取很二個j,j = i+1,前後對比;相等splice刪,j--;
5、排序:arr.sort(function(a,b){return a-b}),b-a表示從大到小;
6、隨機排:arr.sort(function(a,b){return Math.random()-0.5;});
7、隨機數:Math.round(Math.random();
8、數組連接:arr.concat(arr1,arr2,...); 顛倒位置:arr.reverse();

var arr = [1,2,3]
var arr = new Array(1,2,3)  //區別: var arr = Array(n),表示長度:n

var arr = [1,2,3]
arr.length = 1; //可寫
console.log(arr); // [1]

arr.length = 0;
arr = [] //清空數組,效率可能高

var str = 'abc'
str.length = 1; //字符串的length無法寫
console.log(str); //數組length可寫,字符串不可寫
var arr = [];
arr.push(1, 2, 3) //最後一位添加
console.log(arr.push('abc')); //4 arr.push()返回值為length

arr.unshift(0) //最前面一位添加
console.log(arr.unshift('def')); //6 arr.unshift返回值為length IE67不支持

var arrD = ['ab','bc','cd','de']
arrD.pop() //刪除最後一位
console.log(arrD.pop()); //返回被刪除字符

var arrD2 =  ['ab','bc','cd','de']
arrD2.shift() //刪除第一位
console.log(arrD2.shift()); //返回被刪除字符

排隊 應用:切換圖片交換位置

var arrQ = ['1','2','3','4']
arrQ.unshift(arrQ.pop()) //刪除最後一位,並把刪除元素添加首位
console.log(arrQ); //["4", "1", "2", "3"]

var arrQ2 = ['1','2','3','4']
arrQ2.push(arrQ2.shift())
console.log(arrQ2); //["2", "3", "4", "1"]
//刪除 arr.splice(位置,刪除個數)
var arrS = ['1','2','3','4']
arrS.splice(0, 1)
console.log(arrS);
console.log(arrS.splice(0, 1)); //返回被刪元素

//替換 arr.splice(位置,刪除個數,'替換內容')
var arrS2 = ['1','2','3','4']
arrS2.splice(0, 1, 'a')
console.log(arrS2);
console.log(arrS2.splice(0, 1, 'a')); //返回被刪元素

//添加 arr.splice(位置,刪除0,'添加內容1',...)
var arrS3 = ['1','2','3','4']
arrS3.splice(2, 0, 'a')
console.log(arrS3);

數組去重覆,此方法適用於較少個數,太多會卡死,性能差;

var arr = [1,2,3,4,45,5,5]
for (var i = 0; i < arr.length; i++) {
  for (var j = i + 1; j < arr.length; j++) {
    if (arr[i] == arr[j]) { //第一位與第二位比較
      arr.splice(arr[j], 1)
      j--; //splice成立後會刪除一個,所以arr.length應該減少1位
    }
  }
}
console.log(arr);

排序、從大到小,從小到大,隨機排

var arr = [4,1,2,3,4,454,56,5878,1]
arr.sort()
console.log(arr);
arr.sort(function (a, b) {
  return a - b; //b - a 從大到小
})
console.log(arr);
// 快速,希爾、冒泡、歸並、選擇、插入

var arr = ['323px','123px','10px','2000px']
arr.sort(function (a, b) {
  return parseInt(a) - parseInt(b)
})
console.log(arr);

//隨機排序
var arr = [1,2,3,4,5,6,7,8]
arr.sort(function (a, b) {
  return Math.random() - 0.5;
})
console.log(arr);

隨機範圍及生產
0~1:Math.random(), Math.floor() 向下; Math.ceil() 向上 Math.round()四舍五入
0-10:Math.round(Math.random()* 10)
x~y:function xyNum(x, y) { return Math.round(Math.random() * (y - x) + x) }
0~y:Math.round(Math.random() * y);
1~y:Math.ceil(Math.random() * y);

數組連接 arr.concat(arr1,arr2,arr3,...)
顛倒數組位置:arr.reverse();

var arr = [2,3,4,5,56]
arr.reverse()
console.log(arr)  // [56, 5, 4, 3, 2]

//所以顛倒字符串是
str = 'abcdef'
console.log(str.split('').reverse().join('')); // fedcba 轉成數組,顛倒,轉回字符

不重覆隨機數生產:ex: 1000選500不重複
思路一:

1、創建數組,存範圍內的所有數據 1000,所以每一位都不相同了;
2、新數組獲取500個創建數組的隨機位置,即能不重複;
function randomNumOne(range, count) { //randomNumOne(範圍,個數)
  var arrR = []
  var arrC = []
  for (var i = 0; i < range; i++) {
    arrR.push(i)
  }
  for (var i = 0; i < count; i++) {
    var index = Math.floor(Math.random() * arrR.length); //注間位置範圍隨機產生也需要在數組的長度內,比如使用splice刪除1位,則數組長度也減少1位;
    arrC.push(arrR.splice(index, 1))
  }
  return arrC;
}

思路二:

1、創建數組,存範圍內的所有數據 1000 所以每一位都不相同了;
2、再打亂此數據;
3、返回截取需要數組中的500位,效率較高
function randomNumTwo(range, count) {
  var arrR = [
  ]
  for (var i = 0; i < range; i++) {
    arrR.push(i)
  }
  arrR.sort(function (a, b) {
    return Math.random() - 0.5;
  })
  arrR.length = count;
  return arrR;
}

類似字符串indexOf方法,返回指定元素的們置,找不到返回 -1;

var arr = ['abc','def','123','ggg']
console.log(arrIndexOf(arr, '12d3'));

function arrIndexOf(arr, v) {
  var indexof = -1;
  for (var i = 0; i < arr.length; i++) {
    if (arr[i] == v) {
      indexof = i;
    }
  }
  return indexof
}



JSON


var json = { name:'elmok','age':30 };
var json = { 'name':'elmok','age':30 }; //推薦
console.log(json.name); //json.name = 'ooo'
console.log(json['name']); //json['name'] = 'ooo'

//數組套json
var arr = [{'name':'ELMOK'},{'age':30}];
console.log(arr[0].name);

for (var attr in json) {
  //  alert(attr)   //前面
  // alert(json[attr]);  //後面
}

//json套數組
var json = {
        url:['1.jpg','2.jpg'],
        txt:['图一','图二']
}
for (var attr in json) { //嵌套找
  for (var i = 0; i < json[attr].length; i++) {
    console.log(json[attr][i]);
  }
}

for in 也可操作對象,注意for in 無for循環裏如1,2,3,4...這樣的屬性,

var str = '';
var num = 0; //設置for in裏的個數
for (var attr in window) {
  str += attr + ':' + window[attr] + '<br />'
  num++
}
console.log(num);
document.body.innerHTML = str;

for 與 for in
1、json無長度,json.length == undefined ,無法使用for循環;
2、數組可使用for in,也可使用for

var json = {
  url: ['1.jpg','2.jpg'],
  txt: ['图一','图二']
}
for (var i = 0; i < json.length; i++) {
  alert(json[i])
}
console.log(json.length); //undefined
var arr = [ 1,2,3 ]
for (var i in arr) {
  console.log(arr[i]); // 1,2,3
}

基礎閉包

閉包

1、什么是閉包

fn套fn,內部fn可引用外部fn的參數和變量
內部被引用的參數和變量,不會被JS垃圾回收機制收回

2、閉包有什麼好處,哪方面應用

1).希望一個變量長期在內在中
2).避免全局變量污染
  a.模塊化代碼
  b.在循環中找到對應元素的索引
3).私有成員存在

3、閉包注意的地方

IE下可能引發內存洩漏

最簡單例子首先:

function aaa() {
  var a = 1;
}
aaa() //执行完后即会被垃圾回收机制收回*/

fn套fn,內部fn可引用外部fn的參數和變量

function aaa() {
  var a = 5;
  function bbb() {
    alert(a)
  }
  return bbb;
}
var c = aaa(); //这里aaa()已经执行完
c(); //c(),表示bbb函数*/

再一個:a能累加,但必須是全局變量

var a = 1;
function aaa() {
  a++;
  alert(a)
}
aaa(); //2
aaa(); //3
alert(a) //a是全局,所以能调用到,下面需要变成局布变量;

內部被引用的參數和變量,不會被JS垃圾回收機制收回

問題:如何使a在執行過程中有效,比如a++能累加,並且a又是一個局部變量?

//當a是局部變量時,不會累加了
function aaa() {
  var a = 1;
  a++;
  alert(a);
}
aaa(); //2
aaa(); //2 ,调用重新生成,不会累加,下面 既让a是局布变量,又可以累加*/
function aaa() {
  var a = 1; //相对于内部可被找到,又不受外部执行函数影响
  return function () { //函数嵌套函数
    a++;
    alert(a)
  }
}
var b = aaa()
b(); //2
b(); //3  即时局布变量又能累加
alert(a) //a is not defined,说明a是局部变量*/

問題:如何把以上函數聲明改寫為函數表達式?

//常識: 
function aaa() {
  alert(1)
}
aaa()
//該寫為函數表達式:
(function () { //可以把aaa去掉
  alert(1)
}) ();

所以問題的答案是:
a.模塊化代碼

var aaa = (function () { //aaa是函数执行完后的返回值
  var a = 1;
  return function () {
    a++
    alert(a)
  }
}) ()
aaa(); //2  aaa(),执行的即是return 后的函数
aaa(); //3  a在外面调用不到,又能累加,模块化代码;

問題:定義函數的私有方法?

var aaa = (function () {
  var a = 1; //a是局部变量,bbb,ccc是它的私有方法 在aaa函数外面调用不到
  function bbb() {
    a++;
    alert(a)
  }
  function ccc() {
    a++;
    alert(a)
  }
  return {   //特別留意:定義形式
    b: bbb,
    c: ccc
  }
}) ()
aaa.b() //2  調用
aaa.c() //3  調用
alert(a) //not defined
alert(bbb) //not defined
alert(ccc) //not defined

b.在循環中找到對應元素的索引

<ul>
    <li>第0個li</li>
    <li>第1個li</li>
    <li>第2個li</li>
</ul>
var li = document.getElementsByTagName('li')
for (var i = 0; i < li.length; i++) {
  li[i].onclick = function () {
    alert(i) //都是3 ,循环执行结束时i=3,alert还未执行,当去点击时才会执行
  }
}

解決一:循環中i當參數傳進來

for (var i = 0; i < li.length; i++) {
  (function (i) { //1、先写匿名函数,当去执行时把i传进来
    li[i].onclick = function () { //2、内部函数可以调用外部函数传进来的参数;
      alert(i)
    }
  }) (i)
}

解決二:寫return返回

for (var i = 0; i < li.length; i++) {
  li[i].onclick = (function (i) { //1、当点击时,3、执行完时 5、然后把i传进来
    return function () { //4、写return返回值
      alert(i)
    }
  }) (i) //2、先执行一次 5、把i传进去 
}      //7、因循环时,执行完毕后i已经存在内存中的i,调用时不是外面的i,所以能弹出0,1,2

iE下可能引发内存泄漏
問題描述:当一个变量box由dom获取或数组对象获取时,它的属性如onclick去引用一个内部fn,内部函数的对像box是去引用外面的,即会引发内部泄漏,IE下首尾互相引用时
解決:onunload後把對像變為null; 提前在外面引用,之後對象置null

var box = document.getElementById('box')
box.onclick = function () {
  alert(box.id)
}

解決一:

window.onunload = function () {
  box.onclick = null; //onunload后把box变为null即可
}

解决二:提前在外面引用,比如 var id = box.id,里面调用alert(id),之后對象置null;

var id = box.id
box.onclick = function () {
  alert(id)
}
box = null;

簡單枚舉 | iframe

枚舉:
1、用for從眾多可能出現的答案中找匹配;
2、即通過if找正確的答案。

<p>
    <span>A</span>
    <span>B</span>
    <span>C</span>
    <span>D</span>
    <span>E</span>
</p>
<p>
    <span>A</span>
</p>
<p>
    <span>E</span>
    <span>E</span>
    <span>E</span>
    <span>E</span>
    <span>E</span>
</p>
var _p = document.getElementsByTagName('p')
var _span0 = _p[0].getElementsByTagName('span')
var _span1 = _p[1].getElementsByTagName('span')
var _span2 = _p[2].getElementsByTagName('span')
//枚舉算法,用for從眾多可能出現答案的條件中找匹配,即通過if正確的答案
for (var i = 1; i <= 9; i++) { //A
  for (var j = 0; j <= 9; j++) { //B
    for (var k = 0; k <= 9; k++) { //C
      for (var m = 0; m <= 9; m++) { //D
        for (var n = 0; n <= 9; n++) { //E
          var a = 10000 * i + 1000 * j + 100 * k + 10 * m + n; //_p[0]
          var b = i; //_p[1]
          var c = n * 111111; //_p[2]
          if (a * b == c) {
            _span0[0].innerHTML = i;
            _span0[1].innerHTML = j;
            _span0[2].innerHTML = k;
            _span0[3].innerHTML = m;
            _span0[4].innerHTML = n;
            _span1[0].innerHTML = i;
            for (var z = 0; z < _span2.length; z++) {
              _span2[z].innerHTML = n
            }
          }
        }
      }
    }
  }
}

枚舉小例:
點擊任意a,當前innerHTMl加到ul,若已存在不加[方法返回false],若不存在添加[方法返回true]
要點,創建方法檢測當前點擊innerHTMl是否存在於頁面
拓展:如已存在,則把當前點擊項移到最前面

<a href="javascript:;">北京</a>
<a href="javascript:;">上海</a>
<a href="javascript:;">深圳</a>
<a href="javascript:;">廣州</a>
<a href="javascript:;">杭州</a>
<a href="javascript:;">天津</a>
<a href="javascript:;">成都</a>
<ul id="ul">
</ul>
var a = document.getElementsByTagName('a')
var ul = document.getElementById('ul')
var li = ul.getElementsByTagName('li')
for (var i = 0; i < a.length; i++) {
  a[i].onclick = function () {
    if (mj(this.innerHTML)) { //如果當前innerHTML 沒有相同返回 true
      var _li = document.createElement('li');
      _li.innerHTML = this.innerHTML;
      if (!li[0]) {
        ul.appendChild(_li)
      } 
      else {
        ul.insertBefore(_li, li[0])
      }
    } 
    else { //有相同返回false,無法添加,但可以把當前點擊移到最前面
      mj2(this.innerHTML)
    }
  }
}
//檢測方法
function mj(txt) {
  var result = true;
  for (var i = 0; i < li.length; i++) {
    if (li[i].innerHTML == txt) { //可能出現的找匹配,如果已存在
      result = false
    }
    //  else{result = true;}//切換即可添加 特別留意理解這句放與不放
  }
  return result;
}
function mj2(txt) { //當前新添加移到最上面
  for (var i = 0; i < li.length; i++) { //眾多可能出現的
    if (li[i].innerHTML == txt) { //創建條件
      ul.insertBefore(li[i], li[0])
    }
  }
}
}



操作iframe

1、_iframe.contentWindow.document.getElementById('box') 無兼容性

2、_iframe.contentDocument.getElementById('box') IE6/7不支持
主html

<input type="button" value="操作window"/>
<input type="button" value="操作document"/>
<input type="button" value="該變iframe大小一"/>
<input type="button" value="該變iframe大小二"/>
<iframe src="iframe-被嵌套1.html" frameborder="0" scrolling="no"></iframe>
<iframe src="iframe-反操作.html" frameborder="0"></iframe>
<div id="box">這是正常文檔的內容,被iframe反操作的box</div>
var _iframe = document.querySelectorAll('iframe') [0]
var _iframe2 = document.querySelectorAll('iframe') [1]
var inp = document.querySelectorAll('input') [0]
var inp2 = document.querySelectorAll('input') [1]
var inp3 = document.querySelectorAll('input') [2]
var inp4 = document.querySelectorAll('input') [3]
inp.onclick = function () {
  console.log(_iframe.contentWindow); //iframe的window對象,無兼容性
  _iframe.contentWindow.document.getElementById('box').style.background = 'red'
}
inp2.onclick = function () {
  _iframe.contentDocument.getElementById('box').style.color = '#fff'
  //IE6/IE7不支持
}

iframe-被嵌套1.html

<div id="box">這是iframe裏的內容,被所調用的操作</div>
<div style="width: 300px;height: 300px;background: #f90;"></div>

iframe反操作

iframe-反操作.html
1、window.parent 獲取父層頁面;
2、window.top 獲取最頂層頁面;
3、iframe防止被嵌套;if(window!=window.top){ window.top.location.href = window.location.href; }

<input type="button" value="iframe反操作" />
<div style="width: 200px;height: 200px;background: green;"></div>
var inp = document.querySelector('input')
//獲取父層的頁面 window.parent
inp.onclick = function () {
  window.parent.document.getElementById('box').style.background = 'peru' //無兼容性
}
//window.top最頂層
window.top.document.getElementById('box').style.color = '#fff'

//防止被嵌套
if (window != window.top) { //當前window !=最頂層window
  window.top.location.href = window.location.href; //跳轉至頁面
}

iframe.onload 事件

var _iframe = document.createElement('iframe')
_iframe.src = 'iframe-反操作.html'
document.body.appendChild(_iframe)
//        _iframe.onload = function () {
//            alert(123)
//        }
//ie: iframe.onload 事件 只能用綁定的形式;
_iframe.attachEvent('onload', function () {
  //alert(123)
})

iframe 設置寬高
如多頁面切換需設置定時器,否則會因執行太快而產生bug設置失效

function changeHeight() {
  setTimeout(function () { 
    _iframe.height = _iframe.contentWindow.document.body.offsetHeight //本頁面展示的高 = iframe頁面展示的高
  }, 100)
}

//使用
inp3.onclick = function () {
  _iframe.src = 'iframe-被嵌套1.html'
  changeHeight()
}
inp4.onclick = function () {
  _iframe.src = 'iframe-反操作.html'
  changeHeight()
}
//JQuery获得iframe的window对象
var win = $('#ifr')[0].contentWindow;  

//JS原生方法获得iframe的window对象
document.getElementById("ifr").contentWindow;  

$('#ifr')[0].contentWindow 和 document.getElementById("ifr") ;

var ifr1 = document.getElementById("ifr");  
var ifr2 = window.frames[0];  
ifr2.frameElement 是等价于 ifr1;

JS性能基礎

DOM性能優化
DOM :getElementById innerHTMl......
ECMA:if for ......
BOM:location open close......

var box = document.getElementById('box')
var str = '';
for (var i = 0; i < 5000; i++) {
  str += 'a'
}
//獨立js中操作
box.innerHTML = str //DOM與jq只交互1次,

chrome:dom方法appendChild要比直接innerHTMl性能要好,其他都為innerHTMl性能較好。



DOM 與JS

* 1、減少DOM操作str cloneNode()
* 2、訪問元素集合,盡量使用局部變量 len
* 3、盡量只獲取元素節點的方法 如若childNodes 元素節點,文本節點, children來替換
* 4、選擇器API querySelector/querySelectorAll
//片斷一
for (var i = 0; i < 10000; i++) {
  var li = document.createElement('li')
  li.innerHTML = 'li'
  ul.appendChild(li)
}
//片斷二
for (var i = 0; i < 10000; i++) {
  str += '<li></li>'
}
ul.innerHTML = str;
//片斷三
var li = document.createElement('li')
li.innerHTML = 'li'
console.time('hello3')
for (var i = 0; i < 10000; i++) {
  var liN = li.cloneNode(true);//使用cloneNode
  ul.appendChild(liN)
}
//片斷四
for (var i = 0; i < li.length; i++) {
  li[i].innerHTML = 'li';
}
//片斷五
for (var i = 0, len = li.length; i < len; i++) {
  li[i].innerHTML = 'li';
}
 var box = document.getElementsByTagName('li')
 var box = document.querySelectorAll('#box li')



DOM 與瀏覽器

* 1、重排、改變頁面內容 ,如通過js該變位置寬高或形狀
* 2、重繪:瀏覽器顯示內容,如重排結束後需要顯示效果,如只該變背景,不改變寬高,則只發生重繪,不會發生重排
* 3、添加順序:盡量在appendChild前添加操作,
* 4、合並dom操作:利用cssText
* 5、緩存布局信息
* 6、文檔碎片 createDocumentFragment()
//片斷六
for (var i = 0; i < 5000; i++) {
  var li = document.createElement('li')
  ul.appendChild(li)
  li.innerHTML = 'li'
}
//片斷七
for (var i = 0; i < 5000; i++) {
  var li = document.createElement('li')
  li.innerHTML = 'li' //加在appendChild前面,不會發生重排重繪過程
  ul.appendChild(li)
}
li.style.width = '100px'
li.style.height = '100px'
li.style.background = 'red'
//推薦
li.style.cssText = 'width:100px;height:100px;background:red;'
//片斷八
setInterval(function () {
  box.style.left = box.offsetLeft + 1 + 'px'
  box.style.top = box.offsetTop + 1 + 'px'
}, 30)
//片斷九
var L = box.offsetLeft,T = box.offsetTop;
setInterval(function () {
  L++;
  T++;
  box.style.left = L + 'px'
  box.style.top = T + 'px'
}, 30)
//片斷十
var ul2 = document.getElementById('ul2')
for (var i = 0; i < 5000; i++) {
  var _li = document.createElement('li')
  ul2.appendChild(_li)
}

//片斷十一
var ul2 = document.getElementById('ul2')
var _Frag = document.createDocumentFragment(); //創建一個box,每次添加裏都先加到box裏
for (var i = 0; i < 5000; i++) {
  var _li = document.createElement('li')
  _Frag.appendChild(_li)
}
ul2.appendChild(_Frag) //添加完後再加把box加到ul2裏



DOM與事件:事件委託

DOM與前端模板:能更好的對邏輯和視力分離,MVC架構的基礎 如jquery.tmpl

基礎事件委託 | 歷史管理 | firebug | 快速排序 |遞歸 筆記

事件委託:利用冒泡原理,把事件添加至父級上,觸發執行效果;
好處:1、提高性能;2、新添加元素還會有之前的事件,如新浪圍脖發布效果;
操作要點:1、添加事件到父級;2、找到當前的事件源,在事件源觸發;
兼容寫法: ie:window.event.srcElement 標準:window.event.target
之後使用nodeName判斷標籤源;

<input type="button" value="add" id="inp"/>
<ul id="ul1">
    <li>111</li>
    <li>222</li>
    <li>333</li>
    <li>444</li>
</ul>
var ul = document.getElementById('ul1')
var li = ul.getElementsByTagName('li')
ul.onmouseover = function (ev) {
  var ev = ev || event;
  var target = ev.target || ev.srcElement
  if (target.nodeName.toLowerCase() == 'li') {
    target.style.background = 'red'
  }
}
ul.onmouseout = function (ev) {
  var ev = ev || event;
  var target = ev.target || ev.srcElement //當前操作事件源,比如移動到li即li,移動到ul即ul
  if (target.nodeName.toLowerCase() == 'li') { //只移動到li觸發
    target.style.background = ''
  }
}
//新添加元素還會有之前的事件,如使用for新加元素不會綁定事件
var inp = document.getElementById('inp')
var i = 0;
inp.onclick = function () {
  i++;
  var oli = document.createElement('li')
  oli.innerHTML = 555 * i;
  ul.appendChild(oli);
}



歷史管理

1、onhashchange:事件,當hash有變化時觸發;

2、histoty:事件
存:pushState(數據,標題[未實現],網址顯示)
讀:onpopState事件 event state;注意:網址顯示虛假,使用時須服務器指定

onhashchange簡陋例子

<input type="button" value="生成隨機數" id="inp"/>
<div id="box"></div>
var inp = document.getElementById('inp')
var box = document.getElementById('box')
inp.onclick = function () {
  var num = randomNum(49, 7); //49選7
  box.innerHTML = num;
  window.location.hash = num; //window.location.hash添加值
}
window.onhashchange = function () {
  var num = window.location.hash.substring(1) || '';
  box.innerHTML = num; //當改變時觸發;
}
//隨機數生產方法封裝
function randomNum(alls, now) {
  var arr = []
  var Newarr = []
  for (var i = 1; i <= alls; i++) {
    arr.push(i);
  }
  for (var i = 0; i < now; i++) {
    Newarr.push(arr.splice(Math.floor(Math.random() * arr.length), 1))
  }
  return Newarr;
}

網址變更

var inp = document.getElementById('inp')
var box = document.getElementById('box')
var obj = {} //利用對象
inp.onclick = function () {
  var num = randomNum(49, 7);
  box.innerHTML = num;
  var oRD = Math.random(); //生成隨機數 0.xxxxxxx
  obj[oRD] = num; //對像對應關係,每一個隨機數對應每一個num;
  window.location.hash = oRD; //實際上相當於處理下標元素
}
window.onhashchange = function () {
  var num = obj[window.location.hash.substring(1) || ''];
  box.innerHTML = num; //所以這裏需要套obj, '' 為防止undefined
}

histoty例子

var inp = document.getElementById('inp')
var box = document.getElementById('box')
var i = 1;
inp.onclick = function () {
  var num = randomNum(49, 7);
  box.innerHTML = num;
  history.pushState(num, '', i++); //存到history,這裏第三個參數為可選,可不填寫
}
window.onpopstate = function (e) { //當改變時執行讀取
  e = e || event
  var num = e.state || ''; 
  box.innerHTML = num;
}



跨域
ajax: XMLHttpRequest();不能跨域
jsonp:json + padding [把json放在盒子裏]<blockquote>
1、document.domain = 'xx.com'

2、服務器代理:XMLHttpRequest代理文件

3、script標籤:jsonp

4、location.hash

5、window.name

6、flash

7、html5 postMessage

</blockquote>

function createJS(sUrl){
    var _Script = document.createElement('script')
    _Script.src = sUrl;
    document.getElementsByTagName('head')[0].appendChild(_Script);
}
createJS('jsonp.js')
//createJS('jsonp.js?callback = box')

function box(){
    alert(json.name);
}
//box({name:elmok})  放到jsonp.js文件裏

hash值

<iframe src="xxx.php#key1=value1&key2=value2" frameborder="0"></iframe>
parent.location.hash = self.location.hash; //ie chrome不支持

firebug

console.group('')
console.log('abc')
console.groupEnd('')

console.dirxml(box) //顯示當前元素代碼結構

console.assert(20 == '20') //斷言假提示,成功不提示

function a(){return b()};
function b(){return c()};
function c(){console.trace();return 1}; //當前fn執行過程
a();

console.time('計時器')
    for(var i=0;i<10000;i++){
    }
console.timeEnd('計時器')  //計算fn執行時間

function a() {  //部分fbug無法顯示!
  for (var i = 0; i < 10; i++) {
    b(); //調用10次b
  }
  for (var i = 0; i < 5; i++) {
    c(); //調用5次c
  }
  function b() {
    var b = 10;
  }
  function c() {
    var c = 5;
  }
}
console.profile();
a();
console.profileEnd();

快速排序

30 12 5 6 9 18 57 2
取基准點9,9跟其他數比, [小於] 9 [大於]
5 6 2 9 30 12 18 57
取基准點 30 [小於] 30 [大於]
5 6 2 9 12 18 30 57
...以此類推
利用遞歸進行下次比較

//方法封裝

function quickSort(arr) {
  if (arr.length <= 1) { //有可能為0
    return arr;
  }
  var num = Math.floor(arr.length / 2) //向下取整,找到中間數
  var numV = arr.splice(num, 1); //找到基準點的數值
  var left = []; //存小於基准點的值
  var right = []; //存大於基準點的值
  for (var i = 0; i < arr.length; i++) {
    if (arr[i] < numV) {
      left.push(arr[i]);
    } 
    else {
      right.push(arr[i]);
    }
  }
  //以上一次操作,下面再利用遞歸原理
  return quickSort(left).concat([numV], quickSort(right));
  //左邊.concat(基准數,右邊)
}
alert( quickSort([30,12,5,6,9,18,57,2]) )



函数声明与函数表达式

函数声明:function 函数名(){}

函数表达式:function 函数名(){},命名与匿名表达式;

function aaa() {} //函数声明

var a = function aaa() {} //命名函数表达式
var b = function () {} //匿名函数表达式

(function aaa() {}) //函数表达式
~function aaa() {} //函数表达式
-function aaa() {} //函数表达式
+function aaa() {} //函数表达式
~function aaa() {} //函数表达式

区别:1、函数表达式可直接后面加括号执行,函数声明不行;

 2、函数声明可以被提前解析出来;<br />

在一些语句中若想执行不同函数时,不要用函数声明,用函数表达式;

if (true) {
  function bbb() {
    alert(1)
  }
} 
else {
  function bbb() {
    alert(2)
  }
}
a(); //ff、IE11正常弹1,其它弹2 [因为函数声明被预解析],

所以修改为:

if (true) {
  var a = function bbb() {
    alert(1)
    alert(typeof bbb)
  }
} 
else {
  var a = function bbb() {
    alert(2)
  }
}
a();//正常都弹1
bbb() //IE8下能弹出2,其它出错 [IE8下解析成两个函数 a(), bbb()]bbb()外面找不到,里面可找到,外面不要去调用函数表达式;



對象引用
遞歸算法:1、函數調用函數,永遠不會return,遞的過程

2、最後一次判斷一個終止條件,可以執行歸的動作。終止條件必須寫在最前面

典型例子:階乘

function factorial(n) {
  if (n == 1) { return 1 } //條件,最後一次為1 終止條件寫在最前面
  return n * factorial(n - 1);
}
console.log(factorial(5));
var a = 5;
var b = a;
b += 3;
alert(b) //b的改变不会影响到a,赋值类型
var arr = [1,2,3]
var arrN = arr //arrN與arr指向同一地址
arrN.push(4)
console.log(arrN); //[1,2,3,4]
console.log(arr); //[1,2,3,4] 影响到arr,对象和函数都是地址引用的关系
var arr = [1,2,3]
var arrN = arr
arrN = [1,2,3,4] //相当于赋另一块地址给arrN,arrN重新战胜一块地址,与arr分离
console.log(arrN); //[1,2,3,4]
console.log(arr); //[1,2,3]
var obj = {
  a: 10
}
var objN = obj;
objN.a = 20;
console.log(obj.a); //20,复制对象的问题,改变objN,同时影响到obj*/

第一種:淺拷貝

var obj = {
  a: 10
}
function copyO(obj) {
  var newO = {
  };
  for (var attr in obj) {
    newO[attr] = obj[attr]; //所有值都复制给新对象
  }
  return newO
}
var objN = copyO(obj);
objN.a = 20;
console.log(obj.a); //10  只有一層不會影響

第二種:深拷貝

var obj = {
  a: {b: 10} // 可能會有無數層
}
function deepcopyO(obj) { //深拷貝 遞歸
  if (typeof obj != 'object') { //什麼時候不是對象即能返回
    return obj;
  }
  var newO = {};
  for (var attr in obj) {
    newO[attr] = deepcopyO(obj[attr]); //進入下一層拷貝
  }
  return newO
}
var objN = deepcopyO(obj);
objN.a.b = 20;
console.log(obj.a.b); //10,再多層也不影響

基礎行為 | 鼠標滾動 | Cookie 筆記

阻止默認行為
return false: 1、適用於obj.on[xxx] = fn所觸發的行為 2、attachEvent綁定;
e.preventDefault():適用於addEventListener綁定的事件。

function (ev) {
  ev = ev || event
  if (ev.preventDefault) {
    ev.preventDefault();
  } 
  else {
    ev.returnValue = false;
    return false;
  }
}

鼠標滾動
ie/chrome : e.onmousewheel
底下 e.wheelDelta 數字類型:上 : 120 , 下 : -120
ff : DOMMouseScroll 必須用addEventListener綁定 [ ff認為給obj添加一個onmousewheel屬性 ]
底下 e.detail 數字類型:上 : -3,下 : 3


box.onmousewheel = fn
if (box.addEventListener) { //做判斷,否則ie8報錯
  box.addEventListener('DOMMouseScroll', fn, false)
}


function fn(e) { //updown為true滾上,為false滾下
  var updown = true;
  var e = e || event;
  if (e.wheelDelta) {
    updown = e.wheelDelta > 0 ? true : false;
  } 
  else {
    updown = e.detail < 0 ? true : false
  }
  if (updown) {
    // do something
  } else {
    // do something
  }
  return false
  if (e.preventDefault) {
    e.preventDefault()
  }
}

Cookie
1、不同瀏覽器位置不同;
2、cookie以域名形式存;
3、cookie數據可設置名字,j.name = elmok;
4、通過document.cookie 來獲取當前網站下的cookie,得到字符串形式值;
5、域名下存放多個cookie ,不同瀏覽器不同;
6、每個cookie存放內容大小也是有限制,不同瀏覽器不同;
7、長時間存放cookie需要設置時間;document.cookie = '名稱 = 值;expires='+時間【必須是字符串格式】;toGMTString
8、cookie默認臨時存儲,當瀏覽器關閉進程時自動銷毀;
9、有特殊如n,使用encodeURI/decodeURI;

//設置一個cookie
var _Date = new Date();
_Date.setDate(_Date.getDate() + 7)        //7天以後
document.cookie = 'username = elmok;expires=' + _Date.toGMTString();
console.log(_Date);// Date {Fri Aug 21 2015 22:24:41 GMT+0800};

console.log(encodeURI('你好'))
console.log(decodeURI('%E4%BD%A0%E5%A5%BD'))

//方法封裝
function getCookie(key) {
  var arr = document.cookie.split('; ')
  for (var i = 0; i < arr.length; i++) {
    var arrN = arr[i].split('=')
    if (arrN[0] == key) {
      return decodeURI(arrN[1]);
    }
  }
}

function setCookie(key, value, t) {
  var _Date = new Date();
  _Date.setDate(_Date.getDate() + t)
  document.cookie = key + '=' + value + ';expires=' + _Date.toGMTString()
}

function removeCookie(key) {
  setCookie(key, '', - 1);
}

getCookie('username');
setCookie('sex', '男', 10);
removeCookie('sex')

//ex
var _uname = document.getElementById('username')
var _login = document.getElementById('login')
var _del = document.getElementById('del')
if (getCookie('username')) {
  _uname.value = getCookie('username')
}
_login.onclick = function () {
  alert('ok')
  setCookie('username', _uname.value, 5)
}
_del.onclick = function () {
  removeCookie('username')
  _uname.value = '';
}

基礎焦點 | 事件 | 健盤 | 移動 | 拖拽 筆記

焦点事件

txt1.onfocus = function () {
  if (this.value == 'please input something') {
    this.value = ''
  }
}
txt1.onblur = function () {
  if (this.value == '') {
    this.value = 'please input something'
  }
}

// obj.focus()//给指定元素设置焦点
// obj.blue() //取消元素焦点
// obj.select() /选择指定元素的文本

btn1.onclick = function () {   txt1.select() } 

事件对象
1、event:事件对象,当一个事件发生时,和当前对象发生的这个事件有关的一些详细的信息都会保存到一个指定地方:event对象供我们在需要时调用
2、如果一个函数被事件调用,那么这个函数定义的第一个参数就是事件对象

for (var attr in ev) {   console.log(attr + '=' + ev[attr]); } 

FF无even内部定义全局对象
div鼠标移动

document.onmousemove = function (ev) {
  var ev = ev || event;
  var sct = document.documentElement.scrollTop || document.body.scrollTop;
  var scl = document.documentElement.scrollLeft || document.body.scrollLeft;
  box.style.left = ev.clientX + scl + 'px'
  box.style.top = ev.clientY + sct + 'px'
}

事件流:1、事件冒泡;2、事件捕获

function fn1() {
  alert(this.id)
}
box1.onclick = fn1; //给元素加函数;//告诉box1,如果他接收到一个点击事件,那么他就去执行fn1  //事件函数绑定
box2.onclick = fn1;
box3.onclick = fn1;
//从中间截断,即不会再有冒泡,box3也冒泡不到box1
box2.onclick = function (ev) {
  var ev = ev || event
  ev.cancelBubble = true;
}
var box = document.getElementById('box')
var inp = document.getElementById('btn')
inp.onclick = function (ev) {
  box.style.display = 'block'
  //阻止inp的冒泡 阻止当前对象的当前事件冒泡  即只阻止onclick,如onmouseover等都会有冒泡
  var ev = ev || event
  ev.cancelBubble = true;
}
document.onclick = function () {
  box.style.display = 'none'
}
//FB显示隐藏
var div1 = document.getElementById('div1')
div1.onmouseover = function () { //移到div2时,冒泡到div1了,所以能显示
  this.style.left = 0
}
div1.onmouseout = function () {
  this.style.left = - 100 + 'px'
}

1、事件绑定第一种形式:obj.onclick = fn; 多个绑定会覆盖前面绑定;
2、事件绑定第二种形式:

IE:obj.attachEvent(事件名,事件函数) document.attachEvent('onclick',fn1) IE7下顺序会相反
   <blockquote> 1)无捕获
    2)事件名称有on
    3)IE7下事件执行顺序相反
    4)this指向window
    5)使用call,函数下一个方法,改变一个函数运行中this指向,第二个开始就是原来函数的参数
ockquote>
标准下:obj.addEventListener(事件名,事件函数,是否捕获?) obj.addEventListener('click','fn1', true)
ckquote> 1)有捕获<br />
    2)事件名称无on<br />
    3)顺序正常<br />
    4)this指向触发该函数的对象</blockquote>
//事件绑定方法封装
function on(obj, evt, fn) {
  if (obj.addEventListener) {
    obj.addEventListener(evt, fn, false)
  } 
  else {
    obj.attachEvent('on' + evt, function () {
      fn.call(obj);
    })
  }
}
on(document, 'click', fn1)
function fn1() {
  alert(this)
}
<div id="box1">
    <div id="box2">
        <div id="box3"></div>
    </div>
</div>
//先出后进
box1.addEventListener('click', function () {
  alert(1)
}, false)
box1.addEventListener('click', function () {
  alert(3)
}, true)
box3.addEventListener('click', function () {
  alert(2)
}, false)

取消事件绑定
ie:obj.adttachEvent(事件名称,事件函数)
标准 : obj.removeEventListener(事件名称,事件函数,是否捕获)

document.onclick = null;
document.removeEventListener('click',fn1,false)

健盘事件
onkeydown:按按下时触发
onkeyup:按健抬起时触发
event.keyCode:数字类型,健值
ctrlKey,shiftKey altKey ,boolean值,当一个事件发生时,如果ctrl || shift || alt是按下的状态返回true,否则返回false

document.onkeydown = function (ev) {
  var ev = ev || event
  alert(ev.keyCode)
}
document.onclick = function (ev) {
  var ev = ev || event
  alert(ev.ctrlKey)
}
txt1.onkeyup = function (ev) {
  var ev = ev || event
  //alert(this.value)
  if (this.value != '') {
    if (ev.keyCode == 13) {
      var oli = document.createElement('li')
      oli.innerHTML = this.value;
      if (ul1.children[0]) { //如果存在子元素
        ul1.insertBefore(oli, ul1.children[0])
      } 
      else { //如果不存在子元素
        ul1.appendChild(oli)
      }
    }
  }
}

移動元素,按健連續觸發延遲問題

<div id="div1" style="width: 100px; height: 100px; background: #bf0000; position: absolute;"></div>
var div1 = document.getElementById('div1')
//有焦点的元素才能够接收健盘事件;
var timer = null;
var onoff = true; //設置開關
var clw = document.documentElement.clientWidth;
var clh = document.documentElement.clientHeight;
document.onkeydown = function (e) { //把健盘事件加到document上
  e = e || event;
  switch (e.keyCode) {
    case 37: //左
      if (onoff) {
        timer = setInterval(function () {
          var dl = div1.offsetLeft;
          if (dl < 10) {
            dl = 10
          }
          onoff = false
          div1.style.left = dl - 10 + 'px'
        }, 14)
      }
      break;
    case 38://上
      if (onoff) {
        timer = setInterval(function () {
          var dt = div1.offsetTop
          if (dt < 10) {
            dt = 10
          }
          onoff = false
          div1.style.top = dt - 10 + 'px'
        }, 14)
      }
      break;
    case 39://右
      if (onoff) {
        timer = setInterval(function () {
          var dl = div1.offsetLeft;
          if (dl > (clw - div1.offsetWidth - 10)) {
            dl = clw - div1.offsetWidth - 10
          }
          onoff = false
          div1.style.left = dl + 10 + 'px'
        }, 14)
      }
      break;
    case 40://下
      if (onoff) {
        timer = setInterval(function () {
          var dt = div1.offsetTop
          if (dt > (clh - div1.offsetHeight - 10)) {
            dt = clh - div1.offsetHeight - 10
          }
          onoff = false
          div1.style.top = dt + 10 + 'px'
        }, 14)
      }
      break;
  }
}
document.onkeyup = function () {
  onoff = true;
  clearInterval(timer);
}

事件默認行為: return false;
自定義右健菜單

document.oncontextmenu = function (e) {
  var e = e || event;
  var scl = document.documentElement.scrollLeft || document.body.scrollLeft;
  var sct = document.documentElement.scrollTop || document.body.scrollTop;
  box.style.display = 'block'
  box.style.left = e.clientX + scl + 'px'
  box.style.top = e.clientY + sct + 'px'
  return false;
}
document.onclick = function () {
  box.style.display = 'none'
}

元素拖拽,方法封裝
拖拽過程如果有文字被選中會產生問題:
原因:默認行為
標準下:阻止拖拽默認行為;return false;
ie:全局捕獲 obj.setCapture() ; 當給一個元素設置全局捕獲以後,此元素會監聽後續發生的所有事件,當有事件發生時就會被當前設置了全局捕獲的元素觸發;

inp1.onclick = function(){
    alert(1);
}
inp2.onclick = function(){
    alert(2);
}
if(inp1.setCapture){
inp1.setCapture()
}  //第一次點任意地方都將觸發alert(1);
function drag(obj) {
  var cw = document.documentElement.clientWidth;
  var ch = document.documentElement.clientHeight;
  obj.onmousedown = function (e) {
    var e = e || event;
    var disW = e.clientX - this.offsetLeft;
    var disH = e.clientY - this.offsetTop;
    //解決IE文字選中後移動問題:
    if (obj.setCapture) {
      obj.setCapture();
    }
    document.onmousemove = function (e) {
      var e = e || event;
      var cw_w = e.clientX - disW;
      var ch_h = e.clientY - disH
      if (cw_w < 0) {
        cw_w = 0
      } 
      else if (ch_h < 0) {
        ch_h = 0
      } 
      else if (cw_w > cw - obj.offsetWidth) {
        cw_w = cw - obj.offsetWidth
      } 
      else if (ch_h > ch - obj.offsetHeight) {
        ch_h = ch - obj.offsetHeight
      }
      obj.style.left = cw_w + 'px'
      obj.style.top = ch_h + 'px'
    }
    document.onmouseup = function () {
      document.onmousemove = null;
      //解決IE8抬起鼠標,釋放全局捕獲 releaseCapture();
      if (obj.releaseCapture) {
        obj.releaseCapture()
      }
    }
    return false; //down事件觸發時陰止默認行為;
  }
}

基礎DOM | children | offset | 表格 | 表單 | BOM 筆記

背景

<ul id="ul">
    <li>001</li>
    <li>002</li>
    <li>003</li>
    <li>004</li>
</ul>

1、childNodes包含文本、元素、属性、等节点;
2、children只包含元素节点

var ul = document.getElementById('ul')
console.log( ul.childNodes.length ) //9
console.log( ul.children.lenght )  //4

// alert(ul.childNodes[0].nodeType)
// alert(ul.attributes.length)
//alert(ul.attributes[0].name)
//alert(ul.attributes[0].value)

使用children,IE7不会包含非法嵌套内容;
兼容写法:first/last/next/prev

var _first = ul.firstElementChild || ul.firstChild;
var _last = ul.lastElementChild || ul.lastChild;
var _next = _first.nextElementSibling || _first.nextSibling;
var _prev = _last.previousElementSibling || _last.previousSibling;

parentNode 无兼容性问题,得到的父节点只有一个;

<ul id="ul">
    <li>001 <a href="javascript:;">DEL</a></li>
    <li>002 <a href="javascript:;">DEL</a></li>
    <li>003 <a href="javascript:;">DEL</a></li>
    <li>004 <a href="javascript:;">DEL</a></li>
</ul>
var a = ul.getElementsByTagName('a')
for(var i=0;i<a.length;i++){
    a[i].onclick = function(){
        this.parentNode.style.display = 'none'
    }
}

offsetParent offsetLeft offsetTop

<div id="div1">
    <div id="div2">
        <div id="div3"></div>
    </div>
</div>
    var div1 = document.getElementById('div1')
    var div2 = document.getElementById('div2')
    var div3 = document.getElementById('div3')
console.log( div3.offsetLeft ) //自身无定位,则指向有定位父级,如果没有定位默认body
//自身有定位,父级无定位,则IE7指向html,其它指向body
//父级设置zoom,IE7指向html,其它指向body
console.log( div2.currentStyle.hasLayout ) //当前元素是否触发layout 
<div id='box' style='width:99px;height:99px;border:1px solid red;'></div>
var box = document.getElementById('box')
console.log( box.style.width )
console.log( box.clientWidth ) //可視區寬度 樣式寬+padding
console.log( box.offsetWidth ) //可視區寬+border

取得元素在頁面上left top方法

function getPos(obj) {
  var pos = { left: 0,top: 0 };
  while (obj) {
    pos.left += obj.offsetLeft;
    pos.top += obj.offsetTop;
    obj = obj.offsetParent;
  }
  return pos;
}
getPos(box).left;
getPos(box).top;

屬性操作
1、obj.attr 無法操作自定義屬性
2、obj['attr'] 無法操作自定義屬性
3、obj.getAttribute(attr) 可操作自定義屬性,如_a = '123'
4、_img.src _img['src'] 返回全鏈接值 _img.getAttribute('src') 返回相對鏈接值,IE7下還是返回全鏈接值

插入刪除
父級.appendChild( 要插入的元素 );
父級.removeChild( 要刪除的元素 );
父級.insertBefore( 新元素,被插入的元素 ) ;即在指定元素前面插入一個新元素;
父級.replaceChild( 新節點,被替換節點 );
obj.cloneNode( true ); 複製節點

兼容getClassName方法

function getClassName(parent, tagName, className) {
  var aEls = parent.getElementsByTagName(tagName)
  var arr = []
  for (var i = 0; i < aEls.length; i++) {
    var aClassName = aEls[i].className.split(' '); //当前classname拆分成数组
    for (var j = 0; j < aClassName.length; j++) {
      if (aClassName[j] == className) { //如果第j个class == classname
        arr.push(aEls[i]) //则把当前第i个class push进来
        break; //如果class='box box'相同名字,找到一个跳出for
      }
    }
  }
  return arr;
}
getClassName(document, 'li', 'box');

兼容addClass方法

function addClass(obj, className) {
  if (obj.className == '') { //原本无
    obj.className = className;
  } 
  else { //原本有
    var arrClassName = obj.className.split(' ');
    var _index = arrIndexOf(arrClassName, className);
    if (_index == - 1) { //不存在
      obj.className += ' ' + className;
    }
  }
}
//判斷一個數組裏是否存在元素
function arrIndexOf(arr, v) {
  for (var i = 0; i < arr.length; i++) {
    if (arr[i] == v) {
      return i; //当前重複的值出现位置
    }
  }
  return - 1;
}

addClass(box, 'box111');

兼容removeClass方法

function removeClass(obj, className) {
  if (obj.className != '') {   //如果有class
    var arrClassName = obj.className.split(' ');
    console.log(arrClassName);
    var _index = arrIndexOf(arrClassName, className);
    if (_index != - 1) {     //如果有需要移除的class
      arrClassName.splice(_index, 1); //删除数组裏需要移除的
      obj.className = arrClassName.join(' ');//再把處理完的數組class給obj
    } 
  }
}
//判斷一個數組裏是否存在元素
function arrIndexOf(arr, v) {
  for (var i = 0; i < arr.length; i++) {
    if (arr[i] == v) {
      return i; //当前重複的值出现位置
    }
  }
  return - 1;
}

removeClass(box, 'box3')

表格基本操作
tHead 表格頭
tHodie 表格正文 複合
tFoot 表格尾
rows 行 複合
cells 列 複合
數據操作:

var tb = document.getElementsTagName('table')[0];
console.log(tb.tBodies[0].rows[0].cells[0].innerHTML)
var data = [  //數組形式存放
    {id: 1, username: 'elos1', sex: '男'},
    {id: 2, username: 'edlo2', sex: '女'},
    {id: 3, username: 'elfo3', sex: '女'},
    {id: 4, username: 'elos4', sex: '男'}
]
for(var i=0;i<data.length;i++){
    var tr = document.createElement('tr'); //創建一行
//隔行變色
    if(i%2 == 0){
        tr.style.background = '#fff';
    }
    else{
        tr.style.background = '#ccc';
    }
    var td = document.createElement('td')//創建一列
    td.innerHTML = data[i].id;//列加內容
    tr.appendChild(td);//append到tr

    var td = document.createElement('td')
    td.innerHTML = data[i].username;
    tr.appendChild(td);

    var td = document.createElement('td')
    td.innerHTML = data[i].sex;
    tr.appendChild(td);

    tb.tBodies[0].appendChild(tr);
}

表單基本操作
重要屬性:name; form.name
onchange:當值發生改變時觸發,IE7下當值發生改變並且焦點離開時觸發
name屬性一個相同為單數,多個相同name則為複數,即[i]下標取值;
checked 選中屬性,都選中則以最後選中為准
onsubmit 提交時觸發
onreset reset時觸發

<form id="form1" action="">
    <input type="text" id="txt1" name="text1" value="內容"/>
    <input type="radio"  name="sex" value="男" checked/> 男
    <input type="radio"  name="sex" value="女" /> 女
</form>
var form = document.getElementById('form1')
console.log(form.text1.value);
    ofrom.sex[0].onchange = function (){
    ...
}
    if( ofrom.sex[i].checked ){
    ...
    }
form.onsubmit = function(){
    if(form.text1.value==''){
    alert('please input something')
    return false; //阻止提交
    }
}
form.onreset = function(){
    return confirm('are you sure to reset') //詢問對話
}

BOM操作
window.open (页面地址url,打开方式)
页面地址url为空,默认打开空页面
打开方式为空,默认新窗口打开,自身:_self

var opener = null;
opener = window.open();
alert( opener = window );
opener.document.body.style.background = 'red'  //新窗口背景为red

window.close() //兼容性,ff无效,ie chrome有效

opener.close();//关闭新窗口,无兼容性;

window.navigator.userAgent 浏览器信息,字符串

if(window.navigator.userAgent.indexOf('.NET') != -1){
    alert('IE')
}else{ alert('NOT IE') }

window.location 用户,浏览器地址信息
window.location.href
window.location.search: url? 问号后面的内容

window.location.hash: url# 后面的内容

可视区大小
document.documentElement.clientWidth;
document.documentElement.clientHeight

滚动距离
document.body.scrollTop / scrollLeft
document.documentElement.scrollTop / scrollLeft

内容高度
document.body.scrollHeight

文档高度
document.documentElement.offsetHeight
document.body.offsetHeight

//可视区宽
alert(document.documentElement.clientWidth)
//可视区大小兼容,chrome认为滚动是body的
var sTop1 = document.body.scrollTop || document.documentElement.scrollTop;
var sTop2 = Math.max(document.body.scrollTop, document.documentElement.scrollTop)
var sTop3 = document.body.scrollTop + document.documentElement.scrollTop
<div id="boxs" style = 'width: 100px;height: 100px;border: 1px solid red ;padding: 10px;margin: 10px;'>
        <div style="width: 100px;height: 200px;background: #000;"></div>  
</div>
//内容高度:抛开边框,外面的padding+内容内容高度,包括父级被撑开的高度,加隐藏内容不加border
alert(document.getElementById('boxs').scrollHeight)
/*
boxs不加overflow:hidden: 210;
boxs + overflow:hidden: 
    chrome: 220
    ff:210
    IE8+ 210
    IE8- 220
    safari 220
    opera  220
*/
alert( document.getElementById('boxs').offsetHeight ) //122  height + padding + border
alert( document.body.offsetHeight ) //142 height + padding + border + margin //如果body取值则需要加上margin

//IE下,body style =" height: 2000px;" 兼容问题,IE取不到
所以获取body内容高时,推荐使用: document.body.offsetHeight;

onscroll 当滚动条滚动时触发
onresize 当窗口大小发生改变时触发

//回到頂部 兼容寫法
var a = document.querySelector('a')
var timer = null;
window.onscroll = function () {
  var Dsroll = document.body.scrollTop || document.documentElement.scrollTop
Dsroll >= 200?a.style.display = 'block':a.style.display = 'none'
  a.onclick = function () {
    var Dsroll = document.body.scrollTop || document.documentElement.scrollTop
    timer = setInterval(function () {
      Dsroll -= 30;
      if (Dsroll <= 0) {
        clearInterval(timer)
      }
      document.body.scrollTop = Dsroll
      document.documentElement.scrollTop = Dsroll
    }, 30)
  }
}

select操作:

<select name="" id="s">
    <option value="0" selected>0</option>
    <option value="100">text文本100</option>
    <option value="200">text文本200</option>
</select>
<p>value是 <span id="sval"></span> text是 <span id="stxt"></span></p>
    var s = document.getElementById('s')
    var sval = document.getElementById('sval');
    var stxt = document.getElementById('stxt');
    s.onchange = function () {
        var sV = s.value;
        var sT = s.options[s.selectedIndex].text;
        sval.innerHTML = sV;
        stxt.innerHTML = sT;
    }

新浪圍脖登入

連接觸發兼容

if(ie){
this.inp.onpropertychange = function(){}
}
else{
this.inp.oninput = function(){}
}

定義方法:

function Suggset(){
this.inp = document.getElementById('input1')
...
}

定義原型:

Suggset.prototype = {
init:function(){}, //初始化
toChange:function(){}, //主方法
showul:function(){}, //顯示ul方法
toBlur:function (){}, //光標離開時隱藏方法
tips:function(){}, //動態提示方法,即顯示ul篩選
sel:function(){} //選中方法,鼠標及鍵盤
}

正則

var re = new RegExp('@' + value.substring(value.indexOf('@') + 1)); 
//带@判断 匹配@,截取@后面的,即從帶@的位置indexOf開始後1位,使用substring方法截取
re.test(String) //調用

自定義屬性,如果為空,返回false

var email = this.li[i].getAttribute('email') //获取自定义标签email
if(!email)

選擇用onmousedown,非onclick~!
其他:特別注意this指向問題~!
佈局

<div id="box">
<div class="detail">
        <input type="text" id="input1" placeholder="郵箱/會員賬號/手機號" autocomplete="off" node-type="loginname" class="name" tabindex="1" name="loginname"/>
    </div>
    <div class="detail">
        <input type="password" id="password" maxlength="24" placeholder="請輸入密碼" node-type="password" class="pass" tabindex="2" name="password"/>
    </div>
    <ul id="suggest">
        <li class="note">請選擇郵箱類型</li>
        <li email="" class="item"></li>
        <li email="@sina.com" class="item">@sina.com</li>
        <li email="@163.com" class="item">@163.com</li>
        <li email="@sohu.com" class="item">@sohu.com</li>
        <li email="@qq.com" class="item">@qq.com</li>
        <li email="@hotmail.com" class="item">@hotmail.com</li>
        <li email="@gmail.com" class="item">@gmail.com</li>
        <li email="@yahoo.com" class="item">@yahoo.com</li>
        <li email="@139.com" class="item">@139.com</li>
        <li email="@126.com" class="item">@126.com</li>
        <li email="@189.com" class="item">@189.com</li>
        <li email="@vip.qq.com" class="item">@vip.qq.com</li>
    </ul>
</div>
window.onload = function () {
    var s1 = new Suggset();
    s1.init()
}
function Suggset() {
    this.inp = document.getElementById('input1')
    this.ul = document.getElementById('suggest')
    this.li = this.ul.getElementsByTagName('li')
}
Suggset.prototype = {
    init: function () {
        this.toChange()
        this.toBlur();
    },
    toChange: function () {
        //ie:onpropertychange
        //標準:oninput
        var ie = !-[1,
        ]; //ie兼容
        var This = this;
        if (ie) {
            this.inp.onpropertychange = function () {
                if (This.inp.value == '') {
                    This.tips();
                    return
                } //IE下最后一个字母有问题,需要先This.tips(),再return
                else {
                    This.showul(); //注意不能写this.showul() this指  IE8下,onpropertychange打開即會觸發
                    This.tips();
                    This.sel(1);
                }
            }
        }
        else {
            this.inp.oninput = function () {
                This.showul(); //this.showul()
                This.tips();
                This.sel(1);//第一個li特殊處理
            }
        }
    },
    showul: function () {
        this.ul.style.display = 'block';
    },
    toBlur: function () { //光標離開時隱藏
        var This = this
        this.inp.onblur = function () {
            This.ul.style.display = 'none';
        }
    },
    tips: function () {
        var value = this.inp.value;
        var re = new RegExp('@' + value.substring(value.indexOf('@') + 1)); //带@判断 匹配@,截取@后面的
        for (var i = 1; i < this.li.length; i++) { //输入完后清空再输无法再显示,须在if前先全部显示出来!为
            this.li[i].style.display = 'block'
        }
        if (re.test(value)) {
            for (var i = 1; i < this.li.length; i++) {
                var email = this.li[i].getAttribute('email') //获取自定义标签email
                if (i == 1) {
                    this.li[i].innerHTML = value
                }
                else {
                    if (re.test(email)) {
                        this.li[i].style.display = 'block'
                    }
                    else {
                        this.li[i].style.display = 'none'
                    }
                }
            }
        }
        else {
            for (var i = 1; i < this.li.length; i++) {
                var email = this.li[i].getAttribute('email') //获取自定义标签email
                if (!email) { //如果没有自定义标签,即为空
                    this.li[i].innerHTML = value;
                }
                else {
                    this.li[i].innerHTML = value + email;
                }
            }
        }
    },
    sel: function (iNow) { //選中的方法,傳iNow進去
        var This = this
        for (var i = 1; i < this.li.length; i++) { //先還原,才不會出現第一個on與下面兩個同時出現
            this.li[i].className = 'item'
        }
        if (this.inp.value == '') {
            this.li[iNow].className = 'item'
        }
        else {
            this.li[iNow].className = 'on'
        }
        for (var i = 1; i < this.li.length; i++) {
            this.li[i].index = i
            this.li[i].onmouseover = function () {
                for (var i = 1; i < This.li.length; i++) { //再做循環還原class //this有問題
                    This.li[i].className = 'item' //this有問題 []此處的this應該指向父級,This.li[i].className
                }
                this.className = 'on' //當前選中加on //this 正確
                iNow = this.index //如果選到中間,鍵盤控制須在中間開始,所以iNow = this.index;
            }
            this.li[i].onmousedown = function () {
                This.inp.value = this.innerHTML
            }
        }
        this.inp.onkeydown = function (ev) {
            var ev = ev || event //獲取鍵值,
            if (ev.keyCode == 38) {//上
                if (iNow == 1) { //鍵盤控制第一個時返回最後一個
                    iNow = This.li.length - 1;
                }
                else {
                    iNow--;
                }
                for (var i = 1; i < This.li.length; i++) { //再做循環還原class //this有問題
                    This.li[i].className = 'item' //this有問題 []此處的this應該指向父級,This.li[i].className
                }
                This.li[iNow].className = 'on'
            }
            else if (ev.keyCode == 40) {  //下
                if (iNow == This.li.length - 1) { //鍵盤控制到最後一個時返回 == 1
                    iNow = 1;
                }
                else {
                    iNow++;
                }
                for (var i = 1; i < This.li.length; i++) { //再做循環還原class //this有問題
                    This.li[i].className = 'item' //this有問題 []此處的this應該指向父級,This.li[i].className
                }
                This.li[iNow].className = 'on'
            }
            else if (ev.keyCode == 13) { //回車
                This.inp.value = This.li[iNow].innerHTML; //當前選擇
                This.inp.onblur();
            }
        }
    }
};

運行