您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
   
 
 
     
   
 订阅
  捐助
前端神器avalonJS入门(一)
 
作者:vajoy 来源:博客园 发布于 2015-03-17
   次浏览      
 

开始

我们可以在这里获取最新版本的avalonJS,然后将其引入页面中(本章先不考虑搭配requireJS,仅仅先玩一玩、介绍下):

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>初玩阿瓦隆</title>
<script type="text/javascript" src="avalon.js"></script>
</head>
<body>
<div></div>
</body>
</html>

接着,类似于ng的“ng-controller”,avalon的控制域属性名叫做“ms-controller”,你可以把它当作一个监听器,把它绑定到一个容器后,avalon就能扫描和监听这个容器内的所有(绑定了avalon方法或带有插值表达式的)元素了。

我们来给div加上这个监听器,并在里面写一个avalon插值表达式{{XXX}}:

<div ms-controller="wrap">{{a}}</div>

你现在运行它的话,还没有任何效果,因为我们还没有写脚本来让avalon工作起来。我们可以来这么一段简单的脚本:

<body>
<div ms-controller="wrap">{{a}}</div>
<script type="text/javascript">
var abc = avalon.define({ //abc是随便起的一个名字,用作该Model的载体
$id: "wrap", //告诉avalon这个Model是作用于哪个ms-controller的
a: "你好啊" //定义一个avalon对象属性“a”,其值是“你好啊”
});
avalon.scan(); //这句话可以不加,因为avalon有自己的DOMReady模块,会自动扫描全文。
</script>
</body>

在avalon中,我们用 avalon.define({ ... }) 的形式来定义一个Model实例(其参数可以看做一个avalon数据对象),其中的 $id 是内置属性,对应所要扫描和监控的控制域名。

我们还在内部定义了一个属性"a",故在对应的控制域(如这段代码对应的域是绑定ms-controller="wrap"的div标签)里,我们使用avalon插值表达式{{a}}的话,可以自动绑定其值“你好啊”。

注:最后一句 avalon.scan(); 可以不加上,不过后续我们会使用requireJS来配合使用avalon,届时会建议删掉avalon的DOMReady模块,故先养成加上scan的习惯。

上述代码运行效果如下:

当然,avalon有着更类似ng的写法:

avalon.define("wrap", function(vm) {
......
})

但个人觉得没必要,还是下方的写法来的简单(本系列后续的实例也将遵从该写法):

var vm = avalon.define({
$id:wrap,
......
})

下面这段代码可以帮你更好了解avalon的控制域:

<body>
<div ms-controller="wrap">{{a}}</div>
<div ms-controller="wrap2">
{{a}}
<span>{{b}}</span>
</div>
<script type="text/javascript">
var abc = avalon.define({
$id: "wrap",
a: "你好啊"
});
var def = avalon.define({
$id: "wrap2",
a: "大家好",
b: "哈哈哈"
});
avalon.scan();
</script>
</body>

执行效果如下:

两个作用域(ms-controller)之间可以互相访问彼此的数据,还记得我们给avalon.define的前面定义了一个载体么(var XX = avalon.define),利用它就能轻松获取:

<body>
<div ms-controller="wrap">{{a}}</div>
<div ms-controller="wrap2">
{{a}}
<span>{{b}}</span>
</div>
<script type="text/javascript">
var abc = avalon.define({
$id: "wrap",
a: "你好啊"
});
var def = avalon.define({
$id: "wrap2",
a: "大家好",
b: abc.a //获取第一个Model里的属性值
});
avalon.scan();
</script>
</body>

执行效果:

数据和视图同步

上方我们实现了非常简单的数据绑定,将一个avalon对象属性a绑定到DOM元素上。不过avalon更有趣和实用的地方是它实现了数据与视图的同步,说的简单点,我们用脚本修改了a的值,那么DOM上绑定的数据也会跟着改变(当然反过来也是一样的):

<body>
<div ms-controller="wrap">
<span>{{a}}</span>
<input ms-duplex="a" />
</div>
<script type="text/javascript">
var abc = avalon.define({
$id: "wrap",
a: "你好啊"
});
avalon.scan();
</script>
</body>

注意我们这里增加了一个 <input ms-duplex="a" /> ,其中的 ms-duplex 是avalon的双工绑定属性,它除了负责将VM中对应的值(如本例是a)放到表单元素的value中,还对元素偷偷绑定一些事件,用于监听用户的输入从而自动刷新VM。

执行如下:

实例

利用avalon数据-视图同步的特性,我们可以更便捷地、更少代码地实现某些功能。举个例子,我们来实现一个选项卡的功能:

如上图的选项卡你会如何实现呢?可能你会写两个ul来对应下方两个选项卡列表,每个ul里都写上4个li(或者让后端人员通过后端框架来写loop,从而动态生成li),然后你再把第二个ul隐藏了,接着写个方法,让鼠标移到第二个选项卡标题时,第一个ul隐藏,第二个ul显示,对吧。

还有右上角的 “更多XX” 的连接,也可以通过隐藏-显示的方式来实现

