分类 JS 下的文章

openwrt 单网口设置旁路由模式

1、使用 starwind-v2v-converter 把 iso 转为 vmdk
2、按所需要的工具转换,如VMware Workstation 或 ESXi Server image
3、若是ESXi,下一步选 Pre-allocated image
4、旁路由,1G内存够用,可分配多一点CPU
5、网络设置,VMware Workstation 直接桥接复制本地物理网卡
6、vi /etc/config/network 改静态IP
7、接口 -> 修改仅剩的LAN口,并填好IP网关DNS,其它删
8、禁用通告、(DHCP)、DNP功能
9、防火墙,区域这块,入站 出站 转发 全改为 接受
10、联网检测即可
11、若接管整个网关,关闭主路由DHCP,开启OP DHCP
12、记录不需要科学上网的MAC地址,打开 vi /etc/config/dhcp
13、增加

//iot是tag名称,可任意,6开头表示DNS,3开头表示网关
//一、先定义模板
config tag 'iot'
 list dhcp_option '6,119.29.29.29'
 list dhcp_option '3,192.168.1.1'
 option force '1'

//二、再定义需要使用iot的主机
config host
 option dns '1'
 option name 'test'
 option mac 'aa:7d:54:a4:f8:da'
 option tag 'iot'

14、重启DHCP
/etc/init.d/dnsmasq restart

一些方法记录

//获取图片原始宽高
function getImgNaturalDimensions(oImg, callback) {
  var nWidth, nHeight;
  if (!oImg.naturalWidth) {
    nWidth = oImg.naturalWidth;
    nHeight = oImg.naturalHeight;
    callback({w: nWidth, h:nHeight});
  } else {
    var nImg = new Image();
    nImg.onload = function() {
      var nWidth = nImg.width,
          nHeight = nImg.height;
      callback({w: nWidth, h:nHeight});
    }
    nImg.src = oImg.src;
  }
}

getImgNaturalDimensions(e.querySelector('img'),function (_img) {
  console.log(_img.w)
  console.log(_img.h)
})
//复制文字
document.querySelector('.j-copy-mail').onclick=function(){
    var _copymail = this.innerText
    var flag = copyTextToClipboard(_copymail)
    flag ? layer.msg(_copymail+' 已複製!',{offset: '128px'}) : layer.msg('複製失敗請重試!',{offset: '128px'})
    function copyTextToClipboard(text) {
        var textArea = document.createElement("textarea");
        textArea.style.background = 'transparent';
        textArea.value = text;
        document.body.appendChild(textArea);
        textArea.select();
        try {
            var successful = document.execCommand('copy');
            var msg = successful
        } catch (err) {
            var msg= false
        }
        document.body.removeChild(textArea);
        return msg
    }
}

//flex布局

<div class="box">
  <div class="b1">1</div>
  <div class="b2">2</div>
  <div class="b3">3</div>
</div>
//对应css
  .b1{
    background: #cccccc;
    order:2;
/*flex是flex属性是flex-grow,flex-shrink与flex-basis三个属性的简写*/
    flex:1 1 auto; /*等分放大缩小*/
    flex:0 0 auto; /*不放大不缩小*/
  }
  .b2{
    background: #eeeeee;
    order:1;
    /*默认auto,或者以width为自身的宽度,但如果设置了flex-basis,权重会width属性高,因此会覆盖widtn属性*/
    flex-basis:auto;
    flex-basis: 500px;
/*表示是否继承父元素的 align-items属性,若没有父属性,默认stretch*/
    align-self: auto;
  }
  .b3{
   background: #939393;
/*有用,更改元素排列 0开始,数字越小越靠前*/
    order:0;
/*默认0,用于决定项目在有剩余空间的情况下是否放大,0不放大,即使设置了固定宽度也会放大*/
/*若有多个1,则剩余空间平分*/
    flex-grow:1;
/*默认1,用于决定项目在有剩余空间的情况下是否缩小,即空间不足时大家一起等比例缩小*/
    flex-shrink:0;/*设置了这个为0后,即使缩小父box,时,其它两项会缩小,但这项不会缩小宽度*/
  }
  .b1,.b2,.b3{
  text-align: center;
  font-size: 60px;
  line-height: 300px;
  width: 30%;
  width: 600px;
  }
  .box{
    display: flex;
    /*width: 1200px;*/
    height: 900px;

/*控制排序方向与顺序*/
    flex-direction: row-reverse;/*321*/
    flex-direction: column;/*纵 123*/
    flex-direction: column-reverse;/*纵321*/
    flex-direction: row;/*123*/

/*控制是否换行*/
    flex-wrap: nowrap; /* 不换行,假设你200,子设置多少都没用,则是会 200/3来计算子容器*/
    flex-wrap: wrap; /*换行,假设父200,子300,共3个,则子实际变为200 = 父*/
    flex-wrap: wrap-reverse;
    flex-flow:row wrap;/* flex-deriction与flex-wrap属性的简写集合,默认属性为row nowrap */ /*推荐*/

/* 横轴处理*/
    justify-content:flex-start;/*左对齐*/
    justify-content:space-between;
    justify-content:flex-end;
    justify-content:space-around;/* 两边为中间隔的1/2 */
    justify-content:space-evenly; /*间距一致*/

/*纵轴处理*/
    align-items:stretch;/*默认 如果项目没设置高度,或高度为aut 则占满整个屏幕o*/
    align-items:flex-start; /*子容器在顶部*/
    align-items:flex-end; /*子容器在底部*/
    align-items:center;

/*注意:当flex-direction:column,时,justify-content 与 align-items 横纵轴会发过来*/

/*用于控制多行,一行,不会起效果*/
    align-content:stretch;/**/
    align-content:center;
    align-content:space-between;
}
// splice(位置,删除几个,插入)

//插入
var _arr = ['A','B','C','D']
_arr.splice(2,0,'F')  //['A', 'B', 'F', 'C', 'D']    第二个位置,插入一个F
console.log(_arr) 
console.log(_arr.splice(2,0,'F'))  //[]

//删除
var _arr = ['A','B','C','D']
_arr.splice(2,1)
console.log(_arr)  // ['A', 'B', 'D']  第二个位置,删除一个元素
console.log(_arr.splice(2,0)) //[]

//替换
var _arr = ['A','B','C','D']
_arr.splice(2,1,'F') //替换第三个字符为 F
console.log(_arr)  // ['A', 'B', 'F', 'D']
console.log(_arr.splice(2,1,'F')) //['F']


_arr.unshift('E','F') //插前
_arr.push('E','F') //插后
_arr.shift() //删前
_arr.pop() //删后

//箭头函数

  //两个参数
const sum = (num1,num2) =>{
  return num1 + num2
}

//一个参数
const power = (num) =>{
  return num * num
}
------> 一个参数时,() 可省
const power1 = num =>{
  return num * num
}

//fn代码中有一行代码 特殊写法
const mul = (num1,num2)=>num1 * num2
console.log(mul(11, 22));
//数组操作 filter map reduce

//通常:取出所有小于100的数字
const nums = [222,111,2222,333,123,10,20,30,50]
let newNums = []
for(let n of nums){
  if(n<100){
    newNums.push(n)
  }
}
console.log(newNums);

--------------------------------------------------------------------------

//filter 中的回调必须返回一个boolean值 :
//true,内部自动将回调的n加到新的数组中
//false,自动过滤此次n

const nums2 = [222,111,2222,333,123,10,20,30,50]
let nne = nums2.filter(function (n) {
  return n < 100   //返回一个bl值
})
console.log(nne); // [10, 20, 30, 50]

--------------------------------------------------------------------------

//map 如果需要对每个数据的每次回都操作,则用map

const mapArr = [222,111,2222,333,123,10,20,30,50]
let nne2 = mapArr.map(function (n) {
  return n*8
})
console.log(nne2); // [1776, 888, 17776, 2664, 984, 80, 160, 240, 400]

--------------------------------------------------------------------------

//reduce 对数据中所有的内容进行汇总
//reduce(fn,0)
//fn必须传两值:(前一个值即上一个返回值,初始值)
const reduceArr = [1,2,3,4,5,6,7,8,9,10]
let reduceArr2 = reduceArr.reduce(function(preV,n){
    return preV + n
},0)
console.log(reduceArr2)  //55
//第一次 preV = 0  n = 1
//第二次 PreV = 1  n = 2
//第三次 PreV = 2  n = 3
...
//最后一次  PreV = 9  n = 10
//获取Json长度
  function getJsonLength(jsonData){
    var jsonLength = 0;
    for(var item in jsonData){
      jsonLength++;
    }
    return jsonLength;
  }
//数组去重
var _arr = ['','apple','bannna',123,321,'','',123,'bannna']
console.log([...new Set(_arr)])  //["", "apple", "bannna", 123, 321]

零js基礎 | 程序設計 | 16-html脚本编程

XDM核心方法是:postMessage('一个消息','此消息的来源域')
目的::向另一个地方传递数据
接收到XDM消息时,会触发window 对象的message 事件

data:作为postMessage()第一个参数传入的字符串数据
origin:发送消息的文档所在的域,例如"http://www.wrox.com"。
source:发送消息的文档的window 对象的代理。这个代理对象主要用于在发送上一条消息的窗口中调用postMessage()方法。如果发送消息的窗口来自同一个域,那这个对象就是window。

在onmessage 处理程序中检测消息来源可以确保传入的消息来自已知的页面。基本的检测模式如


    EventUtil.addHandler('window','message',function(event){
        if(event.origin == 'http://badiu.com'){
            processMessage(event.data)
            event.source.postMessage('Received!','http://p2p.baidu.com')
        }
    })

注:,event.source 大多数情况下只是window 对象的代理,并非实际的window 对象。换句话说,不能通过这个代理对象访问window 对象的其他任何信息。记住,只通过这个代理调用postMessage()就好,这个方法永远存在,永远可以调用

最好只传入字符串,如果要传入结构化数据,要先在传入数据中JSON.stringify();通过postMessage()传入得到的字符串,然
后再在onmessage 事件处理程序中调用JSON.parse()

拖放元素时,依次触发下列事件:

1、dragstart
2、drag
3、dragend

当某个元素被拖动到一个有效的放置目标上时,下列事件会依次发生:

1、dragenter
2、dragover
3、dragleave 或 drop

上述三个事件的目标都是作为放置目标的元素

零js基礎 | 程序設計 | 14 - 表单

var form = document.getElementById("form1");
var firstForm = document.forms[0];
var myForm = document.forms["form2"];
   objform.elements('objid')

获取方法

    <form action="" name='myFormname' id="myForm">
        <textarea name="" id="" cols="30" rows="10" name='textbox' id='textbox'></textarea>
        <ul>
            <li>
                <input type="radio" name="colorName" id='colorID1' value="red">Red</li>
            <li>
                <input type="radio" name="colorName" id='colorID2' value="green">Green</li>
            <li>
                <input type="radio" name="colorName" id="colorID3" value="blue">Blue</li>
        </ul>
    </form>
        var formId  = document.getElementById('myForm')
        var formName = document.getElementsByName('myFormname')[0]
        var form0 = document.forms[0]
        
        
        
        var colorId = formId.elements['colorName']
        alert(colorId.length)//3
        
        var colorName = formName.elements['colorName']
        alert(colorName.length)//3

,有3 个单选按钮,它们的name 都是"color",意味着这3 个字段是一起的。
在访问elements["color"]时,就会返回一个NodeList,其中包含这3 个元素;不过,如果访问
elements[0],则只会返回第一个元素。来看下面的例子。

var form = document.getElementById("myForm");
var colorFields = form.elements["color"];
alert(colorFields.length); //3
var firstColorField = colorFields[0];
var firstFormField = form.elements[0];
alert(firstColorField === firstFormField); //true

除了fieldset元素之外,所有表单字段都拥有相同的一组属性。由于input类型可以表示多
种表单字段,因此有些属性只适用于某些字段,但还有一些属性是所有字段所共有的。表单字段共有的
属性如下。
 disabled:布尔值,表示当前字段是否被禁用。
 form:指向当前字段所属表单的指针;只读。
 name:当前字段的名称。
 readOnly:布尔值,表示当前字段是否只读。
 tabIndex:表示当前字段的切换(tab)序号。
 type:当前字段的类型,如"checkbox"、"radio",等等。
 value:当前字段将被提

var filed = form.elements[0]
filed.value = 'auther Value'
alert(filed.form === form) //true

//把焦点设置到当前字段
field.focus();

//禁用当前字段
field.disabled = true;

//修改type 属性(不推荐,但对input来说是可行的)
field.type = "checkbox";

这就是个问题:因为会导致费用翻番。
为此,最常见的解决方案,就是在第一次单击后就禁用提交按钮。只要侦听submit 事件,并在该事件
发生时禁用提交按钮即可。以下就是这样一个例子。

EventUtil.addHandler(form, "submit", function(event){
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);

//取得提交按钮
var btn = target.elements["submit-btn"];

//禁用它
btn.disabled = true;
});

注意,不能通过onclick 事件处理程序来实现这个功能,原
因是不同浏览器之间存在“时差”:有的浏览器会在触发表单的submit 事件之前触发click 事件,
而有的浏览器则相反。对于先触发click 事件的浏览器,意味着会在提交发生之前禁用按钮,结果
永远都不会提交表单

focus()和 blur()。

