Router 是 backbone.js 的一個很特別的技術,但並不像 Model 和 View 一樣關鍵,並不是一個必學的項目,因此就算沒有使用 Router 也可以順利做出功能齊全的網頁或 App。
在開始 Router 之前先介紹一下 fragment 的觀念,指的是在一段 URL 當中,緊接在 # (hash tag) 後面的字串(在 RFC3986 當中這段字串叫做分段識別器 Fragment identifier,簡稱 fragment)。例如 http://www.example.org/foo.html#bar 的 bar,就是一個 fragment。
Router 能夠針對不同的 fragment 可以給與相對應的 handler (callback) function,觀念上有點像是 DOM 上的 event listener。因此我們可以針對幾組 fragment 定義被執行或點擊時所要對應到產生的行為,例如讓使用者藉由瀏覽器的「上一頁」或「下一頁」瀏覽同一個頁面內的不同部分且便於觀察瀏覽記錄。
本篇的範例可以到 JSFiddle 取得完整程式碼、瀏覽並練習。
環境的基本設定大致上和過去差不多:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE HTML> | |
<html lang="en-US"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Learning About Backbone.js Routers</title> | |
</head> | |
<body> | |
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> | |
<script type="text/javascript" src="http://documentcloud.github.com/underscore/underscore-min.js"></script> | |
<script type="text/javascript" src="http://documentcloud.github.com/backbone/backbone-min.js"></script> | |
<script type="text/javascript"> | |
/* Your code would be here */ | |
</script> | |
<a href="#foo2">#foo2</a><br /> | |
<a href="#foo2/bar2">#foo2/bar2</a><br /> | |
<a href="#foo2/bar2/2000">#foo2/bar2/2000</a> | |
</body> | |
</html> |
最底下可以看到總共有三個超連結,每個 anchor 都對應到一個 fragment,接著,透過 Backbone.Router.extend 來定義這些連結被執行時要對應到的行為。一個簡單的客制化 Router class 可寫成這樣:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var myRouter = Backbone.Router.extend({ | |
routes: { | |
":foo": "func1", | |
":foo/:bar" : "func2", | |
"*action" : "funcU" | |
}, | |
func1: function(p1) { | |
alert('func1: '+p1); | |
console.log('func1: '+p1); | |
}, | |
func2: function(p1, p2) { | |
alert('func2: '+p1 + ',' + p2); | |
console.log('func2: '+p1 + ',' + p2); | |
}, | |
funcU: function(a) { | |
if (a !== '') { | |
alert('funcU: '+a); | |
console.log('funcU: '+a); | |
} | |
} | |
}); | |
new myRouter(); | |
Backbone.history.start(); |
第一個屬性 routes 是一個 map,定義了不同的 fragment 的樣式(pattern)所要呼叫的 handler function。
Fragment 的樣式有兩種,一種叫做 parameter parts,另一種叫做 splat parts。每一個 parameter part 會對應到 URL 當中用被斜線 / 隔開的字串。而 splat part 代表的是 # 後面一整串的網址。
在 routes 底下的第一個樣式 ":foo" 表示的是網址內的 # 符號後面的「第一個」字串,而且後面沒有其他的斜線 / 存在。以 http://example.com/#happy 這個例子來說,foo 指的就是 happy,在 http://example.com/#coding 裡,foo 指的就是 coding。而 routes 對應的 handler function "func1" 會因為網址的樣式符合了 ":foo" 而被呼叫,並且會把 foo 的內容當作第一個參數傳進 func1,因此如果網址是 http://example.com/#fun,則 func1 的 p1 值就會是 fun。
因此 ":foo/:bar" 指的是 # 後面被斜線 / 隔開的兩個 fragment 的樣式。以 http://example.com/#page/2 為例子,foo 指的是 page 而 bar 指的是 2, 因此 func2 的兩個參數的 p1 會收到 page,而 p2 會收到 2。
請注意這個樣式並不會呼叫 func1 因為 # 後面又多了一個斜線 / ,因此樣式並不吻合 ":foo"。
第三個樣式 "*action" 的意思是 # 後面的任何字串,不考慮斜線。因此以 http://example.com/#foo/bar/2000 這種網址來說,funcU 這個 handler 拿到的參數 a 就是 foo/bar/2000。
這就是 Router 的貼心設計,連網址變化這種小細節也能很有條不紊地監控,Backbone.js 是不是很方便好用呢?
之後將帶給大家的是陣列版本的 Model 叫做 Collection,敬請期待~
Happy Coding!
延伸閱讀
- 幫你的網頁加上Backbone(.js)(一): Model
- 幫你的網頁加上Backbone(.js)(二): View
- 幫你的網頁加上Backbone(.js)(三): Router
- 幫你的網頁加上Backbone(.js)(四): Collection
- 幫你的網頁加上Backbone(.js)(五): AJAX

沒有留言:
張貼留言