你的DOM代码可能是这样的:

<div>
<span id="gg">公告</span><span id="bd">媒体报道</span>
<a id="more_gg" href="#!/gg">更多公告</a><a id="more_bd" href="#!/bd">更多报道</a>
<ul id="gg_list">
<li><a href="#!/gg/1" title="公告文章标题1">公告文章标题1</a></li>
<li><a href="#!/gg/2" title="公告文章标题2">公告文章标题2</a></li>
<li><a href="#!/gg/3" title="公告文章标题3">公告文章标题3</a></li>
<li><a href="#!/gg/4" title="公告文章标题4">公告文章标题4</a></li>
</ul>
<ul id="bd_list">
<li><a href="#!/bd/1" title="媒体报道文章标题1">媒体报道文章标题1</a></li>
<li><a href="#!/bd/2" title="媒体报道文章标题2">媒体报道文章标题2</a></li>
<li><a href="#!/bd/3" title="媒体报道文章标题3">媒体报道文章标题3</a></li>
<li><a href="#!/bd/4" title="媒体报道文章标题4">媒体报道文章标题4</a></li>
</ul>
</div>

但使用avalon的话,一切都更简单:

<div ms-controller="list">
<span ms-mouseover="changeUl(gg)">公告</span>
<span ms-mouseover="changeUL(bd)">媒体报道</span>
<a ms-href="'#!/'+ more_name">{{more_text}}</a>
<ul>
<li ms-repeat="infoList">
<a ms-href="'#!/'+ more_name + '/' + el.id" ms-title="el.title">{{el.title}}</a>
</li>
</ul>
</div>

首先它只有一个“更多XX”的<a>标签,而且只有一个<ul>,而且不存在任何后端标签的介入就能实现数据循环绑定。

它的优势在数据越多的时候会越明显(例如每个ul要显示100条li)。

我们来看看avalon的脚本应当怎么写:

<body>
<script type="text/javascript">
var gg=[{"id":"1","title":"公告文章标题1"},{"id":"2","title":"公告文章标题2"}, {"id":"3","title":"公告文章标题3"},{"id":"4","title":"公告文章标题4"}];
var bd=[{"id":"1","title":"媒体报道文章标题1"},{"id":"2","title":"媒体报道文章标题2"}, {"id":"3","title":"媒体报道文章标题3"},{"id":"4","title":"媒体报道文章标题4"}];
</script>
<div ms-controller="list">
<span ms-mouseover="changeUl(1)">公告</span>
<span ms-mouseover="changeUl(0)">媒体报道</span>
<a ms-href="'#!/'+ more_name">{{more_text}}</a>
<ul>
<li ms-repeat="infoList">
<a ms-href="'#!/'+ more_name + '/' + el.id" ms-title="el.title">{{el.title}}</a>
</li>
</ul>
</div>
<script type="text/javascript">
var vm = avalon.define({
$id: "list",
more_name: "gg",
more_text: "更多公告",
gg:gg,
bd:bd,
infoList:gg,
changeUl:function(flag){
if(flag){ //鼠标移过“公告”选项卡头部
vm.more_name = "gg";
vm.more_text = "更多公告";
vm.infoList = vm.gg;
}else{ //鼠标移过“媒体报道”选项卡头部
vm.more_name = "bd";
vm.more_text = "更多报道";
vm.infoList = vm.bd;
}
}
});
avalon.scan();
</script>
</body>

执行效果:

我们来逐步分析下上方的代码。首先看第一段脚本:

<script type="text/javascript">
var gg=[{"id":"1","title":"公告文章标题1"},{"id":"2","title":"公告文章标题2"}, {"id":"3","title":"公告文章标题3"},{"id":"4","title":"公告文章标题4"}];
var bd=[{"id":"1","title":"媒体报道文章标题1"},{"id":"2","title":"媒体报道文章标题2"}, {"id":"3","title":"媒体报道文章标题3"},{"id":"4","title":"媒体报道文章标题4"}];
</script>

这里的 gg 表示“公告”的列表JSON数据,bd 则是“媒体报道”的列表JSON数据,你可以让后端的朋友直接在此处提供JSON数据过来。我们后续会利用avalon把这些数据绑定到页面视图上。

我们再看DOM结构:

<div ms-controller="list">
<span ms-mouseover="changeUl(1)">公告</span>
<span ms-mouseover="changeUl(0)">媒体报道</span>
<a ms-href="'#!/'+ more_name">{{more_text}}</a>
<ul>
<li ms-repeat="infoList">
<a ms-href="'#!/'+ more_name + '/' + el.id" ms-title="el.title">{{el.title}}</a>
</li>
</ul>
</div>

<span>中的 ms-mouseover 是avalon的“onmouseover”方法,其值 changeUl(X) 是我们在最后的avalon脚本中定义的一个事件方法,然后比如当鼠标移到“媒体报道”的span上,会触发绑定是 changeUl(0) 事件。

