JS DOM

218 阅读8分钟

一、DOM概念:Document Object Model

      提供了专门用于操作HTML文档的API
 DHTML:动态的HTML,一切实现网页动态效果的技术的统称,并不是什么新技术、新概念,仅仅只是一个统称
	HTML+CSS+JS(DOM)

 面试/鄙视题:HTML/XHTML/DHTML/XML:(简答三者间的不同)
HTML:网页
XHTML:更严格的网页
DHTML:动态的网页
XML:数据格式

 DHTML模型:
DOM:见上面
     W3C标准
BOMBrowser Object Model
     提供专门用于操作浏览器的API
     没有标准,但是大部分浏览器厂商已经统一的实现了,除了老IE,具有大量的兼容性问题,使用的较少(重点:定时器、event事件)

 DOM:本来是可以操作一切结构化文档(HTML/XML)的:3部分
1、核心DOM:万能!但是API比较繁琐:elem.setAttribute("属性名","属性值")
2HTML DOM:只能操作HTML文档,API非常的简单:elem.属性名=值;
3XML DOM:垃圾,因为XML基本已经淘汰很多年了
建议:以后优先使用HTML DOMHTML DOM实现不了,在用核心DOM补充

二、***DOM树:保存所有网页内容的树状结构:树根:document,不需要创建,由浏览器的js解释器自动创建,一个页面只有一个树根

DOM节点/对象/元素:一个标签、文本、属性、注释等等
每个DOM节点/对象/元素都有三大属性:
	1、xx.nodeType:获取xx的节点类型(对于现在的开发者,没用)
		document:9
		元素标签:1
		文本节点:3
		属性节点:2
	2、属性节点.nodeValue:获取属性节点的节点值
		现在依然没用:我们现在用getAttribute("")能直接获取到属性的值

 ###### 3、***xx.nodeName:获取属性节点的名称:
		我直接找儿子的话,可能找到多种标签,但是我们希望对不同的标签执行不同的操作
		特殊:获取出来的标签都是全大写

三、通过 节点之间关系 获取元素:

1、父:elem.parentNode;
2、子:elem.children; - 集合:只能找到儿子级
3、第一个儿子:elem.firstElementChild;
4、最后一个儿子:elem.lastElementChild;
5、前一个兄弟:elem.previousElementSibling;
6、后一个兄弟:elem.nextElementSibling;

四、*****递归:函数中,再一次调用函数自己,但迟早有一天要让他停下来

   作用:专门用于【遍历层级不明确的树状结构】
   如何实现:21、创建函数,传入实参树根,形参接住,直接做第一层要做的操作
		function f1(root){
			直接做第一层要做的操作
			//判断自己有没有下一级,如果有再次调用此方法,但传入的实参已经变成了你的下一级
		}

	2、调用函数
		f1(实际的根元素)		

   算法:深度优先!优先遍历当前节点的子节点
	 子节点遍历完,才会跳到兄弟节点

   递归:优点:直观,易用
	 缺点:效率较低,同时开启的函数很多,占用内存空间,不是任何时候都要使用 - 几乎不担心(【遍历层级不明确的树状结构】)
   循环:优点:效率较高
	 缺点:难度极大!

五、遍历API:专门用于【遍历层级不明确的树状结构】

2步:
 1、创建treewalker对象
	var tw=document.createTreeWalker(root,NodeFilter.SHOW_ALL/SHOW_ELEMENT);

 2、反复调用nextNode方法:
	while((node=tw.nextNode())!=null){
		node;//当前节点做什么操作
	}

深度优先算法
注意:此方法必须跳过起点

六、纯循环遍历层级不明确的树状结构 - 别用

总结:以后不用遍历API(只能遍历页面元素),也不用纯循环(难度大),遇到层级不明确的时候,使用递归(不仅遍历元素,还能遍历数据)

七、***查找元素:

 1、按照HTML的特点去查找元素:4var elem=document.getElementById("id");
	找到了是单个元素,没找到一定是null

	var elem=document.getElementsByTagName/ClassName/Name("标签/class名/name值")
	找到了是个集合,没找到一定是一个空集合[]

 2、按照CSS选择器进行查找:21、单个元素,没找到一定是null,如果有多个,也只会找到第一个
		var elem=document.querySelector("任意css选择器")
		
	2、多个元素:找到的是一个集合,没找到空集合
		var elem=document.querySelectorAll("任意css选择器")

