SPA的成功离开不这三个东西,分层架构,路由系统,储存系统。分层架构是我们组织复杂代码的关键,这里特指MVVM的avalon;路由系统是将多个页面压缩在一个页面的关键;储存系统特指本地储存,是安全保存大量数据的关键。本章节介绍的是avalon三柱臣之一的mmRouter(内含mmHistory)。

我们先上一个示例吧。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>路由系统</title>
<script src="avalon.js"></script>
<script>
require(["mmRouter"], function() {
var model = avalon.define({
$id: "test",
currPath: "",
params: {},
query: {},
args: "[]"
})
function callback() {
model.currPath = this.path
var params = this.params
if ("time" in params) {
params.time = avalon.filters.date(params.time, "yyyy年M月dd日")
}
model.params = params
model.args = "[" + [].slice.call(arguments).join(",") + "]"
model.query = this.query
}
avalon.router.get("/aaa/", callback)
avalon.router.get("/bbb", callback)
avalon.router.get("/ccc/:ccc", callback)
avalon.router.get("/ddd/{time:date}/", callback)
avalon.router.get("/eee/{count:\\d{4}}/", callback)
avalon.router.get("/fff", callback)
avalon.history.start({
basepath: "/avalon"
})
avalon.scan()
})
</script>
</head>
<body >
<div ms-controller="test">
<table width="100%" height="300">
<tr>
<td width="250">
<ul>
<li><a href="#!/aaa">aaa</a></li>
<li><a href="#!/bbb?uu=3445345&were=4324">bbb</a></li>
<li><a href="#!/ccc/etretr">ccc</a></li>
<li><a href="#!/ddd/2014-09-19">ddd</a></li>
<li><a href="#!/eee/2222">eee</a></li>
<li><a href="#!/fff?a=1&nn=4&dfg=676">fff</a></li>
</ul>
</td>
<td>
<div style="color:red">this.path: {{currPath}}</div>
<div style="color:blue">arguments: {{args}}</div>
<fieldset>
<legend>this.params</legend>
<ol>
<li ms-repeat="params"> {{$key}}: {{$val}}</li>
</ol>
</fieldset>
<fieldset>
<legend>this.query</legend>
<ol>
<li ms-repeat="query"> {{$key}}: {{$val}}</li>
</ol>
</fieldset>
</td>
</tr>
</table>
<div style="height: 600px;width:1px;"> </div>
<p id="eee">会定位到这里</p>
</div> </body>
</html>

眼见为实,可以看到mmRouter很好地在IE6下运行,对于高版本的浏览器更不在话下。回退按钮,hash如果与页面上的某个锚记同名,它也会自动定拉到那里去。

我们接着详细介绍一下它的用法吧。

  1. 先引入mmRouter(请将mmRouter.jsmmHistory.js这两个文件与avalon.js放在一起)
  2. 定义VM
  3. 定义路由规则
  4. 启动历史管理器
  5. 开始扫描

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

当用户点击页面链接时,路址栏会发生变化,avalon是参考了angular的方式来处理路址栏。

  • Hashbang模式(默认), 这个模式下所有浏览器都支持
  • HTML5模式, 这个只能应用于firefox, chrome, safari,IE10+,如果浏览器不支持此特性,即使你设置avalon.history.start({html5Mode:true}),它也是在Hashbang模式下运行。

当我们使用history API mode的时候,我们对于不同的浏览器,需要不同的链接, 但我们只需要提供其hash部分就行了,例如<a href=“#/aaa”>link</a>

当用户单击这个超链接时:

  • 在Hashbang mode中,URL会改为/index.html#!/aaa
  • 在HTML5 mode中,URL会改为/index.html/aaa

你会发现,Hashbang mode中的#!后面的部分等于HTML5 mode中的除域名外的所有部分。而#!其实是google的 _escaped_fragment_ 爬抓规则, 方便我们的AJAX应用也能被爬虫收录。当然,我们还需要在head标签内添加一个meta标签:

<meta name="fragment" content="!" />