EventUtil.addHandler(window, "load", function(event){
document.forms[0].elements[0].focus();
});

要注意的是,如果第一个表单字段是一个input元素,且其type 特性的值为"hidden",那么
以上代码会导致错误。另外,如果使用CSS 的display 和visibility 属性隐藏了该字段,同样也会
导致错误。

HTML5 为表单字段新增了一个autofocus 属性。在支持这个属性的浏览器中,只要设置这个属性,
不用JavaScript 就能自动把焦点移动到相应字段。例如:

<input type="text" autofocus>

检测是否支持autofocus属性

EventUtil.addHandler(window, "load", function(event) {
    var element = document.forms[0].elements[0];

    if (element.autofocus !== true) {
        element.focus();
        console.log("JS focus");
    }
});

共有字段事件

 blur:当前字段失去焦点时触发。
 change:对于input和textarea元素,在它们失去焦点且value 值改变时触发;对于
select元素,在其选项改变时触发。
 focus:当前字段获得焦点时触发。

。对于input和textarea元素,当它们从获得焦点到失去焦点且value 值改变时,
才会触发change 事件。对于select元素,只要用户选择了不同的选项,就会触发change 事件;
换句话说,不失去焦点也会触发change 事件

获得焦点时选择所有文本

var textbox = document.forms[0].elements["textbox1"];
textbox.select();

取得选择的文本selectionStart 和selectionEnd 即文本选区开头和结尾的偏移

function getSelectedText(textbox){
return textbox.value.substring(textbox.selectionStart, textbox.selectionEnd);
}

因为substring() 方法基于字符串的偏移量执行操作, 所以将selectionStart 和
selectionEnd 直接传给它就可以取得选中的文本。

IE8 及更早的版本中有一个document.selection

function getSelectedText(textbox) {
    if (typeof textbox.selectionStart == "number") {
        return textbox.value.substring(textbox.selectionStart,
            textbox.selectionEnd);
    } else if (document.selection) {
        return document.selection.createRange().text;
    }
}

input textarea

选择部分文本:
setSelectionRange()方法。
现在除select()方法之外,所有文本框都有一个setSelectionRange(第一个字符的索引,要选择的和要选择的最后一个字符之后的字符的索引)
(类似于substring()方法的两个参数)。来看一个例子。

        var forminp = document.forms[0].elements[0]
            //      console.log(form1)
            //    console.log( form1.value)
            
        
        forminp.value = 'hello world'
        
        forminp.setSelectionRange(0,forminp.value.length)   //选中hello world
        
        forminp.setSelectionRange(0,3)  //选中hel
        

IE8以下,不作讨论

textbox.value = "Hello world!";
var range = textbox.createTextRange();
//选择所有文本
range.collapse(true);
range.moveStart("character", 0);
range.moveEnd("character", textbox.value.length); //"Hello world!"
range.select();
//选择前3 个字符
range.collapse(true);
range.moveStart("character", 0);
range.moveEnd("character", 3);
range.select(); //"Hel"
//选择第4 到第6 个字符
range.collapse(true);
range.moveStart("character", 4);
range.moveEnd("character", 3);
range.select(); //"o w"

跨浏览器

function selectText(textbox, startIndex, stopIndex) {
    if (textbox.setSelectionRange) {
        textbox.setSelectionRange(startIndex, stopIndex);
    } else if (textbox.createTextRange) {
        var range = textbox.createTextRange();
        range.collapse(true);
        range.moveStart("character", startIndex);
        range.moveEnd("character", stopIndex - startIndex);
        range.select();
    }
    textbox.focus();
}

这个selectText()函数接收三个参数:要操作的文本框、要选择文本中第一个字符的索引和要选
择文本中最后一个字符之后的索引

textbox.value = "Hello world!"
//选择所有文本
selectText(textbox, 0, textbox.value.length); //"Hello world!"
//选择前3 个字符
selectText(textbox, 0, 3); //"Hel"
//选择第4 到第6 个字符
selectText(textbox, 4, 7); //"o w"

过滤输入

下列代码只允许用户输入数值。


EventUtil.addHandler(textbox, "keypress", function(event) {
    event = EventUtil.getEvent(event);
    var target = EventUtil.getTarget(event);
    var charCode = EventUtil.getCharCode(event);
    if (!/\d/.test(String.fromCharCode(charCode))) {
        EventUtil.preventDefault(event);
    }
});

。这意味着,仅考虑到屏蔽不是数值的字符还不够,还要避免屏蔽这些极为常用和必要的键

在Firefox 中,所有由非字符键触发的keypress 事件对应的字符编码为0,而在Safari 3 以前的版本中,对应的字符编码全部为8。为了让代码更通用,只要不屏蔽那些字符编码小于10 的键即可

EventUtil.addHandler(textbox, "keypress", function(event) {
    event = EventUtil.getEvent(event);
    var target = EventUtil.getTarget(event);
    var charCode = EventUtil.getCharCode(event);
    if (!/\d/.test(String.fromCharCode(charCode)) && charCode > 9) {
        EventUtil.preventDefault(event);
    }
});

还有一个问题需要处理:复制、粘贴及其他操作还要用到Ctrl 键。在除IE 之外的所有
浏览器中,前面的代码也会屏蔽Ctrl+C、Ctrl+V,以及其他使用Ctrl 的组合键。因此,最后还要添加一
个检测条件,以确保用户没有按下Ctrl 键

EventUtil.addHandler(textbox, "keypress", function(event) {
    event = EventUtil.getEvent(event);
    var target = EventUtil.getTarget(event);
    var charCode = EventUtil.getCharCode(event);
    if (!/\d/.test(String.fromCharCode(charCode)) && charCode > 9 &&
        !event.ctrlKey) {
        EventUtil.preventDefault(event);
    }
});

 beforecopy:在发生复制操作前触发。
 copy:在发生复制操作时触发。
 beforecut:在发生剪切操作前触发。
 cut:在发生剪切操作时触发。
 beforepaste:在发生粘贴操作前触发。
 paste:在发生粘贴操作时触发。
在Safari、Chrome 和Firefox
中,beforecopy、beforecut 和beforepaste 事件只会在显示针对文本框的上文菜单(预期将发
生剪贴板事件)的情况下触发
,IE 则会在触发copy、cut 和paste 事件之前先行触发这些事件
在实际的事件发生之前,通过beforecopy、beforecut 和beforepaste 事件可以在向剪贴板发
送数据,或者从剪贴板取得数据之前修改数据。不过,取消这些事件并不会取消对剪贴板的操作——只
有取消copy、cut 和paste 事件,才能阻止相应操作发生。

访问剪贴板 -- 》用clipboardData 对象 IE- - window对象,这个对象是相应event 对象的属性;在Firefox、Safari 和Chorme 中,只有在处理剪贴板事件期间clipboardData 对象才有效,

,这是为了防止对剪贴板
的未授权访问;在IE 中,则可以随时访问clipboardData 对象。为了确保跨浏览器兼容性,最好只
在发生剪贴板事件期间使用这个对象。
clipboardData 对象有三个方法:getData(取得数据的格式)、setData()和clearData()
在IE 中,有两种数据格式:"text"
和"URL"。在Firefox、Safari 和Chrome 中,这个参数是一种MIME 类型;不过,可以用"text"代表
"text/plain"。

类似的其它方法也一样'

扩展getClipboardText与setClipboardText方法;

