本章将介绍如何使用avalon来实现前端路由功能。

我们需要用到两个avalon路由配套模块—— mmHistory.jsmmRouter.js 。其中mmHistory是用于历史管理,它会劫持页面上所有点击链接的行为,当这些链接是以 #/#!/ 开头,就尝试匹配路由规则,阻止页面刷新(通过hash方式或HTML5的replaceState方式)。mmRouter是给我们定义路由规则,路由规则可以更精细地指定每个参数(param)的匹配规则,如果符合就执行对应的回调,如果不符合,就进入error回调。

关于该路由系统更具体的描述,可以查阅这里

作为示例,我们打算制作一个网站的 “用户中心” 页面,其中左侧为导航列表,右侧为受左侧列表控制的内容显示区域:

该“用户中心”页面有这么几个要求:

⑴ 页面不跳转,仅做局部(即内容区域部分)刷新;

⑵ 可以通过不同的url进入对应的页面(即内容区域显示对应的内容);

⑶ 浏览器能记住url状态,比如从“账户详情”点入“我要充值”页面,然后再点击浏览器返回按钮,可以正确回到“账户详情”页面。

由于不是石器时代,自然不会再选择iframe这种内耗高、不友好的元素来架构页面(而且iframe也实现不了后面两个需求呀)。那么我们会很快联想到Ajax技术,这个想法很本质,不过单纯的Ajax也没办法达到我们的要求,所以才需要引入开头提到的两个avalon路由模块。

我们可以先写出简单的页面原型:

index.html:

  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title>账户中心</title>
  6. <link rel="stylesheet" href="css/user.css">
  7. <script src="js/lib/require.js" type="text/javascript" data-main="js/page/user"></script>
  8. </head>
  9. <body ms-controller="user" class="ms-controller">
  10. <script type="text/javascript">
  11. //这里给后端提供数据接口
  12. var conf = {
  13. username: {"id": "11", "name": "VaJoy"}
  14. }
  15. </script>
  16. <header>
  17. <span>{{username.name}}你好,欢迎来到账户中心</span>
  18. </header>
  19. <nav>
  20. <ul>
  21. <li><a href="#!/index">我的首页</a></li>
  22. <li><a href="#!/detail">账户详情</a></li>
  23. <li><a href="#!/recharge">我要充值</a></li>
  24. </ul>
  25. </nav>
  26. <article>
  27. 内容...
  28. </article>
  29. </body>
  30. </html>

user.js:

  1. require.config({
  2. baseUrl: 'js/lib/',
  3. paths:{
  4. avalon: 'avalon',
  5. domReady:'domReady',
  6. mmHistory: 'mmHistory',
  7. mmRouter: 'mmRouter',
  8. jquery: 'jq'
  9. },
  10. shim:{
  11. avalon: { exports: "avalon" },
  12. mmHistory:{ deps: ['avalon']},
  13. mmRouter:{ deps: ['avalon']}
  14. }
  15. });
  16.  
  17. require(['avalon',"domReady!"], function() {
  18. var vm = avalon.define({
  19. $id: "user",
  20. username:conf.username
  21. });
  22. avalon.scan();
  23. });

