WebApi_DOM

WebApi

API(Application Programming Interface,应用程序编程接口),API是一些预先定义的方法,这些方法能够实现某些特定的功能,我们无须知道这些API的实现方式,但是我们需要知道这些API如何使用。

  • 任何开发语言都会提供自己的API
  • API的特征输入和输出(参数/返回值)

通俗的讲,API就是编程语言给我提供的一些工具,通过这些工具,我们可以非常轻易的完成一些功能。

DOM

DOM(Document Object Model)文档对象模型,是W3C组织推荐的一套用于处理HTML的标准编程接口。

DOM又称为文档树模型,因为整个HTML文档是一个树形的结构

DOM会把整个页面看成一个对象,我们需要操作文档,只需要操作对象;

DOM:把页面中所有的东西都看成对象

Document 对象

  • 每个载入浏览器的 HTML 文档都会成为 Document 对象。
  • Document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问。
  • 提示:Document 对象是 Window 对象的一部分,可通过 window.document 属性对其进行访问。

document 返回整个网页页面,包含html

document.documentElement 返回html dom中的root 节点 即 <html>

document.body 返回html dom中的body节点 即 <body>

DOM的初体验

console.log(); 打印一个元素的时候,是以标签的形式进行展示的

console.dir();打印一个元素的时候,是以对象的形式进行展示的

标签中的属性和对象中的属性是一一对应的,可以通过操作DOM对象来改变标签的属性

获取元素

通过ID获取元素

var 变量名 = document.getElementById('元素ID'); 返回值是一个元素

<script></script>要写在html的内容后面,才能保证页面加载完成后获取到这个对象。

通过ID来获取这个对象,如果存在这个ID,返回值是一个元素;

如果没有这个ID,返回值是null

在JS中直接使用ID来获取对象,而不是通声明获取返回值 ;

这个方法只有 document.getElementById("元素的id");

在早期,是ie提出来,id在页面中是唯一的,所以呢,在js中可以直接使用id,仅仅是ie提出来,不是规范,其他浏览器也支持。不推荐这么写

通过标签名获取元素

参数:标签名

返回值:一个伪数组,伪数组不是数组,不能使用属性的方法,但是可以跟数组一样进行遍历和使用下标进行操作。

注意:返回值有没有获取到元素,都是一个伪数组,即便元素只有一个;如果没有这个标签返回的是一个空的伪数组

伪数组不能直接注册,需要通过下标来操作这个伪数组注册。

var 变量名s = document.getElementsByTagName("标签名"); 返回值是一个伪数组

var 变量名s = box.getElementsByTagName("标签名"); 返回值是一个伪数组

通过类名获取元素:

var 变量名s = document.getElementsByClassName("class");

参数:字符串类型的类名

返回值:伪数组

注意:这个方法ie678不支持

根据name获取:只适用表单

只适用于表单元素

var ps = document.getElementsByName("aa");

根据css选择器获取

var 对象名 = document.querySelector();

参数:是一个css选择器, 如果是类选择器 .demo;如果是id选择器:#aa

返回值:只会返回一个对象,如果有很多个,会返回第一个

var 变量名 = document.querySelectorAll();

参数:是一个css选择器

返回值:会匹配到所有满足条件的,返回一个伪数组,0~n个,都会返回伪数组

this

  • 给某个对象注册事件的时候,在事件内的this表示就是这个对象
  • 伪数组使用this的必要性
    • 当获取的对象返回的是伪数组时候,这个时候给每个元素注册事件使用for循环,但是for循环在被触发前就已经结束,再使用触发事件的时候调用的function的时候,内部使用了 伪数组.[i]=值; i的值在for循环结束的时候就已经改变了,触发的也不是当前的对象值了。
    • 所以这个时候就必须使用this了
  • 为了避免某些问题,极力推荐使用this来表示当前对象
  • 函数内部的this是window
  • 方法内部的this,指向当前的对象
  • 构造函数内部的this,新创建的对象
  • 事件里面的this,当前对象

阻止a标签的跳转

  • return false
    • 对a注册事件,事件处理程序的函数代码: return false;
    • return false; 写在function内部最后,return后面的代码不会被执行
  • javascript:void(0);
    • href:如果写了javascript:表示a标签不执行跳转,执行js代码
    • javascript:; a标签不跳转
  • # 一般用在以后需要实现页面跳转的时候先用#代替

标签操作

修改标签属性

标签中的 alt title width src href

class在js中是一个保留字, 标签中class对应了对象中的className

1
selector.alt = 值

