1.DOM
DOM就是文档对象模型,什么是文档对象模型?这就需要好好说说了。
HTML的文档document页面是一切的基础,没有它dom就无从谈起。
当创建好一个页面并加载到浏览器时,DOM就悄然而生,它会把网页文档转换为一个文档对象,主要功能是处理网页内容。
在这个文档对象里,所有的元素呈现出一种层次结构,就是说除了顶级元素html外,其他所有元素都被包含在另外的元素中。
那么它的树就应该是下面这样的一颗倒长的树:
2.节点类型
节点表示网络中的一个连接点,一个网络就是由一些节点构成的。
而文档就是由节点构成集合,只不过他们是构成节点树上的树枝树叶而已。
这些节点有许多不同的类型,我们先来看看其中的三种:
元素节点、文本节点和属性节点。
HTML的标签元素就是DOM的元素节点,它提供了一份文档的结构。
但这份文档本身不会包含任何内容,因此元素节点可以包含其他的节点。
文本节点是节点类型的一种,它总是被包含在元素节点内部,形成页面文档的主要内容。
属性节点用于对元素做出个个具体的描述,例如:
a元素的href属性,img元素的alt属性。
属性总是被放在起始标签里,因此属性节点也总是被包含在元素节点中。
虽然并非所有的元素节点都包含属性,但所有的属性一定都被元素节点包含。
3.节点操作
3.1获取元素节点
获取元素节点有4种方法,分别通过元素ID,标签名字,类名和css选择器来获取。
3.1.1 元素ID
getElementById方法是document对象特有的函数,传入一个参数即元素的id属性值,将返回一个对象。
这个对象对应那个id属性为指定值的节点,我们还可以用typeof来验证它的类型:
document.getElementById(“car”);
alert(typeof document.getElementById(“car”));
实际上文档中每一个元素都是一个对象,利用DOM提供的方法可以得到任意一个对象。
不过要是为每一个元素都定义一个独一无二的ID值那就太麻烦了,所以DOM还提供了另外的方法来获取没有id的对象。
3.1.2 标签名字
getElementsByTagName方法会返回一个对象数组,数组的元素就是和getElementById差不多的获取到的对象:
document.getElementsByTagName(“li”);
还可以用数组的方法length来获取这个数组的长度:
document.getElementsByTagName(“li”).length;
3.1.3 类名
getElementsByClassName方法让我们能够通过class类名来访问元素。
它的返回值和getElementsByTagName类似,都是返回一个对象数组:
document.getElementsByClassName(“sale”);
值得注意的是它还可以匹配含有多个class的元素,指定多个类名的时候
只需要在字符串参数中间yoga空格分隔类名就可以了,顺序不重要前后都可以。
另外它也可以和前面两种方法混合使用,用法和getElementById和getElementsByTagName结合使用的例子一致。
3.1.4 CSS选择器
还有html5中新增的两个方法,让我们可以用css选择器的方法来选择DOM节点,这两个方法必须在IE8以上的现代浏览器中才能使用。
第一个方法是返回了单个节点,如果有多个匹配元素就只返回第一个,如果找不到匹配就返回。
第二个方法是返回一个节点列表集合。参数则都为CSS选择器字符串:
document.querySelector(“#foo");
document.querySelectorAll(“.bar");
3.2 获取和设置属性
在得到元素后,就可以获取他们的属性,然后更改属性的值了:
3.2.1 getAttribute
getAttribute函数是一个属于节点对象的方法,可以通过传入参数获取节点对象下的各种属性:
var p = document.getElementById(“parse”);
var title = p.getAttribute(“title”);
alert(title);
3.2.2 setAttribute
setAttribute方法与getAttribute对应,它不再是获取,而是修改,因此它的参数有两个:
第一个是属性名,第二个是想要修改为的值:
var p = document.getElementById(“parse”);
p.setAttribute(“title”, “nice day!”);
alert(p.getAttribute(“title”));
值得注意的是,这个时候如果去查看源代码,会发现P元素的title属性值并没改变。
这是因为DOM的工作模式是:
先加载静态内容,再动态刷新,动态刷新不影响文档的静态内容。
3.3 在树上爬行
childNodes,在一颗节点树上,这个属性可以用来获取一个元素的所有子元素,得到一个包含所有子元素的数组:
element.childNodes
// 如果要获得body元素下的全体子元素
document.getElementsByTagName(“body”)[0].childNodes;
parentNode,获取当前节点的父节点元素,如果指定节点没有父元素那么会返回null。
nodeType, 每个节点都有nodeType属性,这个属性是一个数值,让我们可以知道正在处理哪种类型的节点。
节点类型有十多种,但其中我们最需要了解的有3种:
元素节点的nodeType属性值是1
属性节点的nodeType属性值是2
文本节点的nodeType属性值是3
这就意味着我们可以只对特定类型的节点进行处理,比如只处理元素节点。
alert(node.nodeType);
nodeValue,如果想改变文本节点的值,就可以使用这个属性:
node.nodeValue;
比如当有一个p元素节点,里面有一些文本内容,如果想取得这些文本内容,那么直接对p元素使用nodeValue会得到一个null空值。
因为这样得到的是p元素节点的值而不是它的子元素文本节点的值,因此可以这样来得到真正需要的内容:
p.childNodes[0].nodeValue;
firstChild和lastChild,是对子元素数组更简易操作的属性,就是childNodes的第一个和最后一个,这样更简短也更有可读性。
3.4 动态创建
前面的方法都是对已经存在的元素做出搜索和修改。
然而js也可以用来改变网页的结构和内容,可以通过创建新元素和改变现有元素来改变网页结构。
3.4.1 传统方法
document.write()方法可以方便快捷的把字符串插入到文档中
innerHTML属性可以用来读写html的内容
3.4.2 DOM操作法
如果想把一段文本内容放到p元素中,然后将p元素插入到页面的某个节点后,那么这个任务可以分为几个步骤:
a.创建一个p元素节点
b.把这个p元素节点最佳到文档中的#parent元素节点上
c.创建一个文本节点
d.把这个文本节点追加到刚才创建的p元素节点上
var para = document.createElement(“p”);
var parent = document.getElementById(“parent”);
parent.appendChild(para);
var txt = document.createTextNode(“hello world”);
para.appendChild(txt);
来认识一下这几个方法:
createElement,创建一个元素节点,传入的参数就是标签名字符串。但它只是一个文档碎片,还不是DOM节点树上的组成部分,无法显示在浏览器里。
createTextNode,创建一个文本节点用于放文本内容,和上面几乎一样,只是传入的参数就是文本字符串,创建好后依旧是文档中的一个游荡的孤儿。
appendChild,想把新创建的节点插入节点树的最简单办法之一,让它成为某个节点的一个子节点。
insertBefore,这个方法可以在已有元素前插入一个新元素。
调用这个方法时必须知道三件事:新元素和目标元素和父元素,其语法是这样的:
parentElement.insertBefore(newElement, targetElement);
比如想在一个img图片前插入一个p标签,那么可以这样做:
var img = document.getElementById(“img”);
var p = document.getElementById(“p”);
img.parentNode.insertBefore(p, img);
4.操作封装
前面说到过insertBefore方法,那是不是也该有个对应的insertAfter()呢,很遗憾,没有。。。
那么我们其实可以自己实现一个这样的方法:
function insertAfter(newEle, targetEle) {
var parent = targetEle.parentNode;
if (parent.lastChild == targetEle) {
parent.appendChild(newEle);
} else {
parent.insertBefore(newEle, targetEle.nextSibling);
}
}
它的实现步骤是这样的:
a.首先,这个函数有两个参数,一个是将被插入的元素,一个是目标元素。
b.把目标元素的父元素保存到变量parent里
c.检查目标元素是不是父元素parent的最后一个子元素
d.如果是,就用appendChild方法把新元素追加到父元素parent上,这样新元素就恰好被插入到目标元素之后
e.如果不是,就把新元素插入到目标元素的下一个兄弟元素之前,这样新元素就在目标元素之后
通过这样一个函数,加上已知的几个方法,就能自己封装出自己所需要的方法了。
5.BOM
BOM,browser object model,浏览器对象模型,这个对象就是对应着浏览器窗口window。
它提供了一些方法用于访问浏览器的功能,这些功能和网页内容无关。
5.1 window对象
window对象是BOM的核心,表示浏览器正打开的窗口,它是一个全局对象。
它还有一些属性方法和子对象,我们其实已经默默的使用过它了。
比如alert()方法,但因为它是widow对象的直接后代,所以不需要加上window前缀。
另外我们定义的全局变量,其实也是定义到了window上的。
5.1.1 全局作用域
var car = “Tesla”;
function run() {
alert(this.car);
};
alert(window.car);
run();
window.run();
在全局作用域中定义了变量car和函数run,它们会自动归为window对象的,因此可以通过window点来访问它们。
另外run函数存在于全局作用域中,因此this也被指向window。
5.1.2 系统对话框
alert(), confirm(), prompt()这几个方法可以调用系统对话框向用户显示消息。
alert生成一个警告框,用于显示一些用户无法控制的消息,看过后只能关闭了事。
confirm生成的对话框和前者的不同在于多一个cancel按钮,可以让用户决定是否执行,并返回一个布尔值
true表示点击了确定,false表示点击了取消。
prompt则是生成一个提示框,用于提示用户输入一些文本内容,这个方法接受2个参数:
文本提示和输入框的默认值。用户操作点击ok后,返回文本框输入的值;
如果点击cancel或者直接关闭,则会返回null。
5.1.3 窗口操作
5.2 location对象
这个对象让我们可以访问当前载入的URI(统一资源标识符)的任意信息
//如果想查询字符串参数,用已有的属性并不方便,因此可以创建这样一个函数来解析查询字符串
function getQueryStringArgs(){
//取得查询字符串并去掉开头的问号
var qs = (location.search.length > 0 ? location.search.substring(1) : "”),
//保存数据的对象 args = {},
//取得每一项
items = qs.length ? qs.split("&") : [], item = null,
name = null,
value = null,
//在 for 循环中使用
i = 0,
len = items.length;
//逐个将每一项添加到 args 对象中
for (i=0; i < len; i++){
item = items[i].split("=");
name = decodeURIComponent(item[0]);
value = decodeURIComponent(item[1]);
if (name.length) {
args[name] = value;
}
}
return args;
}
//假设查询字符串是?q=javascript&num=10
var args = getQueryStringArgs();
alert(args["q"]); //"javascript"
alert(args["num"]); //"10"
可以通过location的属性来改变当前url,当然下面这两种写法是一样的效果:
window.location = “www.baidu.com”;
location.href = “www.baidu.com”;
另外也能使用location的属性改变URL,以重新加载
5.3 navigator对象
这个对象提供几个属性,用于辅助检测浏览器环境
因为js经常做的事情之一就检测用户正在使用哪种浏览器。
不过这个对象的属性非常多,可以在浏览器的调试工具中直接打出来看看它的属性和方法
5.4 history对象
这个对象提供了通过用户访问产生的浏览历史来向前或向后移动的方法。
用go()方法可以在历史记录中任意跳转,可以向前也可以向后
这个方法接受一个参数,表示向前或向后页面数的一个整数,负值表示向后,正数表示向前。
另外还有两个简写方法back和forward来替代go,只是每次只能前进或后退一页,无需参数:
//后退一页
history.go(-1);
history.back();
//前进一页
history.go(-1);
history.forward();
//后退两页
history.go(-2);
(内容来自