有兩種常用的 add_action 鉤子可以加載 腳本和CSS到WordPress:
在南縣等地區,都構建了全面的區域性戰略布局,加強發展的系統性、市場前瞻性、產品創新能力,以專注、極致的服務理念,為客戶提供成都網站制作、網站設計 網站設計制作定制設計,公司網站建設,企業網站建設,品牌網站建設,全網整合營銷推廣,成都外貿網站建設公司,南縣網站建設費用合理。
init: 確保始終為您的網站頭部加載腳本和CSS(如果使用home.php,index.php或一個模板文件),以及其他“前端”文章、頁面和模板樣式。
wp_enqueue_scripts:“適當”的鉤子方法,并不總是有效的,根據你的WordPress設置。
下面的所有例子都在WordPress多站點模式、WordPress 3.4.2 通過測試(如果不支持后續版本,請留言告知)
加載外部 jQuery 庫和主題自定義的腳本、樣式
下面這個例子在 add_action 鉤子中使用 init。使用 init 有兩個原因,一是因為我們正在注銷WordPress默認的jQuery庫,然后加載谷歌的jQuery庫;二是確保在WordPress的頭部就加載腳本和CSS。
使用if ( !is_admin() )是為了確保這些腳本和css只在前端加載,不會再后臺管理界面加載。
/** Google jQuery Library, Custom jQuery and CSS Files */
function myScripts() {
wp_register_script( 'google', '' );
wp_register_script( 'default', get_template_directory_uri() . '/jquery.js' );
wp_register_style( 'default', get_template_directory_uri() . '/style.css' );
if ( !is_admin() ) { /** Load Scripts and Style on Website Only */
wp_deregister_script( 'jquery' );
wp_enqueue_script( 'google' );
wp_enqueue_script( 'default' );
wp_enqueue_style( 'default' );
}
}
add_action( 'init', 'myScripts' );
加載WP默認 jQuery 庫和主題自定義的腳本、樣式
第3行:使用 array(‘jquery’) 是為了告訴 WordPress 這個 jquery.js 是依賴WordPress 的jQuery庫文件,從而使 jquery.js 在WordPress jQuery庫文件后加載。
/** Add Custom jQuery and CSS files to a Theme */
function myScripts() {
wp_register_script( 'default', get_template_directory_uri() . '/jquery.js', array('jquery'), '' );
wp_register_style( 'default', get_template_directory_uri() . '/style.css' );
if ( !is_admin() ) { /** Load Scripts and Style on Website Only */
wp_enqueue_script( 'default' );
wp_enqueue_style( 'default' );
}
}
add_action( 'init', 'myScripts' );
加載 print.css 到你的WordPress主題
第 3 行:最后的 ‘print’是媒體屏幕調用,確保 print.css 在網站的打印機中的文件加載時才加載。
/** Adding a Print Stylesheet to a Theme */
function myPrintCss() {
wp_register_style( 'print', get_template_directory_uri() . '/print.css', '', '', 'print' );
if ( !is_admin() ) { /** Load Scripts and Style on Website Only */
wp_enqueue_style( 'print' );
}
}
add_action( 'init', 'myPrintCss' );
使用 wp_enqueue_scripts 替換 init
如果你要在文章或頁面加載唯一的腳本,那就應該使用 wp_enqueue_scripts 替換 init。使用 wp_enqueue_scripts 僅僅只會在前臺加載腳本和CSS,不會在后臺管理界面加載,所以沒必要使用 !is_admin() 判斷。
使用 is_single() 只在文章加載腳本或CSS
第 3 行的 # 替換為文章的ID就可以讓腳本和css只加載到那篇文章。當然,如果直接使用 is_single() (不填ID),就會在所有文章加載腳本和CSS。
/** Adding Scripts To A Unique Post */
function myScripts() {
if ( is_single(#) ) { /** Load Scripts and Style on Posts Only */
/** Add jQuery and/or CSS Enqueue */
}
}
add_action( 'wp_enqueue_scripts', 'myScripts' );
使用 is_page() 只在頁面加載腳本或CSS
第 3 行的 # 替換為頁面的ID就可以讓腳本和css只加載到那個頁面。當然,如果直接使用 is_single() (不填ID),就會在所有頁面加載腳本和CSS。
/** Adding Scripts To A Unique Page */
function myScripts() {
if ( is_page(#) ) { /** Load Scripts and Style on Pages Only */
/** Add jQuery and/or CSS Enqueue */
}
}
add_action( 'wp_enqueue_scripts', 'myScripts' );
使用 admin_enqueue_scripts 加載腳本到后臺
這個例子將在整個后臺管理界面加載腳本和CSS。這個方法不推薦用在插件上,除非插件重建了整個后臺管理區。
第 10 行使用 admin_enqueue_scripts 替換了 init 或 wp_enqueue_scripts
第 5、6 行,如果你要自定義后臺管理區,你可以需要禁用默認的WordPress CSS調用。
/** Adding Scripts To The WordPress Admin Area Only */
function myAdminScripts() {
wp_register_script( 'default', get_template_directory_uri() . '/jquery.js', array('jquery'), '' );
wp_enqueue_script( 'default' );
//wp_deregister_style( 'ie' ); /** removes ie stylesheet */
//wp_deregister_style( 'colors' ); /** disables default css */
wp_register_style( 'default', get_template_directory_uri() . '/style.css', array(), '', 'all' );
wp_enqueue_style( 'default' );
}
add_action( 'admin_enqueue_scripts', 'myAdminScripts' );
加載腳本和CSS到WordPress登錄界面
第 6 行:我無法弄清楚如何在在登錄頁面注冊/排序 CSS文件,所以這行手動添加樣式表。
第 10-14行:用來移除WordPress默認的樣式表。
/** Adding Scripts To The WordPress Login Page */
function myLoginScripts() {
wp_register_script( 'default', get_template_directory_uri() . '/jquery.js', array('jquery'), '' );
wp_enqueue_script( 'default' );
?
link rel='stylesheet' id='default-css' href='?php echo get_template_directory_uri() . '/style.css';?' type='text/css' media='all' /
?php }
add_action( 'login_enqueue_scripts', 'myLoginScripts' );
/** Deregister the login css files */
function removeScripts() {
wp_deregister_style( 'wp-admin' );
wp_deregister_style( 'colors-fresh' );
}
add_action( 'login_init', 'removeScripts' );
加載腳本和CSS到WordPress插件
WordPress插件加載腳本和CSS也是常見的。主要的不同之處在于文件的 URL。主題使用的是 get_template_directory_uri ,而插件應該用 plugins_url ,因為文件是從插件目錄進行加載的。
從插件加載腳本和CSS
這個例子將在整個網站前端加載腳本和CSS。
/** Global Plugin Scripts for Outside of Website */
function pluginScripts() {
wp_register_script( 'plugin', plugins_url( 'jquery.js' , __FILE__ ), array('jquery'), '' );
wp_register_style( 'plugin', plugins_url( 'style.css' , __FILE__ ) );
if ( !is_admin() ) { /** Load Scripts and Style on Website Only */
wp_enqueue_script( 'plugin' );
wp_enqueue_style( 'plugin' );
}
}
add_action( 'init', 'pluginScripts' );
從插件加載腳本和CSS到后臺管理區
如果你需要在整個后臺管理區加載腳本和CSS,就使用 admin_enqueue_scripts 替換 init。
/** Global Plugin Scripts for The WordPress Admin Area */
function pluginScripts() {
wp_register_script( 'plugin', plugins_url( 'jquery1.js' , __FILE__ ), array('jquery'), '' );
wp_enqueue_script( 'plugin' );
wp_register_style( 'plugin', plugins_url( 'style1.css' , __FILE__ ) );
wp_enqueue_style( 'plugin' );
}
add_action( 'admin_enqueue_scripts', 'pluginScripts' );
從插件加載腳本和CSS到插件設置頁面
例子只會加載所需的腳本和CSS到插件設置頁面,不會在管理區的其他頁面加載。
第 3 行:自定義 page= 后面的值為你的插件設置頁面
/** Adding Scripts On A Plugins Settings Page */
function pluginScripts() {
if ( $_GET['page'] == "plugin_page_name.php" ) {
wp_register_script( 'plugin', plugins_url( 'jquery.js' , __FILE__ ), array('jquery'), '' );
wp_enqueue_script( 'plugin' );
wp_register_style( 'plugin', plugins_url( 'style.css' , __FILE__ ) );
wp_enqueue_style( 'plugin' );
}
}
add_action( 'admin_enqueue_scripts', 'pluginScripts' );
將 jQuery 庫移動到頁腳
你不能將WordPress默認的jQuery 庫移動到頁面底部,但是你可以將自定義的jQuery 或其他外部jQuery 庫(比如Google的)移動到底部。不要將CSS移動到頁面底部。
第 3、4 行:最后的 ‘true’告訴WordPress在頁面底部加載這些腳本。
/** Moves jQuery to Footer */
function footerScript() {
wp_register_script('jquery', (""), false, '', true );
wp_register_script( 'default', get_template_directory_uri() . '/jquery.js', false, '', true );
if ( !is_admin() ) { /** Load Scripts and Style on Website Only */
wp_deregister_script( 'jquery' );
wp_enqueue_script( 'jquery' );
wp_enqueue_script( 'default' );
}
}
add_action( 'init', 'footerScript' );
Vue 提供了?transition?的封裝組件,在下列情形中,可以給任何元素和組件添加 entering/leaving 過渡
條件渲染 (使用?v-if)
條件展示 (使用?v-show)
動態組件
組件根節點
這里是一個典型的例子:
div id="demo"
button v-on:click="show = !show"
Toggle
/button
transition name="fade"
p v-if="show"hello/p
/transition
/div
new Vue({
el: '#demo',
data: {
show: true
}
})
.fade-enter-active, .fade-leave-active {
transition: opacity .5s
}
.fade-enter, .fade-leave-to /* .fade-leave-active in below version 2.1.8 */ {
opacity: 0
}
Toggle
hello
當插入或刪除包含在?transition?組件中的元素時,Vue 將會做以下處理:
自動嗅探目標元素是否應用了 CSS 過渡或動畫,如果是,在恰當的時機添加/刪除 CSS 類名。
如果過渡組件提供了?JavaScript 鉤子函數,這些鉤子函數將在恰當的時機被調用。
如果沒有找到 JavaScript 鉤子并且也沒有檢測到 CSS 過渡/動畫,DOM 操作 (插入/刪除) 在下一幀中立即執行。(注意:此指瀏覽器逐幀動畫機制,和 Vue 的?nextTick?概念不同)
過渡的類名
在進入/離開的過渡中,會有 6 個 class 切換。
v-enter:定義進入過渡的開始狀態。在元素被插入時生效,在下一個幀移除。
v-enter-active:定義過渡的狀態。在元素整個過渡過程中作用,在元素被插入時生效,在?transition/animation?完成之后移除。這個類可以被用來定義過渡的過程時間,延遲和曲線函數。
v-enter-to:?2.1.8版及以上?定義進入過渡的結束狀態。在元素被插入一幀后生效 (于此同時?v-enter?被刪除),在?transition/animation?完成之后移除。
v-leave: 定義離開過渡的開始狀態。在離開過渡被觸發時生效,在下一個幀移除。
v-leave-active:定義過渡的狀態。在元素整個過渡過程中作用,在離開過渡被觸發后立即生效,在?transition/animation?完成之后移除。這個類可以被用來定義過渡的過程時間,延遲和曲線函數。
v-leave-to:?2.1.8版及以上?定義離開過渡的結束狀態。在離開過渡被觸發一幀后生效 (于此同時?v-leave?被刪除),在?transition/animation?完成之后移除。
首先打來safari瀏覽器,找到右上角一個小齒輪圖標。點擊它
在彈出的菜單,點擊偏好設置頁面變化后,再找到?安全性?圖標點擊它。
看到如下圖,用紅圈起來的地方。
將這個項目前面的的?鉤子?全部取消,之后點擊紅叉
現在再打開有JS內容頁面,就會出現提示。(注:這個提示信息是網站制作者設置的,所以不會一樣的。有些網頁更本不會出現,但是顯示內容會出錯的)
JS圖形、圖標庫推薦:
1. JS Charts
JS Charts 是個基于JavaScript的圖表生成器,不需要任何編碼。JS Charts 非常容易使用,只要用戶使用客戶端腳本(比如,在 web 瀏覽器中執行)。它不需要多余的插件和服務器模塊,只需要下載 JS Charts 的腳本,準備好 XML,JSON 或者 JavaScript 數組數據。
2. Canvasjs
CanvasJS 是個易用的 HTML5 JavaScript 圖表庫,基于 Canvas 元素。Graphs 可以通過設備渲染,包括 iPhone,iPad,Android,Windows Phone,Microsoft Surface,Desktops 等等。它允許用戶創建適用于所有設備,不影響 web 應用程序的功能和可維護性的富儀表盤。CanvcasJS 有著非常漂亮的主題和超過傳統的 Flash 和 SVG 圖表 10x 倍以上的速度——生成輕量級,漂亮和響應式的儀表圖。
3. Chart.js
Chart.js 是個簡單的,面向對象的客戶端圖形庫,用戶可以用 6 中不同的方式來可視化數據。每個方式都是動畫效果的,完全自定義,而且看起來非常好看,即使在 retina 顯示。它使用 HTML5 canvas 元素,支持所有現代瀏覽器,并且支持 IE7/8。
4. Aristochart
Aristochart 是個高度自定義,靈活的折線 Canvas 圖表庫,允許用戶集中精力在圖表的審美方面,后臺工作做得非常好。Aristochart 有個持續進步的社區,提供許多不斷增長的主題給用戶選擇。
5. xCharts
xCharts 是一個使用 D3.js 來構建漂亮的可定制的數據驅動的 JavaScript圖表庫,他使用HTML,CSS,SVG實現圖表,xCharts 被設計為一個動態的、流暢的、開放的和可定制化的庫。
6. BonsaiJS
BonsaiJS 是個輕量級的 JavaScript圖形庫,提供直觀的圖形 API 和 SVG 渲染器。主要特性包括:架構分離的運行器和渲染器;iFrame,Worker 和 Node 運行上下文;形狀,路徑,Assets(音頻,圖像,字體,subMovies),Keyframe 和常規動畫,等等。支持現代化瀏覽器: Safari, Chrome 和 Firefox。
7. Sigma.js
Sigma.js 是個免費開源的 JavaScript圖形庫,使用 HTML5 canvas 元素。它的設計是特別為了在 web 界面分享交互式網絡 Map 和動態展示網絡數據庫。
8. Morris.js
Morris.js 是個輕量級的 JavaScript庫,使用 jQuery 和 Raphaenuml 來繪制時序圖。 Morris.js 生命周期是從代碼驅動 howmanyleft.co.uk 圖表開始的。它支持的瀏覽器有: IE6+, Safari/Chrome/Firefox, iOS 3+ 和 Android 3+。它的公共 API 非常的小,只有一個函數: Morris.Line(選項),包括了許多配置選項。
9. Paper.js
Paper.js 是一個開源的向量圖形腳本框架,基于 HTML5Canvas 開發。提供清晰的場景圖、DOM和大量強大的功能用來創建各種向量圖和貝塞爾曲線。
10. AmCharts
AmCharts 是個高級圖表庫,適用于所有數據的可視化。AmCharts 包括: Column, Bar, Line, Area, Step, Step without risers, Smoothed line, Candlestick, OHLC, Pie/Donut, Radar/ Polar, XY/Scatter/Bubble, Bullet, Funnel/Pyramid 等等。
11. Smoothie Charts
Smoothie Charts是個極小的圖表庫,專為實時流媒體數據設計的。Joe Walnes 想展示 WebSocket推動的實時的流數據。雖然很多圖表庫允許用戶動態更新數據,但是沒有一個是可以優化源源不斷的流數據。
12. Dygraphs
Dygraphs 是個快速,靈活,開源的 JavaScript 圖表庫。它允許用戶展示和解析密集的數據集。可以高亮需要強調的數據集。可以使用鼠標點擊或者用鼠標拖動來縮放圖表;可以修改數值或者點擊條目來調整平均周期。
13. Grafico
Grafico 是 Grafico 是一個基于 Rapha?l 和 Prototype.js 構建的 JavaScript 圖表庫,提供了各種圖表類型。這些漂亮的圖表,有利于傳遞他們的信息。
14. Highchart JS
Highcharts JS 是一個制作圖表的純 Javascript類庫,主要特性如下:兼容性:兼容當今所有的瀏覽器,包括 iPhone、IE 和火狐等等;對個人用戶完全免 費;純JS,無BS;支持大部分的圖表類型:直線圖,曲線圖、區域圖、區域曲線圖、柱狀圖、餅裝圖、散布圖;跨語言:不管是 PHP、Asp.net 還是 Java 都可以使用。
15. Flotr
Flotr 是一個基于 Prototype 開發的 JavaScript繪圖工具。支持圖例,鼠標跟蹤,圖片區域選擇,圖片縮放,添加事件鉤子(event hook),通過CSS設置樣式等。
16. Flot
Flot 是受 Plotr 和 PlotKit 的 啟發,Ole Laursen 基于 jquery 開發了一個圖表繪制(WEB Chart)插件并命名為 flot。 flot 是個純 JavaSript 庫,專注于簡單的使用方式,迷人的外觀和交互式特性。支持的瀏覽器有: Internet Explorer 6+, Chrome, Firefox 2+, Safari 3+ and Opera 9.5+。
17. jFreeChart
JFreeChart 主要用來各種各樣的圖表,這些圖表包括:餅圖、柱狀圖(普通柱狀圖以及堆棧柱狀圖)、線圖、區域圖、分布圖、混合圖、甘特圖以及一些儀表盤等等。JFreeChart 項目歷史悠久,而且有大量的開發者在維護。
18. Plotkit
PlotKit 是一個純 JavaScript 繪圖工具包。它支持 HTML Canvas 和 Adobe SVG。有著很完整的文檔,方便用戶使用。
19. Planetary.js
Planetary.js 是個令人稱奇的創建交互式 web 地球儀的 JavaScript庫。它使用 D3 和 TopoJSON 來解析和渲染地理信息。Planetary.js 使用基于插件的架構,甚至默認自身就是個插件!這使得 Planetary.js 非常靈活,而且它是允許用戶完全自定義,包括顏色,大小,rotation 等等。更重要的是,用戶可以在任意位置使用自定義的顏色和大小來顯示動畫“pings”;它還支持鼠標拖動和縮放,100% 免費和開源。
20. Ember Charts
Ember Charts 是個圖表庫,使用 Ember.js 和 d3.js 框架構建的。它包括時間線,條形圖,餅圖和散點圖,非常容易擴展和修改。這些圖表組件都是開箱即用的,在圖表交互和演示方面應用的很好。
21. Sparky
Sparky 是個免費的 JavaScript 波形圖庫,依賴于 Rapha?l ,非常容易使用。支持多個圖表類型(折線,條形,area),折線和區域圖可以有多個顏色選擇。
22. Envision.js
Envision.js 是個 JavaScript 庫,用來簡化,快速創建交互式的 HTML5 可視化圖表。它包括兩個圖表類型:時序圖和 Finance ,提供 API 給開發者,用戶可以直接自定義創建圖表。這個庫氏基于 Flotr2 和 HTML5 Canvas 的。它與框架無關,依賴于幾個小的 JavaScript 庫。
23. Dc.js
dc.js 是個 JavaScript 圖表庫,有著原生的 crossfilter, 支持和允許高效展示大型多維數據集(基于 crossfilter 的示例);圖表使用 dc.js 渲染,是使用原生數據驅動,所以能得到用戶的實時反饋;dc.js 最大的亮點在于能提供一個簡單而強大的 JavaScript 庫,能進行數據可視化和分析;不僅支持桌面瀏覽器還支持移動端。
24. ElyCharts
Elycharts 是一個易于使用的,可定制的 JavaScript圖表繪制組件。這個組件可用于繪制大部分常用的圖表類型包括:line, column, are, bar, pie, sparklines and combinations。它支持多種交互式功能包括:鼠標跟蹤、事件處理、利用各種動畫高亮顯示選擇中的區域,Tooltip,HTML錨點等。可以動 態修改數據,并以漂亮的動畫效果展示圖表中的變化。圖表利用SVG/VML技術生成,基于jQuery + Rapha?l開發。
25. AwesomeChartJS
AwesomeChartJS Awesome Chart JS 是一個 JavaScript生成圖表的類庫,它利用了 HTML5 的 canvas 標簽來創建統計圖表。此類庫就是為了減輕開發者的工作量,使用它只需書寫幾行代碼便能生成漂亮的圖表。
26. Arbor.js
Arbor.js 是一個利用 Web Works 和 jQuery創建的可視化圖形庫,它為圖形組織和屏幕刷新處理提供了一個高效的、力導向的布局算法。
27. CanvasXpress
canvasXpress 是一個基于HTML5 canvas標簽實現的 JavaScript圖表類庫,它能夠支持線性圖、柱形圖、餅圖和熱點圖等多種常見的圖表類型。它所生成的圖表交互性很強,鼠標放 上去時會動態顯示值。除此之外,它也具有相當高的可定制性,可設置圖表的文字、顏色和要顯示/隱藏的元素等。當然更重要的一點是,雖然它使用了 HTML5,但是依然支持IE6瀏覽器。
28. JSXGraph
JSXGraph 是一個支持各種瀏覽器的交互式幾何圖庫繪制。JSXGraph 使用 SVG 和 VML。
29. Rickshaw
Rickshaw 是一個用于繪制時序圖的簡單 jS 庫,基于 Mike Bostock’s delightful D3 庫構建。
30. rGraph
RGraph 是基于HTML5 canvas標簽的HTML5 canvas圖形庫,支持 20 種不同的可視化類型。使用 canvas 標簽,RGraph 創建“HTML5 圖表”,意味著更快的 web 頁面加載和更少的 web 服務器加載。這能幫助減小 web 頁面的大小,低能耗和更快的瀏覽速度。
31. Fusion Chart
FusionCharts Suite XT 是個專業的 JavaScript圖表庫,能創建任何類型的圖表。它創建的圖表都是可以進行完全自定義的,標簽,字體,邊界等等,都可以進行修改。它有很強的交互功能,有許多信息提示,可 點擊的 legend 關鍵字,還有 dril-down,縮放/滾動 和單擊打印圖表功能。
32. Graph Dracula
Dracula 是用一系列的工具來顯示和布局互動圖表,包括各種相關的算法。它只是純 JavaScript 和 SVG ,并無 Flash,Java,其他插件。它非常容易使用,用戶可以很簡單的自定義任意的元素。
33. Bluff
Bluff 是個 JavaScript 的 Ruby 的 Gruff graphing library端口。它支持所有 Gruff 的特性,但是有著最小的依賴。用戶只需要運行一個第三方腳本: JS.Class 副本(壓縮后只有 2.6kB ) 和 Google 的 ExCanvas 副本,用來支持 IE 中的 canvas。這兩個腳本在 Bluff 中都有下載。Bluff 自身壓縮后大小大概有 11KB 。
34. Pizza Pie Chart
Pizza Pie Charts 是個響應式餅圖圖表,基于 Adobe Snap SVG 框架,通過 HTML 標記和 CSS 來替代 JavaScript 對象,更容易集成各種先進的技術。
35. jGraph
HTML5 圖表組件,完全支持l IE 6-8 和觸屏設備。 JGraph 自2001年來就一直提供最先進的圖表軟件組件,是第一個流行的 JGraph Swing 庫。然后在 2005 年走在時代的前沿開發 mxGraph。
1.不要做任何假設
(JavaScript是一個不可靠的助手)
可能不唐突的JavaScript 的最重要的一個特性就是——你要停止任何假設:
* 不要假設JavaScript是可用的,你最好認為它很有可能是不可用的,而不是直接依賴于它。
* 在你經過測試確認一些方法和屬性可以使用之前,不要假設瀏覽器支持它們。
* 不要假設HTML代碼如你想象的那樣正確,每次都要進行檢查,并且當其不可用的時候就什么也不要做。
* 讓JavaScript的功能獨立于輸入設備
* 要記住其他的腳本可能會影響你的JavaScript的功能,所以要保證你的腳本的作用域盡可能地安全。
在開始設計你的腳本之前,要考慮的第一件事情就是檢查一下你要為其編寫腳本的HTML代碼,看看有什么東西可以幫助你達到目的。
2.找出鉤子和節點關系
(HTML是腳本的基石)
在開始編寫腳本之前,要先看一下你要為之編寫JavaScript的HTML。如果HTML是未經組織的或者未知的,那么你幾乎不可能有一個好的腳本編寫方案——很可能就會出現下面的情況:要么是會用JavaScript創建太多標記,要么就是應用太依賴于JavaScript。
在HTML中有一些東西需要考慮,那就是鉤子和節點關系。
1.HTML 鉤子
HTML最初的和最重要的鉤子就是ID,而且ID可以通過最快的DOM方法——getElementById 訪問到。如果在一個有效的HTML文檔中所有的ID都是獨一無二的話(在IE中關于name 和 ID 有一個bug,不過有些好的類庫解決了這個問題),使用ID就是安全可靠的,并且易于測試。
其他一些鉤子就是是HTML元素和CSS類,HTML元素可以通過getElementsByTagName方法訪問,而在多數瀏覽器中都還不能通過原生的DOM方法來訪問CSS類。不過,有很多外部類庫提供了可以訪問CSS類名(類似于 getElementsByClassName) 的方法。
2.HTML 節點關系
關于HTML的另外比較有意思的一點就是標記之間的關系,思考下面的問題:
* 要怎樣才可以最容易地、通過最少的DOM遍歷來到達目標節點?
* 通過修改什么標記,可以盡可能多地訪問到需要修改的子節點?
* 一個給定的元素有什么屬性或信息可以用來到達另外一個元素?
遍歷DOM很耗資源而且速度很慢,這就是為什么要盡量使用瀏覽器中已經在使用的技術來做這件事情。
3.把遍歷交給專家來做
(CSS,更快地遍歷DOM)
有關DOM的腳本和使用方法或屬性(getElementsByTagName, nextSibling, previousSibling, parentNode以及其它)來遍歷DOM似乎迷惑了很多人,這點很有意思。而有趣的是,我們其實早已經通過另外一種技術—— CSS ——做了這些事情。
CSS 是這樣一種技術,它使用CSS選擇器,通過遍歷DOM來訪問目標元素并改變它們的視覺屬性。一段復雜的使用DOM的JavaScript可以用一個CSS選擇器取代:
Java代碼 var n = document.getElementById('nav'); if(n){ var as = n.getElementsByTagName('a'); if(as.length 0){ for(var i=0;as[i];i++){ as[i].style.color = ‘#369′; as[i].style.textDecoration = ‘none’; } } } /* 下面的代碼與上面功能一樣 */ #nav a{ color:#369; text-decoration:none; } var n = document.getElementById('nav'); if(n){ var as = n.getElementsByTagName('a'); if(as.length 0){ for(var i=0;as[i];i++){ as[i].style.color = ‘#369′; as[i].style.textDecoration = ‘none’; } } } /* 下面的代碼與上面功能一樣 */ #nav a{ color:#369; text-decoration:none; }
這是一個可以好好利用的很強大的技巧。你可以通過動態為DOM中高層的元素添加class 或者更改元素ID來實現這一點。如果你使用DOM為文檔的body添加了一個CSS類,那么設計師就很可以容易地定義文檔的靜態版本和動態版本。
Java代碼 JavaScript: var dynamicClass = 'js'; var b = document.body; b.className = b.className ? b.className + ' js' : 'js'; CSS: /* 靜態版本 */ #nav { .... } /* 動態版本 */ body.js #nav { .... } JavaScript: var dynamicClass = 'js'; var b = document.body; b.className = b.className ? b.className + ' js' : 'js'; CSS: /* 靜態版本 */ #nav { .... } /* 動態版本 */ body.js #nav { .... }
4.理解瀏覽器和用戶
(在既有的使用模式上創建你所需要的東西)
不唐突的JavaScript 中很重要的一部分就是理解瀏覽器是如何工作的(尤其是瀏覽器是如何崩潰的)以及用戶期望的是什么。不考慮瀏覽器你也可以很容易地使用JavaScript 創建一個完全不同的界面。拖拽界面,折疊區域,滾動條和滑動塊都可以使用JavaScript創建,但是這個問題并不是個簡單的技術問題,你需要思考下面的問題:
* 這個新界面可以獨立于輸入設備么?如果不能,那么可以依賴哪些東西?
* 我創建的這個新界面是否遵循了瀏覽器或者其它富界面的準則(你可以通過鼠標在多級菜單中直接切換嗎?還是需要使用tab鍵?)
* 我需要提供什么功能但是這個功能是依賴于JavaScript的?
最后一個問題其實不是問題,因為如果需要你就可以使用DOM來憑空創建HTML。關于這點的一個例子就是“打印”鏈接,由于瀏覽器沒有提供一個非 JavaScript的打印文檔功能,所以你需要使用DOM來創建這類鏈接。同樣地,一個實現了展開和收縮內容模塊的、可以點擊的標題欄也屬于這種情況。標題欄不能被鍵盤激活,但是鏈接可以。所以為了創建一個可以點擊的標題欄你需要使用JavaScript將鏈接加入進去,然后所有使用鍵盤的用戶就可以收縮和展開內容模塊了。
解決這類問題的極好的資源就是設計模式庫。至于要知道瀏覽器中的哪些東西是獨立于輸入設備的,那就要靠經驗的積累了。首先你要理解的就是事件處理機制。
5.理解事件
(事件處理會引起改變)
事件處理是走向不唐突的JavaScript的第二步。重點不是讓所有的東西都變得可以拖拽、可以點擊或者為它們添加內聯處理,而是理解事件處理是一個可以完全分離出來的東西。我們已經將HTML,CSS和JavaScript分離開來,但是在事件處理的分離方面卻沒有走得很遠。
事件處理器會監聽發生在文檔中元素上的變化,如果有事件發生,處理器就會找到一個很奇妙的對象(一般會是一個名為e的參數),這個對象會告訴元素發生了什么以及可以用它做什么。
對于大多數事件處理來說,真正有趣的是它不止發生在你想要訪問的元素上,還會在DOM中較高層級的所有元素上發生(但是并不是所有的事件都是這樣,focus和blur事件是例外)。舉例來說,利用這個特性你可以為一個導航列表只添加一個事件處理器,并且使用事件處理器的方法來獲取真正觸發事件的元素。這種技術叫做事件委托,它有幾點好處:
* 你只需要檢查一個元素是否存在,而不需要檢查每個元素
* 你可以動態地添加或者刪除子節點而并不需要刪除相應的事件處理器
* 你可以在不同的元素上對相同的事件做出響應
需要記住的另一件事是,在事件向父元素傳播的時候你可以停止它而且你可以覆寫掉HTML元素(比如鏈接)的缺省行為。不過,有時候這并不是個好主意,因為瀏覽器賦予HTML元素那些行為是有原因的。舉個例子,鏈接可能會指向頁面內的某個目標,不去修改它們能確保用戶可以將頁面當前的腳本狀態也加入書簽。
6.為他人著想
(命名空間,作用域和模式)
你的代碼幾乎從來不會是文檔中的唯一的腳本代碼。所以保證你的代碼里沒有其它腳本可以覆蓋的全局函數或者全局變量就顯得尤為重要。有一些可用的模式可以來避免這個問題,最基礎的一點就是要使用 var 關鍵字來初始化所有的變量。假設我們編寫了下面的腳本:
Java代碼 var nav = document.getElementById('nav'); function init(){ // do stuff } function show(){ // do stuff } function reset(){ // do stuff } var nav = document.getElementById('nav'); function init(){ // do stuff } function show(){ // do stuff } function reset(){ // do stuff }
上面的代碼中包含了一個叫做nav的全局變量和名字分別為 init,show 和 reset 的三個函數。這些函數都可以訪問到nav這個變量并且可以通過函數名互相訪問:
Java代碼 var nav = document.getElementById('nav'); function init(){ show(); if(nav.className === 'show'){ reset(); } // do stuff } function show(){ var c = nav.className; // do stuff } function reset(){ // do stuff } var nav = document.getElementById('nav'); function init(){ show(); if(nav.className === 'show'){ reset(); } // do stuff } function show(){ var c = nav.className; // do stuff } function reset(){ // do stuff }
你可以將代碼封裝到一個對象中來避免上面的那種全局式編碼,這樣就可以將函數變成對象中的方法,將全局變量變成對象中的屬性。 你需要使用“名字+冒號”的方式來定義方法和屬性,并且需要在每個屬性或方法后面加上逗號作為分割符。
Java代碼 var myScript = { nav:document.getElementById('nav'), init:function(){ // do stuff }, show:function(){ // do stuff }, reset:function(){ // do stuff } } var myScript = { nav:document.getElementById('nav'), init:function(){ // do stuff }, show:function(){ // do stuff }, reset:function(){ // do stuff } }
所有的方法和屬性都可以通過使用“類名+點操作符”的方式從外部和內部訪問到。
Java代碼 var myScript = { nav:document.getElementById('nav'), init:function(){ myScript.show(); if(myScript.nav.className === 'show'){ myScript.reset(); } // do stuff }, show:function(){ var c = myScript.nav.className; // do stuff }, reset:function(){ // do stuff } } var myScript = { nav:document.getElementById('nav'), init:function(){ myScript.show(); if(myScript.nav.className === 'show'){ myScript.reset(); } // do stuff }, show:function(){ var c = myScript.nav.className; // do stuff }, reset:function(){ // do stuff } }
這種模式的缺點就是,你每次從一個方法中訪問其它方法或屬性都必須在前面加上對象的名字,而且對象中的所有東西都是可以從外部訪問的。如果你只是想要部分代碼可以被文檔中的其他腳本訪問,可以考慮下面的模塊(module)模式:
Java代碼 var myScript = function(){ //這些都是私有方法和屬性 var nav = document.getElementById('nav'); function init(){ // do stuff } function show(){ // do stuff } function reset(){ // do stuff } //公有的方法和屬性被使用對象語法包裝在return 語句里面 return { public:function(){ }, foo:'bar' } }(); var myScript = function(){ //這些都是私有方法和屬性 var nav = document.getElementById('nav'); function init(){ // do stuff } function show(){ // do stuff } function reset(){ // do stuff } //公有的方法和屬性被使用對象語法包裝在return 語句里面 return { public:function(){ }, foo:'bar' } }();
你可以使用和前面的代碼同樣的方式訪問返回的公有的屬性和方法,在本示例中可以這么訪問:myScript.public() 和 myScript.foo 。但是這里還有一點讓人覺得不舒服:當你想要從外部或者從內部的一個私有方法中訪問公有方法的時候,還是要寫一個冗長的名字(對象的名字可以非常長)。為了避免這一點,你需要將它們定義為私有的并且在return語句中只返回一個別名:
Java代碼 var myScript = function(){ // 這些都是私有方法和屬性 var nav = document.getElementById('nav'); function init(){ // do stuff } function show(){ // do stuff // do stuff } function reset(){ // do stuff } var foo = 'bar'; function public(){ } var myScript = function(){ // 這些都是私有方法和屬性 var nav = document.getElementById('nav'); function init(){ // do stuff } function show(){ // do stuff // do stuff } function reset(){ // do stuff } var foo = 'bar'; function public(){ }
//只返回指向那些你想要訪問的私有方法和屬性的指針
Java代碼 return { public:public, foo:foo } }(); return { public:public, foo:foo } }();
這就保證了代碼風格一致性,并且你可以使用短一點的別名來訪問其中的方法或屬性。
如果你不想對外部暴露任何的方法或屬性,你可以將所有的代碼封裝到一個匿名方法中,并在它的定義結束后立刻執行它:
Java代碼 (function(){ // these are all private methods and properties var nav = document.getElementById('nav'); function init(){ // do stuff show(); // 這里不需要類名前綴 } function show(){ // do stuff } function reset(){ // do stuff } })(); (function(){ // these are all private methods and properties var nav = document.getElementById('nav'); function init(){ // do stuff show(); // 這里不需要類名前綴 } function show(){ // do stuff } function reset(){ // do stuff } })();
對于那些只執行一次并且對其它函數沒有依賴的代碼模塊來說,這種模式非常好。
通過遵循上面的那些規則,你的代碼更好地為用戶工作,也可以使你的代碼在機器上更好地運行并與其他開發者的代碼和睦相處。不過,還有一個群體需要考慮到。
7.為接手的開發者考慮
(使維護更加容易)
使你的腳本真正地unobtrusive的最后一步是在編寫完代碼之后仔細檢查一遍,并且要照顧到一旦腳本上線之后要接手你的代碼的開發者。考慮下面的問題:
* 所有的變量和函數名字是否合理并且易于理解?
* 代碼是否經過了合理的組織?從頭到尾都很流暢嗎?
* 所有的依賴都顯而易見嗎?
* 在那些可能引起混淆的地方都添加了注釋嗎?
最重要的一點是:要認識到文檔中的HTML和CSS代碼相對于JavaScript來說更有可能被改變(因為它們負責視覺效果)。所以不要在腳本代碼中包含任何可以讓終端用戶看到的class和ID,而是要將它們分離出來放到一個保存配置信息的對象中。
Java代碼 myscript = function(){ var config = { navigationID:'nav', visibleClass:'show' }; var nav = document.getElementById(config.navigationID); function init(){ show(); if(nav.className === config.visibleClass){ reset(); }; // do stuff }; function show(){ var c = nav.className; // do stuff }; function reset(){ // do stuff }; }(); myscript = function(){ var config = { navigationID:'nav', visibleClass:'show' }; var nav = document.getElementById(config.navigationID); function init(){ show(); if(nav.className === config.visibleClass){ reset(); }; // do stuff }; function show(){ var c = nav.className; // do stuff }; function reset(){ // do stuff }; }();
這樣維護者就知道去哪里修改這些屬性,而不需要改動其他代碼。