想了解更多关于这个技术的信息,可以查看这里
下面是路由器的API列表:

  • avalon.history.start(opts), 开始监听URL变化,opts。
  • avalon.history.stop(), 中止监听URL变化。
  • avalon.router.get(path, callback),用于添加路由规则。第一个为路由规则,如"/aaa",
    "/bbb/:bbbId","/eee/{eeeId}/ddd/{dddId:[0-9]{6}}" 冒号后的东西或花括号的东西表示为参数,花括号模式下还可以指定匹配规则。callback为回调函数,框架会将冒号后的或花括中的匹配内容传进来,此外this对象,包含了path、 params、 query等对象与属性。
  • avalon.router.add(method, path, callback) , 添加回调,第一个为请求类型,如GET,POST,DELETE什么, 第2个为路由规则,第3个为回调函数
  • avalon.router.error(callback),如果没有一条路由规则满足此请求,那么就转交此回调处理,我们可以在里面写跳转到404页面这样的逻辑
  • avalon.router.navigate(path),强制触发对应路径的回调
  • avalon.router.setLastPath(path) , 这是框架自己调用,保存最近一次跳转的路径
  • *avalon.router.getLastPath() *,取得最近一次跳转的路径,比如用户F5强制页面,你在ready回调中执行此方法,得到path,然后将它放进navigate中就能回到原来的页面了。

最后我们再详细介绍一下路由规则,它是一个字符串,必须以/开头,它可以在每个/后直接接冒号,表示这之后到下一个斜线或末尾是一个参数。它也可以使用花括号表示里面的内容也一个参数。斜钱风格是来自backbone与express的,花括号风格是来自ui-router。花括号风格更为强大些,因此它可以指定更详细的匹配规则。

avalon.router.get("/ddd/:dddID/",callback)
avalon.router.get("/ddd/{dddID}/",callback)
avalon.router.get("/ddd/{dddID:[0-9]{4}}/",callback)
avalon.router.get("/ddd/{dddID:int}/",callback)

mmRouter默认有四个参数匹配器,分别叫做date, init, bool, string。

      $types: {
date: {
pattern: "[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[1-2][0-9]|3[0-1])",
decode: function(val) {
return new Date(val.replace(/\-/g,"/"))
}
},
string: {
pattern: "[^\/]*"
},
bool: {
decode: function(val) {
return parseInt(val, 10) === 0 ? false : true;
},
pattern: "0|1"
},
int: {
decode: function(val) {
return parseInt(val, 10);
},
pattern: "\d+"
}
}

decode方法是用来将我们从地址栏抽取出来的那些小字符串转换为想要的类型或格式。如果你想要更多效果,还可以自己添加,如avalon.router.$type.d4 = { pattern: ’[0-9]{4}’, decode: Number}

 avalon.router.get("/ddd/{dddID:d4}/",callback)

总而言之,mmRouter是远远比angular自带路由器与backbone那个强大N多。未来还会进一步开发类似ui-router那样基于状态管理的路由器,敬请期待!

