面我們已經介紹了事件的概念,而響應某個事件的函數就叫做事件處理程序。事件處理程序的名字以 "on" 開頭,因此 click 事件的處理程序就是 onclick ,load 事件的處理程序就是 onload。
某個元素支持的每種事件,都可以使用一個相應事件處理程序同名的 HTML 特性來指定。這個特性的值應該是能夠執行的 JavaScript 代碼。例如,要在按鈕被單擊時執行一些操作,可以像下面代碼一樣:
<input type="button" value="點擊我" onclick="alert('我被點擊了。。')" />
注意,上面這種寫法不能在其中使用未經轉義的 HTML 語法字符,如果要使用 HTML 語法字符,就需要使用轉義字符了。
在 HTML 中定義的事件處理程序可以包含要執行的具體動作,也可以調用在頁面其他地方定義的腳本,例:
HTML 事件處理程序--調用頁面腳本
上面代碼指定事件處理程序具有一些獨到之處。首先,會創建一個封裝著元素屬性值的函數。這個函數中有一個局部變量 event,通過這個 event 變量,可以直接訪問事件對象,你不用自己定義它,也不用從函數的參數列表中讀取。在這個函數內部,this 值等于事件的目標元素。
不過,在 HTML 中指定事件處理程序有兩個缺點。首先,存在一個時差問題,用戶可能在 HTML 元素一出現在頁面上就觸發了相應的事件,但當時的事件處理程序有可能尚不具備執行條件。前面的例子中,假如 showMessage() 函數是在按鈕下方、頁面的最底部定義的。如果用戶在頁面解析 showMessage() 函數之前就單擊了按鈕,就會出現錯誤。因此,很多 HTML 事件處理程序都會被封裝在一個 try-catch 塊中。其次,這樣擴展事件處理程序的作用域鏈在不同瀏覽器中會導致不同結果。不同 JavaScript 引擎遵循的標識符解析規則存在差異,很可能會在訪問非限定對象成員時出錯。
者 | 單雨
責編 | 屠敏
出品 | CSDN(ID:CSDNnews)
模板繼承
簡介
模板繼承允許你建立一個基本的"骨架"模板, 它包含了網站中所有常見的元素,并定義了可以被子模板覆蓋的 塊(blocks) 。示例:
假如父模板base.html如下:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<title>{% block title %}My amazing site{% endblock %}</title>
</head>
<body>
<div id="sidebar">
{% block sidebar %}
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog/">Blog</a></li>
</ul>
{% endblock %}
</div>
<div id="content">
{% block content %}{% endblock %}
</div>
</body>
</html>
它定義了一個簡單的 HTML 骨架文檔, 假設這是一個簡單的兩列頁面。子模板的工作就是填充空的 塊(block) 中的內容。
在這個例子中, block 標簽定義了三個可以被子模板填充的塊。block標簽告訴了模板系統哪些地方可能被子模板覆蓋。例如,子模板可能如下:
{% extends "base.html" %}
{% block title %}My amazing blog{% endblock %}
{% block content %}
{% for entry in blog_entries %}
<h2>{{ entry.title }}</h2>
<p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}
extends 標簽告訴模板系統這個模板繼承了另外的模板。當模板系統對此模板進行運算時, 首先會尋找他的父模板 ——在這里是"base.html"。
在這一點上, 模板引擎會在 base.html 中發現三個 block 標簽, 并且使用子模板的內容替換掉這些塊。根據變量blog_entries 的值, 輸出可能看起來像這樣:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css">
<title>My amazing blog</title>
</head>
<body>
<div id="sidebar">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/blog/">Blog</a></li>
</ul>
</div>
<div id="content">
<h2>Entry one</h2>
<p>This is my first entry.</p>
<h2>Entry two</h2>
<p>This is my second entry.</p>
</div>
</body>
</html>
注意:因為子模板沒有定義 sidebar 塊, 那么父模板的內容就會被使用。通常來說, 父模板 {% block %} 中的內容會被作為備用的內容,在子模板沒有覆蓋時就會被使用。
多重繼承
模板繼承可以是多重繼承,多重繼承常見的模式是:
創建一個 base.html 模板把控網站的整體風格。
為網站的每個子分類創建一個 baseSECTIONNAME.html模板. 比如, basenews.html, base_sports.html。 這些模板都繼承 base.html 模板。這些模板中包含特定的設計/風格。
為每一種類型的頁面創建一個模板, 比如 news article 或blog 內容。這些模板擴展上一級模板的相應分類。
上述的關系可以用下圖表示:
這樣就能最大限度的重用模板代碼,比如在所有頁面通用的導航欄。
模板繼承注意事項
{% extends %}必須位于模板的最開始, 如果在其他的部分聲明, 則不生效。
在基礎模板盡可能多的使用{%block%} ,子模板不需要定義所有父模板中的塊, 所以你可以在若干的塊中填充默認值, 然后定義之后需要自定義的塊, 有更多的可用塊總是更好的。
如果發現自己在許多模板中有重復內容的了, 這可能需要移動這些內容到父模板的 {% block %} 中。
如果需要得到父模板塊中的內容, 可以用{{ block.super }} 變量。使用 {{ block.super }} 插入的數據不會被自動轉義 ,因為它已經被轉義了。如果需要轉義, 可以在父模板中轉義。
使用模板標簽在{% block %}塊外部創建的變量不能在塊內使用。例如,這個模板不渲染任何東西:
{% trans "Title" as title %}
{% block content %}{{ title }}{% endblock %}
為了具有更好的可讀性,也可以給{% endblock %}塊標簽定義一個名字。例如:
{% block content %}
...
{% endblock content %}
在一個較長的模板中, 這個方法可以讓你知道是哪一個{% block %} 標簽定義結束了。
不能在同一模板中定義多個具有相同名稱的塊標簽。存在這個限制是因為{%block%}標簽是"雙向"定義的。也就是說, 它不僅指定了子模板要填充父模板的哪個塊, 也說明了父模板要引用哪些子模板塊的內容。所以在子模板中有多個同名的{%block%}標簽時, 父模板就不知道到底要引用子模板中哪個塊的內容了。
自動HTML轉義
從模板直接生成HTML存在XSS風險
從模板生成HTML時, 總是有一種風險, 即一個變量將會影響生成的HTML字符。考慮這個模板片段:
Hello, {{ name }}
看起來可能沒有什么風險,但是如果用戶輸入的名字為一個HTML代碼:
<script>alert('hello')</script>
當{{name}}為這個值時,模板將呈現為:
Hello, <script>alert('hello')</script>
這將使瀏覽器彈出一個彈出一個JavaScript警告。同樣的,考慮另外一種情況:
如果名字中包含一個 '<' 符號:
<b>username
對應的模板將為:
Hello, <b>username
這意味著在此之后的文字將呈現為粗體。
由此帶來一個風險:
用戶提交的數據是不可靠的且不應被直接插入到您的網頁, 因為惡意用戶可以使用這種潛在的漏洞做危害網站的事情。這種類型的安全漏洞被稱為 Cross Site Scripting (跨站腳本) (XSS) 攻擊。
使用轉義避免XSS風險
(1)使用escape標簽
確保讓不受信任的變量經過了 escape 過濾器 , 將危險的HTML字符替換為無害的HTML轉義字符。但是這常常被忽略。
(2)使用自動轉義
在Django中, 默認每個模板會自動轉義輸出的每一個變量標簽。具體來說, 這五個字符會被轉義:
< 被替換為 <
> 被替換為 >
' (單引號) 被替換為 '
" (雙引號) 被替換為 "
& 被替換為 &
這種行為是默認的。如果使用的是Django的模板系統, 自然擁有這種保護。
關閉自動轉義
可以在站點,模板和變量三個層級關閉自動轉義。
(1)對單個變量
要為一個單獨的變量禁用自動轉義, 使用 safe 過濾器(https://docs.djangoproject.com/zh-hans/2.2/ref/templates/builtins/#std:templatefilter-safe):
This will be escaped: {{ data }}
This will not be escaped: {{ data|safe }}
如果變量中包含“\”字符,輸出也是“\”。
(2)對于模板文本塊
要在模板中控制自動轉義, 可以在整個模板 (或者模板的特定區域) 使用 autoescape 標簽, 如:
{% autoescape off %}
Hello {{ name }}
{% endautoescape %}}}
autoescape 標簽接受 on 或 off 作為參數。如果需要在某個區域禁用自動轉義,可以這樣使用:
{% autoescape off %}
This will not be auto-escaped: {{ data }}.
Nor this: {{ other_data }}
{% autoescape on %}
Auto-escaping applies again: {{ name }}
{% endautoescape %}
{% endautoescape %}
(3)自動轉義的繼承特性
如果使用自動轉義的模板文本塊中使用{%block%}包含了子模板,那么子模板中也將使用自動轉義,如果基模板中關閉了自動轉義,那么子模板中也將關閉自動轉義:
base.html:
{% autoescape off %}
<h1>{% block title %}{% endblock %}</h1>
{% block content %}
{% endblock %}
{% endautoescape %}
child.html:
{% extends "base.html" %}
{% block title %}This & that{% endblock %}
{% block content %}{{ greeting }}{% endblock %}
因為基模板中關閉了自動轉義,子模板中也將關閉自動轉義,所以在HTML渲染時,greeting 變量被輸出為 <b>Hello!</b>:
<h1>This & that</h1>
<b>Hello!</b>
(4)注意事項
模板的開發者并不需要對自動轉義太過關注. 這是編寫Python的開發者 (寫視圖和寫自定義模板標簽的人) 需要考慮的事. 所以, 你只需要做和模板有關的活。如果你不確定模板在何時會進行自動轉義(或不進行), 那么就向所有需要轉義的變量添加 escape 過濾器. 當自動轉義被打開, escape 過濾器不會再次轉義 -- escape 過濾器不會影響自動轉義的變量。
(5)字符串和自動轉義
過濾器的參數可以是字符串,例如:
{{ data|default:"This is a string literal." }}
作為過濾器參數的字符串都不會自動轉義, django認為它們已經經過safe 過濾。這么做的原因是模板的開發者可以控制字符的輸出, 所以他們應該確保正確的使用轉義后的HTML字面值。
這意味著你應該這么寫:
{{ data|default:"3 < 2" }}
而不是:
{{ data|default:"3 < 2" }}
模板中的對象方法調用
大多數附加到對象上的方法都可以在模板中調用,這使得模板可以從視圖中傳遞過來的上下文變量中獲取對象屬性之外的值。
例如, Django ORM 提供了 "entry_set" 語法尋找一個與外鍵所關聯的對象的集合。因此, 如果有一個叫 "comment" 的模型有外鍵指向了模型 "task",你可以通過給定一個實際的 task模板變量, 像這樣循環輸出與它相關聯所有的 comment對象:
{% for comment in task.comment_set.all %}
{{ comment }}
{% endfor %}
如果你在一個模型中顯示定義了一個方法,你也可以在對應的模板變量中引用它:
模型
class Task(models.Model):
def foo(self):
return"bar"
模板調用
{{ task.foo }}
注意:由于Django有意限制了模板中語言邏輯的處理,所以不能在模板內調用對象方法時向其傳遞參數。數據應當在視圖中計算完成后,再傳遞給模板。
作者簡介:單雨,90后工科男,偽文藝青年。目前就讀于北京理工大學宇航系,喜歡研究AI,網絡爬蟲,微信小程序以及機器人,癡迷于Coding,睡前必擼碼。
【END】
習目標:了解JavaScript是如何與HTML結合來創建動態網頁,網頁中嵌入JavaScript的不同方式,JavaScript的內容類型及其與<script>的關系
<script>是由Netscape創造出來,后來加到HTML規范中的。
<script>有8個屬性:
1、async:表示立即開始下載腳本,但不能阻止其他頁面動作,比如下載資源或者等待其他腳本加載。只對外部腳本文件有效。
2、charset:使用src屬性指定代碼字符集。這個屬性很少用,因為大多數瀏覽器不在乎它的值。
3、crossorigin;配置資源請求的CORS(跨源資源共享)設置。默認情況下不使用CORS。crossorigin = “anonymous”配置文件請求不用設置憑據標志。crossorigin = ”use-credentials“設置憑據標志,意味著出站請求會包含憑據。
4、defer:表示腳本可以延遲到文檔全部解析和顯示后再執行。新版本中只能用于外部腳本。
5、integrity:允許比對接收到的資源和指定的加密簽名以驗證子資源完整性(SRI,Subresource integrity),如果驗證簽名不匹配則腳本不會執行。這個屬性可以用于確保內容分發網絡(CDN,Content Delivery Network)不會提供惡意內容。
6、language:此屬性已被廢止。
7、src:表示包含外部要執行的代碼的外部文件。
8、type:代替language,表示代碼塊中腳本語言的內容類型(也稱為MIME類型),按照慣例這個值始終都是”text/JavaScript“,盡管”text/JavaScript“和”text/ecmascript“都已經廢棄。JavaScript文件的MIME類型通常是”application/x-javascript“,不過給type屬性這個值的話可能會導致腳本被忽略。在非IE的瀏覽器中有效的值還有”application/JavaScript“和”application/ecmascript"。如果這個值是module,則代碼會被當成是ES6模塊,而且只有這時候代碼中才能出現import和export關鍵字。
使用<script>的方式有內聯和外嵌兩種,只要把code寫入<script>code</script>中就好,code中要是包含字符串“<script>”,只要加上轉義字符“\”即可。
如果要外嵌JavaScript代碼只要使用src屬性來鏈接外部文件即可如:
<script src=“example.js”></script>
XHTML 文檔中,可以忽略結束標簽寫成<script src=“example.js”/>即可,但是這在HTML中不能使用。
過去把JavaScript和CSS一起寫在head中,但是這意味著必須下載所有code并解析和解釋完成后才開始渲染頁面,對于JavaScript很多的頁面會導致頁面渲染速度過慢,為解決這個問題,JavaScript一般寫在body元素的頁面內容的最后邊,如下
<html>
<head></head>
<body>
message
<script>code<\script>
<\body>
</html>
在外聯JavaScript時可以使用defer屬性來推遲腳本的運行。可以寫成:
<html>
<head>
<script defer src = "example.js">code<\script>
</head>
<body>
message
<\body>
</html>
async屬性從腳本處理方式上與defer類似,但是不同的是標記async的腳本并不能保證腳本按照他們的出現順序執行,比如:
<html>
<head>
<script sync src = "example1.js">code<\script>
<script sync src = "example2.js">code<\script>
</head>
<body>
message
<\body>
</html>
不能保證example1比example2先執行。
除了<script>以外還可以用其他方式加載腳本。因為JavaScript可以使用DOM API,所以通過向DOM中動態地加入script元素同樣可以加載指定腳本。只要創建一個script元素并將其添加到DOM即可。
let script = document.createElement('script');
script.src = 'gibberish.js';
document.head.appendChild(script);
當然,在把 HTMLElement 元素添加到 DOM 且執行到這段代碼之前不會發送請求。默認情況下,以這種方式創建的<script>元素是以異步方式加載的,相當于添加了 async 屬性。不過這樣做可能會有問題,因為所有瀏覽器都支持 createElement()方法,但不是所有瀏覽器都支持 async 屬性。因此,如果要統一動態腳本的加載行為,可以明確將其設置為同步加載:
let script = document.createElement('script');
script.src = 'gibberish.js';
script.async = false;
document.head.appendChild(script);
以這種方式獲取的資源對瀏覽器預加載器是不可見的。這會嚴重影響它們在資源獲取隊列中的優先級。根據應用程序的工作方式以及怎么使用,這種方式可能會嚴重影響性能。要想讓預加載器知道這些動態請求文件的存在,可以在文檔頭部顯式聲明它們:
<link rel="preload" href="gibberish.js">
可擴展超文本標記語言(XHTML,Extensible HyperText Markup Language)是將 HTML 作為 XML的應用重新包裝的結果。與 HTML 不同,在 XHTML 中使用 JavaScript 必須指定 type 屬性且值為text/javascript,HTML 中則可以沒有這個屬性。XHTML 雖然已經退出歷史舞臺,但實踐中偶爾可能也會遇到遺留代碼,為此本節稍作介紹。在 XHTML 中編寫代碼的規則比 HTML 中嚴格,這會影響使用<script>元素嵌入 JavaScript 代碼。下面的代碼塊雖然在 HTML 中有效,但在 XHML 中是無效的。
<script type="text/javascript">
function compare(a, b) {
if (a < b) {
console.log("A is less than B");
} else if (a > b) {
console.log("A is greater than B");
} else {
console.log("A is equal to B");
}
}
</script>
在 HTML 中,解析<script>元素會應用特殊規則。XHTML 中則沒有這些規則。這意味著 a < b語句中的小于號(<)會被解釋成一個標簽的開始,并且由于作為標簽開始的小于號后面不能有空格,這會導致語法錯誤。避免 XHTML 中這種語法錯誤的方法有兩種。第一種是把所有小于號(<)都替換成對應的 HTML實體形式(<)。結果代碼就是這樣的:
<script type="text/javascript">
function compare(a, b) {
if (a < b) {
console.log("A is less than B");
} else if (a > b) {
console.log("A is greater than B");
} else {
console.log("A is equal to B");
}
}
</script>
這樣代碼就可以在 XHTML 頁面中運行了。不過,缺點是會影響閱讀。好在還有另一種方法。第二種方法是把所有代碼都包含到一個 CDATA 塊中。在 XHTML(及 XML)中,CDATA 塊表示文檔中可以包含任意文本的區塊,其內容不作為標簽來解析,因此可以在其中包含任意字符,包括小于號,并且不會引發語法錯誤。使用 CDATA 的格式如下:
<script type="text/javascript"><![CDATA[
function compare(a, b) {
if (a < b) {
console.log("A is less than B");
} else if (a > b) {
console.log("A is greater than B");
} else {
console.log("A is equal to B");
}
}
]]></script>
在兼容 XHTML 的瀏覽器中,這樣能解決問題。但在不支持 CDATA 塊的非 XHTML 兼容瀏覽器中則不行。為此,CDATA 標記必須使用 JavaScript 注釋來抵消:
<script type="text/javascript">
//<![CDATA[
function compare(a, b) {
if (a < b) {
console.log("A is less than B");
} else if (a > b) {
console.log("A is greater than B");
} else {
console.log("A is equal to B");
}
}
//]]>
</script>
這種格式適用于所有現代瀏覽器。雖然有點黑科技的味道,但它可以通過 XHTML 驗證,而且對XHTML 之前的瀏覽器也能優雅地降級。
自 1995 年 Netscape 2 發布以來,所有瀏覽器都將 JavaScript 作為默認的編程語言。type 屬性使用一個 MIME 類型字符串來標識<script>的內容,但 MIME 類型并沒有跨瀏覽器標準化。即使瀏覽器默認使用 JavaScript,在某些情況下某個無效或無法識別的 MIME 類型也可能導致瀏覽器跳過(不執行)相關代碼。因此,除非你使用 XHTML 或<script>標簽要求或包含非 JavaScript 代碼,最佳做法是不指定 type 屬性。在最初采用 script 元素時,它標志著開始走向與傳統 HTML 解析不同的流程。對這個元素需要應用特殊的解析規則,而這在不支持 JavaScript 的瀏覽器(特別是 Mosaic)中會導致問題。不支持的瀏覽器會把<script>元素的內容輸出到頁面上,從而破壞頁面的外觀。Netscape 聯合 Mosaic 拿出了一個解決方案,對不支持 JavaScript 的瀏覽器隱藏嵌入的 JavaScript 代碼。最終方案是把腳本代碼包含在一個 HTML 注釋中,像這樣:
<script><!--
function sayHi(){
console.log("Hi!");
}
//--></script>
使用這種格式,Mosaic 等瀏覽器就可以忽略<script>標簽中的內容,而支持 JavaScript 的瀏覽器則必須識別這種模式,將其中的內容作為 JavaScript 來解析。雖然這種格式仍然可以被所有瀏覽器識別和解析,但已經不再必要,而且不應該再使用了。在XHTML 模式下,這種格式也會導致腳本被忽略,因為代碼處于有效的 XML 注釋當中。
雖然可以直接在 HTML 文件中嵌入 JavaScript 代碼,但通常認為最佳實踐是盡可能將 JavaScript 代碼放在外部文件中。不過這個最佳實踐并不是明確的強制性規則。推薦使用外部文件的理由如下。
? 可維護性。JavaScript 代碼如果分散到很多 HTML 頁面,會導致維護困難。而用一個目錄保存所有 JavaScript 文件,則更容易維護,這樣開發者就可以獨立于使用它們的 HTML 頁面來編輯代碼。
? 緩存。瀏覽器會根據特定的設置緩存所有外部鏈接的 JavaScript 文件,這意味著如果兩個頁面都用到同一個文件,則該文件只需下載一次。這最終意味著頁面加載更快。
? 適應未來。通過把 JavaScript 放到外部文件中,就不必考慮用 XHTML 或前面提到的注釋黑科技。包含外部 JavaScript 文件的語法在 HTML 和 XHTML 中是一樣的。在配置瀏覽器請求外部文件時,要重點考慮的一點是它們會占用多少帶寬。在 SPDY/HTTP2 中,預請求的消耗已顯著降低,以輕量、獨立 JavaScript 組件形式向客戶端送達腳本更具優勢。比如,第一個頁面包含如下腳本:
<script src="mainA.js"></script>
<script src="component1.js"></script>
<script src="component2.js"></script>
<script src="component3.js"></script>
...
后續頁面可能包含如下腳本:
<script src="mainB.js"></script>
<script src="component3.js"></script>
<script src="component4.js"></script>
<script src="component5.js"></script>
...
在初次請求時,如果瀏覽器支持 SPDY/HTTP2,就可以從同一個地方取得一批文件,并將它們逐個放到瀏覽器緩存中。從瀏覽器角度看,通過 SPDY/HTTP2 獲取所有這些獨立的資源與獲取一個大JavaScript 文件的延遲差不多。在第二個頁面請求時,由于你已經把應用程序切割成了輕量可緩存的文件,第二個頁面也依賴的某些組件此時已經存在于瀏覽器緩存中了。當然,這里假設瀏覽器支持 SPDY/HTTP2,只有比較新的瀏覽器才滿足。如果你還想支持那些比較老的瀏覽器,可能還是用一個大文件更合適。
IE5.5 發明了文檔模式的概念,即可以使用 doctype 切換文檔模式。最初的文檔模式有兩種:混雜模式(quirks mode)和標準模式(standards mode)。前者讓 IE 像 IE5 一樣(支持一些非標準的特性),后者讓 IE 具有兼容標準的行為。雖然這兩種模式的主要區別只體現在通過 CSS 渲染的內容方面,但對JavaScript 也有一些關聯影響,或稱為副作用。本書會經常提到這些副作用。
IE 初次支持文檔模式切換以后,其他瀏覽器也跟著實現了。隨著瀏覽器的普遍實現,又出現了第三種文檔模式:準標準模式(almost standards mode)。這種模式下的瀏覽器支持很多標準的特性,但是沒有標準規定得那么嚴格。主要區別在于如何對待圖片元素周圍的空白(在表格中使用圖片時最明顯)。
混雜模式在所有瀏覽器中都以省略文檔開頭的 doctype 聲明作為開關。這種約定并不合理,因為混雜模式在不同瀏覽器中的差異非常大,不使用黑科技基本上就沒有瀏覽器一致性可言。標準模式通過下列幾種文檔類型聲明開啟:
<!-- HTML 4.01 Strict -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<!-- XHTML 1.0 Strict -->
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!-- HTML5 -->
<!DOCTYPE html>
準標準模式通過過渡性文檔類型(Transitional)和框架集文檔類型(Frameset)來觸發:
<!-- HTML 4.01 Transitional -->
<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<!-- HTML 4.01 Frameset -->
<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Frameset//EN"
"http://www.w3.org/TR/html4/frameset.dtd">
<!-- XHTML 1.0 Transitional -->
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- XHTML 1.0 Frameset -->
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Frameset//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
準標準模式與標準模式非常接近,很少需要區分。人們在說到“標準模式”時,可能指其中任何一個。而對文檔模式的檢測(本書后面會討論)也不會區分它們。本書后面所說的標準模式,指的就是除混雜模式以外的模式。
針對早期瀏覽器不支持 JavaScript 的問題,需要一個頁面優雅降級的處理方案。最終,<noscript>元素出現,被用于給不支持 JavaScript 的瀏覽器提供替代內容。雖然如今的瀏覽器已經 100%支持JavaScript,但對于禁用 JavaScript 的瀏覽器來說,這個元素仍然有它的用處。<noscript>元素可以包含任何可以出現在<body>中的 HTML 元素,<script>除外。在下列兩種情況下,瀏覽器將顯示包含在<noscript>中的內容:
? 瀏覽器不支持腳本;
? 瀏覽器對腳本的支持被關閉。任何一個條件被滿足,包含在<noscript>中的內容就會被渲染。否則,瀏覽器不會渲染<noscript>中的內容。
下面是一個例子:
<!DOCTYPE html>
<html>
<head>
<title>Example HTML Page</title>
<script defer="defer" src="example1.js"></script>
<script defer="defer" src="example2.js"></script>
</head>
<body>
<noscript>
<p>This page requires a JavaScript-enabled browser.</p>
</noscript>
</body>
</html>
這個例子是在腳本不可用時讓瀏覽器顯示一段話。如果瀏覽器支持腳本,則用戶永遠不會看到它。
JavaScript 是通過<script>元素插入到 HTML 頁面中的。這個元素可用于把 JavaScript 代碼嵌入到HTML 頁面中,跟其他標記混合在一起,也可用于引入保存在外部文件中的 JavaScript。本章的重點可以總結如下。
? 要包含外部 JavaScript 文件,必須將 src 屬性設置為要包含文件的 URL。文件可以跟網頁在同一臺服務器上,也可以位于完全不同的域。
? 所有<script>元素會依照它們在網頁中出現的次序被解釋。在不使用 defer 和 async 屬性的情況下,包含在<script>元素中的代碼必須嚴格按次序解釋。
? 對不推遲執行的腳本,瀏覽器必須解釋完位于<script>元素中的代碼,然后才能繼續渲染頁面的剩余部分。為此,通常應該把<script>元素放到頁面末尾,介于主內容之后及</body>標簽之前。
? 可以使用 defer 屬性把腳本推遲到文檔渲染完畢后再執行。推遲的腳本原則上按照它們被列出的次序執行。
? 可以使用 async 屬性表示腳本不需要等待其他腳本,同時也不阻塞文檔渲染,即異步加載。異步腳本不能保證按照它們在頁面中出現的次序執行。
? 通過使用<noscript>元素,可以指定在瀏覽器不支持腳本時顯示的內容。如果瀏覽器支持并啟用腳本,則<noscript>元素中的任何內容都不會被渲染。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。