手记

JS文档对象模型DOM——且听风吟720

DOM(Document Object Model),文档对象模型(是什么,可以用来干什么)

1. DOM方法

1.1 getElementById

  • 返回指定id的第一个对象
var div = document.getElementById("div");//返回id值为div的元素

1.2 getElementsByTagName

  • 返回指定的标签名的一个类数组对象(因为返回的值是一个类数组,可以理解成多个对象,所以方法名中用Elements
  • 如果只要其中的某一个,可以用数组中的方括号来访问(起始下标为0)
  • 想知道一共有几个,可以用length属性
var div = document.getElementsByTagName("div");//返回所有div元素组成的类数组对象
var div1 = document.getElementsByTagName("div")[0];//返回所有div元素中的第一个
var len = div.length;//返回div元素的数量(Number类型)

1.3 getAttribute

  • 获取元素的指定的某一个属性
var mydiv = document.getElementById("div");
var iden = mydiv.getAttribute("id");//获得ID为div元素的ID属性值

1.4 setAttribute

  • 设置元素的属性(包括了添加修改,设置为空也可以理解成删除
var mydiv = document.getElementById("div");
mydiv.setAttribute("class","mydiv");//把div元素的class属性值设置为mydiv

1.5 removeAttribute

  • 删除元素的属性
var mydiv = document.getElementById("div");
mydiv.removeAttribute("class");//删除div元素的class属性,即为空

2. DOM属性

2.1 style

  • 设置元素的CSS样式
var myDiv = document.getElementById("div");
div.style.background="blue";//ID值为div的元素的背景颜色被设置成为蓝色

2.2 innerHTML

  • 返回元素标签内部的HTML(注意不一定是文档),可以理解成“读取”
  • 设置元素标签内部的HTML,可理解成“写入”
var mydiv = document.getElementById("div");
var inner = mydiv.innerHTML;//获取ID为div的元素的内部的内容
//如果有内部嵌套标签则连同嵌套标签和文档一并返回
mydiv.innerHTML = "<p>Hello, world</p>"//内部套上p标签,文本内容为hello,world

2.3 className

  • 返回元素的class属性值,可理解成“读取”
  • 设置元素的class属性值,可理解成“写入”
var mydiv = document.getElementById("div");
mydiv.className;//返回ID为div元素的class属性,未设置时,控制台无输出
mydiv.className = "mydiv";//给div元素设置class属性为mydiv

3. DOM事件

事件,即文档/浏览器窗口发生的一些特定的交互瞬间

3.1 鼠标事件

3.1.1 onload

  • 在页面加载完毕时触发
  • 适用于script标签放在head部分时/针对文档内部标签相应的事件(必须在文档加载好之后才触发事件)
window.onload=function(){}//页面加载完毕后运行匿名函数function内部指令

3.1.2 onclick/onmouseover/onmouseout

  • 鼠标点击时/移动到元素上方时/移出元素时触发
var div = document.getElementById("div");
function myalert1(){alert("你的鼠标放在一个div上面");}
var myAlert = function myalert2(){alert("你已经移出了div");}
div.onclick=function(){alert("你点击了一个div");}
div.onmouseover=myalert1();
div.onmouseout=myAlert;//鼠标移入后移出时触发,注意此处只要用变量名,不需要函数名

3.1.3 onmousedown/onmouseup/onmousemove

  • 鼠标按下/松开/移动指针时触发
  • onmousedown、onmouseup合在一起成就了onclick事件
  • 发生顺序为:onmousedown、onmouseup、onclick
var div = document.getElementById("div");
div.onmousemove=function(){console.log("你在div里面移动了");}//在div里移动,控制台打印
div.onmousedown=function(){console.log("你点击了div");}
div.onmouseup=function(){console.log("你松开了div");}//点击和松开时控制台打印

3.1.4 onfocus/onblur

  • 获得/失去焦点时触发
  • 适用于input标签中type为text、password的以及textarea标签
var username = document.getElementById("username");
//当光标在username输入框,执行函数
username.onfocus=function(){p.innerHTML="请输入用户名!");}
//当光标离开username输入框,执行函数
username.onblur=function(){p.innerHTML="用户名输入正确!";)}

3.1.5 onchange

  • 域的值发生变化时触发
  • 主要适用于select下拉菜单、radio单选、checkbox多选