我们再看看 <a ms-href="'#!/'+ more_name">{{more_text}}</a> 这里的 ms-href 自然也是avalon中的“href”属性,可以植入avalon对象属性(如这里的more_name),也可以加上字符串(如这里的'#!/'),但要用引号括起来,不然会被当作avalon对象属性处理。

接着是最重要的部分:

<li ms-repeat="infoList">
<a ms-href="'#!/'+ more_name + '/' + el.id" ms-title="el.title">{{el.title}}</a>
</li>

我们使用了 ms-repeat="XX" 属性来绑定要重复显示的哈希数据,同时会生成一个代理VM对象,该代理对象拥有el,$index, $first, $last, $remove 等属性(点这里查看详细),其中我们用到的 el 表示指向当前的数据元素,从而可以通过 el.id ,el.title 来获取infoList数组对象的具体元素。

最后咱再看看avalon脚本:

<script type="text/javascript">
var vm = avalon.define({
$id: "list",
more_name: "gg",
more_text: "更多公告",
gg:gg, //获取公告JSON数据
bd:bd, //获取媒体报道JSON数据
infoList:gg, //infoList缺省值为公告JSON数据
changeUl:function(flag){
if(flag){ //鼠标移过“公告”选项卡头部
vm.more_name = "gg";
vm.more_text = "更多公告";
vm.infoList = vm.gg; //infoList变为公告JSON数据
}else{ //鼠标移过“媒体报道”选项卡头部
vm.more_name = "bd";
vm.more_text = "更多报道";
vm.infoList = vm.bd; //infoList变为媒体报道JSON数据
}
}
});
avalon.scan();
</script>

这里要注意的是我们用了

 gg:gg,   //获取公告JSON数据
bd:bd, //获取媒体报道JSON数据

来获取和存储“公告/媒体报道”的JSON数据到avalon对象的属性中(左侧的gg和bd是avalon对象属性,右侧的gg和bd是全局变量),这样做的原因是后续的回调事件changeUl(flag)要通过参数来判断和修改vm.infoList的值,而其值应同为avalon对象属性。如果把代码改为这样会出错(刚用avalon的朋友可能就会这样写):

<script type="text/javascript">
var vm = avalon.define({
$id: "list",
more_name: "gg",
more_text: "更多公告",
infoList:gg, //infoList缺省值为公告JSON数据
changeUl:function(flag){
if(flag){ //鼠标移过“公告”选项卡头部
vm.more_name = "gg";
vm.more_text = "更多公告";
vm.infoList = gg;
}else{ //鼠标移过“媒体报道”选项卡头部
vm.more_name = "bd";
vm.more_text = "更多报道";
vm.infoList = bd;
}
}
});
avalon.scan();
</script>

执行效果如下:

是的,鼠标第一次移上去的时候是无误的,但再移到其它选项卡的时候就不按常理出牌了,这是为什么?

我个人认为,在我们第一次获取全局变量之后,avalon可能会直接把该变量跟引用它的属性同步绑定了,比如这里的 “vm.infoList=gg” ,若vm.infoList的值改变了,那么gg的值也会同步改变。你可以这样来调试:

var vm = avalon.define({
$id: "list",
more_name: "gg",
more_text: "更多公告",
infoList:gg,
changeUl:function(flag){
console.table(gg); //console出“公告”变量的数据信息
if(flag){
vm.more_name = "gg";
vm.more_text = "更多公告";
vm.infoList = gg;
}else{
vm.more_name = "bd";
vm.more_text = "更多报道";
vm.infoList = bd;
}
}
});
avalon.scan();

结果(第一次回调事件的gg是正常的,但第二次开始就变成了媒体报道的数据):

因此我们要记得,若存在外部引入的数据,应用一个avalon对象属性保存起来。

第一篇入门文章就到这里,下一篇我们开始以配合requireJS的形式来使用avalon。

   
次浏览       
相关文章 相关文档 相关课程



深度解析:清理烂代码
如何编写出拥抱变化的代码
重构-使代码更简洁优美
团队项目开发"编码规范"系列文章
重构-改善既有代码的设计
软件重构v2
代码整洁之道
高质量编程规范
基于HTML5客户端、Web端的应用开发
HTML 5+CSS 开发
嵌入式C高质量编程
C++高级编程
最新活动计划
LLM大模型应用与项目构建 12-26[特惠]
QT应用开发 11-21[线上]
C++高级编程 11-27[北京]
业务建模&领域驱动设计 11-15[北京]
用户研究与用户建模 11-21[北京]
SysML和EA进行系统设计建模 11-28[北京]

Android手机开发(一)
理解Javascript
非典型ajax实践
彻底的Ajax
javascript 使用Cookies
使用 jQuery 简化 Ajax 开发
更多...   


Struts+Spring+Hibernate
基于J2EE的Web 2.0应用开发
J2EE设计模式和性能调优
Java EE 5企业级架构设计
Java单元测试方法与技术
Java编程方法与技术


某航空公司IT部 JavaScript实践
某电视软件 HTML5和JavaScript
中航信 JavaScript高级应用开发
大庆油田 web界面Ajax开发技术
和利时 使用AJAX进行WEB应用开发
更多...