迷你MVVM框架 avalonjs 学习教程20、路由系统的更多相关文章

  1. 迷你MVVM框架 avalonjs 学习教程19、avalon历史回顾

    avalon最早发布于2012.09.15,当时还只是mass Framework的一个模块,当时为了解决视图与JS代码的分耦,参考knockout开发出来. 它的依赖收集机制,视图扫描,绑定的命名d ...

  2. 迷你MVVM框架 avalonjs 学习教程18、一步步做一个todoMVC

    大凡出名的MVC,MVVM框架都有todo例子,我们也搞一下看看avalon是否这么便宜. 我们先从react的todo例子中扒一下HTML与CSS用用. <!doctype html> ...

  3. 迷你MVVM框架 avalonjs 学习教程3、绑定属性与扫描机制

    在MVVM框架中,你都会看到页面定了许多奇怪的属性,比如knockout的data-☆,angular的ng-☆,avalon的ms-☆,此外还有一些只写文本节点上的双花括号,它们统称为指令.ms-☆ ...

  4. 迷你MVVM框架 avalonjs 学习教程1、引入avalon

    avalon是国内最强大的MVVM框架,没有之一,虽然淘宝KISSY团队也搞了两个MVVM框架,但都无疾而终.其他的MVVM框架都没几个.也只有外国人与像我这样闲的架构师才有时间钻研这东西.我很早之前 ...

  5. 迷你MVVM框架 avalonjs 学习教程16、过滤器

    avalon的过滤器是参考自angular与rivets.它也被称做管道文本过滤器,它的处理对象只能是文本(字符串),它只能用在文本绑定中,并且只能是双花括号形式.下面是各大家的过滤器比较: rive ...

  6. 迷你MVVM框架 avalonjs 学习教程11、循环操作

    avalon是通过ms-repeat实现对一组数据的批量输出.这一组数据可以是一个数组,也可以是一个哈希(或叫对象).我们先从数组说起吧. 第二节就说,凡是定义在VM中的数组,如果没有以$开头或者没放 ...

  7. 迷你MVVM框架 avalonjs 学习教程4、数据填充

    MVVM是前端的究极解决方案,你们可能用过jQuery,但那个写的代码不易维护:你们可以听过说requirejs与seajs,传说中的模块开发,加载器,但它们的最终目标是打包:你们可能听过unders ...

  8. 迷你MVVM框架 avalonjs 学习教程2、模块化、ViewModel、作用域

    一个项目是由许多人分工写的,因此必须要合理地拆散,于是有了模块化.体现在工作上,PM通常它这为某某版块,某某频道,某某页面.某一个模块,必须是包含其固有的数据,样式,HTML与处理逻辑.在jQuery ...

  9. 迷你MVVM框架 avalonjs 学习教程22、avalon性能大揭密

    avalon之所以能在页面处理1W个绑定(angular对应的数字是2000),出于两个重要设计--基于事件驱动的双向绑定链及智能CG回收机制. avalon的双向绑定链是通过Object.defin ...

随机推荐

  1. net core 2.0学习笔记(一):开发运行环境搭建 (转)

    期待已久的.net core 2.0终于发布了!大家等的花儿都谢了. 不过比预期提前了一个多月,这在微软历史上还真的不多见.按照历史经验看,2.0版本应该比较靠谱,我猜这也是社区非常火爆的原因吧.下面 ...

  2. AppBox Mvc数据库初始化

    下载AppBoxMvc后,以为CTRL_F5运行后就能数据库初始化了.一直报失败 我的环境是VS2017,利用VS2017自带的数据库 后修改: 1.  修改AppBoxContext.cs publ ...

  3. java中String对象的存储位置

    public class Test { public static void main(String args[]) { String s1 = "Java"; String s2 ...

  4. 百度地图JavaScript如何清除指定类型的覆盖物

    由于一个地图中有很多种类型的覆盖物,由于某个覆盖物(一般是自定义)整个地图中只允许出现一次 那第一想到的就是,每次创建这个类型的覆盖物时先清除这一类型的覆盖物,比较简单判断覆盖物的类型 instanc ...

  5. 解决nginx启动时域名解析失败而导致服务启动失败的问题

    问题: nginx启动或者reload的时候,会对proxy_pass后面的域名进行DNS解析,如果解析失败,启动就会失败或者reload失败. 我们是to B的产品,客户的环境可能是不通公网的,因此 ...

  6. spring boot学习(4) SpringBoot 之Spring Data Jpa 支持(1)

    第一节:Spring Data Jpa 简介 Spring-Data-Jpa JPA(Java Persistence API)定义了一系列对象持久化的标准,目前实现这一规范的产品有Hibernate ...

  7. 设置多个ip ,实现ip欺骗

    网关和DNS填写: 使用IP欺骗功能必须得本地有多个可用IP,通常普通的PC机只有一个物理网卡,这就需要我们手工设置多IP绑定同一网卡:         a.开始菜单 -> 控制面板 -> ...

  8. [转]连连看游戏 C#

    源代码下载地址 http://files.cnblogs.com/files/z5337/%E8%BF%9E%E8%BF%9E%E7%9C%8B%E6%B8%B8%E6%88%8F.rar 代码由 & ...

  9. 【转载】Linux内存中buffer和 cached的比较

    经常遇到一些刚接触Linux的新手会问内存占用怎么那么多? 在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是linux内存管理的一个优秀特性,在 ...

  10. Linux下的压缩(zip)解压(unzip)缩命令

      .zip命令 zip -r myfile.zip ./* 将当前目录下的所有文件和文件夹全部压缩成myfile.zip文件,-r表示递归压缩子目录下所有文件. 2.unzip命令 unzip -o ...