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 }();
View Code

 

使用方法

使用情形:

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>元素的操作)


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com