淺談JavaScript 瀏覽器對象,淺談javascript
window
window對象不但充當全域範圍,而且表示瀏覽器視窗。
window對象有innerWidth和innerHeight屬性,可以擷取瀏覽器視窗的內部寬度和高度。內部寬高是指除去功能表列、工具列、邊框等佔位元素後,用於顯示網頁的淨寬高。還有一個outerWidth和outerHeight屬性,可以擷取瀏覽器視窗的整個寬高。
補充:
網頁可見地區寬:document.body.clientWidth 網頁可見地區高:document.body.clientHeight 網頁可見地區寬:document.body.offsetWidth (包括邊線和捲軸的寬) 網頁可見地區高:document.body.offsetHeight (包括邊線的寬) 網頁本文全文寬:document.body.scrollWidth 網頁本文全文高:document.body.scrollHeight 網頁被捲去的高:document.body.scrollTop 或者 jQuery(document).scrollTop() 網頁被捲去的左:document.body.scrollLeft 網頁本文部分上:window.screenTop 網頁本文部分左:window.screenLeft 螢幕解析度的高:window.screen.height 螢幕解析度的寬:window.screen.width 螢幕可用工作區高度:window.screen.availHeight 螢幕可用工作區寬度:window.screen.availWidth 螢幕彩色位元: window.screen.colorDepth 螢幕像素/英寸比例: window.screen.deviceXDPI 瀏覽器視窗的高度: $(window).height() 瀏覽器視窗的寬度: $(window).width()
特殊1: document.body.scrollTop總為0的解決方案 var scrollPos; if (typeof window.pageYOffset != 'undefined') { scrollPos = window.pageYOffset; } else if (typeof document.compatMode != 'undefined' && document.compatMode != 'BackCompat') { scrollPos = document.documentElement.scrollTop; } else if (typeof document.body != 'undefined') { scrollPos = document.body.scrollTop; } alert(scrollPos ); 特殊2: 網頁本文全文寬:"+ document.body.scrollWidth; 網頁本文全文高:"+ document.body.scrollHeight; 以上函數有時擷取不了,就用以下方法。 var xScroll, yScroll; if (window.innerHeight && window.scrollMaxY) { xScroll = document.body.scrollWidth; yScroll = window.innerHeight + window.scrollMaxY; } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac xScroll = document.body.scrollWidth; yScroll = document.body.scrollHeight; } else { //Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari xScroll = document.body.offsetWidth; yScroll = document.body.offsetHeight; }
navigator
navigator對象表示瀏覽器的資訊,最常用的屬性包括:
•navigator.appName:瀏覽器名稱;
•navigator.appVersion:瀏覽器版本;
•navigator.language:瀏覽器設定的語言;
•navigator.platform:作業系統類型;
•navigator.userAgent:瀏覽器設定的User-Agent字串。
初學者為了針對不同瀏覽器編寫不同的代碼,喜歡用if判斷瀏覽器版本,例如:
var width;if (getIEVersion(navigator.userAgent) < 9) { width = document.body.clientWidth;} else { width = window.innerWidth;}
但這樣既可能判斷不準確,也很難維護代碼。正確的方法是充分利用JavaScript對不存在屬性返回undefined的特性,直接用短路運算子||計算:
var width = window.innerWidth || document.body.clientWidth;
screen
screen對象表示螢幕的資訊,常用的屬性有:
•screen.width:螢幕寬度,以像素為單位;
•screen.height:螢幕高度,以像素為單位;
•screen.colorDepth:返回顏色位元,如8、16、24。
location
location對象表示當前頁面的URL資訊。例如,一個完整的URL:
http://www.example.com:8080/path/index.html?a=1&b=2#TOP
可以用location.href擷取。要獲得URL各個部分的值,可以這麼寫:
location.protocol; // 'http'location.host; // 'www.example.com' location.port; // '8080'location.pathname; // '/path/index.html'location.search; // '?a=1&b=2'location.hash; // 'TOP'
要載入一個新頁面,可以調用location.assign()。如果要重新載入當前頁面,調用location.reload()方法非常方便。
document
document對象表示當前頁面。由於HTML在瀏覽器中以DOM形式表示為樹形結構,document對象就是整個DOM樹的根節點。
document的title屬性是從HTML文檔中的<title>xxx</title>讀取的,但是可以動態改變:
document對象還有一個cookie屬性,可以擷取當前頁面的Cookie。
Cookie是由伺服器發送的key-value標示符。因為HTTP協議是無狀態的,但是伺服器要區分到底是哪個使用者發過來的請求,就可以用Cookie來區分。當一個使用者成功登入後,伺服器發送一個Cookie給瀏覽器,例如user=ABC123XYZ(加密的字串)...,此後,瀏覽器訪問該網站時,會在要求標頭附上這個Cookie,伺服器根據Cookie即可區分出使用者。
Cookie還可以儲存網站的一些設定,例如,頁面顯示的語言等等。
JavaScript可以通過document.cookie讀取到當前頁面的Cookie:
document.cookie; // 'v=123; remember=true; prefer=zh'
由於JavaScript能讀取到頁面的Cookie,而使用者的登入資訊通常也存在Cookie中,這就造成了巨大的安全隱患,這是因為在HTML頁面中引入第三方的JavaScript代碼是允許的:
<!-- 當前頁面在wwwexample.com --><html> <head> <script src="http://www.foo.com/jquery.js"></script> </head></html>
如果引入的第三方的JavaScript中存在惡意代碼,則www.foo.com網站將直接擷取到www.example.com網站的使用者登入資訊。
為瞭解決這個問題,伺服器在設定Cookie時可以使用httpOnly,設定了httpOnly的Cookie將不能被JavaScript讀取。這個行為由瀏覽器實現,主流瀏覽器均支援httpOnly選項,為了確保安全,伺服器端在設定Cookie時,應該始終堅持使用httpOnly。
document.write() 僅僅向文檔輸出新內容
如果在文檔已完成載入後執行 document.write,整個 HTML 頁面將被覆蓋:
參考:http://www.w3school.com.cn/tiy/t.asp?f=js_write_over
DOM | Document
// 返回ID為'test'的節點:var test = document.getElementById('test');// 擷取節點test下的所有直屬子節點:var cs = test.children;var first = test.firstElementChild;
第二種方法是使用querySelector()和querySelectorAll(),需要瞭解selector文法,然後使用條件來擷取節點,更加方便:
// 通過querySelector擷取ID為q1的節點:var q1 = document.querySelector('#q1');// 通過querySelectorAll擷取q1節點內的合格所有節點:var ps = q1.querySelectorAll('div.highlighted > p');
嚴格地講,我們這裡的DOM節點是指Element,但是DOM節點實際上是Node,在HTML中,Node包括Element、Comment、CDATA_SECTION等很多種,以及根節點Document類型,但是,絕大多數時候我們只關心Element,也就是實際控制頁面結構的Node,其他類型的Node忽略即可。根節點Document已經自動綁定為全域變數document。
修改Dom
修改CSS也是經常需要的操作。DOM節點的style屬性對應所有的CSS,可以直接擷取或設定。因為CSS允許font-size這樣的名稱,但它並非JavaScript有效屬性名稱,所以需要在JavaScript中改寫為駝峰式命名fontSize:
// 擷取<p id="p-id">...</p>var p = document.getElementById('p-id');// 設定CSS:p.style.color = '#ff0000';p.style.fontSize = '20px';p.style.paddingTop = '2em';
插入DOM
有兩個辦法可以插入新的節點。一個是使用appendChild,把一個子節點添加到父節點的最後一個子節點。例如:
<!-- HTML結構 --><p id="js">JavaScript</p><div id="list"> <p id="scheme">Scheme</p></div>
把<p id="js">JavaScript</p>添加到<div id="list">的最後一項:
var js = document.getElementById('js'), list = document.getElementById('list');list.appendChild(js);
現在,HTML結構變成了這樣:
<!-- HTML結構 --><div id="list"> <p id="scheme">Scheme</p> <p id="js">JavaScript</p></div>
因為我們插入的js節點已經存在於當前的文檔樹,因此這個節點首先會從原先的位置刪除,再插入到新的位置。
更多的時候我們會從零建立一個新的節點,然後插入到指定位置:
haskell = document.createElement('p');
動態建立一個節點然後添加到DOM樹中,可以實現很多功能。舉個例子,下面的代碼動態建立了一個<style>節點,然後把它添加到<head>節點的末尾,這樣就動態地給文檔添加了新的CSS定義:
var d = document.createElement('style');d.setAttribute('type', 'text/css');d.innerHTML = 'p { color: red }';document.getElementsByTagName('head')[0].appendChild(d);
insertBefore
如果我們要把子節點插入到指定的位置怎麼辦?可以使用parentElement.insertBefore(newElement, referenceElement);,子節點會插入到referenceElement之前。
很多時候,需要迴圈一個父節點的所有子節點,可以通過迭代children屬性實現:
var i, c, list = document.getElementById('list');for (i = 0; i < list.children.length; i++) { c = list.children[i]; // 拿到第i個子節點}
刪除DOM
要刪除一個節點,首先要獲得該節點本身以及它的父節點,然後,調用父節點的removeChild把自己刪掉:
// 拿到待刪除節點:var self = document.getElementById('to-be-removed');// 拿到父節點:var parent = self.parentElement;// 刪除:var removed = parent.removeChild(self);removed === self; // true
注意到刪除後的節點雖然不在文檔樹中了,但其實它還在記憶體中,可以隨時再次被添加到別的位置。
當你遍曆一個父節點的子節點並進行刪除操作時,要注意,children屬性是一個唯讀屬性,並且它在子節點變化時會即時更新。因此,刪除多個節點時,要注意children屬性時刻都在變化。
動作表單
用JavaScript動作表單和操作DOM是類似的,因為表單本身也是DOM樹。
不過表單的輸入框、下拉框等可以接收使用者輸入,所以用JavaScript來動作表單,可以獲得使用者輸入的內容,或者對一個輸入框設定新的內容。
HTML表單的輸入控制項主要有以下幾種:
•文字框,對應的<input type="text">,用於輸入文本;
•口令框,對應的<input type="password">,用於輸入口令;
•單選框,對應的<input type="radio">,用於選擇一項;
•複選框,對應的<input type="checkbox">,用於選擇多項;
•下拉框,對應的<select>,用於選擇一項;
•隱藏文本,對應的<input type="hidden">,使用者不可見,但表單提交時會把隱藏文本發送到伺服器。
擷取值
如果我們獲得了一個<input>節點的引用,就可以直接調用value獲得對應的使用者輸入值:
// <input type="text" id="email">var input = document.getElementById('email');input.value; // '使用者輸入的值'
這種方式可以應用於text、password、hidden以及select。但是,對於單選框和複選框,value屬性返回的永遠是HTML預設的值,而我們需要獲得的實際是使用者是否“勾上了”選項,所以應該用checked判斷:
// <label><input type="radio" name="weekday" id="monday" value="1"> Monday</label>// <label><input type="radio" name="weekday" id="tuesday" value="2"> Tuesday</label>var mon = document.getElementById('monday');var tue = document.getElementById('tuesday');mon.value; // '1'tue.value; // '2'mon.checked; // true或者falsetue.checked; // true或者false
設定值
設定值和擷取值類似,對於text、password、hidden以及select,直接設定value就可以:
// <input type="text" id="email">var input = document.getElementById('email');input.value = 'test@example.com'; // 文字框的內容已更新
對於單選框和複選框,設定checked為true或false即可。
HTML5控制項
HTML5新增了大量標準控制項,常用的包括date、datetime、datetime-local、color等,它們都使用<input>標籤:
<input type="date" value="2015-07-01">
<input type="datetime-local" value="2015-07-01T02:03:04">
<input type="color" value="#ff0000">
不支援HTML5的瀏覽器無法識別新的控制項,會把它們當做type="text"來顯示。支援HTML5的瀏覽器將獲得格式化的字串。例如,type="date"類型的input的value將保證是一個有效YYYY-MM-DD格式的日期,或者Null 字元串。
提交表單
最後,JavaScript可以以兩種方式來處理表單的提交(AJAX方式在後面章節介紹)。
方式一是通過<form>元素的submit()方法提交一個表單,例如,響應一個<button>的click事件,在JavaScript代碼中提交表單:
<form id="test-form"> <input type="text" name="test"> <button type="button" onclick="doSubmitForm()">Submit</button></form><script>function doSubmitForm() { var form = document.getElementById('test-form'); // 可以在此修改form的input... // 提交form: form.submit();}</script>
這種方式的缺點是擾亂了瀏覽器對form的正常提交。瀏覽器預設點擊<button type="submit">時提交表單,或者使用者在最後一個輸入框按斷行符號鍵。因此,第二種方式是響應<form>本身的onsubmit事件,在提交form時作修改:
<form id="test-form" onsubmit="return checkForm()"> <input type="text" name="test"> <button type="submit">Submit</button></form><script>function checkForm() { var form = document.getElementById('test-form'); // 可以在此修改form的input... // 繼續下一步: return true;}</script>
注意要return true來告訴瀏覽器繼續提交,如果return false,瀏覽器將不會繼續提交form,這種情況通常對應使用者輸入有誤,提示使用者錯誤資訊後終止提交form。
在檢查和修改<input>時,要充分利用<input type="hidden">來傳遞資料。
例如,很多登入表單希望使用者輸入使用者名稱和口令,但是,安全考慮,提交表單時不傳輸明文口令,而是口令的MD5。普通JavaScript開發人員會直接修改<input>:
<form id="login-form" method="post" onsubmit="return checkForm()"> <input type="text" id="username" name="username"> <input type="password" id="password" name="password"> <button type="submit">Submit</button></form><script>function checkForm() { var pwd = document.getElementById('password'); // 把使用者輸入的明文變為MD5: pwd.value = toMD5(pwd.value); // 繼續下一步: return true;}</script>
這個做法看上去沒啥問題,但使用者輸入了口令提交時,口令框的顯示會突然從幾個*變成32個*(因為MD5有32個字元)。
要想不改變使用者的輸入,可以利用<input type="hidden">實現:
<form id="login-form" method="post" onsubmit="return checkForm()"> <input type="text" id="username" name="username"> <input type="password" id="input-password"> <input type="hidden" id="md5-password" name="password"> <button type="submit">Submit</button></form><script>function checkForm() { var input_pwd = document.getElementById('input-password'); var md5_pwd = document.getElementById('md5-password'); // 把使用者輸入的明文變為MD5: md5_pwd.value = toMD5(input_pwd.value); // 繼續下一步: return true;}</script>
注意到id為md5-password的<input>標記了name="password",而使用者輸入的id為input-password的<input>沒有name屬性。沒有name屬性的<input>的資料不會被提交。
操作檔案
在HTML表單中,可以上傳檔案的唯一控制項就是<input type="file">。
注意:當一個表單包含<input type="file">時,表單的enctype必須指定為multipart/form-data,method必須指定為post,瀏覽器才能正確編碼並以multipart/form-data格式發送表單的資料。
出於安全考慮,瀏覽器只允許使用者點擊<input type="file">來選擇本地檔案,用JavaScript對<input type="file">的value賦值是沒有任何效果的。當使用者選擇了上傳某個檔案後,JavaScript也無法獲得該檔案的真實路徑:
待上傳檔案:
通常,上傳的檔案都由後台伺服器處理,JavaScript可以在提交表單時對副檔名做檢查,以便防止使用者上傳無效格式的檔案:
var f = document.getElementById('test-file-upload');var filename = f.value; // 'C:\fakepath\test.png'if (!filename || !(filename.endsWith('.jpg') || filename.endsWith('.png') || filename.endsWith('.gif'))) { alert('Can only upload image file.'); return false;}
File API
由於JavaScript對使用者上傳的檔案操作非常有限,尤其是無法讀取檔案內容,使得很多需要操作檔案的網頁不得不用Flash這樣的第三方外掛程式來實現。
隨著HTML5的普及,新增的File API允許JavaScript讀取檔案內容,獲得更多的檔案資訊。
HTML5的File API提供了File和FileReader兩個主要對象,可以獲得檔案資訊並讀取檔案。
下面的例子示範了如何讀取使用者選取的圖片檔案,並在一個<div>中預覽映像:
圖片預覽:
var fileInput = document.getElementById('test-image-file'), info = document.getElementById('test-file-info'), preview = document.getElementById('test-image-preview'); // 監聽change事件: fileInput.addEventListener('change', function () { // 清除背景圖片: preview.style.backgroundImage = ''; // 檢查檔案是否選擇: if (!fileInput.value) { info.innerHTML = '沒有選擇檔案'; return; } // 擷取File引用: var file = fileInput.files[0]; // 擷取File資訊: info.innerHTML = '檔案: ' + file.name + '<br>' + '大小: ' + file.size + '<br>' + '修改: ' + file.lastModifiedDate; if (file.type !== 'image/jpeg' && file.type !== 'image/png' && file.type !== 'image/gif') { alert('不是有效圖片檔案!'); return; } // 讀取檔案: var reader = new FileReader(); reader.onload = function(e) { var data = e.target.result; // 'data:image/jpeg;base64,/9j/4AAQSk...(base64編碼)...' preview.style.backgroundImage = 'url(' + data + ')'; }; // 以DataURL的形式讀取檔案: reader.readAsDataURL(file);});
上面的代碼示範了如何通過HTML5的File API讀取檔案內容。以DataURL的形式讀取到的檔案是一個字串,類似於data:image/jpeg;base64,/9j/4AAQSk...(base64編碼)...,常用於設定映像。如果需要伺服器端處理,把字串base64後的字元發送給伺服器並用Base64解碼就可以得到原始檔案的二進位內容。
回調
上面的代碼還示範了JavaScript的一個重要的特性就是單線程執行模式。在JavaScript中,瀏覽器的JavaScript執行引擎在執行JavaScript代碼時,總是以單線程模式執行,也就是說,任何時候,JavaScript代碼都不可能同時有多於1個線程在執行。
你可能會問,單線程模式執行的JavaScript,如何處理多任務?
在JavaScript中,執行多任務實際上都是非同步呼叫,比如上面的代碼:
reader.readAsDataURL(file);
就會發起一個非同步作業來讀取檔案內容。因為是非同步作業,所以我們在JavaScript代碼中就不知道什麼時候操作結束,因此需要先設定一個回呼函數:
reader.onload = function(e) { // 當檔案讀取完成後,自動調用此函數:};
當檔案讀取完成後,JavaScript引擎將自動調用我們設定的回呼函數。執行回呼函數時,檔案已經讀取完畢,所以我們可以在回呼函數內部安全地獲得檔案內容。
以上這篇淺談JavaScript 瀏覽器對象就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援幫客之家。