avalonJS

前端神器avalonJS入门(一)

时间 2014-10-31 17:41:56  博客园精华区

原文  http://www.cnblogs.com/vajoy/p/4063824.html

主题 RequireJS

avalonJS是司徒正美开发和维护的前端mvvm框架,可以轻松实现数据的隔离和双向绑定,相比angularJS等前端框架它有如下优势:

1.压缩后仅有60多kb,而angular的min版是2MB左右(无视其gzip版);

2.兼容IE6+,符合天朝市场需求;

3.效率更高,跑起来比angular和knockout都要更快,在移动端上该优势会更大(avalon有移动端专版的avalon.modern.js)。关于其性能更详细的介绍可以看 这里

4.涵盖了angular的大部分功能,且实现方式更为便捷、上手更容易;

5.有配套的UI库(当然这个按需选择即可),由司徒正美及其“去哪儿”团队维护,有相关的中文文档(下方会提到),除了在github提交issue,你也可以加入正美的Q群79641290 来交流问题或提交bug。

(这位兄台,谷歌送温暖,开门查水表)

然而avalon也有自己的劣势——知名度较低。不过毕竟国产的东西没经BAT推广,要像seaJS那样驰名中外倒是不容易。

相关中文文档

正美其实私下写了不少avalon的官方api和教程,大家可以访问如下地址:

GitHub (下载最新的avalon以及实例(examples文件夹里),通过实例来掌握某些功能的实现是很好的学习途径)

Avalon简单介绍

Avalon快速入门 (比较快捷的入门课程,只用了几篇文章来介绍了最常用的一些功能)

API文章(正美的博文,篇幅较大,涵盖知识点很多,可以当作API来查阅,只是正美的博客排版真的。。。看起来略吃力),也可以在 这里 查看更规范的API。

Avalon乱炖 (强烈推荐,用了20多篇文章较详细地、渐进地介绍avalon,必读的就是啦)

本系列初衷

虽然正美已经细心编写了不少中文文档,不过有的文章技术门槛有点高,不太适合初学者,另外作为avalon的用户,以用户的角度来较详细地介绍avalon或许会更合适些。

本系列相比正美的教程,会更侧重于“怎么用”,而非其机制或原理的介绍。

另外也希望本系列能为推广avalon出一份绵薄之力,希望能让更多的前端爱好者开始接触avalon,并喜欢上这个前端利器。

本系列技术需求

本系列除了avalonJS之外,还会搭配requireJS做辅助,特别是后面我们会使用avalon的路由系统,来做一个单页面站点(放到移动端就是SPA了),需要requireJS及其插件来按需加载脚本和样式文件,故建议查阅本系列的朋友要多多少少会一点requireJS的知识。

个人还是觉得avalon搭配requireJS的话,在前端可谓hold住全场了(咱忽略node及其框架...)~

我们可以在 这里 获取最新版本的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扫描文档,从而执行起来
</script>
</body>

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

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

上述代码运行效果如下:

当然,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的前面定义了一个载体么(varXX= 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>

注意我们这里增加了一个 <inputms-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) 事件。

我们再看看 <ams-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就会把该变量变为一个avalon对象,导致该变量的值就这么被改变了,你可以这样来调试:

