JavaScript高级程序设计(第三版)学习笔记8、9、10章
第8章,BOM
BOM的核心对象是window,具有双重角色,既是js访问浏览器的一个接口,又是ECMAScript规定的Global对象。因此,在全局作用域中声明的函数、变量都会变成window对象的属性和方法。
例:
var age = 20; function sayAge(){ alert(this.age); } alert(window.age); //20 window.sayAge(); //20
定义全局变量与在window对象上直接定义属性区别:全局变量不能通过delete操作符删除,而直接在window对象上定义的属性可以。
注:尝试访问未声明的变量会抛出错误,但通过查询window对象,可以知道某个未声明变量是否存在
例:
//这里会出错,因为oldValue未定义 var value = oldValue; //这里不会抛出错误,因为这是一次属性查询 //value的值是undefined var value = window.oldValue;
全局对象location和navigation实际上都是window对象的属性
窗口关系及框架
如果页面包含框架,则每个框架都有自己的window对象,并且保存在frames集合中。在frames集合中,可以使用索引(从0开始,从左到右,从上到下),或框架名称来访问相应的window对象。
<html> <head> <title>Frameset Example</title> </head> <frameset row="160,*"> <frame src="frame.html" name="topFrame"> <frameset cols="50%,50%"> <frame src="anotherframe.html" name="leftFrame"></frame> <frame src="yetanotherframe.html" name="rightFrame"></frame> </frameset> </frameset> </html>
以上代码创建了一个框架集,可以通过window.frames[0]或者window.frames[“topFrame”]来引用上方框架,不过,最好使用top而非window访问
top对象始终指向最高(最外)层框架,使用他可以确保在一个框架中正确地访问另一个框架,与top相对的window对象是parent,parent始终指向当前框架的直接上层框架,在某些情况下,parent等于top,没有框架的情况,parent一定等于top。
与框架有关的最后一个对象是self,始终指向window,实际上,self和window对象可以互换使用
使用下例代码可以跨浏览器取得窗口左边和上边的位置
var leftPos = (typeof window.screenLeft == “number”)? window.screenLeft : window.screenX; var topPos = (typeof window.screenTop == “number”)? window.screenTop : window.screenY; window.moveTo(); //接收两个参数,新位置的x,y window.moveBy(); //接收两个参数,水平和垂直移动的像素
窗口大小
window.resizeTo(); //接收两个参数,新窗口的宽和高 window.resizeBy(); //接收两个参数,相对旧窗口的宽和高之差 window.open(); //接收四个参数:要加载的url,窗口目标,一个特性字符串,一个表示新页面是否取代浏览器历史记录中当前加载页面的布尔值,最后一个参数只在不打开新窗口的情况下使用
间歇调用和超时调用
js是单线程语言,但允许通过设置超时时间和间歇时间来调度代码在特定时刻执行
超时调用
使用window的setTimeout方法,接收两个参数,要执行的代码和超时时间毫秒数,可以是字符串,也可以是函数。
//不建议传递字符串 setTimeout(“alert(‘hello,world’)”,1000); //推荐使用方式 setTimeout(function(){ alert(‘hello,world’); },1000);
setTimeout返回一个数值ID,是计划执行的唯一标识符,可以通过clearTimeout()来取消
间歇调用
使用setInterval()方法,与setTimeou方法接收的参数一样,写法一致,也会返回一个数值ID,也是唯一标识符,可以使用clearInterval方法取消
建议:最好不使用间歇调用,可以使用超时调用模拟间歇调用,因为在某些情况下后一个间歇调用,有可能会在前一个未结束之前启动
系统对话框
alert(),只有确定按钮
confirm(),有确定和取消按钮,用法与alert一致,不过,confirm会返回布尔值,确定返回true,取消返回false
prompt(),比confirm多了一个文本输入域,接收两个参数:提示文本以及输入默认文本,点击ok,返回文本,其他方式关闭对话框,返回null
//显示查找对话框 window.find(); //显示打印对话框 window.print();
location对象
既是window对象属性,也是document对象属性,即window.location与document.location引用的是同一个对象
location对象属性
属性名 |
例子 |
说明 |
hash |
“#contents” |
返回url中的hash,#号后跟的字符,没有则返回空串 |
host |
“www.wrox.com:80” |
返回服务器名称和端口号 |
hostname |
“www.wrox.com” |
返回服务器名称 |
href |
“http:/www.wrox.com” |
返回完整url,location的toString也会返回相同值 |
pathname |
“/WileyCDA/” |
返回url中的目录和或文件名 |
port |
“8080” |
返回url中的端口号 |
protocol |
“http:” |
返回页面使用的协议 |
search |
“?q=javascript” |
返回url从?号开始到结束的字符串即返回查询字符串,以?号开头 |
注:每次修改location的属性(hase除外),都会以新url刷新页面
location.replace()方法只接受一个参数,新的url,调用此方法后,用户无法返回上一个页面
location.reload()方法,重新加载当前页面,有可能从缓存加载,传递true之后则从服务器重新加载
navigation对象
对象的属性通常用于检测显示网页的浏览器类型
检测插件
对于非IE浏览器使用plugins数组来达到目的
name:插件名字
description:插件描述
filename:插件文件名
length:插件所处理的MIME类型数量
screen对象
并没有多大用处
history对象
用户浏览的历史记录
go方法,传入数值(正值前进,负值后退)和字符串参数(url)
back(),返回,forward(),前进。
length,保存历史记录的数量
第9章,客户端检测
尽量不使用客户端检测。先设计最通用的方案,再使用特定的浏览器方法增强该方案
能力检测
检测浏览器是否具备某一能力。
尽可能使用typeof进行能力检测,对所要使用的函数或者属性进行是否符合预期的检测,可以降低出错的风险
并不需要知道用户使用的是什么浏览器,只需要知道用户的浏览器是否具备某些开发所需的功能即可,毕竟浏览器的功能是会改变的,并不能保证现在独有的属性未来不会有其他浏览器实现。
怪癖检测
检测浏览器的特殊行为,与能力检测类似,不过,怪癖检测是想要知道浏览器存在什么缺陷。
用户代理检测
通过检测用户代理字符串来确定实际使用的浏览器。在每一次的http请求过程中,用户代理字符串是作为响应首部发送的,可以通过js的navigator.userAgent属性访问。这服务端这是常见而广为接受的做法,客户端是万不得已的做法。
识别呈现引擎
注意检测五大呈现引擎:IE,Gecko,WebKit,KHTML和Opera
注意识别顺序Opera,WebKit,KHTML,Gecko,IE,前一个引擎有包含后一个引擎的某些属性,顺序错误将不能正确识别
识别浏览器
识别平台
识别windows操作系统
识别移动设备
识别游戏系统
完整的用户代理检测代码
1 //完整代码 2 var client = function(){ 3 //呈现引擎 4 var engine = { 5 ie:0, 6 gecko:0, 7 webkit:0, 8 khtml:0, 9 opera:0, 10 11 //完整版本号 12 ver:null 13 }; 14 15 //浏览器 16 var browser = { 17 //主要浏览器 18 ie:0, 19 firefox:0, 20 safari:0, 21 konq:0, 22 opera:0, 23 chrome:0, 24 25 //具体版本号 26 ver:null 27 }; 28 29 //平台、设备和操作系统 30 var system = { 31 win:false, 32 mac:false, 33 x11:false, 34 35 //移动设备 36 iphone:false, 37 ipod:false, 38 ipad:false, 39 ios:false, 40 android:false, 41 nokiaN:false, 42 winMobile:false, 43 44 //游戏系统 45 wii:false, 46 ps:false 47 }; 48 49 //检测呈现引擎和浏览器 50 var ua = navigator.userAgent; 51 if(window.opera){ 52 engine.ver = browser.ver = window.opera.version(); 53 engine.opera = browser.opera = parseFloat(engine.ver); 54 }else if(/AppleWebKit\/(\S+)/.test(ua)){ 55 engine.ver = RegExp["$1"]; 56 engine.webkit = parseFloat(engine.ver); 57 58 //确定是Chrome还是Safari 59 if(/Chrome\/(\S+)/.test(ua)){ 60 browser.ver = RegExp["$1"]; 61 browser.chrome = parseFloat(browser.ver); 62 }else if(/Version\/(\S+)/.test(ua)){ 63 browser.ver = RegExp["$1"]; 64 browser.safari = parseFloat(browser.ver); 65 }else{ 66 //近似地确定版本号 67 var safariVersion = 1; 68 if(engine.webkit < 100){ 69 safariVersion = 1; 70 }else if(engine.webkit < 312){ 71 safariVersion = 1.2; 72 }else if(engine.webkit < 412){ 73 safariVersion = 1.3; 74 }else{ 75 safariVersion = 2; 76 } 77 78 browser.safari = browser.ver = safariVersion; 79 } 80 }else if(/KHTML\/(S+)/.test(ua) || /Konqueror\/([^;]+)/.test(ua)){ 81 engine.ver = browser.ver = RegExp["$1"]; 82 engine.khtml = browser.konq = parseFloat(engine.ver); 83 }else if(/rv:([^\)]+)\) Gecko\/\d{8}/.test(ua)){ 84 engine.ver = RegExp["$1"]; 85 browser.gecko = parseFloat(engine.ver); 86 87 //确定是不是Firefox 88 if(/Firefox\/(\S+)/.test(ua)){ 89 browser.ver = RegExp["$1"]; 90 browser.firefox = parseFloat(browser.ver); 91 } 92 }else if(/MSIE ([^;]+)/.test(ua)){ 93 engine.ver = browser.ver = RegExp["$1"]; 94 engine.ie = browser.ie = parseFloat(engine.ver); 95 } 96 97 //检测浏览器 98 browser.ie = engine.ie; 99 browser.opera = engine.opera; 100 101 //检测平台 102 var p = navigator.platform; 103 system.win = p.indexOf("Win") == 0; 104 system.mac = p.indexOf("Mac") == 0; 105 system.x11 = (p == "X11") || (p.indexOf("Linux") == 0); 106 107 //检测windows操作系统 108 if(system.win){ 109 if(/Win(?:dows )?([^do]{2})\s?(\d+\.\d+)?/.test(ua)){ 110 if(RegExp["$1"] == "NT"){ 111 switch(RegExp["$2"]){ 112 case "5.0": 113 system.win = "2000"; 114 break; 115 case "5.1": 116 system.win = "XP"; 117 break; 118 case "6.0": 119 system.win = "Vista"; 120 break; 121 case "6.1": 122 system.win = "7"; 123 break; 124 default: 125 system.win = "NT"; 126 break; 127 } 128 }else if(RegExp["$1"] == "9x"){ 129 system.win = "ME"; 130 }else{ 131 system.win = RegExp["$1"]; 132 } 133 } 134 } 135 136 //移动设备 137 system.iphone = ua.indexOf("iPhone") > -1; 138 system.ipod = ua.indexOf("iPod") > -1; 139 system.ipad = ua.indexOf("iPad") > -1; 140 system.nokiaN = ua.indexOf("NokiaN") > -1; 141 142 //windows mobile 143 if(system.win == "CE"){ 144 system.winMobile = system.win; 145 }else if(system.win == "Ph"){ 146 if(/Windows Phone OS (\d+.\d+)/.test(ua)){ 147 system.win = "Phone"; 148 system.winMobile = parseFloat(RegExp["$1"]); 149 } 150 } 151 152 //检测IOS版本 153 if(system.mac && ua.indexOf("Mobile") > -1){ 154 if(/CPU (?:iPhone )?OS (\d+_\d+)/.test(ua)){ 155 system.ios = parseFloat(RegExp.$1.replace("_",".")); 156 }else{ 157 system.ios = 2; //不能真正检测出来,所以只能猜测,猜测低版本会更适当点 158 } 159 } 160 161 //检测Android版本 162 if(/Android (\d+\.\d+)/.test(ua)){ 163 system.android = parseFloat(RegExp.$1); 164 } 165 166 //游戏系统 167 system.wii = ua.indexOf("Wii") > -1; 168 system.ps = /playstation/i.test(ua); 169 170 //返回这些对象 171 return { 172 engine:engine, 173 browser:browser, 174 system:system 175 }; 176 }();
使用方法
使用情形:
1、不能直接准确地使用能力检测或怪癖检测
2、同一款浏览器在不同平台下具备不同的能力
3、为了跟踪分析等目的需要知道确切的浏览器
第10章,DOM
DOM(文档对象模型),针对HTML和xml文档的一个API
DOM可以将任何HTML和xml文档描绘成一个由多层节点构成的结构
文档节点是每个文档的根节点,文档元素是文档的最外层元素,每个文档只能有一个文档元素,html中文档元素始终是<html>元素,xml中任何元素都可能是文档元素
一种示例文档结构
Node类型
DOM1级定义了一个Node接口,由DOM中所有节点类型实现。在js中作为Node类型实现,除IE外,都可以访问这个类型。js中所有节点类型都继承自Node类型,so,所有节点都有相同的基本属性和方法
每个节点都有nodeType属性,用于表示节点类型,由以下12个常量表示:
Node.ELEMENT_NODE(1)
Node.ATTRIBUTE_NODE(2)
Node.TEXT_NODE(3)
Node.CDATA_SECTION_NODE(4)
Node.ENTITY_REFERENCE_NODE(5)
Node.ENTITY_NODE(6)
Node.PROCESSING_INSTRUCTION_NODE(7)
Node.COMMENT_NODE(8)
Node.DOCUMENT_NODE(9)
Node.DOCUMENT_TYPE_NODE(10)
Node.DOCUMENT_FRAGMENT_NODE(11)
Node.NOTATION_NODE(12)
使用nodeName和nodeValue可以了解节点具体信息
每个节点都有childNodes属性,保存着NodeList对象,有length属性,是一个类数组对象。NodeList独特之处在于,基于DOM结构动态执行查询的结果,因此DOM的变化能够自动反映到NodeList对象中。可以通过方括号,也可以通过item()方法
例:
var firstChild = someNode.childNodes[0]; var secondChild = someNode.childNodes.item(1); var count = someNode.childNodes.length;
每个节点还都有parentNode,previousSibling,nextSibling属性,分别访问父节点,同一列表的前一个节点,同一列表的下一个节点,列表第一个节点previousSibling和最后一个节点的nextSibling为null,父节点的firstChild和lastChild属性分别指向childNodes列表中的第一个和最后一个节点
所有节点都有ownerDocument属性,指向整个文档节点,表示任何节点都属于它所在的文档,任何节点都不能同时存在两个或多个文档中,可以通过此属性直接访问文档节点
操作节点
appendChild(),向childNodes列表末尾添加新的节点,若传入到appendChild的节点已经存在文档中,则将该结点从原来位置转移到新位置,返回新节点
insertBefore方法在childNodes列表中某个位置插入节点,接收两个参数,要插入的节点,作为参照的节点,若参照节点传入null,则操作结果和appendChild结果一样,返回新节点
replaceChild方法接收两个参数,要插入的节点,要替换的节点,返回要替换的节点,并从文档树移除
removeChild方法,接收一个参数,要移除的节点,返回被移除的节点
注:以上四个方法要使用必须先得到父节点
所有类型节点都有的方法:
cloneNode,用于创建当前节点的完全相同的副本,接收一个布尔值参数,true执行深复制,false执行浅复制
注:cloneNode不会复制添加到DOM中的js属性,例如事件处理程序,只复制特性、(在明确指定情况下)子节点,其他都不会复制,IE却有bug,会复制事件处理程序,所以,建议复制前移除事件处理程序
normalize方法,唯一作用是处理文档树中的文本节点,合并文本节点
Document类型
js通过Document类型表示文档,浏览器中,document对象是HTMLDocument(继承自Document)的一个实例。特征:
nodeType:9
nodeName:#document
nodeValue:null
parentNode:null
ownerDocument:null
子节点可能是DocumentType(最多一个),Element(最多一个),ProcessingInstruction或Comment
可以使用documentElement属性(始终指向html中的<html>元素)和childNodes列表访问Document节点的子节点
作为HTMLDocument实例,document还有一个body属性,用于访问body元素
作为HTMLDocument实例,document对象还有一些标准Document对象所没有的属性:
title包含<title>信息,修改title属性会直接修改<title>元素
URL属性包含页面完整的URL
domain属性只包含页面域名
referrer属性保存着连接到当前页面的那个页面的URL
只有domain是可设置的,却不能设置成任何值。
查找元素
getElementById(),getElementByTatName()
getElementById接收一个参数,元素ID,必须与页面中的元素ID完全匹配,包括大小写,只返回文档中第一次出现的元素
getElementByTatName接收一个参数,标签名,返回包含零或多个元素的NodeList,在HTML文档中会返回一个HTMLCollection对象,可以使用item或方括号法访问对象中的项。HTMLCollection对象还有一个方法:namedItem,通过元素name属性取得集合中的项
当为getElementByTatName传入*号时,返回页面所有元素,IE会多加返回所有注释节点
注:在html中传给getElementByTatName的标签名不需区分大小写,在xml包括xhtml,则需要区分大小写
只有HTMLDocument类型才有的方法:getElementByName,返回带有给定name特性的所有元素
特殊集合:(都是HTMLCollection对象)
document.anchors,所有带有name特性的a标签
document.applets,所有<applets>元素,因为不推荐使用<applets>元素,所以,不推荐使用此集合
document.forms,包含所有<form>元素,与document.getElementByTagName(“form”)返回结果一样
document.images,所有<img>元素
document.links,所有带有href的a元素
DOM一致性检测
document.implementation属性为检测浏览器实现了DOM哪些部分提供相应信息和功能对象
DOM1级只规定了一个方法hasFeature,接收两个参数,要检测的DOM功能名称和版本号
注:在使用DOM某些特殊功能之前,最好除了检测hasFeature,还同时使用能力检测
文档写入
方法:write,writeln,open,close
write,writeln接收一个字符串参数,写入到输出流的文本
Element类型
Element节点具有特征:
nodeType:1
nodeName:元素标签名
nodeValue:null
parentNode:Document或Element
子节点可能是:Element,Text,Comment,ProcessingInstruction,CDATASection,EntityReference
访问元素标签名:nodeName,tagName属性会返回相同的值
html元素
所有html元素都由HTMLElement类型表示,不是直接通过这个类型,也是通过它的子类型来表示,HTMLElement继承自Element,并添加一些属性,添加的属性:
id,元素在文档中的唯一标识符
titile,有关元素的附加说明信息,一般通过工具提示条出来
lang,元素内容的语言代码,很少使用
dir,语言方向,ltr(left-to-right),rtl(right-to-left),很少使用
className,元素所使用的class特性
取得特性
getAttribute()、setAttribute()、removeAttribute(),可针对任何特性使用
getAttribute接收一个参数,要获取的属性名,较少使用getAttribute,而使用对象属性。只有在获取自定义特性时使用getAttribute
setAttribute接收两个参数,要设置的属性名以及值,已存在则覆盖现有值,不存在新建属性赋值
removeAttribute接收一个参数,要删除的属性名,不仅会清除特性的值,也会从元素中完全删除特性,不常用,IE6之前不支持
attribute属性
Element类型是唯一一个使用attribute属性的DOM节点类型,attribute包含一个NamedNodeMap,与NodeList类似,元素的每一个特性都有一个Attr节点表示,每个节点都保存在NamedNodeMap中,方法:
getNamedItem(name):返回nodeName属性等于name的节点
removeNamedItem(name):移除nodeName属性等于name的节点
setNamedItem(name):向列表添加新节点,以节点的nodeName属性为索引
item(pos):返回位于pos位置处的节点
每个节点的nodeName就是特性名称,nodeValue就是特性值
例:
var id = element.attributes.getNamedItem(“id”).nodeValue; var id = element.attributes[“id”].nodeValue;
也可以使用以上方法设置特性值
removeNamedItem与removeAttribute效果相同,唯一不同就是会返回被删除特性的Attr节点
创建元素:
document.createElement()接收一个参数,要创建的元素标签名,也可以将传入完整的元素标签,例:
var div = document.createElement(“<div id=\”myNewDiv\” class=\”box\”></div>”);
以上方法可避免IE7及更早版本中动态创建元素的某些问题
Text类型
可以包含转义后的HTML字符,但不能包含HTML代码,特征:
nodeType:3
nodeName:#text
nodeValue:节点所包含文本
parentNode:Element
nodeValue和data属性可以访问Text节点包含的文本
创建文本节点
document.createTextNode(),接收一个参数,要插入节点中的文本,参数文本会按照HTML或xml格式进行编码
规范化文本节点,对父元素调用normalize,会将所有文本节点合并成一个节点
分隔文本节点
Text类型提供了一个与normalize相反的方法splitText(),按照指定位置分割nodeValue值,原文本节点保留开始位置到指定位置之前的值,新文本节点包含剩下的文本,并返回
Comment类型
注释在DOM中通过Comment类型表示,特征:
nodeType:8
nodeName:#comment
nodeValue:注释的内容
parentNode:可能是Document或Element
不支持子节点
Comment与Text类型继承自相同的基类,为此包含除了splitText之外的所有字符串操作方法
使用document.createComment并为其传递注释文本也可以创建注释节点
CDATASection类型
只针对xml文档,表示的是CDATA区域,与Text继承同一个基类,拥有除splitText之外所有方法
DocumentType类型
DocumentType包含着文档的doctype有关的所有信息
在DOM1级中不能动态创建DocumentType对象
DocumentFragment类型
可以当仓库来使用,将所有要添加的节点放到其中,在全部创建完后统一添加到文档树中
例:
<ul id="myList"></ul>
var fragment = document.createDocumentFragment(); var ul = document.getElementById("myList"); var li = null; for(var i = 0;i < 3;i++){ li = document.createElement("li"); li.appendChild(document.createTextNode("Item"+(i+1))); fragment.appendChild(li); } ul.appendChild(fragment);
如果逐项添加,会导致浏览器反复渲染,以上方法使用DocumentFragment类型可以避免该问题
DOM操作技术
个人理解:实质就是DOM的操作,对于<script>,<link>,<style>,<table>元素的操作
动态脚本,动态创建js脚本文件(对于<script>元素的操作)
动态样式,动态创建css样式,创建的<link>元素必须添加到<head>中而不是<body>中(对于<link>,<style>元素的操作)
操作表格,繁琐(对于<table>元素的操作)
世界 -- 因技术而精彩