var EventUtil = {
    addHandler: function(element, type, handler) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    getEvent: function(event) {
        return event ? event : window.event;
    },
    getTarget: function(event) {
        return event.target || event.srcElement;
    },
    preventDefault: function(event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },
    removeHandler: function(element, type, handler) {
        if (element.removeEventListener) {
            element.removeEventListener(type, handler, false);
        } else if (element.detachEvent) {
            element.detachEvent("on" + type, handler);
        } else {
            element["on" + type] = null;
        }
    },
    stopPropagation: function(event) {
        if (event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    },
    getRelatedTarget: function(event) {
        if (event.relatedTarget) {
            return event.relatedTarget;
        } else if (event.toElement) {
            return event.toElement;
        } else if (event.fromElement) {
            return event.fromElement;
        } else {
            return null;
        }
    },
    getButton: function(event) {
        if (document.implementation.hasFeature("MouseEvents", "2.0")) {
            return event.button;
        } else {
            switch (event.button) {
                case 0:
                case 1:
                case 3:
                case 5:
                case 7:
                    return 0;
                case 2:
                case 6:
                    return 2;
                case 4:
                    return 1;
            }
        }
    },
    getWheelDelta: function(event) {
        if (event.wheelDelta) {
            return (event.wheelDelta);
        } else {
            return -event.detail * 40;
        }
    },
    getCharCode: function(event) {
        if (typeof event.charCode == "number") {
            return event.charCode;
        } else {
            return event.keyCode;
        }
    },
    getClipboardText: function(event) {
        var clipboardData = (event.clipboardData || window.clipboardData);
        return clipboardData.getData("text");
    },
    setClipboardText: function(event, value) {
        if (event.clipboardData) {
            return event.clipboardData.setData("text/plain", value);
        } else if (window.clipboardData) {
            return window.clipboardData.setData("text", value);
        }
    }
}

例如,如果一个文本框只接受数值,那么就必须检测粘贴过来的值,以确保有效。在paste
事件中,可以确定剪贴板中的值是否有效,如果无效,就可以像下面示例中那样,取消默认的行为。

EventUtil.addHandler(textbox, "paste", function(event) {
    event = EventUtil.getEvent(event);
    var text = EventUtil.getClipboardText(event);
    if (!/^\d*$/.test(text)) {
        EventUtil.preventDefault(event);
    }
});

自动切换焦点:

<form action="" name='myFormname' id="myForm">
<input type="text" name="tel1" id="txtTel1" maxlength="3">
<input type="text" name="tel2" id="txtTel2" maxlength="3">
<input type="text" name="tel3" id="txtTel3" maxlength="4">
</form>

,用户在第一个文本框中输入了3 个数字之后,焦点就会切换到第二个文
本框,再输入3 个数字

(function() {
    function tabForward(event) {
        event = EventUtil.getEvent(event);
        var target = EventUtil.getTarget(event);
        if (target.value.length == target.maxLength) {
            var form = target.form;
            for (var i = 0, len = form.elements.length; i < len; i++) {
                if (form.elements[i] == target) {
                    if (form.elements[i + 1]) {
                        form.elements[i + 1].focus();
                    }
                    return;
                }
            }
        }
    }
    var textbox1 = document.getElementById("txtTel1");
    var textbox2 = document.getElementById("txtTel2");
    var textbox3 = document.getElementById("txtTel3");
    EventUtil.addHandler(textbox1, "keyup", tabForward);
    EventUtil.addHandler(textbox2, "keyup", tabForward);
    EventUtil.addHandler(textbox3, "keyup", tabForward);
})();

HTML5验证
必填字段

<input type="text" name="username" required>

可以检查某个表单字段是否为必填字段。

var isUsernameRequired = document.forms[0].elements["username"].required;

使用下面这行代码可以测试浏览器是否支持required 属性。

var isRequiredSupported = "required" in document.createElement("input");

其它输入类型

<input type="email" name ="email">  //会把-@-当作有效电子邮件地址
<input type="url" name="homepage">

要检测浏览器是否支持这些新类型,可以在JavaScript 创建一个<input>元素,然后将type 属性
设置为"email"或"url",最后再检测这个属性的值

var input = document.createElement("input");
input.type = "email";
var isEmailSupported = (input.type == "email");

例如,想让用户只能输入0 到100 的值,而且这个值必须是5 的倍数,可以这样写代码:

<input type="number" min="0" max="100" step="5" name="count">
  1. 输入模式

HTML5 为文本字段新增了pattern 属性。这个属性的值是一个正则表达式,用于匹配文本框中的
值。例如,如果只想允许在文本字段中输入数值,可以像下面的代码一样应用约束:

<input type="text" pattern="\d+" name="count">

注意,模式的开头和末尾不用加^和$符号(假定已经有了)。这两个符号表示输入的值必须从头到
尾都与模式匹配。

使用以下代码可以检测浏览器是否支持pattern 属性。

var isPatternSupported = "pattern" in document.createElement("input");

检测有效性
用checkValidity()方法可以检测表单中的某个字段是否有

if (document.forms[0].elements[0].checkValidity()){
//字段有效,继续
} else {
//字段无效
}

可以在表单自身调用checkValidity()方法。如果所有表单字段都有
效,这个方法返回true;即使有一个字段无效,这个方法也会返回false。

if(document.forms[0].checkValidity()){
//表单有效,继续
} else {
//表单无效
}
function validity(){
console.log( document.forms[0].elements['emailName'].validity )
console.log( document.forms[0].elements['emailName'] )
}

因此,要想得到更具体的信息,就应该使用validity 属性来检测表单的有效性。下面

var input = document.forms[0].elements['emailName']
if (input.validity && !input.validity.valid) {
    if (input.validity.valueMissing) {
        alert("Please specify a value.")
    } else if (input.validity.typeMismatch) {
        alert("Please enter an email address.");
    } else {
        alert("Value is invalid.");
    }
}

禁用验证
通过设置novalidate 属性,可以告诉表单不进行验证。

<form method="post" action="signup.php" novalidate>
<!--这里插入表单元素-->
</form>

document.forms[0].noValidate = true; //禁用验证

如果一个表单中有多个提交按钮,为了指定点击某个提交按钮不必验证表单,可以在相应的按钮上
添加formnovalidate 属性。

<form method="post" action="foo.php">
<!--这里插入表单元素-->
<input type="submit" value="Regular Submit">
<input type="submit" formnovalidate name="btnNoValidate"
value="Non-validating Submit">
</form>
//禁用验证
document.forms[0].elements["btnNoValidate"].formNoValidate = true;

选择框脚本

select option创建
add(newOption,relOption):插入新的option,其位置相关项relOption之前
multiple,布尔值,允许多项选择,等价于html中的multiple特性;
remove(index),移除给定位置的选项
size:选择框中可见的行数,等价于html中的size特性;
选择的type属性不是'select-one'就是'select-mutiple'这取决于HTML代码中有没有multiple特性;选择框的value属性由当前选中项决定,相应规则如下:

如果没有选中的项,则选择框的value 属性保存空字符串。
如果有一个选中项,而且该项的value 特性已经在HTML 中指定,则选择框的value 属性等
于选中项的value 特性。即使value 特性的值是空字符串,也同样遵循此条规则。
如果有一个选中项,但该项的value 特性在HTML 中未指定,则选择框的value 属性等于该
项的文本。
如果有多个选中项,则选择框的value 属性将依据前两条规则取得第一个选中项的值。
以下面的选择框为例:

var sel = document.getElementById('selLocation');
console.log(sel.value)
<select name="location" id="selLocation">
<option value="Sunnyvale, CA" selected>Sunnyvale</option>  // Sunnyvale, CA
<option value="" selected>Sunnyvale</option> // 空 ''
<option selected>Australia</option> //没有value , //Australia
</select>

每个<option>元素都有一个HTMLOptionElement 对象表示,有下列属性:

index:当前选项在options 集合中的索引。
label:当前选项的标签;等价于HTML 中的label 特性。
selected:布尔值,表示当前选项是否被选中。将这个属性设置为true 可以选中当前选项。
text:选项的文本。
value:选项的值(等价于HTML 中的value 特性)。

访问值:DOM方法(不推荐,效率低)

var selectbox = document.forms[0].elements["location"];
var text = selectbox.options[0].firstChild.nodeValue;
var value = selectbox.options[0].getAttribute('value')
console.log(value)

选项属性代码:(推荐)

var selectbox = document.forms[0].elements["location"];
var text = selectbox.options[0].text;
var value = selectbox.options[0].value;
console.log(value) 

对于只允许选择一项的选择框,访问选中项的最简单方式,就是使用选择框的selectedIndex 属性

//选中的项
var selectedOption = selectbox.options[selectbox.selectedIndex]

console.log(selectedOption) //<option selected="">Australia</option>

console.log('selected index: '+ selectbox.selectedIndex)
console.log('selected text: '+ selectedOption.text)
console.log('selected value: '+ selectedOption.value)

设置select

selectbox.options[0].selected = true;

//但设置多个 

selectbox.options[1].selected = true;
selectbox.options[0].selected = true; //后面覆盖前面

添加option选项一:

var newOption = document.createElement('option')
newOption.appendChild(document.createTextNode('option text'))
newOption.setAttribute('value','Option value')
selectbox.appendChild(newOption)

添加option选项二:Option构造函数,第二个参数可选(IE8不支持)

var newoption = new Option('option txt','option value')
selectbox.appendChild(newoption)

添加option选项三:
add(要添加的新选项,位于新选项之后的选项),为第二个参数传undefined

var nnoption = new Option('ooption ttt','option value')
selectbox.add(nnoption,undefined)  //最佳

移除选项

//1
selectbox.removeChild(selectbox.options[0])
//2
selectbox.remove(0)
//3
selectbox.options[0] = null

//移除所有
function clearSelect(selectbox){
  for(var i=0;i<selectbox.options.length;i++){
    selectbox.remove(i)
  } 
}
clearSelect(selectbox)

移动和重排选项
一个select的option移到另一个select的options
如果为appendChild()方法传入一个文档中已有的元素,那么就从该元素的父节点中移除它,再把它添加到指定的位置

var sel = document.getElementById('selLocation');
var sel2 = document.getElementById('selLocation2');
sel2.appendChild(sel.options['caname'])

要将选择框中的某一项移动到特定位置,最合适的DOM 方法就是insertBefore();appendChild()方法只适用于将选项添加到选择框的最后。要在选择框中向前移动一个选项的位置,可以使用以下代码:

//向前移动一个选项

var optionMoveTo = sel.options[1];
sel.insertBefore(optionMoveTo,sel.options[optionMoveTo.index-1])

表单select序列化

function serialize(form) {
    var parts = [],
        field = null,
        i,
        len,
        j,
        optLen,
        option,
        optValue;
    for (i = 0, len = form.elements.length; i < len; i++) {
        field = form.elements[i];
        switch (field.type) {
            case "select-one":
            case "select-multiple":
                if (field.name.length) {
                    for (j = 0, optLen = field.options.length; j < optLen; j++) {
                        option = field.options[j];
                        if (option.selected) {
                            optValue = "";
                            if (option.hasAttribute) {
                                optValue = (option.hasAttribute("value") ?
                                    option.value : option.text);
                            } else {
                                optValue = (option.attributes["value"].specified ?
                                    option.value : option.text);
                            }
                            parts.push(encodeURIComponent(field.name) + "=" +
                                encodeURIComponent(optValue));
                        }
                    }
                }
                break;
            case undefined: //字段集
            case "file": //文件输入
            case "submit": //提交按钮
            case "reset": //重置按钮
            case "button": //自定义按钮
                break;
            case "radio": //单选按钮
            case "checkbox": //复选框
                if (!field.checked) {
                    break;
                }
                /* 执行默认操作 */
            default:
                //不包含没有名字的表单字段
                if (field.name.length) {
                    parts.push(encodeURIComponent(field.name) + "=" +
                        encodeURIComponent(field.value));
                }
        }
    }
    return parts.join("&");
}

马上变成可编辑选项,contenteditable

 <div class="editable" id="richedit" contenteditable></div>

也可在关闭

var div = document.getElementById("richedit");
div.contentEditable = "true";

富文编辑略。。。。

零js基礎 | 程序設計 | 13 - 事件

<input type="button" value="Click Me" onclick="try{showMessage();}catch(ex){}">

使用try catch捕获错误

        try {
            var dd = document.getElemedntById('dd')

        } catch (ex) {
            alert(123)
        }

addEventListener(),最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程

try {
    btn.addEventListener('click', function() {
        alert(this.id)
    }, false)
} catch (ex) {
    btn.attachEvent('onclick', function() {
        alert(123)
    })
}

removeEventListener(),要使用命名函数才能移除


btnfn = function() {
    alert(this.id)
}

btn.addEventListener('click', btnfn, false)

btn.removeEventListener('click',btnfn,false)

attachEvent()与detachEvent(),1、this作用域为window; 2、执行顺序由后往前;

btn.attachEvent('onclick',function(){
    alert(this)  //特别注意,这里是window
})

btn.attachEvent("onclick", function(){
alert("Clicked"); //弹2
});
btn.attachEvent("onclick", function(){
alert("Hello world!"); //弹1
});

兼容方法:

var EventUtil = {
    addHandler: function(element, type, handler) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    removeHandler: function(element, type, handler) {
        if (element.removeEventListener) {
            element.removeEventListener(type, handler, false);
        } else if (element.detachEvent) {
            element.detachEvent("on" + type, handler);
        } else {
            element["on" + type] = null;
        }
    }
};

var handler = function() {
    alert('abc')
}

EventUtil.addHandler(btn, 'click', handler)
EventUtil.removeHandler(btn, "click", handler);

事件对象

对象this 始终等于currentTarget 的值,而target 则只包含事件的实
际目标。如果直接将事件处理程序指定给了目标元素,则this、currentTarget 和target 包含相同
的值。来看下面的例子。

btn.onclick = function(event){
    alert(event.currentTarget === this)
    alert(event.target === this)
}
document.body.onclick = function(event) {
    alert(event.currentTarget == document.body) //true
    alert(this === document.body) //true
    alert(event.target == document.getElementById('mybtn')) //true
}

使用event.type判断不同事件;

var handler = function(event) {
    switch (event.type) {
        case 'click':
            alert('clicked')
            break;
        case 'mouseover':
            alert('mouseovered')
            break;
        case 'mouseout':
            alert('mouseouted');
            break;
    }
}
btn.onclick = handler;
btn.onmouseover = handler;
btn.onmouseout = handler;
btn.onclick = function(event) {
    alert('clicked')
    event.stopPropagation()
}
document.body.onclick = function(event) {
    alert('body clicked')
}

IE下的事件;

所以不能认为this 会始终等于事件目标。故而,最好还是使用event.srcElement 比较保

var btn = document.getElementById("myBtn");
btn.onclick = function(){
alert(window.event.srcElement === this); //true
};
btn.attachEvent("onclick", function(event){
alert(event.srcElement === this); //false
});

cancelBubble 属性与DOM 中的stopPropagation()方法作用相同,都是用来停止事
件冒泡的。由于IE 不支持事件捕获,因而只能取消事件冒泡;但stopPropagatioin()可以同时取消
事件捕获和冒泡

所以综合起来的跨浏览器事件代码为:


var EventUtil = {
    addHandler: function(element, type, handler) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    getEvent: function(event) {
        return event ? event : window.event;
    },
    getTarget: function(event) {
        return event.target || event.srcElement;
    },
    preventDefault: function(event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },
    removeHandler: function(element, type, handler) {
        if (element.removeEventListener) {
            element.removeEventListener(type, handler, false);
        } else if (element.detachEvent) {
            element.detachEvent("on" + type, handler);
        } else {
            element["on" + type] = null;
        }
    },
    stopPropagation: function(event) {
        if (event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    }
};

//使用
btn.onclick = function(event) {
    event = EventUtil.getEvent(event);
};
btn.onclick = function(event) {
    event = EventUtil.getEvent(event);
    var target = EventUtil.getTarget(event);
};
var link = document.getElementById("myLink");
link.onclick = function(event) {
    event = EventUtil.getEvent(event);
    EventUtil.preventDefault(event);
};
var btn = document.getElementById("myBtn");
btn.onclick = function(event) {
    alert("Clicked");
    event = EventUtil.getEvent(event);
    EventUtil.stopPropagation(event);
};
document.body.onclick = function(event) {
    alert("Body clicked");
};

图片加载完后显示弹出

var image = document.getElementById('myimage')
EventUtil.addHandler(image,'load',function(event){
    event = EventUtil.getEvent(event);
    alert(EventUtil.getTarget(event).src);
})

EventUtil.addHandler(window,'load',function(){
    var image = new Image();
    EventUtil.addHandler(image,'load',function(event){
        alert('Image Loaded')
    })
    image.src = 'smail.gif'
})

script外部地址加载完成

EventUtil.addHandler(window,'load',function(){
 var _srcipt = document.createElement('script')
 EventUtil.addHandler(_srcipt,'load',function(event){
     alert('loaded')
 })
 _srcipt.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js'
 document.body.appendChild(_srcipt)
})

css外部检测,低版本chrome/firefox可能不支持,未验证

EventUtil.addHandler(window, 'load', function() {
    var _css = document.createElement('link')
    _css.type = 'text/css'
    _css.rel = 'stylesheet'
    EventUtil.addHandler(_css, 'load', function(event) {
        alert('loaded')
    })
    _css.href = 'https://assets-cdn.github.com/assets/frameworks-827a4e004aa05724993ea7616e4af53894825443811a270e2b9bce76e3453f19.css'
    document.body.appendChild(_srcipt)
})

resize事件,推荐写法

EventUtil.addHandler(window, "resize", function(event) {
    alert("Resized");
});

EventUtil.addHandler(window, "scroll", function(event) {
    if (document.compatMode == "CSS1Compat") {
        alert(document.documentElement.scrollTop);
    } else {
        alert(document.body.scrollTop);
    }
});

焦点事件会在页面元素获得或失去焦点时触发。利用这些事件并与document.hasFocus()方法及
document.activeElement 属性配合,可以知晓用户在页面上的行踪。有以下6 个焦点事件。

 blur:在元素失去焦点时触发。这个事件不会冒泡;所有浏览器都支持它。
 DOMFocusIn:在元素获得焦点时触发。这个事件与HTML 事件focus 等价,但它冒泡。只有
Opera 支持这个事件。DOM3 级事件废弃了DOMFocusIn,选择了focusin。
 DOMFocusOut:在元素失去焦点时触发。这个事件是HTML 事件blur 的通用版本。只有Opera
支持这个事件。DOM3 级事件废弃了DOMFocusOut,选择了focusout。
focus:在元素获得焦点时触发。这个事件不会冒泡;所有浏览器都支持它。
 focusin:在元素获得焦点时触发。这个事件与HTML 事件focus 等价,但它冒泡。支持这个
事件的浏览器有IE5.5+、Safari 5.1+、Opera 11.5+和Chrome。
 focusout:在元素失去焦点时触发。这个事件是HTML 事件blur 的通用版本。支持这个事件
的浏览器有IE5.5+、Safari 5.1+、Opera 11.5+和Chrome。

当焦点从页面中的一个元素移动到另一个元素,会依次触发下列事件:
(1) focusout 在失去焦点的元素上触发;
(2) focusin 在获得焦点的元素上触发;
(3) blur 在失去焦点的元素上触发;
(4) DOMFocusOut 在失去焦点的元素上触发;
(5) focus 在获得焦点的元素上触发;
(6) DOMFocusIn 在获得焦点的元素上触发。

事件都不冒泡

var _mybtn = document.getElementById('mybtn')

EventUtil.addHandler(_mybtn, 'focus', function() { //获得
    alert(1)
})
EventUtil.addHandler(_mybtn, 'blur', function() {//失去
    alert(2)
})
EventUtil.addHandler(_mybtn, 'focusin', function() {//获得
    alert(1)
})
EventUtil.addHandler(_mybtn, 'focusout', function() {//失去
    alert(2)
})

鼠标与滚轮事件

click/dblclick/mouseenter/mouseleave/mousemove/mouseout/mouseover/mouseup/

执行顺序:
(1) mousedown
(2) mouseup
(3) click
(4) mouseup
(5) dblclick
可以使用类似下列代码取得鼠标事件的客户端坐标信息:

var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
alert("Client coordinates: " + event.clientX + "," + event.clientY);
});