var vm = avalon.define({
    $id: "list",
    more_name: "gg",
    more_text: "更多公告",
    gg:gg,
    bd:bd,
    infoList:gg,
    changeUl:function(flag){
      console.table(gg); //console出“公告”变量的数据信息
      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();

结果(第一次回调事件的gg是正常的,但第二次开始就改变了):

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

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

时间: 2024-11-20 15:28:59

avalonJS的相关文章

AvalonJS+MVVM实战部分源码

轻量级前端MVVM框架avalon,它兼容到 IE6 (其他MVVM框架,KnockoutJS(IE6), AngularJS(IE9), EmberJS(IE8), WinJS(IE9) ),它可以更高效地运行于IE10等新版本浏览器中.代码量少,方便格式化输出. AvalonJS的使用很方便,类似基础标签绑定值,前端代码非常简洁,如果你有一定的JS基础,上手都是很快的.大家下来可以了解一下. 不闲聊,直接看部分代码示例: 1 <script type="text/javascript&

使用MVVM框架(avalonJS)快速开发运营活动

背景 在运营活动开发中,因为工作的重复性很大,同时往往开发时间短,某些情况下也会非常紧急,导致了活动开发时间被大大压缩,同时有些活动逻辑复杂,数据或者状态变更都需要手动渲染,容易出错,正是因为这些问题的存在,所以才有了MV*框架的诞生,比如大名鼎鼎的angularJS.今天就跟大家讲讲国产的MVVM框架avalonJS是如何快速进行开发的,同时大家也可以对比石器时代的开发模式(jquery或者zepto)与mv*模式的区别. avalonJS简介 avalonJS是前端大牛司徒正美开发和维护的m

利用Bootstrap+Avalonjs+EntityFramework 开发ASP.NET WebForm应用程序(上)

本文将介绍如何利用Bootstrap+Avalonjs+EntityFramework 开发ASP.NET WebForm应用程序,分为上下两篇.上篇主要介绍实现,下篇主要介绍界面. 打开Visual Studio Web Express2013新建一个空白应用程序 ContactSample--联系人示例 (1)数据库 引入界面文件BootStrap,JS文件jquery和avalon,建立联系人页面Contact.aspx. 打开数据库,设计数据库ContactSample,数据库比较简单,

迷你MVVM框架 avalonjs 入门教程(司徒正美)

迷你MVVM框架 avalonjs 入门教程 关于AvalonJs 开始的例子 扫描 视图模型 数据模型 绑定属性与动态模板 作用域绑定(ms-controller, ms-important) 模板绑定(ms-include) 数据填充(ms-text, ms-html) 类名切换(ms-class, ms-hover, ms-active) 事件绑定(ms-on,……) 显示绑定(ms-visible) 插入绑定(ms-if) 双工绑定(ms-duplex) 样式绑定(ms-css) 数据绑

迷你MVVM框架 avalonjs 沉思录 第1节 土耳其开局

#cnblogs_post_body p{ text-indent:2em; margin-top: 1em; } 正如一切传说的开端那样,有一远古巨神开天辟地,然后就是其他半神喧宾夺主.我们对最巨贡献与创建力的远古巨神懵懂不知,却对巫师们的话语津津乐道.这同样也是我们前端的现实. MVVM是来自.NET,另一个遥远的界域.前端,相对于后端,怎么看都是蛮夷之地.JS这个肩负着前端一切交互工作的语言,竟然被视为恶魔,屡屡被屏蔽禁用.些微可用的脚本,变量与函数没有组织地野蛮生长着,直到JAVA的传教

闲话js前端框架(1)——从avalonjs的模板说起

闲话js前端框架 前端人员=美工+设计+代码+测试 --题记 专题文章: 一.从avalonjs的模板说起 二.庞大的angularjs 三.再也不想碰DOM 四.组件化?有没有后端的事? 五.再看自己一年前设计的微型渲染引擎 六.在浏览器标准上做文章 七.抛开浏览器,构建应用容器 八.为何Flash.银光和Java都在网页端一蹶不振 本文属 西风逍遥游 原创, 转载请注明出处: 西风世界 http://blog.csdn.net/xfxyy_sxfancy 一.从avalonjs的模板说起 我

迷你MVVM框架 avalonjs 沉思录 第3节 动态模板

模板的发明是编程史上的一大里程碑,让我们摆脱了烦锁且易出错的字符串拼接,维护性大大提高. 都在JSP,ASP时代,人们已经学会使用include等语句,将多个页面片断拼接成一个页面. 此外,为了将数据库中的数据或业务中用到的变量输出到页面,我们需要将页面某个地方标记一下,将变量塞到里面去. 最后,出于方便循环输出一组数据,就需要将each语句从HTML里撕开一道口子,加上其他什么if语句,页面上其实变撕裂成两部分 一种是与后端语言相近的逻辑部分,一个是够为纯净的HTML部分,到最后,模板引擎就发

迷你MVVM框架 avalonjs 1.3.1发布

avalon1.3.1发布. interpolate支持注释节点做定界符,avalon.config({interpolate:["<!--","-->"]}) 监控数组添加pushArray方法,类似于push方法,不过参数是一个数组 data-duplex-changed回调会在第一次赋值就触发 添加一配置项,调整ms-repeat的对象池的大小,avalon.config({maxRepeatSize:30}) 迷你MVVM框架在github的仓库

本来说好的研究avalonJS最后演变成了看着大神在那边互相比拼实力。。js高级群的那些事

JS高级群的日常!写一个从10到0的倒计时,用console.log打印,不可以用 setInterval!本来说好的研究avalonJS最后演变成了看着大神在那边互相比拼实力.. 小森执行一个函数  没有全局变量 写一个从10到0的倒计时   用console.log打印  不可以用 setInterval 小白..额,可以多次调用setTimeout()吗 某个被打败的神Function fn(a){console.log(a--);if(a>=0)   Settimeout(fn,1000