home.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. define({
  2. title: 'SPA - 为WebApp设计的路由控制和视图转换框架',
  3. body: '<nav class="navbar navbar-default navbar-static-top" role="navigation">\
  4. <div class="navbar-header">\
  5. <a class="navbar-brand" href="#">SPA</a>\
  6. </div>\
  7. <!--a href="#" class="btn btn-default navbar-btn btn-link pull-left"><span class="glyphicon glyphicon-align-justify"></span></a-->\
  8. <!--a href="#" class="btn btn-default navbar-btn btn-link pull-right">关于</a-->\
  9. </nav>\
  10. <div class="page-container-navbar">\
  11. <div class="container">\
  12. <div class="page-header"><h1>概述</h1></div>\
  13. <p class="lead">SPA是为构建WebApp设计的路由控制和视图转换框架</p>\
  14. <p>\
  15. SPA专注于解决构建WebApp时遇到的共性问题,尤其适用于构建MobileApp,\
  16. 我们和<a href="http://jquerymobile.com/" target="_blank">jQuery Mobile</a>、<a href="http://www.sencha.com/products/touch/" target="_blank">Sencha Touch</a>等框架不同,\
  17. 并不是一个构建移动端应用的前端整体解决方案,所以我们不包含UI组件,如果你不想自己设计界面,\
  18. 可以用<a href="http://getbootstrap.com/" target="_blank">Bootstrap</a>、<a href="http://topcoat.io/" target="_blank">Topcoat</a>等UI Components框架配合SPA,\
  19. 来快速构建你的WebApp;\
  20. </p>\
  21. <p>\
  22. SPA依赖<a href="http://zeptojs.com/" target="_blank">Zepto</a>或<a href="http://jquery.com/" target="_blank">jQuery</a>,\
  23. 并且每个视图可以通过<a href="http://requirejs.org/" target="_blank">RequireJS</a>、<a href="http://seajs.org/docs/" target="_blank">Sea.js</a>等CommonJS解决方案或者自定义的方式进行模块化组织、异步加载;\
  24. </p>\
  25. <p>\
  26. SPA支持移动端和桌面端的现代浏览器;\
  27. </p>\
  28. <p>\
  29. <iframe src="http://ghbtns.com/github-btn.html?user=zhaoda&repo=spa&type=watch" allowtransparency="true" frameborder="0" scrolling="0" width="53" height="20"></iframe>\
  30. <iframe src="http://ghbtns.com/github-btn.html?user=zhaoda&repo=spa&type=fork" allowtransparency="true" frameborder="0" scrolling="0" width="53" height="20"></iframe>\
  31. <iframe src="http://ghbtns.com/github-btn.html?user=zhaoda&type=follow" allowtransparency="true" frameborder="0" scrolling="0" width="132" height="20"></iframe>\
  32. </p>\
  33. <p>\
  34. <a href="https://travis-ci.org/zhaoda/spa" title="Build Status" target="_blank"><img src="https://travis-ci.org/zhaoda/spa.png?branch=master"/></a>\
  35. <a href="https://david-dm.org/zhaoda/spa#info=devDependencies" title="Dependency status" target="_blank"><img src="https://david-dm.org/zhaoda/spa/dev-status.png"/></a>\
  36. <a href="https://sourcegraph.com/github.com/zhaoda/spa" title="Total views" target="_blank"><img src="https://sourcegraph.com/api/repos/github.com/zhaoda/spa/counters/views.png"/></a>\
  37. </p>\
  38. <div class="page-header"><h1>为什么使用SPA</h1></div>\
  39. <h3>提供快速的开发实现</h3>\
  40. <p>\
  41. 你可以像开发传统网站一样,先设计并制作每个视图,比如页面、导航、对话框等等,然后通过SPA提供的接口把每个视图拼装组织,完成一个拥有NativeApp体验的WebApp;\
  42. </p>\
  43. <h3>保留更大的设计自由度</h3>\
  44. <p>\
  45. SPA相对于jQuery Mobile和Sencha Touch等框架,SPA是非常轻量级的,我们只关心并解决WebApp的路由控制和视图转换等共性问题,每个场景被模拟成一个&lt;body&gt;节点,场景内的具体界面和交互设计完全交给开发者;\
  46. </p>\
  47. <h3>减少后端依赖</h3>\
  48. <p>\
  49. 视图的渲染和路由是在前端完成的,后端只需要提供一个简单的入口页面(Single-page application)和应用所需的异步数据接口;如果再配合使用javascript模版,还可以最大化的利用前端缓存,减少网络流量请求;\
  50. </p>\
  51. <h3>事件驱动</h3>\
  52. <p>\
  53. SPA不提供类、对象或函数库,利用jQuery的自定义事件和事件代理,SPA的接口都绑定到DOM上,所有的操作都是触发相关DOM上的自定义事件,将各个视图的代码解耦隔离,降低开发复杂度,这个特性和<a href="http://flightjs.github.io/" target="_blank">Flight</a>框架一致。\
  54. </p>\
  55. <div class="page-header"><h1>路由控制</h1></div>\
  56. <p>\
  57. WebApp中不同的视图(页面)通常需要被链接、收藏或分享,所以需要记录视图的地址,SPA提供基于hash fragments的URL路由控制,每个路由规则都绑定相应的页面视图,应用启动后将根据路由的变化自动转换视图;\
  58. </p>\
  59. <p>\
  60. SPA中的hash路由被设计成基于字符串片段的规则,每个片段用斜线<code>/</code>分割,\
  61. 片段可以包含以冒号为前缀的参数<code>:param</code>,\
  62. 以星号为前缀<code>*splat</code>可以匹配任意数量的片段,\
  63. 括号括起来<code>(:optional)</code>可以匹配可选的片段(有或者无),\
  64. 路由规则还可以直接用正则表达式创建;\
  65. </p>\
  66. <p>\
  67. 解析后的请求参数数组<code>requestData</code>会存储到对应的页面视图对象中,以提供给视图渲染、视图初始化等回调函数所使用;\
  68. </p>\
  69. <p>\
  70. 比如:\
  71. </p>\
  72. <p>\
  73. 规则<code>"search/:keyword/page:num"</code>可以匹配路由请求<code>#search/something/page2</code>,并将参数<code>"something"</code>和<code>"2"</code>存储到视图对象;\
  74. </p>\
  75. <p>\
  76. 规则<code>"file/*path"</code>可以匹配路由请求<code>#file/some/folder/file.txt</code>,并将参数<code>"some/folder/file.txt"</code>存储到视图对象;\
  77. </p>\
  78. <p>\
  79. 规则<code>"docs/:section(/:subsection)"</code>可以匹配路由请求<code>#docs/faq</code>和<code>#docs/faq/install</code>,并将参数<code>"faq"</code>存储到第一个视图对象,将参数<code>"faq"</code>和<code>"install"</code>存储到第二个视图对象;\
  80. </p>\
  81. <p>\
  82. 规则<code>"/^(.*?)\/open$/"</code>可以匹配路由请求<code>#some/thing/open</code>,并将参数<code>"some/thing"</code>存储到视图对象;\
  83. </p>\
  84. <p>\
  85. 当用户点击链接、浏览器后退按钮或者输入url hash进行路由请求时,window的<code>popstate</code>事件将被触发,然后寻找匹配的路由规则,创建对应的页面视图,并进行初始化,再通过对应的转换动画来显示;\
  86. </p>\
  87. <pre>\
  88. var pageHome = {\n\
  89. route: "",\n\
  90. classname: "home",\n\
  91. animate: "fadeIn",\n\
  92. view: function() {\n\
  93. var $page = this\n\
  94. requirejs(["home"], function(viewData) {\n\
  95. $doc.trigger("spa:initview", [$page, viewData])\n\
  96. })\n\
  97. }\n\
  98. }\n\
  99. \n\
  100. $doc.trigger("spa:route", [pageHome])\n\
  101. </pre>\
  102. <p>\
  103. 除了用户操作,还可以通过<code>spa:navigate</code>事件主动进行路由请求。\
  104. </p>\
  105. <pre>\
  106. $doc.trigger("spa:navigate", {\n\
  107. hash: "go/to/some/pageview"\n\
  108. })\
  109. </pre>\
  110. <div class="page-header"><h1>视图转换</h1></div>\
  111. <p>\
  112. SPA提供了两类视图,分别是<strong>页面视图</strong>和<strong>面板视图</strong>,不同视图之间通过设定的动画规则进行转换;\
  113. </p>\
  114. <h3>页面视图</h3>\
  115. <p>\
  116. 页面视图需要绑定路由规则,每次路由请求都会寻找匹配的路由规则,然后激活对应的页面视图;\
  117. </p>\
  118. <p>\
  119. 页面视图是用一组<code>&lt;div&gt;</code>节点构造的容器,模拟成<code>&lt;body&gt;</code>节点承载视图内容并覆盖整个视图区域;\
  120. <code>.spa-page-<em>customclassname</em></code>区分不同视图,添加自定义样式;\
  121. 每个节点的背景色默认透明;\
  122. <code>.spa-page-body</code>节点用来承载内容,通常在不需要半透明背景色的视图中,视图的背景色应该设置到该节点;\
  123. </p>\
  124. <pre>\
  125. &lt;!--页面视图的DOM结构--&gt;\n\
  126. &lt;div class="spa-page spa-page-<em>customclassname</em>"&gt;\n\
  127. &lt;div class="spa-page-body"&gt;\n\
  128. &lt;!--视图内容会被渲染到这里--&gt;\n\
  129. &lt;/div&gt;\n\
  130. &lt;/div&gt;\
  131. </pre>\
  132. <p>\
  133. <a href="#demo/newpage" class="btn btn-sm btn-info">打开新页面视图</a>\
  134. </p>\
  135. <pre>\
  136. //demo:打开新页面视图\n\
  137. var demoNewPage = {\n\
  138. route: "demo/newpage",\n\
  139. classname: "demo-newpage",\n\
  140. animate: "pushInLeft",\n\
  141. view: function() {\n\
  142. var $page = this\n\
  143. requirejs(["demo.newpage"], function(viewData) {\n\
  144. $doc.trigger("spa:initview", [$page, viewData])\n\
  145. })\n\
  146. }\n\
  147. }\n\
  148. \n\
  149. $doc.trigger("spa:route", [demoNewPage])\n\
  150. </pre>\
  151. <h3>面板视图</h3>\
  152. <p>\
  153. 面板视图不需要绑定路由规则,即没有对应的路由请求,需要在javascript中主动打开,面板视图可以用来做侧边栏菜单、对话框等应用组件;\
  154. </p>\
  155. <pre>\
  156. //打开面板\n\
  157. $doc.trigger("spa:openpanel", [<em>panelid</em>, <em>pushData</em>])\n\
  158. </pre>\
  159. <p>\
  160. 面板视图的容器结构是在页面视图容器结构的基础上进行扩展;\
  161. 增加了节点id<code>#spa-panel-<em>panelid</em></code>和classname<code>.spa-panel</code>;\
  162. </p>\
  163. <pre>\
  164. &lt;!--面板视图的DOM结构--&gt;\n\
  165. &lt;div id="spa-panel-<em>panelid</em>" class="spa-page spa-panel spa-page-<em>customclassname</em>"&gt;\n\
  166. &lt;div class="spa-page-bg"&gt;&lt;/div&gt;\n\
  167. &lt;div class="spa-page-body"&gt;\n\
  168. &lt;!--视图内容会被渲染到这里--&gt;\n\
  169. &lt;/div&gt;\n\
  170. &lt;/div&gt;\
  171. </pre>\
  172. <p>\
  173. <a href="#" data-panel="demoPanelSidemenu" class="btn btn-sm btn-info btn-demo-panel">侧边栏菜单</a>\
  174. <a href="#" data-panel="demoPanelAlert" class="btn btn-sm btn-info btn-demo-panel">提示对话框</a>\
  175. <a href="#" data-panel="demoPanelConfirm" class="btn btn-sm btn-info btn-demo-panel">确认对话框</a>\
  176. </p>\
  177. <pre>\
  178. //demo:侧边栏菜单\n\
  179. var demoPanelSidemenu = {\n\
  180. id: "demoPanelSidemenu",\n\
  181. classname: "demo-panel-sidemenu",\n\
  182. animate: "revealInRight",\n\
  183. view: function() {\n\
  184. var $panel = this\n\
  185. requirejs(["demo.panelsidemenu"], function(viewData) {\n\
  186. $panel.trigger("spa:initpanel", viewData)\n\
  187. })\n\
  188. }\n\
  189. }\n\
  190. \n\
  191. //demo:提示对话框\n\
  192. var demoPanelAlert = {\n\
  193. id: "demoPanelAlert",\n\
  194. classname: "demo-panel-alert",\n\
  195. animate: "zoomIn",\n\
  196. view: function() {\n\
  197. var $panel = this\n\
  198. requirejs(["demo.panelalert"], function(viewData) {\n\
  199. $panel.trigger("spa:initpanel", viewData)\n\
  200. })\n\
  201. }\n\
  202. }\n\
  203. \n\
  204. //demo:确认对话框\n\
  205. var demoPanelConfirm = {\n\
  206. id: "demoPanelConfirm",\n\
  207. classname: "demo-panel-confirm",\n\
  208. animate: "overlayInUp",\n\
  209. view: function() {\n\
  210. var $panel = this\n\
  211. requirejs(["demo.panelconfirm"], function(viewData) {\n\
  212. $panel.trigger("spa:initpanel", viewData)\n\
  213. })\n\
  214. }\n\
  215. }\n\
  216. \n\
  217. //添加面板\n\
  218. $doc.trigger("spa:panel", [demoPanelSidemenu, demoPanelAlert, demoPanelConfirm])\n\
  219. \n\
  220. //点击按钮打开面板\n\
  221. $doc.trigger("spa:openpanel", [<em>panelid</em>]) //panelid = demoPanelSidemenu, demoPanelAlert, demoPanelConfirm\n\
  222. </pre>\
  223. <h3>转换动画</h3>\
  224. <p>\
  225. SPA内置了22组视图转换动画,每组包含一个入场动画和一个相反的出场动画,比如<code>fadeIn & fadeOut</code>、<code>pushInRight & pushOutLeft</code>,\
  226. 其中有12组动画是只支持面板视图,比如<code>overlayInUp & overlayOutDown</code>,\
  227. </p>\
  228. <p>\
  229. 可以通过<code>$doc.trigger("spa:addTransitPageAnimates", <em>Animates</em>)</code>添加自定义的视图转换动画;\
  230. </p>\
  231. <p>\
  232. 如果视图通过异步加载,将触发遮罩层和loading动画(可自定义);\
  233. </p>\
  234. <h4>页面视图转换动画</h4>\
  235. <p>\
  236. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="default">default</a>\
  237. </p>\
  238. <p>\
  239. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="fadeIn">fadeIn</a>\
  240. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="fadeOut">fadeOut</a>\
  241. </p>\
  242. <p>\
  243. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="slideInLeft">slideInLeft</a>\
  244. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="slideOutRight">slideOutRight</a>\
  245. </p>\
  246. <p>\
  247. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="slideInRight">slideInRight</a>\
  248. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="slideOutLeft">slideOutLeft</a>\
  249. </p>\
  250. <p>\
  251. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="slideInUp">slideInUp</a>\
  252. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="slideOutDown">slideOutDown</a>\
  253. </p>\
  254. <p>\
  255. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="slideInDown">slideInDown</a>\
  256. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="slideOutUp">slideOutUp</a>\
  257. </p>\
  258. <p>\
  259. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="pushInLeft">pushInLeft</a>\
  260. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="pushOutRight">pushOutRight</a>\
  261. </p>\
  262. <p>\
  263. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="pushInRight">pushInRight</a>\
  264. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="pushOutLeft">pushOutLeft</a>\
  265. </p>\
  266. <p>\
  267. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="pushInUp">pushInUp</a>\
  268. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="pushOutDown">pushOutDown</a>\
  269. </p>\
  270. <p>\
  271. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="pushInDown">pushInDown</a>\
  272. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="pushOutUp">pushOutUp</a>\
  273. </p>\
  274. <p>\
  275. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="zoomIn">zoomIn</a>\
  276. <a href="#demo/transitpage" class="btn btn-sm btn-info btn-transitpage" data-animate="zoomOut">zoomOut</a>\
  277. </p>\
  278. <h4>面板视图转换动画</h4>\
  279. <p class="text-warning">注意:面板视图只支持正向的入场动画</p>\
  280. <p>\
  281. <a href="#" class="btn btn-sm btn-info btn-transitpanel" data-animate="overlayInLeft">overlayInLeft</a>\
  282. <a href="#" class="btn btn-sm btn-default" disabled="disabled">overlayOutRight</a>\
  283. </p>\
  284. <p>\
  285. <a href="#" class="btn btn-sm btn-info btn-transitpanel" data-animate="overlayInRight">overlayInRight</a>\
  286. <a href="#" class="btn btn-sm btn-default" disabled="disabled">overlayOutLeft</a>\
  287. </p>\
  288. <p>\
  289. <a href="#" class="btn btn-sm btn-info btn-transitpanel" data-animate="overlayInUp">overlayInUp</a>\
  290. <a href="#" class="btn btn-sm btn-default" disabled="disabled">overlayOutDown</a>\
  291. </p>\
  292. <p>\
  293. <a href="#" class="btn btn-sm btn-info btn-transitpanel" data-animate="overlayInDown">overlayInDown</a>\
  294. <a href="#" class="btn btn-sm btn-default" disabled="disabled">overlayOutUp</a>\
  295. </p>\
  296. <p>\
  297. <a href="#" class="btn btn-sm btn-info btn-transitpanel" data-animate="revealInLeft">revealInLeft</a>\
  298. <a href="#" class="btn btn-sm btn-default" disabled="disabled">revealOutRight</a>\
  299. </p>\
  300. <p>\
  301. <a href="#" class="btn btn-sm btn-info btn-transitpanel" data-animate="revealInRight">revealInRight</a>\
  302. <a href="#" class="btn btn-sm btn-default" disabled="disabled">revealOutLeft</a>\
  303. </p>\
  304. <p>\
  305. <a href="#" class="btn btn-sm btn-info btn-transitpanel" data-animate="revealInUp">revealInUp</a>\
  306. <a href="#" class="btn btn-sm btn-default" disabled="disabled">revealOutDown</a>\
  307. </p>\
  308. <p>\
  309. <a href="#" class="btn btn-sm btn-info btn-transitpanel" data-animate="revealInDown">revealInDown</a>\
  310. <a href="#" class="btn btn-sm btn-default" disabled="disabled">revealOutUp</a>\
  311. </p>\
  312. <p>\
  313. <a href="#" class="btn btn-sm btn-info btn-transitpanel" data-animate="pushPartInLeft">pushPartInLeft</a>\
  314. <a href="#" class="btn btn-sm btn-default" disabled="disabled">pushPartOutRight</a>\
  315. </p>\
  316. <p>\
  317. <a href="#" class="btn btn-sm btn-info btn-transitpanel" data-animate="pushPartInRight">pushPartInRight</a>\
  318. <a href="#" class="btn btn-sm btn-default" disabled="disabled">pushPartOutLeft</a>\
  319. </p>\
  320. <p>\
  321. <a href="#" class="btn btn-sm btn-info btn-transitpanel" data-animate="pushPartInUp">pushPartInUp</a>\
  322. <a href="#" class="btn btn-sm btn-default" disabled="disabled">pushPartOutDown</a>\
  323. </p>\
  324. <p>\
  325. <a href="#" class="btn btn-sm btn-info btn-transitpanel" data-animate="pushPartInDown">pushPartInDown</a>\
  326. <a href="#" class="btn btn-sm btn-default" disabled="disabled">pushPartOutUp</a>\
  327. </p>\
  328. <div class="page-header"><h1>API文档和用例</h1></div>\
  329. <p>\
  330. <a class="btn btn-lg btn-success" href="https://github.com/zhaoda/spa/wiki" target="_blank">spa wiki</a>\
  331. </p>\
  332. <div class="page-header"><h1>License</h1></div>\
  333. <p>\
  334. SPA遵循<a href="https://github.com/zhaoda/spa/blob/master/LICENSE" target="_blank">MIT协议</a>,无论个人还是公司,都可以免费自由使用。\
  335. </p>\
  336. </div>\
  337. </div>\
  338. ',
  339. init: function(pageData) {
  340. var $view = this
  341. // 获取hash
  342. function getHash(url) {
  343. url = url || location.href
  344. return url.replace(/^[^#]*#?\/?(.*)\/?$/, '$1')
  345. }
  346. $('pre', $view).each(function(i, e) { hljs.highlightBlock(e) })
  347. $view.on('click', '.btn-demo-panel', function(event) {
  348. event.preventDefault()
  349. var $btn = $(this),
  350. panelid = $btn.attr('data-panel')
  351. $doc.trigger('spa:openpanel', [panelid])
  352. })
  353. $view.on('click', '.btn-transitpage', function(event) {
  354. event.preventDefault()
  355. var $btn = $(this),
  356. animate = $btn.attr('data-animate'),
  357. hash = getHash($btn.attr('href'))
  358. $doc.trigger('spa:navigate', {hash: hash, pushData: {animate: animate}})
  359. })
  360. $view.on('click', '.btn-transitpanel', function(event) {
  361. event.preventDefault()
  362. var $btn = $(this),
  363. animate = $btn.attr('data-animate')
  364. $doc.trigger('spa:openpanel', ['demoPanelTransit', {animate: animate}])
  365. })
  366. $('.page-container-navbar', $view).trigger('spa:scroll')
  367. }
  368. })