面试题:getXXX和querySelectXXX的区别?
	1、返回结果不同:
		getXXX - 返回是一个动态集合(每次DOM树修改,都会悄悄的再次查找)
		querySelectXXX - 返回是一个静态集合 (每次DOM树修改,不会再次查找,只管第一次找到的结果)
	2、动态集合,不支持forEach
	   静态集合,支持forEach
	3、复杂查找时,尽量使用var elem=document.querySelectorAll("任意css选择器"

ES5新特性:

1、保护对象的成员
1、四大特性
	Object.defineProperties(obj,{
		"属性名":{"value":值,"writable":true,"enumerable":true,"configurable":true},
		...
	})

2、三个级别:
	防扩展:防添加
		Object.preventExtensions(obj);

	密封:防添加、删除
		Object.seal(obj);

	冻结:防添加、删除、修改
		Object.freeze(obj);
2、数组的API:
函数名:every/some  forEach/map  filter/reduce
	arr.函数名((val,i,arr)=>判断条件/操作)

	arr.函数名((val,i,arr)=>val+=1)
3、

var child=Object.create(father,{ "属性名":{"value":值,"writable":true,"enumerable":true,"configurable":true}, ... });

4、call/apply:

临时替换了函数中的this,借,立刻执行 不是自己的方法我们也可以使用(数据类型的结构大致相同) 语法:函数名.call/apply(借用对象,实参); 区别:call:实参需要一个一个传入 apply:只能传入一个实参,并且是一个数组

  bind:永久替换了函数中的this,买,不会立刻执行,需要自己调用
	  语法:var 新函数=函数名.bind(指定对象,永久固定实参);

	固定套路:
	    1Math.max/min.apply(Math,arr);
	    2Object.prototype.toString.call/apply(arr)=="[object Array]"
	    3、将类数组转为普通数组:
	       var 新变量=Array.prototype.slice.call/apply(类数组)
5、严格模式:
"use strict";
作用:
  1、禁止了全局污染,禁止给未声明的变量直接赋值
  2、静默失败升级为了错误

ES6新特性:

1、模板字符串:我希望做出运算${a+b}

2、块级作用域: let 变量名=值; 作用: 1、禁止了声明提前 2、添加了块级作用域->{} 3、绑定事件如果你的循环用了let,那么会记录着当前元素的下标

3、箭头函数:

4、for...of循环: for(var v of arr){ v;//当前值 }

创建元素&渲染页面&删除元素:

1、创建元素:3步
1var 空标签=document.createElement("标签名");

2、设置必要的属性或事件
	空标签.属性名="值"
	空标签.on事件名=function(){
		操作
	}

3、渲染页面元素:3种
       *父元素.appendChild(新元素);//新元素会插入到父元素里面的末尾
	父元素.insertBefore(新元素,已有子元素);//新元素会插入到父元素里面的已有子元素之前 - 不推荐:修改其他的人下标
	父元素.replaceChild(新元素,已有子元素);//新元素会替换掉父元素里面的已有子元素

4、删除元素:
	元素.remove();

核心DOM学习完毕:已经无敌了 - 增 删 改 查:元素、内容、属性、样式
2、HTML DOM提供了一些常用对象:简化了核心DOM的操作:但是不是人人都能简化
1、image:简化了创建
   	var img=new Image();
   强调:在DOM中,不是人人都具有构造函数创建方式,只有我讲到的人才有

2、form:简化了查找
   查找form元素:var form=document.forms[i];
   查找表单控件:var input=form.elements[i];
   专属事件:onsubmit事件 -> 提交的一瞬间会执行,也可以阻止提交return false;

3、*select:
	属性:2个
	  1、options === children:获取到select下面的所有的option
	  2、*selectedIndex - 获取到当前选中项的下标,只要是做联动,必不可少

	方法:
	  1、*select.add(option) - 完全等效于appendChild,追加元素
	  2、select.remove(i); - 删除select中的第i个option

	专属事件:onchange-> 选中项发生改变时触发

4、*option:简化了创建
	var opt=new Option("innerHTML","value");

核心DOM主要作用 增、删、改、查/元素、内容、属性、样式

增:

1、元素:3步 1、var elem=document.createElement("标签名"); 2、elem.属性名="属性值" elem.on事件名=function(){} 3、父.appendChild(elem); 父.insertBefore(elem,已有子元素); 父.replaceChild(elem,已有子元素);

2、内容:elem.innerHTML/innerText/value+="新内容"

3、属性:elem.setAttribute("class","d1 d2");

4、样式:elem.style.css属性名="css属性值";//没有叫添加,有了叫替换

删:

1、元素:elem.remove();

2、内容:elem.innerHTML/innerText/value=""

3、属性:elem.removeAttribute("属性名");

4、样式:elem.style.css属性名="";//没有叫添加,有了叫替换

改:

1、元素:父.replaceChild(elem,已有子元素);

2、内容:elem.innerHTML/innerText/value="新值"

3、属性:elem.setAttribute("class","d2");

4、样式:elem.style.css属性名="css属性值";//没有叫添加,有了叫替换

查:

1、元素: 1、直接找: document.getXXX document.querySelectorXXX

2、通过关系查找

3、层级不明确:递归(元素、数据)、遍历API、纯循环	

2、内容:elem.innerHTML/innerText/value;

3、属性:elem.getAttribute("属性名");

4、样式:elem.style.css属性名;//只能获取内联样式


新版本改动内容:

1、属性: 删除: 判断有没有:elem.hasAttribute("属性名"); -- 只能判断有没有不能判断具体值是什么 推荐: if(elem.getAttribute("属性名")=="值"){ }

2、样式: 样式表: 获取:document.styleSheets[i].cssRules[i].style.css属性名 设置:document.styleSheets[i].cssRules[i].style.css属性名="css属性值"

3、渲染页面:3种:最推荐appendChild 删除元素:

4、HTML DOM常用对象:个别可以简化

1imagevar img=new Image();

2formvar form=document.forms[i]
	var input=form.elements[i]
	onsubmit

3select1options===children
	2selectedIndex === 获取当前选中项的下标
	3add()
	4remove(i) === 删除下标为ioption
	5onchange

4optionselect.add(new Option("innerHTML","value"))