//根据选项调整页面的背景颜色
function changeBack(){
	var div1 = document.getElementById("mydiv");
	var menu = document.getElementById("changeColor");
	menu.onchange=function(){
		//可通过下拉菜单的options来创建类数组,通过selectedIndex访问选定的元素下标
		var bg = menu.options[menu.selectedIndex].value;
		div1.style.background=bg;
	}
}
window.onload=changeBack;//注意事件触发时调用函数无需()

3.1.6 onsubmit

  • 表单中确认按钮被点击时触发
  • 该事件添加在表单元素上,而不是提交按钮上
<form action="post" id="test1">
	<input type="text">
	<input type="submit" value="提交" id="test2">
</form>
<script>
	window.onload=myHere;
	function myHere(){
		var tijiao = document.getElementById("test1");
		//注意此处onsubmit事件必须绑定在表单元素上才可以,绑定在提交按钮上无效
		tijiao.onsubmit=function(){alert("谢谢提交");}
	}
</script>

3.1.7 onresize/onscroll

  • 当窗口大小发生变化/滚动条滚动时触发该事件
  • 两个事件常常用在window对象上,但也可以用在div等块级元素上

3.2 键盘事件

3.2.1 onkeydown/onkeypress/onkeyup

  • 在按下按键/按下键盘按键(字母、数字、符号、回车、空格)/松开按键时发生
  • 发生顺序为onkeydown、onkeypress、onkeyup
  • 可用keyCode属性返回按下键的编码

4. DOM操作

4.1 创建节点

4.1.1 createElement

  • 创建元素节点
  • 该方法创建的HTML5标签是可以兼容IE8以下的浏览器的
  • IE6-8下可以创建HTML中不存在的标签
//创建一个li节点
var li = document.createElement("li");

4.1.2 createTextNode

  • 创建文本节点
//创建一个text节点并把其添加到li节点中
var text = document.createTextNode("hello world");
li.appendChild(text);

4.1.3 createDocumentFragment

  • 创建文档片段
  • 创建目的:在DOM树中,文档片段被其所有的子元素所代替。 因为文档片段存在于内存中,并不在DOM树中,所以将子元素插入到文档片段时不会引起页面回流(对元素位置和几何上的计算)。因此,使用文档片段通常会带来更好的性能

4.1.4 createComment

  • 创建注释(极少用)

4.1.5 innerHTML

  • 创建标签内部的HTML文档,可以添加文本也可以添加标签和属性,以字符串形式传入即可
  • 读取标签内部的HTML文档,包括标签、属性、文本、注释等
  • 限制:
    • IE6-8中,传入的字符串左侧的空白会被自动删除
    • 只有IE8及更早版本可以在script内部传入内容后执行script内部脚本,但script元素得有defer属性,且script前必须为有作用域元素(即不可为空)
    • IE8及以前的浏览器

4.1.6 outerHTML

  • 包括了父节点下的所有元素(包括自己)

4.1.7 innerText

  • 只读取指定元素内部的文本,忽略其他(标签、属性、注释等)节点
  • 写入时,会把标签一并当做文本写入
  • IE4以上、Safari3以上、opera8以上、chrome支持,火狐不支持(有特有的textContent属性)
<div id="box">
    我是div
    <p>我是p标签</p>
    <!--我是一个捣蛋的注释-->
    <ul>
        <li>li1</li>
        <li>li2</li>
        <li>li3</li>
    </ul>
</div>
<script>
	var box = document.getElementById('box');
	console.log(box.innerText);//控制台只输出“我是div 我是p标签 li1 li2 li3”
	box.innerText="<p>我是新的p标签</p>";//div中内容变成<p>我是新的p标签</p>
</script>
//对所有类型的浏览器通用的innerText方法
//读取版本
function getInnerText(element){
	if(typeof element.textContent == "string"){
		return element.textContent;
	}
	else{
		return element.innerText;
	}
}
//写入版本
function writeInnerText(element,text){
	if(typeof element.textContent == "string"){
		text = element.textContent;
	}
	else{
		text = element.innerText;
	}
}

4.1.8 outerText

  • 读取时,同innerText功能一致
  • 写入时,会把调用元素的子节点(包括子节点)全部替换掉
  • 由于使用后会导致调用改属性的元素不再存在,不建议使用