var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
alert("Page coordinates: " + event.pageX + "," + event.pageY);
});

在页面没有滚动的情况下,pageX 和pageY 的值与clientX 和clientY 的值相等。

滚动情况下:page 一定大于 client

EventUtil.addHandler(document.body, "click", function(event) {
    event = EventUtil.getEvent(event);
    console.log("Page coordinates: " + event.pageX + "," + event.pageY);
});

EventUtil.addHandler(document.body, "click", function(event) {
    event = EventUtil.getEvent(event);
    console.log("client coordinates: " + event.clientX + "," + event.clientY);
});

IE8不支持page,所以可用client + scroll 相加计算出

var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event) {
    event = EventUtil.getEvent(event);
    var pageX = event.pageX,
        pageY = event.pageY;
    if (pageX === undefined) {
        pageX = event.clientX + (document.body.scrollLeft ||
            document.documentElement.scrollLeft);
    }
    if (pageY === undefined) {
        pageY = event.clientY + (document.body.scrollTop ||
            document.documentElement.scrollTop);
    }
    alert("Page coordinates: " + pageX + "," + pageY);
});

鼠标相对于整个屏幕坐标位置,screenX 和 screenY

var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event){
event = EventUtil.getEvent(event);
alert("Screen coordinates: " + event.screenX + "," + event.screenY);
});

虽然鼠标事件主要是使用鼠标来触发的,但在按下鼠标时键盘上的某些键的状态也可以影响到所要
采取的操作。这些修改键就是Shift、Ctrl、Alt 和Meta(在Windows 键盘中是Windows 键,在苹果机中
是Cmd 键),它们经常被用来修改鼠标事件的行为。DOM 为此规定了4 个属性,表示这些修改键的状
态:shiftKey、ctrlKey、altKey 和metaKey。这些属性中包含的都是布尔值,如果相应的键被按
下了,则值为true,否则值为false。当某个鼠标事件发生时,通过检测这几个属性就可以确定用户
是否同时按下了其中的键。来看下面的

var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "click", function(event) {
    event = EventUtil.getEvent(event);
    var keys = new Array();
    if (event.shiftKey) {
        keys.push("shift");
    }
    if (event.ctrlKey) {
        keys.push("ctrl");
    }
    if (event.altKey) {
        keys.push("alt");
    }
    if (event.metaKey) {
        keys.push("meta");
    }
    alert("Keys: " + keys.join(","));
});

DOM通过event 对象的relatedTarget 属性提供了相关元素的信
只对于mouseover和mouseout 事件才包含值,其它值是null
IE8及之前版本不支持relatedTarget

mouseover -->IE 的fromElement
mouseout --》IE 的toElement