标签自定义属性

  • 我们之前讨论的属性,都是HTML规范中,标签本来就有的属性,对于标签自定义的一些属性,比较特殊。
  • JS获取到html页面的对象后,是以对象的方式来存储标签的固有属性;
  • 这个时候我们在DOM中操作为这个标签添加一些原本没有的属性,是不能够显示的,但是会存在这个对象中,在DOM中可以调用这些属性。

attribute方法:attribute方法设置的标签自定义属性可以显示在标签中,也可以设置原本就存在的属性的值

1
2
3
selector.getAttribute(name)//获取标签的属性
selector.setAttribute(name, value)//设置标签的属性
selector.removeAttribute(name)//移除标签的属性

标签的内容属性

innerText:内部的文本

innerHTML:内部的html

获取的时候:

innerHTML:会获取到内部的标签和内容,获取标签内容的时候,不管标签还是文本,都能获取到

innerText:只会获取文本,获取标签内容的时候,只会获取文本,标签扔掉了

1
2
3
var box = document.getElementById("box");
console.log(box.innerHTML);
console.log(box.innerText);

设置的时候:

如果是innerHTML,标签会生效,innerHTML设置内容的时候,覆盖原来内容,标签也能生效,浏览器能解析这个标签。

如果使用innerText:标签不会生效,innerText对标签转义了。设置标签内容的时候,覆盖原来内容,对标签进行转义(目的:把标签直接当文本来用)

innerText和innerHTML设置的时候,都会覆盖原来的内容;

1
2
box.innerHTML = "<h3>呵呵</h3>";
box.innerText = "<h3>呵呵</h3>";

innerHTML和innerText用哪个?

innerHTML:能够识别html标签,标签能生效

innerText:不识别标签,对标签转义,当成文本

设置标签的内容,推荐使用 innerText,防止xss攻击,保证标签不生效

innerHTML:所有浏览器都支持

innerText:是IE提出来,IE浏览器是支持这个属性, 低版本的火狐不支持

textContent: 火狐推出来,低版本的IE678不支持

所有的浏览器基本都支持innerText和textContent

1
2
3
4
var box = document.getElementById("box");
console.log(box.innerHTML);
console.log(box.innerText);
console.log(box.textContent);

思路:以前的时候,怎么办?

如何处理兼容性问题? you can you up

先使用innerText去获取值,如果能获取到,直接用,如果获取不到,换成textContent

1
2
3
4
5
6
7
8
9
function getInnerText(element) {
if(typeof element.innerText === 'string'){
return element.innerText;
}else {
return element.textContent;
}
}

console.log(getInnerText(box));

表单的属性

所有的表单元素想要获取文本值,都要用value来获取

  • 常见的表单属性有:disabled、type、value、checked、selected;
  • 对于disabled、checked、selected三个属性来说,比较特殊。
  • 在标签中,只要指定了disabled属性,无论有值没值,都代表这个input是被禁用的。注意,标签的disabled仅仅是默认值。
  • 在DOM对象中,disabled的属性是一个布尔类型的属性,值只有true或者false

样式操作(className添加类)

div.className = "box";

给div添加一个类,类名是box,需要注意的是通过className添加类的时候会把原来class的所有类名覆盖掉,所以添加的时候要特别注意,原先样式有哪些类,一般不推荐使用

样式操作(style属性)

标签不仅可以通过class属性操作样式,还可以通过style属性操作样。同样的DOM对象可以通过className操作样式,也可以通过style属性操作样。

style设置的样式是行内样式,因此优先级要高于className设置的样式

  • style在DOM中是一个对象,在对象里通过键值对的形式存储了行内样式属性。
  • style的属性中如果带了-(会被当做减号)的在JS中应该用驼峰命名法来使用。
  • style只能获取到标签内的行内样式属性,在类样式中定义的属性是获取不到的。
  • 关于cssText;可以一次性设置style多个值,但是会覆盖掉原本存在的所有属性
1
2
3
4
//优点:可以一次性设置多个值
//缺点:会覆盖其他值
var box = document.getElementById("box");
box.style.cssText = "background-color:red; font-size:20px;";

html的几个特殊标签

document.body: body比较常用,并且在页面中时唯一的,因此可以使用document.body直接获取。
document.documentElement: 可以获取html元素
document.head: 可以直接获取head元素
document.title: 可以直接获取title的文本

排他思想

排他思想就是,通过遍历来干掉所有的人,然后通过this来复活自己,重新赋值;

