DOM编程:(学习书籍为Java DOM编程艺术)
<script>标签建议放在文档最后,</body>之前
1.DOM提供的五个方法:
getElementById() 返回一个对象
getElementByTagName()返回一个对象数组
getElementByClassName()返回一个对象数组
getAttribute(attribute)获取属性值
setAttribute(attribute,value)改变属性值
细节:setAttribute(attribute,value)方法不改变文档源代码,说明DOM工作模式:先加载文档静态内容再动态刷新。DOM的真正威力:对页面内容进行刷新却不需要在浏览器里面刷新页面。
2.事件调用函数
在onclick事件处理函数里加一条return false;,就可以防止用户被带到目标链接窗口(a标签)。
3.DOM的一些新属性
childNodes返回全部子元素数组
nodeType返回节点类型:值1:元素结点 2:属性节点 3:文本节点(由此可以只对特定类型节点进行处理)
nodeValue得到节点值
使用nodeValue注意,诸如<p>元素里的文本是另一种节点,是<p>元素的第一个子节点
firstChild
lastChild
2019.5.8
1.分离java script
将代码打包在函数xx中,然后用windows.οnlοad=xx;可以使含有document对象的js代码正常运行(P69)
2.向后兼容
对象检测技术:一定要将方法名后的括号去掉,否则测试的将是方法的结果
if(!document.getElementById) return false;
3.平稳退化,确保可访问
2019.5.20
共享onload事件:多个函数需要在页面加载时执行
window.οnlοad=firstfunction;
window.οnlοad=secondfunction;
这么做的话,只有secondfunction会被绑定,因为前面的值被后面的值覆盖了。那么该怎么办?
方法1:匿名函数
window.onload=function(){
firstFunction();
secondFunction();
}
方法2:(推荐使用)addLodEvent函数,将那些在页面加载完毕时执行的函数创建为一个队列
function addLoadEvent(func) {
var oldonload = window.onload;//将现有的事件处理函数的值存入变量中
if (typeof window.onload != 'function') {
window.onload = func;//如果这个事件处理函数没有绑定任何函数,就把新函数添加给它
} else {
window.onload = function() {
oldonload();
func();//如果已经绑定了函数,就把新函数追加到现有指令的末尾
}
}
}
2019.7.9
nodeName属性只返回大写字母
下面给出书上例子的js最终代码
function showPic(whichpic) {
if (!document.getElementById("placeholder")) return true;
var source = whichpic.getAttribute("href");
var placeholder = document.getElementById("placeholder");
placeholder.setAttribute("src",source);//填充图片
if (!document.getElementById("description")) return false;
if (whichpic.getAttribute("title")) {
var text = whichpic.getAttribute("title");
} else {
var text = "";
}
var description = document.getElementById("description");
if (description.firstChild.nodeType == 3) {//如果是文本节点
description.firstChild.nodeValue = text;
}
return false;
}
function prepareGallery() {
if (!document.getElementsByTagName) return false;
if (!document.getElementById) return false;
if (!document.getElementById("imagegallery")) return false;
var gallery = document.getElementById("imagegallery");
var links = gallery.getElementsByTagName("a");//links代表id为imagegallery的列表中的a标签集合
for ( var i=0; i < links.length; i++) {
links[i].onclick = function() {
return showPic(this)?false:true;//如果showpic返回true,我们就返回false,浏览器就不会打开链接(阻止默认行为)。
}
links[i].onkeypress = links[i].onclick;//onkeypress模仿onclick行为,目的是为了只使用键盘用户,不过书中最后并没有使用。
}
}
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
oldonload();
func();
}
}
}
addLoadEvent(prepareGallery);
到目前为止,所做的优化有:
1.引入多项测试和检查,使js代码平稳退化
2.最重要的是将事件处理函数分离到了一个外部的js文件。js代码不再依赖HTML文档的内容和结构
3.不使用onkeypress,使js代码的可访问性得到保证(onkeypress函数用户每按下一个按键都会触发,意味着只要onkeypress事件处理函数返回的是false,用户将永远无法离开当前链接。上述showpic函数如果成功返回的就是false)
依然存在的问题:
placeholder和description(图片展示和文字描述)只为showpic函数而存在,不支持js的浏览器最好不呈现这两个元素。
因此,接下来学习如何使用DOM提供的方法属性去创建HTML元素,并把他们插入HTML文档。
第七章 动态创建标记
1.一些传统方法
document.write():js与html混杂,不推荐
innerHTML属性:该属性无细节可言,一旦使用了这个属性,它的全部内容都将被替换。同时innerHTML是HTML专有属性,不适用任何其他标记语言文档。
2.DOM方法 (并不是在创建标记,而是在改变节点树。)
创建一个元素,把这个元素加到节点树
2.1 createElement:创建一个元素节点
把结果赋值给一个变量是一个好主意
例如 var para=document.createElement("p")
2.2 appendChild
把新创建的节点插入节点树的最简单的方法就是:让它成为这个文档某个现有节点的一个子节点
parent.appendChild(child)
2.3 createTextNode:创捷文本节点
var txt=document.createTextNode(text)
3.1在已有元素前插入一个元素
parent.insertBefore(newElement,targetElement)
不必在乎parent具体是哪个,targetElement的parentNode属性值就是它。
例:把A插入到B前
B.parentNode.insertBefore(A,B)
3.2在已有元素后插入一个元素
没有现成函数使用,可以自己写一个
function insertAfter(newElement,targetElement) {
var parent = targetElement.parentNode;
if (parent.lastChild == targetElement) {
parent.appendChild(newElement); //如果targetElement是父元素最后一个子元素,那么刚好直接添加就可以
} else {
parent.insertBefore(newElement,targetElement.nextSibling);//如果不是,则插在targetElement的下一个兄弟元素前
}
}
nextsibling属性:下一个兄弟节点
4 Ajax(异步加载页面的技术)
4.1XMLHTTPRequest对象
function getHTTPObject() {
if (typeof XMLHttpRequest == "undefined")
XMLHttpRequest = function () {
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); }
catch (e) {}
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); }
catch (e) {}
try { return new ActiveXObject("Msxml2.XMLHTTP"); }
catch (e) {}
return false;
}
return new XMLHttpRequest();
}
var request=getHTTPObject();
open方法,用来指定服务器上将要访问的文件,指定请求类型GET/POSY/SEND,第三个参数指定请求是否以异步方式发送和处理。
request.open("GET","example.txt",true)
onreadyStatechange:是一个事件处理函数,他会在服务器给XMLHTTPRequest对象送回响应的时候被触发执行。
可以指定一个处理函数
request.onreadyStatechange=function(){
//处理响应
}
也可以引用一个函数
request.onreadyStatechange=doSomething;(不加括号,加括号表示立即调用)
在指定了请求目标,也明确如何处理之后就可以用send方法发送请求了。
request.send(null);
这里可能会遇到XMLHTTPRequest对象不支持的问题,当浏览器向XMLHTTPRequest对象发回响应的时候,浏览器会在不同阶段更新readyState属性的值,他有5个可能的值:
- 0 表示未初始化
- 1 表示正在加载
- 2 表示加载完毕
- 3 表示正在交互
- 4 表示完成
只要readyState属性的值变成了4,就可以访问服务器发回来的数据了。
访问发回的数据时,需要通过两个属性
responseText 保存文本字符串形式的数据 例如var txt=document.createTextNode(request.responseText);
responseXML 保存Content-Type头部中指定为“text/xml”的数据,其实是一个DocumentFragment对象
使用Ajax时,要注意同源策略,使用XMLHTTPRequest对象发送的请求只能访问与其HTML处于同一个域中的数据。
异步请求有一个容易被忽略的问题就是异步性,脚本在发送XMLHTTPRequest请求之后,仍然会继续执行,不会等待响应返回。
Ajax应用只要依赖服务器端处理,而非客户端处理。
Ajax会在12章更具体的介绍。
第八章 充实文档的内容
本章具体介绍了一些实例,比如把文档中的缩略语显示为一个缩略语列表(因为缩略语<abbr>标签的title属性用户不可见),下面仅仅写一些我认为重要的点。
直接上完整代码:
function displayAbbreviations() {
if (!document.getElementsByTagName || !document.createElement || !document.createTextNode) return false;
// 获取所有abbr元素
var abbreviations = document.getElementsByTagName("abbr");
if (abbreviations.length < 1) return false;
var defs = new Array();
// 遍历
for (var i=0; i<abbreviations.length; i++) {
var current_abbr = abbreviations[i];
if (current_abbr.childNodes.length < 1) continue;//因为低版本IE不支持abbr元素,所以返回abbr元素的子节点为0.如此就就立刻开始下一个循环。
var definition = current_abbr.getAttribute("title");//title属性保存的是全称。
var key = current_abbr.lastChild.nodeValue;//其实就是文本节点,abbr元素有且仅有一个子节点。也就是缩写
defs[key] = definition;//比如def["w3c"]="World Wide Web Consortium"
}
// 创建定义列表
var dlist = document.createElement("dl");
// loop through the definitions
for (key in defs) {
var definition = defs[key];
// 创建定义标题
var dtitle = document.createElement("dt");
var dtitle_text = document.createTextNode(key);
dtitle.appendChild(dtitle_text);
// 创建定义描述
var ddesc = document.createElement("dd");
var ddesc_text = document.createTextNode(definition);
ddesc.appendChild(ddesc_text);
// 把他们添加到定义列表
dlist.appendChild(dtitle);
dlist.appendChild(ddesc);
}
if (dlist.childNodes.length < 1) return false;//因为低版本IE不支持abbr元素defs数组就是空的,自然dl元素也没有子节点,如此便退出函数。
// 创建标题
var header = document.createElement("h2");
var header_text = document.createTextNode("Abbreviations");
header.appendChild(header_text);
// 把标题添加到页面主体
document.body.appendChild(header);
// 把定义列表添加到页面主体
document.body.appendChild(dlist);
}
addLoadEvent(displayAbbreviations);
另外两个例子大同小异。其中有个需要把提取出来的文献来源链接添加到blockquote元素最后的地方,这里就存在一个问题。
例子中结尾</p>和</blockquote>之间存在一个换行符,有些浏览器会把这当成一个文本节点,所以用lastChild属性就不对了。
解决办法:
// 取得当前blockquote元素包含的所有元素节点
var quoteChildren = quotes[i].getElementsByTagName('*');
// 如果没有,就退出本次循环
if (quoteChildren.length < 1) continue;
//因为getElementsByTagName获取的都是元素节点,自然而然最后一个就是我们需要的
var elem = quoteChildren[quoteChildren.length - 1];
TIPS:如果没有百分之百的把握,需要去检查nodeType的值,有很多DOM方法只能用于元素节点。用在文本节点就会出错。
第九章 CSS-DOM
本章主要介绍用js去设置css属性。
首先介绍一个style属性,查询这个属性返回的是一个对象,样式都存放在这个对象的属性了,可以读写。
用法:element.style.property
- style对象只包含在HTML代码里用style属性声明的样式,但这几乎没有实用价值。
- style对象的属性值永远是一个字符串。
- style对象的属性值必须放在引号里,单双引号都可以,否则会认为等号右边是一个变量。
如何寻找下一个元素节点?
function getNextElement(node) {
if(node.nodeType == 1) {
return node;
}
if (node.nextSibling) {
return getNextElement(node.nextSibling);
}
return null;
}
固然可以用DOM直接设置或修改样式,但这样行为层就干预了表示层,后期修改也麻烦,有一种更好的做法:
与其使用DOM直接改变某个元素的样式,不如通过JavaScript代码去更新这个元素的class属性
可以用setAttribute函数来做这个事情。更简单的办法是更新className属性,className是一个可读可写的属性。这样修改样式只需要修改css文件。
这个技巧只有一个不足:每次都是替换(而不是追加)该元素的原有的的class设置。编写一个函数来解决这个问题
function addClass(element,value) {
if (!element.className) { //如果原有设置为空
element.className = value;
} else { //不为空则追加
element.className+= " ";
element.className+= value;
}
}
第十章 用JavaScript实现动画效果