摘要
本书重点介绍了几种最有用的DOM方法和属性。本书的精华在于JavaScript和DOM脚本编程工作的基本原则、良好习惯和正确思路。本书强调最佳实践,特别是渐进增强。本书于2011年出版,较为经典,但也略微过时。适合初学者看,其中有一些案例可以在看的时候同步练习,加深掌握程度。
本书涉及领域
- javascript : Js 发展史 / Js 语法 / Js 操作 Dom / Js 操作 Css
- HTML5
- Ajax
- jQuery
受众
- 程序员
- 喜欢使用CSS和HTML的人
- 愿意遵守编程规范的Web设计师
目的
让大家理解DOM脚本编程技术背后的思路和原则。
宗旨
- 平稳退化、渐进增强、以用户为中心的设计。
javascript起源
- 由Netscape公司与Sun公司合作开发。目前网景已倒闭。sun(发明java)被甲骨文收购。
- Javascript 1.0 出现在1995年,Netscape 2.0 浏览器中。此时,IE还是小弟。
- 微软在IE 3发布了VBScript语言,同时以JScript为名发布了JavaScript的一个版本。
- 面对微软的竞争,Netscape和Sun公司联合ECMA(欧洲计算机制造商协会)对JavaScript语言进行了标准化。出现了ECMAScript语言。
- 到了1996年,JavaScript、ECMAScript、JScript——随便你们怎么称呼它——已经站稳了脚跟。
- Netscape和微软公司在各自的第3版浏览器中都不同程度地支持JavaScript 1.1语言。
BOM
- BOM 浏览器对象模型,可以用来调用整个浏览器窗口的高度、宽度和位置属性
DOM
- 文档对象模型
- DOM是一套对文档的内容进行抽象和概念化的方法。DOM树就是以树形结构组织文档的模型。
“第0级DOM”(DOM Level 0)
- 试验性质的初级dom。在还未形成统一标准的初期阶段,常见用途是翻转图片和验证表单数据。
浏览器战争
- 1997年微软和IE在双方第四版浏览器的战争
- DHTML
- 浏览器间的不兼容问题导致对DOM操作的差异
- 结局:IE获胜。原因:所有运行Windows操作系统的个人电脑都预装了它。
“第1级DOM”(DOM Level 1)
- W3C结合大家的优点推出了一个标准化的DOM。
- W3C对DOM的定义是:一个与系统平台和编程语言无关的接口,程序和脚本可以通过这个接口动态地访问和修改文档的内容、结构和样式。
开源Web浏览器引擎
小结
- 以上是JavaScript发展简史。
- DHTML曾被认为是HTML/XHTML、CSS和JavaScript相结合的产物,就像今天的HTML5那样,但把这些东西真正凝聚在一起的是DOM。
DOM
把你编写的网页文档转换为一个文档对象
-
D:document。
-
O:object。(“对象”是一种自足的数据集合,与某个特定对象相关联的变量被称为这个对象的属性;只能通过某个特定对象去调用的函数被称为这个对象的方法。)
- 对象有三种类型。
- 用户定义对象(user-defined object):由程序员自行创建的对象。
- 内建对象(native object):内建在JavaScript语言里的对象,如Array、Math和Date等。
- 宿主对象(host object):由浏览器提供的对象。
- 对象有三种类型。
-
M:model。
节点
- 文档是由节点构成的集合
- 其中重要的三种:元素节点、文本节点和属性节点。 nodeType属性总共有12种可取值,但其中仅有3种具有实用价值。
- 元素节点的nodeType属性值是1。
- 属性节点的nodeType属性值是2。
- 文本节点的nodeType属性值是3。
小结
5个常用DOM方法:
-
getElementById
-
getElementsByTagName
-
getElementsByClassName
- (使用这个方法还可以查找那些带有多个类名的元素。)
-
getAttribute
- (getAttribute方法不属于document对象,所以不能通过document对象调用。它只能通过元素节点对象调用。)
-
setAttribute
-
DOM的工作模式:先加载文档的静态内容,再动态刷新,动态刷新不影响文档的静态内容
javascript图片库
- html结构如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>image gallery</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<h1>Snapshots</h1>
<ul>
<li><a href="./images/pic1.png" title="a firework display" onclick="showPic(this);return false;">fireworks</a></li>
<li><a href="./images/pic2.png" title="a cup of black coffee" onclick="showPic(this);return false;">coffee</a></li>
<li><a href="./images/pic3.png" title="a red, red rose" onclick="showPic(this);return false;">rose</a></li>
</ul>
<img src="#" alt="占位符" id="placeholder">
<p id="description">choose an image.</p>
<script type="text/javascript" src='index.js'></script>
</body>
</html>
- 在点击事件中使用this关键字。this表示“这个a元素节点”
- 我们可以把任意数量的JavaScript语句放在onclick="XX;YY;"这对引号之间,只要把各条语句用分号隔开即可。
- onclick事件处理函数的工作机制:事件处理函数执行时可以返回一个值,这个值将被传递给那个事件处理函数。例如,给某个链接添加一个onclick事件处理函数,并让这个处理函数所触发的JavaScript代码返回布尔值true或false。这样一来,当这个链接被点击时,如果那段JavaScript代码返回的值是true, onclick事件处理函数就认为“这个链接被点击了”;反之,如果返回的值是false, onclick事件处理函数就认为“这个链接没有被点击”。就不会跳转。
index.js如下:
function showPic(whichpic) {
var source = whichpic.getAttribute('href');
var title = whichpic.getAttribute('title');
var placeholder = document.getElementById('placeholder');
placeholder.setAttribute('src', source);
var description = document.getElementById('description');
description.innerHTML = title;
}
index.css如下:
body{
font-family: 'Helvetica','Arial',serif;
color: #333;
background-color: #ccc;
margin: 1em 10%;
}
h1{
color: #333;
background-color: transparent;
}
a{
color: #c60;
background-color: transparent;
font-weight: bold;
text-decoration: none;
}
ul{
padding: 0;
}
li{
float: left;
padding: 1em;
list-style: none;
}
img{
display: block;
clear: both;
}
小结
DOM提供的几个新属性:
- childNodes
- nodeType (值是一个数字)
- nodeValue
- firstChild
- lastChild
最佳实践
- ❑ 平稳退化:确保网页在不支持运行JavaScript的情况下也能正常访问。
- ❑ 分离JavaScript:把网页的结构和内容与JavaScript脚本的动作行为分开。
- ❑ 向后兼容性:确保老版本的浏览器不会因为你的JavaScript脚本而死掉。
- ❑ 性能考虑:确定脚本执行的性能最优。
Flash的遭遇
制作短小精悍的矢量图形和视频片段本是Flash技术的强项之一。当视频片段的数量越来越多、体积也越来越大,网页的下载时间也不可避免地变得越来越长。于是它就有了降低网站可用性和可访问性的坏名声。
“javascript:”伪协议
“真”协议用来在因特网上的计算机之间传输数据包,如HTTP协议(http://)、FTP协议(ftp://)等,伪协议则是一种非标准化的协议。“javascript:”伪协议让我们通过一个链接来调用JavaScript函数。
- 最好别用伪协议。
<a href="javascript:abc();">execute abc</a>
较老的浏览器则会去尝试打开那个链接但失败。<a href="#">execute abc</a>
是未指向任何目标的内部链接。
平稳退化为什么这么重要?
- 平稳退化的含义是:让不支持js的浏览器也能顺利访问你的网站。你可能会疑惑,现代浏览器还有不支持js的吗?如果这个访问者是一个搜索机器人,它们浏览Web的目的是为了把各种网页添加到搜索引擎的数据库里。搜索机器人不能够理解JavaScript代码。所以,如果你的JavaScript网页不能平稳退化,它们在搜索引擎上的排名就可能大受损害。 解决办法:在href中写一个真实的url。
分离js
- 就是将javascript文件单独拎出来。在window.onload时执行函数。文档将被加载到一个浏览器窗口里,document对象又是window对象的一个属性。当window对象触发onload事件时,document对象已经存在。也就能获取dom了。
向后兼容
- 对象检测。判断有无document.getElementById。使用if(document.getElementById)
- “浏览器嗅探”指通过提取浏览器供应商提供的信息来解决向后兼容问题。这种方法不好的地方在于,浏览器可以伪装,甚至有一些允许用户修改。
性能考虑
- 尽量少访问DOM(document.getElementById获取一次,多复用)和尽量减少标记(减少不必要的html元素,不然过多不必要的元素只会增加DOM树的规模,进而增加遍历DOM树以查找特定元素的时间)
- 合并脚本。推荐的做法是把functionA.js、functionB.js、functionC.js和functionD.js合并到一个脚本文件中。这样,就可以减少加载页面时发送的请求数量。而减少请求数量通常都是在性能优化时首先要考虑的。
- 压缩脚本。去掉空格换行。
为什么将js脚本放在文档末尾?
- 脚本在html中的位置对页面初次加载影响很大。如果放在head中,可能阻塞图像或者其他脚本加载。因为根据http规范,浏览器每次从同一域名中最多同时下载两个文件。在下载脚本期间,不会下载其他任何(无论是不是资源)文件(无论是同一域名还是不同域名)。其他资源就要等待。
- 将script放到文档末尾。
</body>
前。在加载脚本时,window.onload事件就能对document文档执行各种操作,因为document是window的一个children节点,有window必然有document。
小结
确定脚本执行的性能最优,文件不宜过大,压缩文件/拆分文件,js脚本放在文档末尾。请求不宜过多,适量合并小资源文件请求。
案例研究:图片库改进版
- 检验函数/对象是否存在,是什么类型之类的。
if (!document.getElementById)
- 有多个出口,将其集中在函数头部
if (!document.getElementById) {
return false;
}
if (!document.getElementsByTagName) {
return false;
}
if (!document.getElementById("imagegalley")) {
return false;
}
- 函数执行的时机在link[i]被点击时执行
for (var i = 0; i < links.length; i++) {
links[i].onclick = function() {
return !showPic(this); // 这里定义了一个匿名函数,将在links[i]元素所对应的链接被点击时执行;
}
}
-
共享onload事件
- 把现有的 window.onload 事件处理函数的值存入变量 oldonload。
- 如果在这个处理函数上还没有绑定任何函数,就想平时那样把新函数添加给他。
- 如果这里处理函数上已经绑定了一些函数,就把新函数追加到现有指令的末尾。
function addLoadEvent(func) {
var oldFunc = window.onload;
//如果window.onload没有内容,则执行新添加的func函数
if (typeof window.onload != 'function') {
window.onload = func;
}
//如果window.onload已经存在函数,则window.onload先执行旧函数,再执行新添加的func函数
else {
window.onload = function() {
oldFunc();
func();
}
}
}
-
键盘访问
- 作为一个众所周知的事实,不使用鼠标也可以浏览Web。键盘上的Tab键可以让我们从这个链接移动到另一个链接,而按下回车键将启用当前链接。不使用 onkeypress 事件。因为即使按tab键也会触发onkeypress事件。
dom core和html dom
- 核心 DOM - 针对任何结构化文档(包括HTM、XHTML和XML)的标准模型
- XML DOM - 针对 XML 文档的标准模型
- HTML DOM - 针对 HTML 文档的标准模型
相同点:HTML DOM的很多对象模型来自于核心DOM。
比如:
- getElementById
- getElementsByTagName
- getAttribute
- setAttribute
不同点:HTML DOM可以以简单的方式访问DOM树
小结
- 结构与行为的分离程度越大越好。
- 支持平稳退化:禁用 js后也可以浏览图片,链接可以正常工作。
动态创建标签
传统方法
-
document.write
- 违背了“行为应该与表现分离”的原则。
- 即使将它放在函数中,也还是要在部分使用
- MIME类型application/xhtml+xml与document.write不兼容,浏览器在呈现这种XHTML文档时根本不会执行document.write方法。(MIME表示文档文件或字节流的性质和格式)
-
innerHTML属性
- innerHTML属性也是HTML专有属性,不能用于任何其他标记语言文档。
- 浏览器在呈现正宗的XHTML文档(即MIME类型是application/xhtml+xml的XHTML文档)时会直接忽略掉innerHTML属性。
dom方法
-
createElement
- 用这个方法创建的元素是一个文档碎片
-
appendChild
-
createTextNode
- 你需要创建一个文本节点,你可以用createTextNode方法来实现它。
-
insertBefore
- Node.insertBefore
实现insertAfter函数
function insertAfter(newElement, targetElement //现存元素) {
var parent = targetElement.parentNode;
if (parent.lastChild == targetElement) { //目标函数是不是 parent 的最后一个子元素
parent.appendChild(newElement); //如果是,直接追加子元素到最后
} else { //如果不是,把新元素插入到目标元素的下一个兄弟元素之前
parent.insertBefore(newElement, targetElement.nextSibling);
}
}
Ajax
- 使用 Ajax 就可以做到只更新页面中的一小部分,不必每次加载整个页面。
- Ajax的主要优势就是对页面的请求以异步方式发送到服务器。而服务器不会阻塞整个页面来响应请求,它会在后台处理请求,与此同时用户还能继续浏览页面并与页面交互。
- 在使用Ajax时,千万要注意同源策略。使用XMLHttpRequest对象发送的请求只能访问与其所在的HTML处于同一个域中的数据,不能向其他域发送请求。此外,有些浏览器还会限制Ajax请求使用的协议。比如在Chrome中,如果你使用file://协议从自己的硬盘里加载example.txt文件,就会看到“Cross origin requests are only supported for HTTP”(跨域请求只支持HTTP协议)的错误消息。
XMLHttpRequest对象
- ajax技术的核心
- 这个对象充当着浏览器中的脚本(客户端)与服务器之间的中间人的角色。以往的请求都由浏览器发出,而JavaScript通过这个对象可以自己发送请求,同时也自己处理响应。
addloadEvent(getNewContent);
function getHTTPObject() {
if (typeof XMLHttpRequest == 'undefined') {
XMLHttpRequest = function() {
try {
return new ActiveXObject('Msxml2.XMLHTTP.6.0');
} catch (e) {
// statements
console.log(e);
}
try {
return new ActiveXObject('Msxml2.XMLHTTP.3.0');
} catch (e) {
// statements
console.log(e);
}
try {
return new ActiveXObject('Msxml2.XMLHTTP');
} catch (e) {
// statements
console.log(e);
}
}
}
return new XMLHttpRequest();
}
function getNewContent() {
var request = getHTTPObject();
// XMLHttpRequest对象有许多的方法。其中最有用的是open方法,它用来指定服务器上将要访问的文件,指定请求类型:GET、POST或SEND。这个方法的第三个参数用于指定请求是否以异步方式发送和处理。
request.open('GET', 'example.txt', true);
if (request) {
// onreadystatechange是一个事件处理函数,它会在服务器给XMLHttpRequest对象送回响应的时候被触发执行。根据服务器的具体响应做相应的处理。
request.onreadystatechange = function() {
//readyState可能有5个值:❑ 0表示未初始化❑ 1表示正在加载❑ 2表示加载完毕❑ 3表示正在交互❑ 4表示完成
if (request.readyState == 4) {
var para = document.createElement('p');
//访问服务器发送回来的数据要通过两个属性完成。一个是responseText属性,这个属性用于保存文本字符串形式的数据。另一个属性是responseXML属性,用于保存Content-Type头部中指定为"text/xml"的数据,其实是一个DocumentFragment对象。
var txt = document.createTextNode(request.responseText);
para.appendChild(txt);
document.getElementById('new').appendChild(para);
}
};
request.send(null);
} else {
alert('sorry');
}
}
小结
- 动态创建标签的方法
- Ajax和异步请求
8.充实文档的内容
不应该做什么
不要滥用 DOM 技术,重要内容不要通过 Javascript 添加到网页,各大搜索引擎的搜索机器人还不支持 Javascript。
- 渐进增强(prograssive enhancement):根据内容使用标记良好的结构(HTML);然后再逐步加强这些内容,通过 CSS 改进呈现效果。
- 平稳退化:样式和行为支持平稳退化,缺乏 CSS 和 DOM 支持的访问者仍可以访问到核心内容。
把“不可见”变成“可见”
通过 DOM 实现一些小部件:
- 得到隐藏在属性里的信息
- 创建标记封装这些信息
- 把这些标记插入到文档
- 这个标签的含义是缩略语,其title属性可以写缩略语的全称。
是html5的文档类型声明
- 在写标签和属性时,HTML既允许使用大写字母(比如
),也允许使用小写字母(比如
);XHTML却要求所有的标签名和属性名都必须使用小写字母。
- HTML5的文档类型声明
<!DOCTYPE html>
html5默认使用标准模式呈现文档。兼容模式意味着浏览器要模仿某些早期浏览器的“怪异行为”,并容许那些不规范的页面在新浏览器也能正常工作。
- 浏览器大战中,网景公司和微软公司曾把和标签当做它们的武器之一。在竞争最激烈时,微软决定不在自己的浏览器里实现abbr元素。微软的IE浏览器直到IE7才支持abbr元素。所以,在老式IE浏览器中,如果你去获取abbr元素中的属性/文本节点,很有可能会得到一条报错信息。
小结
JavaScript脚本只应该用来充实文档的内容,要避免使用DOM技术来创建核心内容。
DOM core 以属性方式访问getAttrbute()
Html-dom 以.的方式访问
第9章 CSS-DOM
- 三位一体的网页指的是:结构层html/表示层css/行为层js
style
-
读取
- element.style.property
- 返回颜色:
element.style.color
- 返回font-family:
element.style.fontFamily
,注意不能出现连字符(-),使用驼峰命名法代替。 - style 属性只能返回内嵌样式,不能检索外部样式的属性。
-
设置
- element.style.property = value (note:value as string)
- 会覆盖原有属性值
-
通过元素class属性去更新样式
- Element.className=value (note:value as string)
- 追加className,Element.className+=' '+value (note:空格+value )
- 为类型都是text的input添加样式。
-
input[type*='text']{ font-size:16px; }
小结
- 表示层应该与行为层分离。但常有灰色地带。诸如:hover和:focus之类的伪类允许你根据用户触发事件改变元素的呈现效果。改变元素的呈现效果当然是表示层的“势力范围”,但响应用户触发的事件却是行为层的领地。表示层和行为层的这种重叠形成了一个灰色地带。
第10章 用JavaScript实现动画效果
- 要想用js获取style.left必须将style.left写成行内样式。而不是外部引入的css。
- position 属性的合法值有:
- static:默认值,出现在文档流中
- fixed:脱离文档流,相对于浏览器可视区的固定位置
- relative:不文档流,相对于自身的定位
- absolute:脱离文档流,相对于父容器的固定位置
- overflow属性的可取值有4种:visible、hidden、scroll和auto。
❑ visible:不裁剪溢出的内容。浏览器将把溢出的内容呈现在其容器元素的显示区域以外,全部内容都可见。
❑ hidden:隐藏溢出的内容。内容只显示在其容器元素的显示区域里,这意味着只有一部分内容可见。
❑ scroll:类似于hidden,浏览器将对溢出的内容进行隐藏,但显示一个滚动条以便让用户能够滚动看到内容的其他部分。
❑ auto:类似于scroll,但浏览器只在确实发生溢出时才显示滚动条。如果内容没有溢出,就不显示滚动条。
- 安全检查的重要性。在常见常用的各种库里面的,第一步就是安全检查。
缓动动画函数
function animate(obj, target, callback) {
//如果给按钮绑定点击后添加定时器的功能 多次点击会导致元素的速度加快
//解决方法就是让元素只有一个定时器执行 即清除多余(原来的)定时器
clearInterval(obj.timer);
obj.timer = setInterval(function () {
// 将步长值写在定时器里面
var step = (target - obj.offsetLeft) / 10;
// 把步长值改为整数 不要出现小数的问题 使用Math.ceil()方法向上取整
// 往回退的时候 step为负值 则需要Math.floor()方法向下取整
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if(obj.offsetLeft == target){
clearInterval(obj.timer);
if(callback) {
callback();
}
}
obj.style.left = obj.offsetLeft + step +'px';
}, 15);
第11章 HTML5
新增加的标签:
<section>
<article>
<header>
<footer>
多媒体元素:
<audio>
<video>
<canvas>
Javascript API:
- Geolocation
- Storage
- Drap-and-Drop
- Socket
Canvas
- 绘制矢量及位图
利用 canvas 在浏览器中把一副彩色图片变成灰度图片。 当用户的鼠标悬停到图片上面时,再把它切换回原始的彩色图片。
- 在这个例子中遇到了一个大问题:pen.js:14 Uncaught DOMException: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.通过在img上面加上crossorigin="anonymous"这个属性就解决了。这个属性允许我们访问未经验证的资源,所以当我们加上时,我们最好确认这是可以信任的资源。如果加上后依然有跨域问题,那么就是后端设置了 Access-Control-Allow-Origin 的header
audio 和 video
- 在二者之前,通过
<object>
引用各种影片播放器,例如QuickTime、RealPlayer或Flash,并使用这些插件在浏览器中播放影片。问题在于它需要向网页中嵌入视频需要用到一大堆重复的和元素,其中一些在HTML4中甚至都无法通过有效性验证。- 编解码器决定了浏览器在播放时应该如何解码音频和视频。编解码器的核心就是一个算法,用于压缩和存储视频,以减少原始文件的大小,同时可能会也可能不会损失品质。
表单
- 以前只有type='text'
新的输入控件类型包括:
❑ email,用于输入电子邮件地址;
❑ url,用于输入URL;
❑ date,用于输入日期和时间;
❑ number,用于输入数值;
❑ range,用于生成滑动条;
❑ search,用于搜索框;
❑ tel,用于输入电话号码;
❑ color,用于选择颜色。
html5其他新特性
- 使用localStorage和sessionStorage在客户端存储大型和复杂数据集的更有效方案
- 使用WebSocket与服务器端脚本进行开放的双向通信
- 使用Web Worker在后台执行JavaScript
- 标准化的拖放实现
- 在浏览器中实现地理位置服务