user.css:

  1. body,html{padding:;margin:;background: #EEE;}
  2. .ms-controller{visibility: hidden;}
  3. header{height: 50px;background: white;}
  4. header>span{display:block;padding: 16px;}
  5. nav{position: absolute;left:;margin-top:50px;width: 200px;}
  6. nav>ul>li{margin-top: 12px;}
  7. nav>ul>li>a{text-decoration: none;color:blue;}
  8. nav>ul>li>a:hover{color:red;}
  9. article{padding: 15px;margin-left:200px;min-height: 600px;background: white;}

运行结果如下:

接着我们要新建三个页面——mine.html、detail.html 和 recharge.html ,分别对应“我的首页”、“账户详情” 和 “我要充值” 的右侧内容,咱在里面随便写点内容意思意思即可,比如mine.html我就写了一句话:

接着我们默认先把mine.html引入到index.html中,这里我们借助avalon的 ms-include-src 接口,修改下index.html:

  1. <nav>
  2. <ul>
  3. <li><a href="#!/index">我的首页</a></li>
  4. <li><a href="#!/detail">账户详情</a></li>
  5. <li><a href="#!/recharge">我要充值</a></li>
  6. </ul>
  7. </nav>
  8. <article ms-include-src="pageUrl"> <!--这里使用ms-include-src接口,它会引入pageUrl属性所对应的文件-->
  9. </article>

接着修改 user.js的部分:

  1. require(['avalon',"domReady!"], function() {
  2. var vm = avalon.define({
  3. $id: "user",
  4. username:conf.username,
  5. pageUrl:"mine.html" //默认为mine.html
  6. });
  7. avalon.scan();
  8. });

运行如下:

接着是时候让 mmHistory.js 和 mmRouter.js 发挥它们的作用了,我们修改下user.js的部分代码:

  1. require(['mmHistory','mmRouter',"domReady!"], function() {
  2. var vm = avalon.define({
  3. $id: "user",
  4. username:conf.username,
  5. pageUrl:"mine.html" //默认为mine.html
  6. });
  7. function callback() {
  8. if(this.path==="/index"){
  9. vm.pageUrl="mine.html";
  10. }else {
  11. var path_tail = this.path.replace(/\//, "");
  12. vm.pageUrl = path_tail + ".html"; //动态修改pageUrl属性值
  13. }
  14. }
  15. avalon.router.get("/*path", callback); //劫持url hash并触发回调
  16. avalon.history.start(); //历史记录堆栈管理
  17. avalon.scan();
  18. });

注意由于在 require.config 的 shim 中我们已经定义了 mmHistory.js 和 mmRouter.js 是依赖于avalon的,故此处无须再引入avalon模块,requireJS执行该代码段之前会先加载好avalon的。

我们通过这两行代码执行了路由和历史记录的管理:

  1. avalon.router.get("/*path", callback); //劫持url hash并触发回调
  2. avalon.history.start(); //历史记录堆栈管理

其中router.get() 的第一个参数表示路由匹配规则,比如这里的“/*path”表示匹配全部路径,匹配到了就触发回调callback函数。

更多的匹配规则我们可以直接在  mmRouter.js 中查看注释信息:

router.get() 在触发callback前会生成一个this.path属性供callback调用(你也可以给回调函数定义一个参数,其默认值等同与path),其值为当前匹配到的路径,比如当url后缀变成 #!/recharge 的时候,this.path的值为匹配到的"/recharge" 。了解了这个之后,callback 函数也很好理解了:

  1. function callback() {
  2. if(this.path==="/index"){
  3. vm.pageUrl="mine.html"; //如果url后缀变成"#!/index",则pageUrl为“mine.html”
  4. }else {
  5. var path_tail = this.path.replace(/\//, ""); //去掉this.path值的第一个斜杠
  6. vm.pageUrl = path_tail + ".html"; //动态修改pageUrl属性值
  7. }
  8. }

这时候的运行结果如下所示:

自此便实现了我们的需求。但是这样还不够完美——每个页面的样式咋处理呢?

我们可以直接在页面上写<style>标签,或者直接写个<link>引入外部样式文件,但前者不好维护,后者毕竟不是插入到head中的不太规范。那么我们能否也用requireJS模块化动态引入样式文件呢?答案是肯定的,不过得借助于其组件css.js

以“账户详情”(detail.html)为例,我们创建一个detail.css文件,里面设置 .detail{color:red;}。

先确保require.config中的paths里加上了该组件:

  1. paths:{ //这里配置的地址,都是相对于上方的baseUrl的
  2. avalon: 'avalon',
  3. domReady:'domReady',
  4. mmHistory: 'mmHistory',
  5. mmRouter: 'mmRouter',
  6. css: 'css' //加上css.js
  7. }

然后修改detail.html页面内容:

  1. <section ms-controller="detail" class="detail ms-controller">
  2. 哟哟哟,这里是详情页面,{{username.name}}你好
  3. </section>
  4. <script>
  5. require(['avalon','css!../../css/detail.css'], function(){
  6. //下面的其实建议写成一个模块detail.js然后由require引入
  7. avalon.define({
  8. $id: "detail",
  9. username: conf.username
  10. });
  11. avalon.scan();
  12. })
  13. </script>

“css!/XXX.css” 是css.js的写法,注意以"css!"开头即可。

运行结果如下:

以上便是avalon前端路由的简单实现,本章的示例代码可以从这里下载。

后续章节可能会开始写一写avalon的API。共勉~

前端神器avalonJS入门(三)的更多相关文章

  1. 前端神器avalonJS入门(一)

    转自:http://www.cnblogs.com/vajoy/p/4063824.html avalonJS是司徒正美开发和维护的前端mvvm框架,可以轻松实现数据的隔离和双向绑定,相比angula ...

  2. 前端神器avalonJS入门(二)

    本章开始搭配requireJS来使用avalon,开始之前,我们可以对avalon进行精简改造(注:新版的avalon已提供了shim版本,无需再做如下的精简了,直接点这里获取). avalon源码里 ...

  3. avalonJS入门

    前端神器avalonJS入门(一) posted @ 2014-10-31 17:44 vajoy 阅读(8759) 评论(42) 编辑 收藏   avalonJS是司徒正美开发和维护的前端mvvm框 ...

  4. avalonJS入门(一)

    前端神器avalonJS入门(一) posted @ 2014-10-31 17:44 vajoy 阅读(1665) 评论(32) 编辑 收藏   avalonJS是司徒正美开发和维护的前端mvvm框 ...

  5. 前端之Android入门(3):MVC模式(上)

    很多Android的入门书籍,在前面介绍完布局后就会逐个介绍组件,然后开始编写组件使用的例子.每每到此时小伙伴们都可能会有些疑问:是否应该先啃完一本<Java编程思想>学点 Java 知识 ...

  6. web前端怎么样才能入门

    web前端怎么样才能入门,首先我们要从什么是初级web前端工程师说起: 按照我的想法,我把前端工程师分为了入门.初级.中级.高级这四个级别: 入门级别指的是了解什么是前端(前端到底是什么其实很多人还是 ...

  7. 常用 Gulp 插件汇总 —— 基于 Gulp 的前端集成解决方案(三)

    前两篇文章讨论了 Gulp 的安装部署及基本概念,借助于 Gulp 强大的 插件生态 可以完成很多常见的和不常见的任务.本文主要汇总常用的 Gulp 插件及其基本使用,需要读者对 Gulp 有一个基本 ...

  8. 【原创】NIO框架入门(三):iOS与MINA2、Netty4的跨平台UDP双向通信实战

    前言 本文将演示一个iOS客户端程序,通过UDP协议与两个典型的NIO框架服务端,实现跨平台双向通信的完整Demo.服务端将分别用MINA2和Netty4进行实现,而通信时服务端你只需选其一就行了.同 ...

  9. ORACLE SQL前端补0的三种方式。

    前端补0的三种方式. select lpad(sal,8,'0') from emp;select to_char(sal,'00000000') from emp;select substr('00 ...

随机推荐

  1. https://github.com/chenghuige/tensorflow-exp/blob/master/examples/sparse-tensor-classification/

        https://github.com/chenghuige/tensorflow-exp/blob/master/examples/sparse-tensor-classification/ ...

  2. python学习笔记(4)--函数

    1.函数 函数是指将一组语句的集合通过一个名字封装起来.要想执行这个函数,只需调用其函数名即可. 函数的特性: 1.减少重复代码 2.使程序变的课扩展 3.使程序变得易维护 语法定义: def pri ...

  3. 闪回查询(SELECT AS OF)

    使用Flashback Query的场景包括如下: 摘自官档 Recovering lost data or undoing incorrect, committed changes. For exa ...

  4. HTTP 的重定向301,302,303,307(转)

    HTTP 的重定向301,302,303,307(转) (2012-12-11 11:55:04) 转载▼ 标签: 杂谈 分类: 网络 301 永久重定向,告诉客户端以后应从新地址访问.302 作为H ...

  5. ubuntu14 备份

    备份命令 # tar cvpjf backup.tar.bz2 –exclude=/proc –exclude=/lost+found –exclude=/backup.tar.bz2 –exclud ...

  6. css3选择器

    原网站 cnblogs.com/tianshang/p/5982513.html通配符选择器 通配选择器的作用就是对页面上所有的元素都生效, 页面上的所有标签都会展示出通配符选择器设定的样式. 这样的 ...

  7. HTML导航栏

    先看效果(两种,1:自己写样式,写交互,2.用jQueryUI 的menu),如下图 第一种:       第二种:   第一种样式: 然后就开始准备了,单村用js和css也可以写出来,不过既然有jq ...

  8. jquery函数理解与运用

    javascript中有多种不用的方式去理解函数,函数类似于我们以前学过的数学函数,但是在程序设计中,我是按照下面的方式进行理解: 函数的理解: 函数是一个代码块,内容被包含在函数内,通常我们是把一些 ...

  9. 转:学习笔记: Delphi之线程类TThread

    学习笔记: Delphi之线程类TThread - 5207 - 博客园http://www.cnblogs.com/5207/p/4426074.html 新的公司接手的第一份工作就是一个多线程计算 ...

  10. ASP.NET MVC3中Controller与View之间的数据传递

    在ASP.NET MVC中,经常会在Controller与View之间传递数据,因此,熟练.灵活的掌握这两层之间的数据传递方法就非常重要.本文从两个方面进行探讨: 一.  Controller向Vie ...