4.2 遍历节点

4.2.1 DOM遍历的原理

  • DOM文档也是一棵树,以document为根,包括了多种节点

4.2.2 父子节点之间的遍历

  • 父节点到子节点:firstChild、lastChild、childNodes[i]、childNodes.item(i)
  • 子节点到父节点:parentNode
  • 子节点之间:nextSibling、previousSibling

4.2.3 其他方法

  • 返回文档根节点:documentElement、ownerDocument(任意元素直接返回
  • 返回元素标签名:tagName
  • 判断一个节点是否有子节点:hasChildNodes()

4.2.4 节点遍历的实现

//思路:判断当前节点是否有子节点,如果有则重复调用函数,遍历所有子节点,否则结束
var s = "";
//space为传入的连接符号,node为建树的起始节点
function travel(space,node){
	if(node.tagName){
		s += space + node.tagName + "<br/>";
	}
	var len = node.childNodes.length;
	for(var i = 0;i < len;i++){
		travel(space+"*",node.childNodes[i]);
	}
}
travel("",document);
document.write(s);

4.2.5 节点遍历时的问题及方法(空白节点)

4.2.5.1 问题的原因
  • childNode属性中,IE8以前的浏览器会忽略标签之间的空格
  • 新浏览器会把这些空格当成节点
  • 因此,遇到HTML.childNodes[1]时,浏览器识别出的不是body而是text
4.2.5.2 过滤掉空白的文本节点的方法
  1. 删除空白(不建议
  2. 用tagname属性判断(不建议
  3. 用nodeType属性(1为元素,2为属性,3为文本)

4.2.6 节点遍历的新方法(解决空白节点的问题)

  • 父节点到子节点(从标签到标签):firstElementChild、lastElementChild、children[i]
  • 子节点之间(从标签到标签):nextElementSibling、previousElementsSibling
  • 返回所有子节点个数(只是子节点):childElementCount

4.3 类数组对象

4.3.1 Nodelist

  • childNodes里保存着的对象
  • 不是array实例,没有数组对象方法,只是保存一组有序节点
  • 访问值可用方括号,方法和属性包括:
    • item方法
    • length属性
<div id="box">
    <div class="box1"></div>
    <div class="box2"></div>
    <div class="box3"></div>
</div>
<script>
    var box = document.getElementById("box");
    var nodes = box.childNodes;
    console.log(nodes[1]);//得到box1这个div(空白节点也算入item里了)
    console.log(nodes.item(1));//得到box1这个div(空白节点也算入item里了)
    console.log(nodes.length);//结果为7(空白节点也算入length)
</script>
  • 如果想把NodeList中内容转换成真的数组对象,可以用以下两种方法:
    • Array对象的prototype属性下的slice方法(低版本IE运行时会报错
    • 元素循环遍历后输出
function makeArray(nodelist){
	var arr = null;
	try{
		return Array.prototype.slice.call(nodelist);//把nodelist转换成数组
	}
	catch(e){
		arr = new Array();
		for(var i=0,len=nodelist.length;i<len;i++){
			arr.push(nodelist[i]);
		}
	}
	return arr;
}

4.3.2 HTMLCollection

  • 表示HTML元素的集合
  • 会返回HTMLCollection的常用属性和方法有:
    • getElementsByTagName:返回指定标签的集合
    • document.scripts:返回document里所有script元素集合
    • document.links/images/forms:返回页面中所有a/图片/表单元素
    • tr.cells:返回该表格的tr的所有td
    • select.options:返回select的所有选项
    • td.namedItem:在该表格元素集合中先找id为指定名的元素,若没有,找第一个name为指定名的元素,返回元素
  • 方法和属性有:
    • item方法
    • length属性
    • namedItem方法:在该元素集合下找id为指定名称的元素,若没有,找第一个name为指定名的元素,返回元素
<div id="box">
    <div id="box1">我是div1</div>
    <div name="box2">我是div2</div>
    <div name="box2">我是div3</div>
</div>
<script>
    var box = document.getElementsByTagName("div");
    console.log(box.namedItem('box2'));//返回我是div2这个div
</script>

4.3.3 namedNodeMap

  • 通过访问元素的attributes属性得到,返回元素节点特性的集合
  • 常用方法和属性有:
    • item:返回某一个元素节点特性
    • length:返回元素节点特性数量

4.3.4 类数组对象的动态性

  • Nodelist、HTMLColletcion、NamedNodeMap都是基于DOM结构动态查询的结果,DOM结构只要有变化,其也会相应发生变化
  • 文档结构更新,三者都会更新,因此三者保存最新、最准确信息

4.4 节点查找

4.4.1 getElementById

  • 返回id属性值为给定值的标签元素
    • IE低版本浏览器中会把在id值为查找值之前name值为查找值的元素找出来
    • 文本里设定两个id值相同的元素时,会查找到第一个
  • 只可通过document对象来调用
<div name="box1">这个是错误的元素</div>
<div id="box1">这个才是正确的元素</div>
<div id="box1">这个是另一个正确的元素</div>
<button id="button1">点我</button>
<script>
    function getElBId(){
        var btn = document.getElementById("button1");
        btn.onclick=function(){
            var box = document.getElementById("box1");
            console.log(box.innerHTML);//打印“这才是正确的元素”
        }
    }
    window.onload=getElBId;//低版本IE下,会打印出“这个是错误的元素”
</script>
  • 解决getElementById的bug(针对IE)的方法
    • 避免在同一页面文档里出现同一名称的name和id(有时较难
    • 用document.all方法来解决
//思路:获取元素后判断该元素的id是否显示设置
//是的话,判断id是否为该值,如果不是该值,用document.all方法来获取文档中
//所有name和id为指定值的元素,一个个判断id值是否为给定值
var getElementById = function(id){
	var el = document.getElementById(id);
	//此处,\v在IE中被解析为v,其他浏览器中解析为垂直制表符(可理解成空格)
	//\v1随后被转化为字符串v1/数字1,加号试图转化为数字(IE转化成NaN)
	//取反后IE为true,其他为false
	if(!+"\v1"){
		if(el && el.id === id){return el;}
		else{
			var els = document.all[id],
				n = els.length;
			for(var i = 0;i < n;i++){
				if(els[i].id === id){return els[i];}
			}
		}
	}
	return el;
}

4.4.2 getElementsByName

  • 返回指定name属性值的一个类数组对象
  • 只可通过document对象来调用
  • 在IE6和Opera7.5上有bug
    • 返回id为给定值的元素
    • 仅对input和image元素起作用

4.4.3 getElementsByTagName

  • 返回指定标签名的所有元素的一个类数组(传入值不区分大小写)
  • 传入参数为!时,返回注释节点
    • IE6-8下,文档类型声明也被当成了注释
    • Chrome不支持该方法
  • 传入参数为*时,返回页面上的所有元素

4.4.4 getElementsByClassName

  • 返回指定class值的所有元素的一个类数组
    • 传入多个class名时,用空格隔开
    • Firefox3、Chrome、IE9、Safari4以上可以使用
  • 解决兼容性问题的方法
//思路:(未完待续)

4.4.5 querySelector

  • 以CSS选择器的方法来选择元素(.调用类,#调用id)
  • 可以用任意元素来调用该方法(document或文档子节点)
  • 找不到元素时,返回null
  • 几乎所有主流浏览器都支持(IE8及以上支持

4.4.6 querySelectorAll

  • 返回一个查找的元素的集合staticNodelist(静态的类数组,数组第一次查找完后不会因为DOM的变化而实时更新)
  • 当找不到元素时,返回一个空的集合
  • 几乎所有主流浏览器都支持(IE8及以上支持

4.5 节点操作

4.5.1 appendChild

  • 在指定元素最后一个子节点后添加节点,返回新添加的节点
  • 如果添加的是已经存在的子元素,则会把这个子元素移动到最后
<ul id="box1">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
</ul>
<script>
var ul = document.getElementById('box1');
var cs = box1.firstElementChild;
ul.appendChild(cs);//ul的顺序改成2341
</script>

4.5.2 insertBefore

  • 把指定节点放到指定的节点的前面
  • 传入的第二个参数为null时,可以把节点添加到最后相当于appendChild
<ul id="box1">
    <li>1</li>
    <li>2</li>
    <li>3</li>
</ul>
<script>
	var ul = document.getElementById('box1');
	var li = document.createElement('li');
	var text = document.createTextNode('5');
	li.appendChild(text);
	var li2 = ul.children.item(1);
	ul.insertBefore(li,li2);//在第二个li前面插入新的li元素
	ul.insertBefore(li,null);//
</script>

4.5.3 replaceChild

  • 替换一个子节点,返回这个替换的节点
ul.replaceChild(li,li2);//把ul里的li2替换成li

4.5.4 cloneNode

  • 克隆一个节点,返回这个父本
  • 传入参数true时,复制其中的子节点(默认为false)
<ul id="ul">
	<li></li>
</ul>
<script>
	var ul = document.getElementById('ul');
	ul.cloneNode();//只拷贝ul这个节点,不包括内部的li
	ul.cloneNode(true);//拷贝ul和内部的li
</script>

4.5.5 normalize

  • 把文本节点合并
<div id="div">hello
world
</div>
<script>
	var div = document.getElementById('div');
	div.normalize();//div内部的文本会拼接成一个文本
</script>

4.5.6 splitText

  • 按照指定的位置,把一个文本节点分割成两个
  • 返回新的文本节点
<div id="div">helloworld
</div>
<script>
	var div = document.getElementById('div');
	div.splitText(5);//div内部第五个字符开始往后的成为一个新的字符串
</script>

4.6 删除节点

4.6.1 removeChild

  • 删除某个节点中指定的子节点
  • 传入的参数为删除的节点,且该方法必须传入参数
  • 同innerHTML的“删除”比较:
    • IE6-8,removeChild为掰断树枝,但树枝还可以继续用
    • IE6-8,innerHTML为把树枝拔下来,烧掉
    • Chrome浏览器,两者都只是掰断树枝

4.6.2 removeNode

  • 把目标节点从文档中删除,返回删除的节点
  • 参数为布尔值,默认为false(只删除目标节点,保留其下的子节点)
  • 只在IE中起作用

5. DOM属性

5.1 属性介绍

  • 固有属性property:浏览器捆绑好的属性
  • 自定义属性attribute:自己设置的属性
    • 同名的属性,以先定义的为准
    • 属性名称全部为小写
    • 无法通过元素后的属性访问,只能用getNamedItem()方法以及nodeValue属性访问属性值
    • 不可通过console.log()方法输出,输出结果为undefined

5.2 方法和属性

5.2.1 getNamedItem()

  • 该方法返回指定的属性节点
  • 不能访问没有显式定义的属性,即便是固有属性也不可以

5.2.2 attributes

  • 返回指定节点的属性集合
  • 可通过.attributes[i].nodeValue访问某个节点第i个属性值

5.2.3 removeNamedItem()

  • 删除一个属性,参数为待删除属性的名字

5.2.4 setNamedItem()

  • 把创建好的属性添加到指定的元素上
var div = document.getElementById('div');
var test1 = document.createAttribute("xxx");
test1.nodeValue='hello';
div.attributes.setNamedItem(test1);//把test1这个属性值添加到div元素上

5.2.5 getAttribute()

  • 操作固有属性和自定义属性的通用方法
  • 获得指定属性名的属性值
    • style、onclick属性用getAttribute和属性(div.style)获取时,返回值会不同
    • 一般用JS来操作DOM时,不使用getAttribute方法,只有在取自定义属性的值时才使用getAttribute

5.2.6 setAttribute()

  • 设置元素属性值,两个参数(属性名,属性值)
  • IE7及更早版本不支持

5.2.7 removeAttribute()

  • 删除属性
  • 兼容IE6

5.3 布尔属性

  • 传入的属性值参数会进行隐式的类型转换
  • 常用的有:
    • radio和checkbox中的checked
    • option标签中的selected
    • input的type值为text的readonly(设置属性时readOnly记得O大写
    • disabled
    • select中的multiple
    • hidden

5.4 data属性

  • 用来存储页面/应用程序私有定义的属性
  • 用dataset属性来获取data属性的值
    • 一个-直接用名字(data-toggle)
    • 多个-用驼峰式写名称(data-xxx-yyy变成dataXxxYyy)

5.5 classList

  • IE11及以上才支持
  • 方法:
    • add:添加
    • remove:移除
    • has:判断是否存在
    • toggle:存在就移除,不存在就添加
0人推荐
随时随地看视频
慕课网APP