tab案例中的li对应div;可以通过设置自定义属性的值来定义下标,在通过这个值下标来对应this需要的下标

tab案例

lis[i].setAttribute("index", i); 这个设置的属性会存储到DOM对象中,也会显示在标签中,

lis[i].index = i; 在外循环注册事件的时候就将值存储,只是将这个属性存到了DOM的对象中,但是标签没有这个原有属性,所以标签不会显示;

通过什么样的方法来存值,就用什么方法来获取;

tab案例中li对应的div可以通过直接赋值

假设成立法

假设某种结果成立,设置一个标记来判断;

通过设置一个变量值来判断,最好是布尔类型的,好判断,如果满足了某个条件而对这个变量进行改变值,那就说明假设没有成立。

节点操作

子女节点child

  • childNodes 获取所有的孩子节点(包括了元素节点和其他很多类型的节点,基本不常用)
  • children 获取所有的子元素(用途很广泛),兼容性:IE678会把注释节点算上。
    • children 是一个只读属性,不能修改他
    • 动态变化会随着页面内的子元素实时变化的,比如伪数组的长度
  • firstChild 第一个子节点
  • firstElementChild 第一个子元素 有兼容性问题(IE678)
  • lastChild 最后一个节点
  • lastElementChild 最后一个子元素 有兼容性问题(IE678)

兄弟姐妹节点Sibling

  • nextSibling 下一个兄弟节点
  • nextElementSibling 下一个兄弟元素(IE678不兼容)
  • previousSibling 上一个兄弟节点
  • previousElementSibling 上一个兄弟元素 有兼容性问题 可以封装一个兼容性方法

父母节点parent

parentNode 父节点,没有兼容性问题

克隆节点clone

会在内存中克隆一个节点, 这个节点克隆出来之后,就不会影响到原来的节点了。

语法:var newNode = node.cloneNode(deep)

  • node:需要克隆的节点名
  • deep:参数
    • 默认false, 表示浅复制,只会复制一个标签,并不会复制内容
    • true, 表示深复制,会复制所有的内容
  • 注意
    • 克隆出来的节点跟原来的节点没有关系了,修改了也不会相互影响。
    • 如果克隆的节点带了id,我们需要给id重新设置一个值,不让id冲突

添加节点

  • appendChild

语法:parent.appendChild(newChild)

  • parent:调用者,父节点来调用
  • newChild:需要添加的那个孩子。
  • 作用:把newChild添加到parent的孩子的最后面。
  • 如果添加的是页面中本来就存在的元素,是一个剪切的效果,原来的就不在了。
  • insertBefore

语法:parent.insertBefore(newChild, refChild);

  • parent:必须要父节点来调用
  • newChild:需要添加的那个节点
  • refChild:添加到哪一个节点的前面。
  • parent.insertBefor(newChild, null); 添加到父元素的最后一个子元素的后面
  • parent.insertBefor(newChild, paren.firstElementChild); 添加到父元素的第一个子元素前面

创建节点

  • document.write

直接往页面添加节点,但是如果在页面加载完后,再使用 document.write 添加元素会覆盖掉所有加载完成的内容;

不推荐使用,基本不用;

可以生成新的节点,但是不推荐使用。如果页面已经加载完成了,你还是用 document.write 写内容的话,会把之前的页面给覆盖掉;

原理:页面从上往下加载的时候,会开启一个文档流,当页面加载完,文档流就会关闭。

document.write 的本意就是在文档流上写入内容。如果页面没加载完成,文档流还是开着的,document.write 直接在这个文档流上写东西;

如果页面加载完成了,还是用 document.write 写东西,会重新开启一个新的文档流,往新的文档流上写东西,旧的文档流就被新的文档流覆盖了。

  • innerHTML

innerHTML 创建新的节点会把原有的内容都覆盖掉,想要保留原有内容使用+=,但是会出现效率问题

慎用:很容易出现效率问题

innerHTML 不要频繁的使用,用字符串把结构拼接好,一次性使用 innerHTML 添加节点

  • createElement

语法:var element = document.createElement("tagName");

作用:在内存中创建一个新的节点;

参数:”tagName”字符串新元素名,支持识别标签;

返回一个元素

用途广泛

删除节点

语法:parent.removeChild(child)

功能:由父盒子调用,删除里面的元素

参数:可以是找到的其他节点或者直接元素名(不能是伪数组)

替换节点

语法:parentNode.replaceChild(newChild, oldChild);

newChild 用来替换 oldChild 的新节点,如果 newChild 已经存在于DOM树中,则它会被从原始位置删除。