继续完善

        var EventUtil = {
            addHandler: function(element, type, handler) {
                if (element.addEventListener) {
                    element.addEventListener(type, handler, false);
                } else if (element.attachEvent) {
                    element.attachEvent("on" + type, handler);
                } else {
                    element["on" + type] = handler;
                }
            },
            getEvent: function(event) {
                return event ? event : window.event;
            },
            getTarget: function(event) {
                return event.target || event.srcElement;
            },
            preventDefault: function(event) {
                if (event.preventDefault) {
                    event.preventDefault();
                } else {
                    event.returnValue = false;
                }
            },
            removeHandler: function(element, type, handler) {
                if (element.removeEventListener) {
                    element.removeEventListener(type, handler, false);
                } else if (element.detachEvent) {
                    element.detachEvent("on" + type, handler);
                } else {
                    element["on" + type] = null;
                }
            },
            stopPropagation: function(event) {
                if (event.stopPropagation) {
                    event.stopPropagation();
                } else {
                    event.cancelBubble = true;
                }
            },
            getRelatedTarget: function(event) {
                if (event.relatedTarget) {
                    return event.relatedTarget;
                } else if (event.toElement) {
                    return event.toElement;
                } else if (event.fromElement) {
                    return event.fromElement;
                } else {
                    return null;
                }
            }

        };

    var div = document.getElementById("myDiv");
    EventUtil.addHandler(div, "mouseout", function(event) {
    event = EventUtil.getEvent(event);
    var target = EventUtil.getTarget(event);
    var relatedTarget = EventUtil.getRelatedTarget(event);
    alert("Moused out of " + target.tagName + " to " + relatedTarget.tagName);
    //Moused out of DIV to BODY

鼠标按钮
DOM的button 属性可能有如下3 个值:0 表示主鼠标按钮,1 表示中间的鼠
标按钮(鼠标滚轮按钮),2 表示次鼠标按钮。在常规的设置中,主鼠标按钮就是鼠标左键,而次鼠标
按钮就是鼠标右
最常见的做法就是将IE 模型规范化为DOM 方式

添加getButton

var EventUtil = {
    addHandler: function(element, type, handler) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    getEvent: function(event) {
        return event ? event : window.event;
    },
    getTarget: function(event) {
        return event.target || event.srcElement;
    },
    preventDefault: function(event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },
    removeHandler: function(element, type, handler) {
        if (element.removeEventListener) {
            element.removeEventListener(type, handler, false);
        } else if (element.detachEvent) {
            element.detachEvent("on" + type, handler);
        } else {
            element["on" + type] = null;
        }
    },
    stopPropagation: function(event) {
        if (event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    },
    getRelatedTarget: function(event) {
        if (event.relatedTarget) {
            return event.relatedTarget;
        } else if (event.toElement) {
            return event.toElement;
        } else if (event.fromElement) {
            return event.fromElement;
        } else {
            return null;
        }
    },
    getButton: function(event) {
        if (document.implementation.hasFeature("MouseEvents", "2.0")) {
            return event.button;
        } else {
            switch (event.button) {
                case 0:
                case 1:
                case 3:
                case 5:
                case 7:
                    return 0;
                case 2:
                case 6:
                    return 2;
                case 4:
                    return 1;
            }
        }
    }
};

var div = document.getElementById("myDiv");
EventUtil.addHandler(div, "mousedown", function(event) {
    event = EventUtil.getEvent(event);
    alert(EventUtil.getButton(event)); //左0 中1 右2
});

鼠标滚轮:
mousewheel 事件时显示wheelDelta 的值,
ff:支持:DOMMouseScroll

EventUtil.addHandler(document, "mousewheel", function(event){
event = EventUtil.getEvent(event);
console.log(event.wheelDelta); //上120,下-120
});

//ff

EventUtil.addHandler(window, "DOMMouseScroll", function(event) {
    event = EventUtil.getEvent(event); // 上-3  下3
    alert(event.detail);
});

整合添加:

var EventUtil = {
addHandler: function(element, type, handler) {
    if (element.addEventListener) {
        element.addEventListener(type, handler, false);
    } else if (element.attachEvent) {
        element.attachEvent("on" + type, handler);
    } else {
        element["on" + type] = handler;
    }
},
getEvent: function(event) {
    return event ? event : window.event;
},
getTarget: function(event) {
    return event.target || event.srcElement;
},
preventDefault: function(event) {
    if (event.preventDefault) {
        event.preventDefault();
    } else {
        event.returnValue = false;
    }
},
removeHandler: function(element, type, handler) {
    if (element.removeEventListener) {
        element.removeEventListener(type, handler, false);
    } else if (element.detachEvent) {
        element.detachEvent("on" + type, handler);
    } else {
        element["on" + type] = null;
    }
},
stopPropagation: function(event) {
    if (event.stopPropagation) {
        event.stopPropagation();
    } else {
        event.cancelBubble = true;
    }
},
getRelatedTarget: function(event) {
    if (event.relatedTarget) {
        return event.relatedTarget;
    } else if (event.toElement) {
        return event.toElement;
    } else if (event.fromElement) {
        return event.fromElement;
    } else {
        return null;
    }
},
getButton: function(event) {
    if (document.implementation.hasFeature("MouseEvents", "2.0")) {
        return event.button;
    } else {
        switch (event.button) {
            case 0:
            case 1:
            case 3:
            case 5:
            case 7:
                return 0;
            case 2:
            case 6:
                return 2;
            case 4:
                return 1;
        }
    }
},
getWheelDelta: function(event) {
    if (event.wheelDelta) {
        return (event.wheelDelta);
    } else {
        return -event.detail * 40;
    }
}
}

//使用
//handleMouseWheel()函数可以用作两个事件的处理程序(如果指定的事件不存在,则为该事件指定处
理程序的代码就会静默地失败)
function handleMouseWheel(event){
    event = EventUtil.getEvent(event);
    var delta = EventUtil.getWheelDelta(event);
    alert(delta); //下-120,上120
}
EventUtil.addHandler(document, "mousewheel", handleMouseWheel);
EventUtil.addHandler(document, "DOMMouseScroll", handleMouseWheel);

键盘与文本
键盘事件:
keydown当用户按下键盘上的任意键时触发,而且如果按住不放的话,会重复触发此事件
keypress:当用户按下键盘上的字符键时触发,而且如果按住不放的话,会重复触发此事件。
按下Esc 键也会触发这个事件。Safari 3.1 之前的版本也会在用户按下非字符键时触发keypress
事件。
keyup:当用户释放键盘上的键时触发。
文本事件:textInput,对keypress补充

按下字符:keydown--》keypress【前两个是文本变化之前】--》keyup
连续按:连接触发:keydown--》keypress

按下非字符:keydown --》keyup
也有shiftKey、ctrlKey、altKey 和metaKey[非IE] 属性

键码
在发生keydown 和keyup 事件时,event 对象的keyCode 属性中会包含一个代码

var textbox = document.getElementById("myText");
EventUtil.addHandler(textbox, "keyup", function(event) {
    event = EventUtil.getEvent(event);
    alert(event.keyCode); //显示keyCode值
});
var EventUtil = {
    addHandler: function(element, type, handler) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    getEvent: function(event) {
        return event ? event : window.event;
    },
    getTarget: function(event) {
        return event.target || event.srcElement;
    },
    preventDefault: function(event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },
    removeHandler: function(element, type, handler) {
        if (element.removeEventListener) {
            element.removeEventListener(type, handler, false);
        } else if (element.detachEvent) {
            element.detachEvent("on" + type, handler);
        } else {
            element["on" + type] = null;
        }
    },
    stopPropagation: function(event) {
        if (event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    },
    getRelatedTarget: function(event) {
        if (event.relatedTarget) {
            return event.relatedTarget;
        } else if (event.toElement) {
            return event.toElement;
        } else if (event.fromElement) {
            return event.fromElement;
        } else {
            return null;
        }
    },
    getButton: function(event) {
        if (document.implementation.hasFeature("MouseEvents", "2.0")) {
            return event.button;
        } else {
            switch (event.button) {
                case 0:
                case 1:
                case 3:
                case 5:
                case 7:
                    return 0;
                case 2:
                case 6:
                    return 2;
                case 4:
                    return 1;
            }
        }
    },
    getWheelDelta: function(event) {
        if (event.wheelDelta) {
            return (event.wheelDelta);
        } else {
            return -event.detail * 40;
        }
    },
    getCharCode: function(event) {
        if (typeof event.charCode == "number") {
            return event.charCode;
        } else {
            return event.keyCode;
        }
    }
}

var textbox = document.getElementById("myText");
EventUtil.addHandler(textbox, "keypress", function(event) {
    event = EventUtil.getEvent(event);
    alert(EventUtil.getCharCode(event));//值出字符编码
});

之后可以使用String.fromCharCode(number),再转为正常字符;

所有非字符

特殊情况: ff o 分号键keyCode = 59 【ASCII分号编码】; ie safari分号键 = 186;【按键编码】

由于存在跨浏览器问题,因此本书不推荐使用key、keyIdentifier 或char。

textInput事件
替代keypress 的textInput 事件的行为稍有不同。
区别一:就是任何可以获得焦点的元素都可以触发keypress 事件,但只有可编辑区域才能触发textInput事件。
区别二:textInput 事件只会在用户按下能够输入实际字符的键时才会被触发,
而keypress事件则在按下那些能够影响文本显示的键时也会触发(例如退格键)。

由于textInput 事件主要考虑的是字符,因此它的event 对象中还包含一个data 属性,这个属
性的值就是用户输入的字符(而非字符编码)。换句话说,用户在没有按上档键的情况下按下了S 键,
data 的值就是"s",而如果在按住上档键时按下该键,data 的值就是"S"。

var textbox = document.getElementById("myText");
EventUtil.addHandler(textbox, "textInput", function(event){
event = EventUtil.getEvent(event);
alert(event.data); //按下什么输出什么
});

HTML5事件

  1. contextmenu 事件显示菜单,支持contextmenu 事件的浏览器有IE、Firefox、Safari、Chrome 和Opera 11+。
EventUtil.addHandler(window, "load", function(event) {
    var div = document.getElementById("myDiv");
    EventUtil.addHandler(div, "contextmenu", function(event) {
        event = EventUtil.getEvent(event);
        EventUtil.preventDefault(event);
        var menu = document.getElementById("myMenu");
        menu.style.left = event.clientX + "px";
        menu.style.top = event.clientY + "px";
        menu.style.visibility = "visible";
    });
    EventUtil.addHandler(document, "click", function(event) {
        document.getElementById("myMenu").style.visibility = "hidden";
    });
});
  1. beforeunload 事件,是为了让开发人员有可能在页面卸载前阻止这一操作,为了显示这个弹出对话框,必须将event.returnValue 的值设置为要显示给用户的字符串(对IE 及Fiefox 而言),同时作为函数的值返回
    [

returnValue Boolean 读/写 默认值为true,但将其设置为false就可以取消事件的默认行为(与
DOM中的preventDefault()方法的作用相同)
]

EventUtil.addHandler(window, "beforeunload", function(event) {
    event = EventUtil.getEvent(event);
    var message = "I'm really going to miss you if you go.";
    event.returnValue = message;
    return message;
});
  1. DOMContentLoaded 事件 DOM加载完成后触发;
    要处理DOMContentLoaded 事件,可以为document 或window 添加相应的事件处理程序(尽管

这个事件会冒泡到window,但它的目标实际上是document)。来看下面的例子。
注:这个事件始终都会在load 事件之前触发

EventUtil.addHandler(document, "DOMContentLoaded", function(event){
    alert("Content loaded");
});

不支持的浏览器使用:

setTimeout(function(){
//在此添加事件处理程序
}, 0);
  1. readystatechange 事件
    支持readystatechange 事件的每个对象都有一个readyState 属性

uninitialized(未初始化):对象存在但尚未初始化。
loading(正在加载):对象正在加载数据。
loaded(加载完毕):对象加载数据完成。
interactive(交互):可以操作对象了,但还没有完全加载。
complete(完成):对象已经加载完毕。

不支持则会跳过,所以一般readystatechange事件经常会少于4次;而readyState则总是不连续;

EventUtil.addHandler(document, "readystatechange", function(event) {
    if (document.readyState == "interactive") {
        alert("Content loaded");
    }
});

同时检测交互和完成阶

EventUtil.addHandler(document, "readystatechange", function(event) {
    if (document.readyState == "interactive" || document.readyState == "complete") {
        EventUtil.removeHandler(document, "readystatechange", arguments.callee);
        alert("Content loaded");
    }
});

对于上面的代码来说,当readystatechange 事件触发时,会检测document.readyState 的值,
看当前是否已经进入交互阶段或完成阶段。如果是,则移除相应的事件处理程序以免在其他阶段再执行。
注意,由于事件处理程序使用的是匿名函数,因此这里使用了arguments.callee 来引用该函数。然
后,会显示一个警告框,说明内容已经加载完毕。这样编写代码可以达到与使用DOMContentLoaded
十分相近的效

下面展示了一段加载外部JavaScript/css 文件的代码

//js
EventUtil.addHandler(window, "load", function() {
    var script = document.createElement("script");
    EventUtil.addHandler(script, "readystatechange", function(event) {
        event = EventUtil.getEvent(event);
        var target = EventUtil.getTarget(event);
        if (target.readyState == "loaded" || target.readyState == "complete") {
            EventUtil.removeHandler(target, "readystatechange", arguments.callee);
            alert("Script Loaded");
        }
    });
    script.src = "example.js";
    document.body.appendChild(script);
});

//css
EventUtil.addHandler(window, "load", function() {
    var link = document.createElement("link");
    link.type = "text/css";
    link.rel = "stylesheet";
    EventUtil.addHandler(script, "readystatechange", function(event) {
        event = EventUtil.getEvent(event);
        var target = EventUtil.getTarget(event);
        if (target.readyState == "loaded" || target.readyState == "complete") {
            EventUtil.removeHandler(target, "readystatechange", arguments.callee);
            alert("CSS Loaded");
        }
    });
    link.href = "example.css";
    document.getElementsByTagName("head")[0].appendChild(link);
});
  1. pageshow 和pagehide 事件

(略)

  1. hashchange 事件
    必须要把hashchange 事件处理程序添加给window 对象,然后URL 参数列表只要变化就会调用

它。此时的event 对象应该额外包含两个属性:oldURL 和newURL。这两个属性分别保存着参数列表
变化前后的完整URL。例如:

EventUtil.addHandler(window, "hashchange", function(event){
    alert("Old URL: " + event.oldURL + "\nNew URL: " + event.newURL);
}); //前后变化,完整url

EventUtil.addHandler(window, "hashchange", function(event){
    alert("Current hash: " + location.hash);
});//当前 #后字符

检测是否支持

var isSupported = ("onhashchange" in window) && (document.documentMode ===
undefined || document.documentMode > 7);

13.4.8 设备事件

  1. orientationchange 事件

苹果公司为移动Safari 中添加了orientationchange 事件,以便开发人员能够确定用户何时将设
备由横向查看模式切换为纵向查看模式。移动Safari 的window.orientation 属性中可能包含3 个值:
0 表示肖像模式,90 表示向左旋转的横向模式(“主屏幕”按钮在右侧),-90 表示向右旋转的横向模
式(“主屏幕”按钮在左侧)。相关文档中还提到一个值,即180 表示iPhone 头朝下;但这种模式至今
尚未得到支持。图13-10 展示了window.orientation 的每个值的含义

只要用户改变了设备的查看模式,就会触发orientationchange 事件。此时的event 对象不包
含任何有价值的信息,因为唯一相关的信息可以通过window.orientation 访问到。下面是使用这个
事件的典型示例

EventUtil.addHandler(window, "load", function(event) {
    var div = document.getElementById("myDiv");
    div.innerHTML = "Current orientation is " + window.orientation;
//改变时触发
    EventUtil.addHandler(window, "orientationchange", function(event) {
        div.innerHTML = "Current orientation is " + window.orientation;
    });
});
//横屏
window.orientation == 90 || window.orientation == -90
//竖屏
window.orientation == 0 || window.orientation == 180
//粗略检测,并不准,ie都返回false
alert(document.implementation.hasFeature("orientationchange", "2.0"))
  1. deviceorientation 事件
  2. 事件的意图是告诉开发人员设备在空间中朝向哪儿,而不是如何移动;

设备在三维空间中是靠x、y 和z 轴来定位的 三个值都是0

x轴: 左 --》 右;
y轴: 下 --》 上;
z轴: 后 --》 前;

事件对象包含以下5 个属性。
 alpha:在围绕z 轴旋转时(即左右旋转时),y 轴的度数差;是一个介于0 到360 之间的浮点数。
 beta:在围绕x 轴旋转时(即前后旋转时),z 轴的度数差;是一个介于180 到180 之间的浮点数。
 gamma:在围绕y 轴旋转时(即扭转设备时),z 轴的度数差;是一个介于90 到90 之间的浮点数。
 absolute:布尔值,表示设备是否返回一个绝对值。
 compassCalibrated:布尔值,表示设备的指南针是否校准过。

13.4.9 触摸与手势事件

touchstart/touchmove/touchend/touchcancel
每個event對象都有以下常見屬性;
bubbles、cancelable、view、clientX、clientY、screenX、screenY、detail、altKey、shiftKey、ctrlKey 和metaKey。

touches:表示当前跟踪的触摸操作的Touch 对象的数组。
 targetTouchs:特定于事件目标的Touch 对象的数组。
 changeTouches:表示自上次触摸以来发生了什么改变的Touch 对象的数组。
每个Touch 对象包含下列属性。

clientX:触摸目标在视口中的x 坐标。
 clientY:触摸目标在视口中的y 坐标。
 identifier:标识触摸的唯一ID。
 pageX:触摸目标在页面中的x 坐标。
 pageY:触摸目标在页面中的y 坐标。
 screenX:触摸目标在屏幕中的x 坐标。
 screenY:触摸目标在屏幕中的y 坐标。
 target:触摸的DOM 节点目标。
使用这些属性可以跟踪用户对屏幕的

function handleTouchEvent(event) {
    if (event.touches.length == 1) {
        var _output = document.getElementById('output')
        switch (event.type) {
            case 'touchstart':
                _output.innerHTML = 'Touch started' + event.touches[0].clientX + ',' + event.touches[0].clientY
                break;
            case 'touchend':
                _output.innerHTML += '<br> Touche ended' + event.changedTouches[0].clientX + ':' +
                    event.changedTouches[0].clientY + ';';
                break;
            case 'touchmove':
                event.preventDefault();
                _output.innerHTML += '<br> Touch move' +
                    event.changedTouches[0].clientX + ':' +
                    event.changedTouches[0].clientY + ';';
                break;
        }
    }
}

EventUtil.addHandler(document, 'touchstart', handleTouchEvent)
EventUtil.addHandler(document, 'touchend', handleTouchEvent)
EventUtil.addHandler(document, 'touchmove', handleTouchEvent)

當touchstart發生: 觸摸信息輸出到

中 當touchmove發生:取消默認行為,阻止滾動,輸出變化信息
當touchend發生時:輸出有關觸摸操作信息,在touchend發生時:touches集合中就沒有任何信息,因為不存在活動觸摸操作,此時必須使用changeTouches集合

發生順序如下:

(1) touchstart
(2) mouseover
(3) mousemove(一次)
(4) mousedown
(5) mouseup
(6) click
(7) touchend

  1. 手势事件

當兩個手指觸摸時,就會產生手勢,手勢通常會改變顯示項大小,或旋轉顯示項,三個事件

 gesturestart:当一个手指已经按在屏幕上而另一个手指又触摸屏幕时触发。
 gesturechange:当触摸屏幕的任何一个手指的位置发生变化时触发。
 gestureend:当任何一个手指从屏幕上面移开时触发。

当一个手指在屏幕时,触发touchstart
另一个手指放在屏幕,先触发gesturestart事件,随后触发该手指的touchstart
如果一个或两个手指在屏幕移动,触发gesturechange事件,但只要有一手指移开,触发gestureend事件,
最后再触发该手指的touchend事件;

每个event对象包含::
bubbles、cancelable、view、clientX、clientY、screenX、screenY、detail、altKey、shiftKey、
ctrlKey 和metaKey、还有两个额外属性:rotation、scale

rotation: 表示手指变化引起的旋转角度, -值逆时针,+ 顺时针(该值从0开始)
scale: 表示两个手指距离变化情况,如内收缩会缩短距离,从1开始;

function handleTouchEvent(event) {

    var _output = document.getElementById('output')
    switch (event.type) {
        case 'gesturestart':
            _output.innerHTML = 'Gesture started rotation = ' + event.rotation + ', scale' + event.scale;
            break;
        case 'gestureend':
            _output.innerHTML += '<br> Gesture end rotation = ' + event.rotation + ', scale' + event.scale;
            break;
        case 'gesturechange':
            event.preventDefault();
            _output.innerHTML += '<br> Gesture change rotation = ' + event.rotation + ', scale' + event.scale;
            break;
    }
}

EventUtil.addHandler(document, 'gesturestart', handleTouchEvent)
EventUtil.addHandler(document, 'gestureend', handleTouchEvent)
EventUtil.addHandler(document, 'gesturechange', handleTouchEvent)

13.5.1 事件委托

var list = document.getElementById('myLinks')
EventUtil.addHandler(list, 'click', function(event) { //父级绑定click
    event = EventUtil.getEvent(event)
    var target = EventUtil.getTarget(event)
    switch (target.id) {  //检测目标元素属性
        case 'doSomething':
            document.title = 'i cahnge the document is ttile'
            break;
        case 'goSomewhere':
            location.href = 'http://www.x.com';
            break;
        case 'sayHi':
            alert('hi')
            break;
    }
})
var btn = document.getElementById('myBtn')
btn.onclick = function(){
    document.getElementById('myDiv').innerHTML = 'processing'  //按钮被替换了,但click事件还在
}

//所以
var btn = document.getElementById('myBtn')
btn.onclick = function(){
    btn.onclick = null; //先移除
    document.getElementById('myDiv').innerHTML = 'processing'  //按钮被替换了,但click事件还在
}

13.6.1 DOM中的事件模拟

  1. 模拟鼠标事件
    创建新的鼠标事件对象并为其指定必要的信息,就可以模拟鼠标事件。创建鼠标事件对象的方法是

为createEvent()传入字符串"MouseEvents"。返回的对象有一个名为initMouseEvent()方法,
用于指定与该鼠标事件有关的信息。这个方法接收15 个参数,分别与鼠标事件中每个典型的属性一一
对应;这些参数的含义如下。

对应;这些参数的含义如下。
 type(字符串):表示要触发的事件类型,例如"click"。
 bubbles(布尔值):表示事件是否应该冒泡。为精确地模拟鼠标事件,应该把这个参数设置为
true。
 cancelable(布尔值):表示事件是否可以取消。为精确地模拟鼠标事件,应该把这个参数设
置为true。
 view(AbstractView):与事件关联的视图。这个参数几乎总是要设置为document.defaultView。
 detail(整数):与事件有关的详细信息。这个值一般只有事件处理程序使用,但通常都设置为0。
 screenX(整数):事件相对于屏幕的X 坐标。
 screenY(整数):事件相对于屏幕的Y 坐标。
 clientX(整数):事件相对于视口的X 坐标。
 clientY(整数):事件想对于视口的Y 坐标。
 ctrlKey(布尔值):表示是否按下了Ctrl 键。默认值为false。
 altKey(布尔值):表示是否按下了Alt 键。默认值为false。
 shiftKey(布尔值):表示是否按下了Shift 键。默认值为false。
 metaKey(布尔值):表示是否按下了Meta 键。默认值为false。
 button(整数):表示按下了哪一个鼠标键。默认值为0。
 relatedTarget(对象):表示与事件相关的对象。这个参数只在模拟mouseover 或mouseout
时使用。

var btn = document.getElementById('myBtn')

//创建事件对象
var event = document.createEvent('mouseEvents')

//初始化
event.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0, 0, 0,
false, false, false, false, 0, null);

//触发
btn.dispatchEvent(event)
  1. 模拟键盘事件
    一、DOM3 级规定,调用createEvent()并传入"KeyboardEvent"就可以创建一个键盘事件。返回的

事件对象会包含一个initKeyEvent()方法,这个方法接收下列参数
 type(字符串):表示要触发的事件类型,如"keydown"。
 bubbles(布尔值):表示事件是否应该冒泡。为精确模拟鼠标事件,应该设置为true。
 cancelable(布尔值):表示事件是否可以取消。为精确模拟鼠标事件,应该设置为true。
 view (AbstractView ):与事件关联的视图。这个参数几乎总是要设置为document.
defaultView。
 key(布尔值):表示按下的键的键码。
 location(整数):表示按下了哪里的键。0 表示默认的主键盘,1 表示左,2 表示右,3 表示
数字键盘,4 表示移动设备(即虚拟键盘),5 表示手柄。
 modifiers(字符串):空格分隔的修改键列表,如"Shift"。
 repeat(整数):在一行中按了这个键多少次。

DOM3级不提倡使用keypress 事件,因此只能利用这种技术来模拟keydown 和keyup 事件。

var textbox = document.getElementById("myTextbox"),
    event;
//以DOM3 级方式创建事件对象
if (document.implementation.hasFeature("KeyboardEvents", "3.0")) {
    event = document.createEvent("KeyboardEvent");
    //初始化事件对象
    event.initKeyboardEvent("keydown", true, true, document.defaultView, "a", 0, "Shift", 0);
}
//触发事件
textbox.dispatchEvent(event);

这个例子模拟的是按住Shift 的同时又按下A 键。在使用document.createEvent
("KeyboardEvent")之前,应该先检测浏览器是否支持DOM3 级事件;其他浏览器返回一个非标准的
KeyboardEvent 对象。

二、在Firefox 中,调用createEvent()并传入"KeyEvents"就可以创建一个键盘事件。返回的事件
对象会包含一个initKeyEvent()方法,这个方法接受下列10 个参数。

 type(字符串):表示要触发的事件类型,如"keydown"。
 bubbles(布尔值):表示事件是否应该冒泡。为精确模拟鼠标事件,应该设置为true。
 cancelable(布尔值):表示事件是否可以取消。为精确模拟鼠标事件,应该设置为true。
 view(AbstractView):与事件关联的视图。这个参数几乎总是要设置为document.default-
View。
 ctrlKey(布尔值):表示是否按下了Ctrl 键。默认值为false。
 altKey(布尔值):表示是否按下了Alt 键。默认值为false。
 shiftKey(布尔值):表示是否按下了Shift 键。默认值为false。
 metaKey(布尔值):表示是否按下了Meta 键。默认值为false。
 keyCode(整数):被按下或释放的键的键码。这个参数对keydown 和keyup 事件有用,默认
值为0。
 charCode(整数):通过按键生成的字符的ASCII 编码。这个参数对keypress 事件有用,默
认值为0。

//只适用于Firefox
var textbox = document.getElementById("myTextbox")
//创建事件对象
var event = document.createEvent("KeyEvents");
//初始化事件对象
event.initKeyEvent("keypress", true, true, document.defaultView, false, false,
false, false, 65, 65);
//触发事件
textbox.dispatchEvent(event);

三、其它浏览器
首先创建了一个通用事件,然后调用initEvent()对其进行初始化,最后又为其添加了
键盘事件的具体信息。在此必须要使用通用事

var textbox = document.getElementById("myTextbox");
//创建事件对象
var event = document.createEvent("Events");
//初始化事件对象
event.initEvent(type, bubbles, cancelable);
event.view = document.defaultView;
event.altKey = false;
event.ctrlKey = false;
event.shiftKey = false;
event.metaKey = false;
event.keyCode = 65;
event.charCode = 65;
//触发事件
textbox.dispatchEvent(event);
  1. 模拟其他事件
    模拟变动事件, 可以使用createEvent("MutationEvents") 创建一个包含

initMutationEvent() 方法的变动事件对象。这个方法接受的参数包括: type 、bubbles 、
cancelable、relatedNode、preValue、newValue、attrName 和attrChange。下面来看一个模
拟变动事件的例子。

var event = document.createEvent("MutationEvents");
event.initMutationEvent("DOMNodeInserted", true, false, someNode, "","","",0);
targ et.dispatchEvent(event);

以上代码模拟了DOMNodeInserted

  1. 自定义DOM 事件

创建新的自定义事件,可以调用createEvent("CustomEvent")。返回的对象有一个名为initCustomEvent()的方法

var div = document.getElementById("myDiv"),
    event;
EventUtil.addHandler(div, "myevent", function(event) {
    alert("DIV: " + event.detail);
});
EventUtil.addHandler(document, "myevent", function(event) {
    alert("DOCUMENT: " + event.detail);
});
if (document.implementation.hasFeature("CustomEvents", "3.0")) {
    event = document.createEvent("CustomEvent");
    event.initCustomEvent("myevent", true, false, "Hello world!");
    div.dispatchEvent(event);
}

创建了一个冒泡事件"myevent"。而event.detail 的值被设置成了一个简单的字符串,
然后在

元素和document 上侦听这个事件。因为initCustomEvent()方法已经指定这个事件应
该冒泡,所以浏览器会负责将事件向上冒泡到document。

支持自定义DOM事件的浏览器有IE9+和Firefox 6+。

13.6.2 IE中的事件模拟
IE8之前的版本
思路相似:先创建event 对象,然后为其指定相应的信息,然后再使用该对象来触发事件
调用document.createEventObject()方法可以在IE 中创建event 对象。但与DOM方式不同的是,这个方法不接受参数,结果会返回一个通用的event 对象
最后一步就是在目标上调用fireEvent()方法

fireEvent(事件处理程序的名称,event对象)

在调用fireEvent()方法时,会自动为event 对象添加srcElement 和type 属性

其他属性则都是必须通过手工添加的。换句话说,模拟任
何IE 支持的事件都采用相同的模式。例如,下面的代码模拟了在一个按钮上触发click 事件过程

var btn = document.getElementById("myBtn");
//创建事件对象
var event = document.createEventObject();
//初始化事件对象
event.screenX = 100;
event.screenY = 0;
event.clientX = 0;
event.clientY = 0;
event.ctrlKey = false;
event.altKey = false;
event.shiftKey = false;
event.button = 0;
//触发事件
btn.fireEvent("onclick", event);

//触发keypress事件

var textbox = document.getElementById("myTextbox");
//创建事件对象
var event = document.createEventObject();
//初始化事件对象
event.altKey = false;
event.ctrlKey = false;
event.shiftKey = false;
event.keyCode = 65;
//触发事件
textbox.fireEvent("onkeypress", event);

零js基礎 | 程序設計 | 12 - DOM2和DOM3

var supportsDOM2Core = document.implementation.hasFeature("Core", "2.0");
var supportsDOM3Core = document.implementation.hasFeature("Core", "3.0");
var supportsDOM2HTML = document.implementation.hasFeature("HTML", "2.0");
var supportsDOM2Views = document.implementation.hasFeature("Views", "2.0");
var supportsDOM2XML = document.implementation.hasFeature("XML", "2.0");

混合svg写法

<html xmlns="http://www.w3.org/1999/xhtml">

<head>
    <title>Example XHTML page</title>
</head>

<body>
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100" style="width:100%; height:100%">
        <rect x="0" y="0" width="100" height="100" style="fill:red" />
    </svg>
</body>

</html>

在DOM2 级中,Node 类型包含下列特定于命名空间的属性。
localName:不带命名空间前缀的节点名称。
namespaceURI:命名空间URI 或者(在未指定的情况下是)null。
prefix:命名空间前缀或者(在未指定的情况下是)null。

nodeName 等于prefix+":"+ localName

<html>元素來說

localName:html
tagName:html
namespaceURI:http://www.w3.org/1999/xhtml
prefix:null

<s:svg>元素

localName:svg
tagName:s:svg
namespaceURI:http://www.w3.org/2000/svg
prefix:s

DOM3 级在此基础上更进一步,又引入了下列与命名空间有关的方法。

isDefaultNamespace(namespaceURI):在指定的namespaceURI 是当前节点的默认命名空
间的情况下返回true。
lookupNamespaceURI(prefix):返回给定prefix 的命名空间。
lookupPrefix(namespaceURI):返回给定namespaceURI 的前缀。

Document变化

只有在文档中存在两个或多个命名空间时,这些与命名空间有关的方法才是必需的。

        //创建一个新的SVG 元素
        var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
        //创建一个属于某个命名空间的新特性
        var att = document.createAttributeNS("http://www.somewhere.com", "random");
        //取得所有XHTML 元素
        var elems = document.getElementsByTagNameNS("http://www.w3.org/1999/xhtml", "*");

Element变化

getAttributeNS(namespaceURI,localName):取得属于命名空间namespaceURI 且名为
localName 的特性。

getAttributeNodeNS(namespaceURI,localName)
getElementsByTagNameNS(namespaceURI, tagName)
hasAttributeNS(namespaceURI,localName)
removeAttriubteNS(namespaceURI,localName)
setAttributeNS(namespaceURI,qualifiedName,value)
setAttributeNodeNS(attNode)

除了第一个参数之外,这些方法与DOM1 级中相关方法的作用相同;第一个参数始终都是一个命
名空间URI。

NamedNodeMap变化
getNamedItemNS(namespaceURI,localName)取得属于命名空间namespaceURI 且名为
localName 的项。
removeNamedItemNS(namespaceURI,localName)

其它变化:

  1. DocumentType 类型的变化 类型新增了3 个属性:publicId、systemId 和internalSubset。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">

中的:publicId == "-//W3C//DTD HTML 4.01//EN",
systemId =="http://www.w3.org/TR/html4/strict.dtd"

alert(document.doctype.publicId);
alert(document.doctype.systemId);
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
[<!ELEMENT name (#PCDATA)>] >
document.doctype.internalSubset //"<!ELEMENT name (#PCDATA)>"
  1. Document 类型的变化
    importNode()
  2. Node 类型的变化
    isSupported()

与DOM1级为document.implementation 引入的hasFeature()方法类似,isSupported()方法用于确定当前节点具有什么能力

if (document.body.isSupported("HTML", "2.0")){
//执行只有"DOM2 级HTML"才支持的操作
}

DOM3 额外引入数据:setUserData(要设置的键,实际的数据(可以是任何数据类型),处理函数)

var value = document.body.getUserData("name");

//创建div
var div = document.createElement("div");

//添加数据
div.setUserData("name", "Nicholas", function(operation, key, value, src, dest) {
    if (operation == 1) {
        dest.setUserData(key, value, function() {});
    }
});

//使用cloneNode复制时,会调用处理函数,从而将数据自动复制到副本
var newDiv = div.cloneNode(true);

//调用getUserData()时,返回与原始结点相同的值
alert(newDiv.getUserData("name")); //"Nicholas"
  1. 框架的变化
var iframe = document.getElementById("myIframe");
var iframeDoc = iframe.contentDocument; //在IE8 以前的版本中无效

兼容

对象,可以使用下列代码。
var iframe = document.getElementById("myIframe");
var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;

cssText
在写入模式下,赋给cssText 的值会重写整个style 特性的值;也就是
说,以前通过style 特性指定的样式信息都将丢失。例如,如果通过style 特性为元素设置了边框,
然后再以不包含边框的规则重写cssText,那么就会抹去元素上的边框。下面是使用cssText 属性的

var div = document.getElementsByTagName('div')[0]
div.style.cssText = 'width:25px;height:100px;background-color:red'

console.log(div.style.cssText)  //width:25px;height:100px;background-color:red

for (var i = 0; i < div.style.length; i++) {

    alert(div.style[i]) //width/height/backgorund-color

    alert(div.style.item(i))

    console.log(div.style.getPropertyValue(div.style[i])) //25px 100px red

}

getPropertyValue()方法取得的始终都是CSS 属性值的字符串表
getPropertyCSSValue()它返回一个包含两个属性的CSSValue 对象,这两个属性分,别是:cssText 和cssValueType。

div.style.removeProperty('width') //移除

getComputedStyle() 要取得樣式的元素與一個為元素字條串如:after,第二個參數可以為null;

無論樣式表還是行間樣式;計算後的值

        var myDiv = document.getElementById("myDiv");
        var computedStyle = document.defaultView.getComputedStyle(myDiv, null);
        alert(computedStyle.backgroundColor); // "red"
        alert(computedStyle.width); // "100px"
        alert(computedStyle.height); // "200px"
        alert(computedStyle.border); // 在某些浏览器中是"1px solid black"

IE下

      var myDiv = document.getElementById("myDiv");
        var computedStyle = myDiv.currentStyle;
        alert(computedStyle.backgroundColor); //"red"
        alert(computedStyle.width); //"100px"
        alert(computedStyle.height); //"200px"
        alert(computedStyle.border); //undefined

綜合

function getStyle(obj, attr) {
    if (obj.currentStyle) {
        return obj.currentStyle[attr]
    } else {
        return getComputedStyle(obj, false)[attr]
    }
};
function getStyleSheet(element){
return element.sheet || element.styleSheet;
}
//取得第一个<link/>元素引入的样式表
var link = document.getElementsByTagName("link")[0];
var sheet = getStyleSheet(link);
var sheet = document.styleSheets[0];
var rules = sheet.cssRules || sheet.rules; //取得规则列表
var rule = rules[0]; //取得第一条规则
alert(rule.selectorText); //"div.box"
alert(rule.style.cssText); //完整的CSS 代码
alert(rule.style.backgroundColor); //"blue"
alert(rule.style.width); //"100px"
alert(rule.style.height); //"200px"
<style>.box{width:100px;}</style>   ----sheet = document.styleSheets[0];
<link rel="stylesheet" href="style.css">----sheet = document.styleSheets[1];
<style>.box{height}</style> --sheet = document.styleSheets[2];


var rules = sheet.cssRules || sheet.rules; //取得规则列表
為每一個sheet裏的每一條;{}裏算一條

必须要注意的是,以这种方式修改规则会影响页面中适用于该规则的所有元素。换句话说,如果有两个带有box 类的

元素,那么这两个元素都会应用修改后的样式。

var sheet = document.styleSheets[0];
var rules = sheet.cssRules || sheet.rules; //取得规则列表
var rule = rules[0]; //取得第一条规则
rule.style.backgroundColor = "yellow"
        function getTop(o) {
            var oTop = o.offsetTop;
            var current = o.offsetParent;

            while (current !== null) {
                oTop += current.offsetTop;
                current = current.offsetParent;
            }
            return oTop;
        }
        alert(getTop(box))

所以视口

        function getViewport() {
            if (document.compatMode == "BackCompat") {
                return {
                    width: document.body.clientWidth,
                    height: document.body.clientHeight
                };
            } else {
                return {
                    width: document.documentElement.clientWidth,
                    height: document.documentElement.clientHeight
                };
            }
        }
        console.log(getViewport())

scrollHeight/scrollWidth/scrollLeft/scrollTop

有些元素(例如<html>元素),即使没有执行任何代码也能自动地添加滚动条;但另外一些元素,则需要通过CSS 的
overflow 属性进行设置才能滚动
scrollWidth 和scrollHeight 主要用于确定元素内容的实际大小

无滚动条时:scrollWidth = clientWidth

实际页面大小:document.documentElement.scrollHeight

视口大小:document.documentElement.clientHeight

无滚动条时:
IE7 chrome

document.documentElement.scrollHeight(页面占用元素大小) < document.documentElement.clientHeight(视口大小)

IE8 /IE9 /IE10 /IE11 firfox

document.documentElement.scrollHeight == document.documentElement.clientHeight

getBoundingClientRect()返回矩形,ie8(2.2),ie9(0,0)

,right 和left 的差值与offsetWidth 的值相等,而bottom 和top 的差值与offsetHeight
相等。而且,left 和top 属性大致等于使用本章前面定义的getElementLeft()和getElementTop()
函数取得的值

function getBoundingClientRect(element) {
    var scrollTop = document.documentElement.scrollTop;
    var scrollLeft = document.documentElement.scrollLeft;
    if (element.getBoundingClientRect) {
        if (typeof arguments.callee.offset != "number") {
            var temp = document.createElement("div");
            temp.style.cssText = "position:absolute;left:0;top:0;";
            document.body.appendChild(temp);
            arguments.callee.offset = -temp.getBoundingClientRect().top - scrollTop;
            document.body.removeChild(temp);
            temp = null;
        }
        var rect = element.getBoundingClientRect();
        var offset = arguments.callee.offset;
        return {
            left: rect.left + offset,
            right: rect.right + offset,
            top: rect.top + offset,
            bottom: rect.bottom + offset
        };
    } else {
        var actualLeft = getElementLeft(element);
        var actualTop = getElementTop(element);
        return {
            left: actualLeft - scrollLeft,
            right: actualLeft + element.offsetWidth - scrollLeft,
            top: actualTop - scrollTop,
            bottom: actualTop + element.offsetHeight - scrollTop
        }
    }
}

alert(getBoundingClientRect(div).left)
alert(getBoundingClientRect(div).right)
alert(div.offsetWidth)
`
DOM2 级遍历和范围

检测是否有DOM2级能力(IE8返回false)

var supportsTraversals = document.implementation.hasFeature("Traversal", "2.0");
var supportsNodeIterator = (typeof document.createNodeIterator == "function");
var supportsTreeWalker = (typeof document.createTreeWalker == "function");

从document 开始依序向前,向下遍历,到开始根节点为止。NodeIterator
和TreeWalker 都以这种方式执行遍历。
    createNodeIterator(root[起点],whatToShow[哪些节点数字代码],filter[NodeFilter对象,一个表示接受或拒绝的特定节点],entityReferenceExpansion[布尔值,表示是否扩展实体引用])

DOM2-----------------------------待放






零js基礎 | 程序設計 | 11 - DOM扩展

DOM扩展

    var div = document.querySelector('#div')

    //返回NodeList實例
    var div = document.querySelectorAll('.divClass')

    console.log(div.item(0))
    console.log(div[0])
    console.log(div)

matchesSelector(CSS選擇符),如果匹配 true,否則 false

if (matchesSelector(div[0], '#div.divClass')) {
    alert(true)
}
//兼容性
function matchesSelector(element, selector) {
    if (element.matchesSelector) {
        return element.matchesSelector(selector);
    } else if (element.msMatchesSelector) {
        return element.msMatchesSelector(selector);
    } else if (element.mozMatchesSelector) {
        return element.mozMatchesSelector(selector);
    } else if (element.webkitMatchesSelector) {
        return element.webkitMatchesSelector(selector);
    } else {
        throw new Error("Not supported.");
    }
}

支持Element Traversal 规范的浏览器有IE 9+、Firefox 3.5+、Safari 4+、Chrome 和Opera 10+。

 childElementCount:返回子元素(不包括文本节点和注释)的个数。
 firstElementChild:指向第一个子元素;firstChild 的元素版。
 lastElementChild:指向最后一个子元素;lastChild 的元素版。
 previousElementSibling:指向前一个同辈元素;previousSibling 的元素版。
 nextElementSibling:指向后一个同辈元素;nextSibling 的元素版。

二、困扰你我的NodeList与HTMLCollection      
  相同点:

    1. 类数组。有length属性,可以用下标索引来访问其中的元素,但没有Array的slice等方法;

    2. 只读。无法增删其中的元素;

    3. 实时同步DOM树的变化。若DOM树有新元素加入,该类型的对象也会将新元素包含进来;

    4. 可通过下标数字类型索引获取集合中指定位置的元素;

    5. 可通过item({String | Number} 索引)方法获取集合中指定位置的元素,若通过索引找不到元素,则以第一个元素作为返回值。

  不同点(主要表现在HTMLCollection比NodeList能力更强大):

    1. HTMLCollection对象可通过namedItem({String} id或name)获取首个匹配的元素,若没有则返回null;

    2. HTMLCollection对象可通过点方式获取第个id或name匹配的元素,若没有则返回undefined。

  各浏览器选择器返回类型差别:

        
        console.log(div instanceof NodeList)  //true

        //帶有.divClass.username的元素
        var div = document.getElementsByClassName('divClass username')
        console.log(div)

        console.log(div instanceof HTMLCollection) //true;

傳統刪class

        var classNames = div.className.split(/\s+/);
        var pos = -1;
        
        for(var i=0;i<classNames.length;i++){
            if(classNames[i] == 'user'){
                pos = i;
                break;
            }
        }
        classNames.splice(i,1);
        div.className = classNames.join(' ');

classList,IE10+,chrome,firefox

        div[0].classList.remove('username')
        div[0].classList.add('current')
        div[0].classList.toggle('divClass')
        
        
        if(div[0].classList.contains('password') && div[0].classList.contains('disabled')){
            alert(true)
        }

焦点管理

var btn = document.getElementById('myButton')
btn.focus()
alert(document.activeElement == btn) //true 

//文档加载完成时,document.activeElement保存的是document.body引用

//确定文档是否获得了焦点
alert(document.hasFocus()) //true

HTMLDocument的变化
1、readyState 两个值 loading:正在加载;complete:已经完成

if(document.readyState == 'complete'){
    
}

2、document.compatMode 的
值等于"CSS1Compat",而在混杂模式下,document.compatMode 的值等于"BackCompat"。

if (document.compatMode == "CSS1Compat") {
    alert("Standards mode");
} else {
    alert("Quirks mode");
}

3、head属性
Chrome 和Safari 5。

var head = document.head || document.getElementsByTagName("head")[0];

字符集属性

alert(document.charset); //"UTF-16"
document.charset = "UTF-8";

defaultCharset,表示根据默认浏览器及操作系统的设置,当前文档默认的字符集
应该是什么

if (document.charset != document.defaultCharset){
alert("Custom character set being used.");
}

自定义数据属性
data-,通过dataset访问 ,dataset是DOMStringMap的一个实例,每个data-name形式的属性都会有一个对应的属性,
比如,自定义属性是data-myname,
那映射中对应的属性就是myname)

<div id="myDiv" data-appId="12345" data-myname="Nicholas"></div>
        var div = document.getElementById('myDiv')
        
        //获取
        var appId = div.dataset.appId;
        var myName = div.dataset.myname;
        //设置
        div.dataset.appId = 123456
        div.dataset.myname = 'elmok'
        
        if(div.dataset.myname){
            alert('hello ' + div.dataset.myname)
        }

插入标记

innerHTML不同浏览器返回的值大小写可能不同
outerHTML返回包括外层
insertAdjacentHTML()两个参数
 "beforebegin",在当前元素之前插入一个紧邻的同辈元素;
 "afterbegin",在当前元素之下插入一个新的子元素或在第一个子元素之前再插入新的子元素;
 "beforeend",在当前元素之下插入一个新的子元素或在最后一个子元素之后再插入新的子元素;
 "afterend",在当前元素之后插入一个紧邻的同辈元素。

<div id="content"></div>
    //作为前一个同辈元素插入
    con.insertAdjacentHTML("beforebegin", "<p>beforebegin!</p>");
    //作为第一个子元素插入
    con.insertAdjacentHTML("afterbegin", "<p>afterbegin!</p>");
    //作为最后一个子元素插入
    con.insertAdjacentHTML("beforeend", "<p>beforeend!</p>");
    //作为后一个同辈元素插入
    con.insertAdjacentHTML("afterend", "<p>afterend!</p>");

之后

<p>beforebegin!</p>
<div id="content">
    <p>afterbegin!</p>
    <p>beforeend!</p>
</div>
<p>afterend!</p>

在使用innerHTML、
outerHTML 属性和insertAdjacentHTML()方法时,最好先手工删除要被替换的元素的所有事件处理
程序和JavaScript 对象属性

for (var i=0, len=values.length; i < len; i++){
ul.innerHTML += "<li>" + values[i] + "</li>"; //要避免这种频繁操作!!
}

//正确做法
var itemsHtml = "";
...

scrollIntoView(),滚动标准作法
如果给这个方法传入true 作为参数,或者不传入任何参数,那么窗口滚动之后会让调用元素的顶部与视口顶部尽可能平齐;
如果传入false 作为参数,调用元素会尽可能全部
出现在视口中,(可能的话,调用元素的底部会与视口顶部平齐。)不过顶部不一定平齐

只有调用才会出现在视口中,类似于a标签本页定位的效果

var btn = document.getElementById('btn')
var div = document.getElementById('content')

btn.onclick = function(){
div.scrollIntoView(true)
}

IE “文档模式”(document mode) 文档模式决定了你可以使用哪个级别的 CSS
要强制浏览器以某种模式渲染页面,可以使用 HTTP头部信息 X-UA-Compatible,或通过等价的 <meta>标签来设置:

//<meta http-equiv="X-UA-Compatible" content="IE=IEVersion"> 

<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7">

    var mode = document.documentMode; 
    alert(mode) // 11/10/9/8/7/5....  

children属性
。IE8及更早版本的 children 属性中也会包含注释节点,但 IE9之后的版本则 只返回元素节点

contains()方法.
经常需要知道某个节点是不是另一个节点的后代

alert(document.documentElement.contains(document.body)); //true
  1. innerText 属性
    outerText 属性 //包括父级也替换

滚动

scrollIntoView()
scrollIntoViewIfNeeded(alignCenter):只在当前元素在视口中不可见的情况下,才滚
动浏览器窗口或容器元素,最终让它可见。如果当前元素在视口中可见,这个方法什么也不做。
如果将可选的alignCenter 参数设置为true,则表示尽量将元素显示在视口中部(垂直方向)。
Safari 和Chrome 实现了这个方法。
 scrollByLines(lineCount):将元素的内容滚动指定的行高,lineCount 值可以是正值,
也可以是负值。Safari 和Chrome 实现了这个方法。
 scrollByPages(pageCount):将元素的内容滚动指定的页面高度,具体高度由元素的高度决
定。Safari 和Chrome 实现了这个方法。
希望大家要注意的是,scrollIntoView()和scrollIntoViewIfNeeded()的作用对象是元素的
容器,而scrollByLines()和scrollByPages()影响的则是元素自身。下面还是来看几个示例吧。

//将页面主体滚动5 行
document.body.scrollByLines(5);
//在当前元素不可见的时候,让它进入浏览器的视口
document.images[0].scrollIntoViewIfNeeded();
//将页面主体往回滚动1 页
document.body.scrollByPages(-1);

由于scrollIntoView()是唯一一个所有浏览器都支持的方法,因此还是这个方法最常用。

零js基礎 | 程序設計 | 10 - DOM

Node.nodeType == 1 元素节点
Node.nodeType == 2 属性节点
Node.nodeType == 3 文本节点

<head>
    <meta charset="UTF-8">
    <title></title>
</head>

    var h = document.getElementsByTagName('head')[0]
 //   h.nodeType == 1 && console.log('this is an elem')
    h.nodeType == 1 && console.log(h.nodeName) //HEAD

//每个节点都有一个childNodes 属性,其中保存着一个NodeList 对象。即类数组对象
    console.log(h.childNodes[0])
    console.log(h.childNodes[1])
    console.log(h.childNodes[2])
    console.log(h.childNodes[3])
    console.log(h.childNodes[4])

    console.log(h.parentNode)  //5

    console.log(h.childNodes.length)

把NodeTypelist转为数组

function convertToArray(nodes) {
    var array = null;
    try {
        array = Array.prototype.slice.call(nodes, 0); //针对非IE 浏览器
    } catch (ex) {
        array = new Array();
        for (var i = 0, len = nodes.length; i < len; i++) {
            array.push(nodes[i]);
        }
    }
    return array;
}

每个Node都有一个parentNode属性,该属性指向文档树中的父节点;
nodeName //HEAD
parentNode //Html文档结构
childNodes //Nodelists节点集合
previousSibling //前一个
nextSibling //后一个

如果没有子节点,那么firstChild 和lastChild 的值均为null

hasChildNodes(),这个方法在节点包含一或多个子节点的情况下返回true;应该说,这是比查询childNodes
列表的length 属性更简单的方法。

h.hasChildNodes()

ownerDocument,所有节点的共同属性,指向整个文档节点

console.log(h.ownerDocument)

操作节点

末尾:
appendChild()相当于向childNodes列表尾部添加一个节点,,如果是已有节点,则相当于剪切;

中间:
insertBefore(),向childNodes列表放在特定的位置上
insertBefore(要插入的节点,作为参照的节点) 【插入之后按顺序前后排:要插入的节点,作为参照的节点】

插入节点后,被插
入的节点会变成参照节点的前一个同胞节点(previousSibling),

returnedNode = someNode.insertBefore(newNode, null);
alert(newNode == someNode.lastChild); //true

//插入后成为第一个子节点
var returnedNode = someNode.insertBefore(newNode, someNode.firstChild);
alert(returnedNode == newNode); //true
alert(newNode == someNode.firstChild); //true

//插入到最后一个子节点前面
returnedNode = someNode.insertBefore(newNode, someNode.lastChild);
alert(newNode == someNode.childNodes[someNode.childNodes.length-2]); //true

替换:

replaceChild(要插入的节点,要替换的节点)

//替换第一个子节点
var returnedNode = someNode.replaceChild(newNode, someNode.firstChild);

//替换最后一个子节点
returnedNode = someNode.replaceChild(newNode, someNode.lastChild);

移除:
removeChild(要移除的节点)

前面介绍的四个方法操作的都是某个节点的子节点,也就是说,要使用这几个方法必须先取得父节
点(使用parentNode 属性)。另外,并不是所有类型的节点都有子节点,如果在不支持子节点的节点
上调用了这些方法,将会导致错误发生。

共有的节点方法:

cloneNode(true/false),需要再使用 appendChild()/insertBefore()/replaceChild()

normalize() /这个方法唯一的作用就是处理文档树中的文本节点



Document类型

 nodeType 的值为9;
 nodeName 的值为"#document";
 nodeValue 的值为null;
 parentNode 的值为null;
 ownerDocument 的值为 null;
Document 节点的子节点可以是DocumentType、Element、ProcessingInstruction
或Comment,

内置访问子节点的快捷方式:
document.documentElement属性

document.documentElement ==
document.childNodes[0] ==
document.firstChild ==

document.body 属性,直接指向<body>元素;

另一个子节点可能是:(浏览器支持有限)

var doctype = document.doctype; //取得对<!DOCTYPE>的引用

文档信息

document对象属性:

//取得文档标题
var originalTitle = document.title;

//设置文档标题
document.title = "New page title";

//取得完整的URL
var url = document.URL;

//取得域名
var domain = document.domain;

//取得来源页面的URL
var referrer = document.referrer;

IE7下,name與ID相同的不同元素使用doc..ById會返回name的元素

    alert(document.getElementById('myelem').nodeName)

不要讓表單字段的name與其他ID相同

var imgs = document.getElementsByTagName('img')
var imgsname = imgs.namedItem('myimgName')

取得單選按鈕【常用】 getElementByName('color');

特殊集合
document.anchors:包括name屬性的a元素
document.links:包含所有帶href特性的a元素
document.images:包含所img元素
document.forms:包含所form元素

一個element類型:

    console.log(box.nodeType)  //1
    console.log(box.nodeName)  //DIV
    console.log(box.nodeValue) //null
    
    console.log(box.parentNode) //<body......body>
    console.log(box.childNodes) //[elem..text..com...]
    
    console.log(box.tagName) //DIV  tagName == nodeName

HTML元素,可读可写

alert(div.id); //"myDiv""
alert(div.className); //"bd"
alert(div.title); //"Body text"
alert(div.lang); //"en"
alert(div.dir); //"ltr"

取得特性

alert(div.getAttribute("id")); //"myDiv"
alert(div.getAttribute("class")); //"bd"
alert(div.getAttribute("title")); //"Body text"
alert(div.getAttribute("lang")); //"en"
alert(div.getAttribute("dir")); //"ltr"

不存在返回null;

自定义属性应该加上data-前缀以便验证

    var div = document.getElementById('myDiv')
        alert(div.my_special_attribute); //undefined(IE<8 弹 hello ,其它弹undefined)

设置属性:
box.setAttribute('style') //如果不写出错 box.setAttribute('style','')//正确

自定义属性不能简单地使用.来设置

        box.mycolor = 'red';  //使用.设置
        alert(box.getAttribute('mycolor')) //null;(IE9<可弹出)
        
        //setAttributte配套使用;
        box.setAttribute('myspace','300px')
        alert(box.getAttribute('myspace'))

div.removeAttribute("class");完全清除,彻底删除元素特性;

  1. attributes 属性
    Element 类型是使用attributes 属性的唯一一个DOM 节点类型。attributes 属性中包含一个

NamedNodeMap,与NodeList 类似,也是一个“动态”的集合。元素的每一个特性都由一个Attr 节
点表示,每个节点都保存在NamedNodeMap 对象中。NamedNodeMap 对象拥有下列方法

遍历元素特性序列化

function outputAttributes(element) {
    var pairs = new Array(),
        attrName,
        attrValue,
        i,
        len;
    for (i = 0, len = element.attributes.length; i < len; i++) {
        attrName = element.attributes[i].nodeName;
        attrValue = element.attributes[i].nodeValue;
        if (element.attributes[i].specified) {
            pairs.push(attrName + "=\"" + attrValue + "\"");
        }
    }
    return pairs.join(" ");
}

console.log(outputAttributes(box)) // id="box" style="font-size:14px;color:#000" class="boxclass"

创建元素

``javascript

var div = document.body.appendChild('div')
div.id = mydiv
document.body.appendChild(div)

创建文本

var box = document.getElementById('box')
if(box.childNodes[0].nodeType == 3 ){
    alert(123)
}
alert(box.childNodes[0].nodeValue)
alert(box.childNodes[0].data)

Text类型
var e = document.createElement('div')
e.className = 'message'
var atnode = document.createTextNode('fuck ')
e.appendChild(atnode)

var atnode2 = document.createTextNode('world')
e.appendChild(atnode2)


alert(e.childNodes.length) //2  个节点 

e.normalize()  //规范化成1个(合并)
alert(e.childNodes.length) //1

alert(e.firstChild.nodeValue) //fuck world

分割  splitText()
var e = document.createElement('div')
e.className = 'message'

var Tnode = document.createTextNode('hello world')
e.appendChild(Tnode)
document.body.appendChild(e);
var newNode = e.firstChild.splitText(2)
alert(e.firstChild.nodeValue) //he 从2的位置开始分割
comment类型 注释类型 nodeType == 8 
CDATASection类型 XML 文档,表示CDATA区域 nodeType == 4 
DocumentType类型 nodeType == 10
DocumentFragment类型 nodeType == 11;
Attr类型 存在于元素的attributes属性中的节点,nodeType == 11; ??

创建动态脚本:

function loadScript(url) {

var script = document.createElement('script')
script.type = 'text/javascript'
script.src = url
document.body.appendChild(script)

}
loadScript('main.js')


代码执行
function loadScriptString(code) {
    var script = document.createElement('script')
    script.type = 'text/javascript'
    try {
        script.appendChild(document.createTextNode(code))
    } catch (ex) {
        script.text = code;
    }
    document.body.appendChild(script)
}
loadScriptString("function sayHi(){alert('hi')}")`
其实效果跟     eval("function sayName(){alert('name')}")  一样; 

动态样式
function loadStyles(url) {
    var link = document.createElement('link')
    link.rel = 'stylesheet'
    link.type = 'text/css'
    link.href = url
    var head = document.getElementsByTagName('head')[0]
    head.appendChild(link)
}
loadStyles('style.css')

function loadStyleString(css) {

var style = document.createElement('style')
style.type = 'text/css'
try {
    style.appendChild(document.createTextNode(css))
} catch (ex) {
    style.style.cssText = css;
}
document.getElementsByTagName('head')[0].appendChild(style);

}

loadStyleString('body{background:#1F78BF}')

操作表格
cell 11 cell 22
cell 33 cell 44
var table = document.createElement('table')
table.border = 1;
table.width = '100%'

//tbody

var tbody = document.createElement('tbody')
table.appendChild(tbody)

//第一行

tbody.insertRow(0)
tbody.rows[0].insertCell(0);
tbody.rows[0].cells[0].appendChild(document.createTextNode('cell 11'))
tbody.rows[0].insertCell(1);
tbody.rows[0].cells[1].appendChild(document.createTextNode('cell 22'))

//第二行

tbody.insertRow(1)
tbody.rows[1].insertCell(0);
tbody.rows[1].cells[0].appendChild(document.createTextNode('cell 33'))
tbody.rows[1].insertCell(1);
tbody.rows[1].cells[1].appendChild(document.createTextNode('cell 44'))

document.body.appendChild(table)

**HTMLCollection、NodeList以及NamedNodeMap这三个集合都是“动态的”,每当文档发生变化时,他们都会更新。他们将始终保持这最新、最准确的消息。且看以下程序:**
var divs = document.getElementsByTagName('div'),
    i, div;
for (i = 0; i < divs.length; i++) {
    div = document.createElement('div')
    document.body.appendChild(div)
}
//以上代码,第一次取得所有div 元素的HTMLCollection,下次取得会更新,造成死循环

//正确使用

var divs = document.getElementsByTagName('div'),
    i, len, div;
for (i = 0, len = divs.length; i < len; i++) {
    div = document.createElement('div')
    document.body.appendChild(div)
}

<hr />

DOM元素的特性(Attribute)  和    属性(Property)

Attribute特性: dom节点自带的属性,例如html中常用的id、class、title、align等:

//赋值:之后立即体现到DOM ,如果是标准特性,也会关联到相对应的属性值 ;

div1.setAttribute('class', 'a');
div1.setAttribute('title1', 'c');
Property属性: 而Property是这个DOM元素作为对象,其附加的内容,例如childNodes、firstChild等:

//取值,用.
var id = div1.id;
var attrs = div1.attributes;

//上面代码中的div1.attributes是取的attributes这一属性,取出来保存到attrs变量中,attrs就成了一个NamedNodeList类型的对象,里面存储了若干个Attr类型。

//赋值 :对属性Property可以赋任何类型的值,而对特性Attribute只能赋值字符串!
div1.className = 'a';



<hr >
NodeList v.s. HTMLCollection

Node及对应集合NodeList
Element(继承Node)及对应集合HTMLCollection
Document(继承Node)