Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4450634
  • 博文数量: 1214
  • 博客积分: 13195
  • 博客等级: 上将
  • 技术积分: 9105
  • 用 户 组: 普通用户
  • 注册时间: 2007-01-19 14:41
个人简介

C++,python,热爱算法和机器学习

文章分类

全部博文(1214)

文章存档

2021年(13)

2020年(49)

2019年(14)

2018年(27)

2017年(69)

2016年(100)

2015年(106)

2014年(240)

2013年(5)

2012年(193)

2011年(155)

2010年(93)

2009年(62)

2008年(51)

2007年(37)

分类: JavaScript

2014-12-24 17:00:24

文章来源:http://www.cnblogs.com/linerz/archive/2012/11/04/first-app.html

目标

使用Emberjs制作一个简单的Todo应用,实现这样一个效果:通过在文本框输入文本,创建一条代办事项,代办事项可以选择优先级,完成的事项可以删除。

准备

完成这个应用,需要做点准备:

1、创建一个html页面,暂时不管样式;

2、脚本:emberjs,handlebars、jQuery。这三个脚本可以从网上获得,我们将把他们加入到head标签里去。

制作

创建页面,加入脚本,就可以开始制作应用。html代码如下:

复制代码
doctype html> <html> <head> <meta charset="utf-8"> <title>Ember--第一个应用title> <script type="text/javascript" src="">script> <script type="text/javascript" src="">script> <script type="text/javascript" src="">script> head> <body> body> html>
复制代码

按照ember的要求,需要用Ember.Application.create()先创建应用实例,这也作为应用的命名空间。这个create方法可以传递一个对象属性ready,属性值是一个函数,在应用准备就绪时调用。Ember还可以使用缩写Em来代替。

在Ember中有一个Em.Logger对象,相当于window.console,可以用来调试。我们可以在这个ready加入一个消息,显示在控制台中。

现在,在head标签里再增加一个script标签来写应用的脚本,实例化一个ember应用,顺便把MVC各模块的区域也加上。脚本代码如下:

复制代码
/********************
    application
    ********************/ window.App = Ember.Application.create(
    {
        ready:function(){
        Em.Logger.info('欢迎使用待办事项应用');
        }
    }
    ); /********************
    model
    ********************/ /********************
    view
    ********************/ /********************
    controlle
    ********************/
复制代码

然后,我们需要一个输入框来输入代办事项,需要创建一个ember文本框视图。ember视图可以用Ember.View类来创建(使用create方法)或扩展(使用extend方法)一个新的视图类。不过对于文本框视图,ember提供了更直接的方式——Ember.TextField类,我们可以先使用这个类来扩展一个自定义的视图,然后再实例化添加到页面上。我们将这个文本框视图类命名AddItemView 。

在脚本代码里的view区域添加上文本框视图代码:

App.AddItemView = Ember.TextField.extend({

    });

可以给它加个提示语,html5支持placeholder,可以拿来用。还需要在按下回车时将内容添加到代表事项列表,这里需要用到一个属性:insertNewline,在按下回车时会调用相应的函数。加入后的代码如下:

App.AddItemView = Ember.TextField.extend({
    placeholder:'输入待办事项',
    insertNewline:function(){}
    });

由于现在还没确定具体添加方法,函数体暂时先不写。

用户在按下回车时增加一条代办事项,需要一个列表来显示,在ember中可以创建CollectionView来存放列表项目视图,对于CollectionView,默认会有一个content属性用于存放列表项目对象,其属性值是一个数组。为了让其列表显示为ul列表,需要定义CollectionView的标签名(tagName)为“ul”。我们给这个列表视图命名为ListView,并增加到文本框视图的下方。最后代码如下:

App.ListView = Ember.CollectionView.extend({
        content:[],
        tagName:'ul' });

现在如果打开页面,是没显示任何内容的,因为视图还没被渲染,要将视图显示出来,需要handlebar模板的支持。

现在来修改html页面的body块,加入刚创建的两个视图,看看效果。

添加handlebar模板的方法是,还可以指定模板名称,在data-template-name属性里定义,待会我们添加列表项目时会需要用到。

在模板里需要通过视图助手(helper)来添加视图,语法也很简单,用两个花括号对包裹,里面通过模板关键字来指定要显示的视图,如:{{view App.AddItemView}}。其他模板助手可以在handlebar网站查到:。

现在先把文本框跟列表视图添加到页面上,修改后的body代码如下:

复制代码
<body> <script type="text/x-handlebars"> <span>请输入待办事项:</span>{{view App.AddItemView}}/> {{view App.ListView}} script> body>
复制代码

现在刷新页面,会显示一句“请输入代办事项”跟一个文本框,列表由于没有内容,不会显示。

这个时候我们可以在content里添加点内容,比如content:['a','b','c'],然后刷新页面,你会发现列表区域只有三个小黑点(如果你没重置列表样式的话)。因为你在content里添加了三项,但列表项还没有指定一个显示的模板,所以,显示为空。为了让你看到效果,我们来给列表项定义个显示的模板吧。这里需要处理两个地方,第一是在页面加指定名称的模板,第二是在列表视图里定义列表项目的属性。

定义列表项目,需要用到itemViewClass,它会将每个content项传递进去并用指定的模板显示。先来修改列表视图ListView 吧,给它增加itemViewClass属性,这也是一种视图,所以需要用Ember.View来创建,在创建时同时指定用来显示的模板名称为itemTemplate,这个名称同时将为出现在html的handlebar模板名称里。修改后的代码如下:

复制代码
App.ListView = Ember.CollectionView.extend({
        content:['a','b','c'],
        tagName:'ul',
        itemViewClass: Ember.View.extend({
            templateName:'itemTemplate',
        })
    });
复制代码

还差一步就完成了,现在来修改html,我们需要在body里再新建一个handlebar模板,并且会用到上面给出的模板名称,代码如下:

接着同样是添加模板助手,要把每一个content项传递给助手,会用到view.content。添加如下代码:

完成后,刷新页面,现在终于把content里的内容显示出来了,而且,模板会自动加上li标签。

继续完善我们的应用。我们总不能把content的内容写成固定的吧,这样用户还怎么添加呢。所以,现在考虑把用户要添加的项目保存到一个数组里,然后content自己去取这个数组的内容。同时,ember框架支持双向绑定,当数组内容修改时,通过绑定的content也会同时改变,反之亦然。现在,就创建一个ember数组,然后跟content绑定吧。

ember数组可以通过ArrayController类来创建,它会把你传进去的普通javascript转变为一个新的ember数组对象,我们把用来管理项目的数组命名为todoStore,放到html页面的controller区域,创建的代码如下:

App.todoStore = Ember.ArrayController.create({
    content:[]
    });

现在可以把ListView 里的content数组放到这个todoStore 的数组里,然后绑定ListView 里的content到todoStore 上,这两个对象将修改为如下所示:

复制代码
App.ListView = Ember.CollectionView.extend({
        contentBinding:'App.todoStore',
        tagName:'ul',
        itemViewClass: Ember.View.extend({
            templateName:'itemTemplate' })
    }); /********************
    controlle
    ********************/ App.todoStore = Ember.ArrayController.create({
        content:['a','b','c']
    });
复制代码

Binding是个后缀,表示绑定,属性值是绑定的对象,默认取该对象的content属性。修改完成后刷新页面,如果你看到的页面跟修改之前的一样,说明修改成功了。接着,是时候去掉content里的值了,我们需要的数据将由用户在文本框里输入。

考虑现在的交互过程,用户在文本框输入内容,按下回车,程序获取到该事件,调用一个方法创建一个新对象,再把这个新对象送给todoStore ,由于绑定作用,列表会自动增加一项。

是时候改造下文本框视图了,还记得insertNewline吗?我们可以在这里创建新的项目。我们会用到三个方法:set()设置属性值、get()获取属性值、pushObject()添加数据,修改AddItemView 后的代码如下:

复制代码
App.AddItemView = Ember.TextField.extend({
    placeholder:'输入待办事项',
    insertNewline:function(){ var item = this.get('value');
            App.todoStore.pushObject(item); this.set('value','');
              }
    });
复制代码

现在刷新页面,然后输入内容,按回车,列表会添加输入的内容,说明修改成功,如果你没把todoStore 的content属性里的内容清空的话,现在会有4个列表项了。

距离我们的目标还有一半啊,我们还缺少两个功能:选择优先级跟删除完成的项目。

要增加下拉列表,可以使用另一个方便的视图:Ember.Select。我们可以直接在模板里直接创建一个,同样通过绑定,把下拉列表视图的content绑定到另一个ember对象上,然后设置默认选中的优先级。优先级也需要用到绑定,这样在页面上选择的时候,才会同时修改对应的ember对象里的内容。先来创建这个ember对象,自定义该对象的selected属性表示选中的值,其他名称也行,这段代码会加到todoStore对象的下面,命名为selectController,代码如下:

App.selectController = Ember.Object.create({
    selected:'低',
    content:['高','中','低']
    });

然后增加一个模板助手,并绑定selectController 里对应的属性,选中项的绑定需要用到selectionBinding,顺便给个文字提示,然后添加到文本框模板的下面,修改后的代码如下:

复制代码
复制代码

现在刷新页面就会出现下拉列表了。

要想让列表项也出现这个优先级,还得花点功夫啊。是时候用model了,我们来创建一个model类,当按下回车时,从这个类创建一个实例,再把实例扔到todoStore里就可以了,另外,模板也要跟着修改,文本框视图的创建方法也得改。这次改动比较多了点。另外,还会用到一个计算属性的功能,当依赖的属性变化时,自动更新。把这个model命名为TodoModel,放到model区域,创建代码如下:

复制代码
/********************
    model
    ********************/ App.TodoModel = Em.Object.extend({
    status:'',
    value:'',
    title:function(){ return '['+this.get('status')+']'+this.get('value');
    }.property('status','value')
    });
复制代码

status表示选择的优先级,value表示文本框里的值,title表示列表项目要显示的内容,这些属性名都是自定义的。其中title不需要提供,因为它设置为计算属性,依赖于status跟value属性,自动计算获取,property()方法就是ember函数转变为计算属性的方法,后面的参数表示title依赖的属性,当status或value变化时,就会自动给出。

接着修改AddItemView的insertNewline属性,需要取到两个数据,一个是文本框里的内容,一个是下拉列表里选中的项目。文本框的值已经知道怎么获取了,下拉列表的值呢?别忘了我们已经将选中项绑定到selectController里的selected属性了,直接从那里取就可以了。修改后的AddItemView代码如下:

复制代码
App.AddItemView = Ember.TextField.extend({
    placeholder:'输入待办事项',
    elementId:'add',
    insertNewline:function(){ var item = App.TodoModel.create({
                status:App.selectController.get('selected'),
                value:this.get('value')
            });
            App.todoStore.pushObject(item); this.set('value','');
              }
    });
复制代码

现在可以通过TodoModel类来实例化一个待办项目并添加到todoStore里了,最后是修改项目列表的模板itemTemplate来显示,在模板里需要取到当前项目的title值来显示,代码如下:

现在添加的新待办事项会显示优先级了。

好了,最后一个功能,删除。跟添加pushObject相反,删除用到的是removeObject。因为它是显示在每个列表项目里的,所以,需要修改itemViewClass跟itemTemplate模板,我们在itemViewClass里添加一个方法,当用户点击时调用,把该方法命名为removeItem,代码如下:

复制代码
App.ListView = Ember.CollectionView.extend({
        contentBinding:'App.todoStore',
        tagName:'ul',
        itemViewClass: Ember.View.extend({
            templateName:'itemTemplate',
            removeItem:function(){this.getPath( 'contentView.content' ).removeObject(this.get( 'content' ));}
        })
    });
复制代码

最后是在itemTemplate模板里增加一个接受点击的链接,用到的是action助手,第一个参数是方法名,target属性用来指定对象,点击时调用指定对象下的方法。修改后的itemTemplate代码如下:

现在新增加的项目都会有个叉在右边,点击时就把当前项目删除。

最后还可以做点改进,当鼠标移动到项目上时才显示删除链接,完成这个功能,需要修改itemViewClass以及在模板里增加逻辑判断助手{{#if}}。你可以自己试着去做,也可以看看最后完整的代码。



点击(此处)折叠或打开

  1. <!doctype html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>Ember--第一个应用</title>
  6. <script type="text/javascript" src=""></script>
  7. <script type="text/javascript" src=""></script>
  8. <script type="text/javascript" src=""></script>
  9. <script>

  10.     /********************
  11.     application
  12.     ********************/

  13.     window.App = Ember.Application.create({
  14.       ready:function() {
  15.         Em.Logger.info('欢迎使用待办事项应用');
  16.       }
  17.     });

  18.     /********************
  19.     model
  20.     ********************/

  21.     App.TodoModel = Em.Object.extend({
  22.       status: '',
  23.       value: '',
  24.       title: function() {
  25.         return '['+this.get('status')+']'+this.get('value');
  26.       }.property('status', 'value')
  27.     });

  28.     /********************
  29.     view
  30.     ********************/
  31.     App.AddItemView = Ember.TextField.extend({
  32.       placeholder: '输入待办事项',
  33.       elementId: 'add',
  34.       insertNewline: function() {
  35.         var item = App.TodoModel.create({
  36.           status: App.selectController.get('selected'),
  37.           value: this.get('value')
  38.         });
  39.         App.todoStore.pushObject(item);
  40.         this.set('value', '');
  41.       }
  42.     });

  43.     App.ListView = Ember.CollectionView.extend({
  44.       contentBinding: 'App.todoStore',
  45.       tagName: 'ul',
  46.       itemViewClass: Ember.View.extend({
  47.         templateName: 'itemTemplate',
  48.         removeItem: function(){ this.getPath('contentView.content').removeObject(this.get('content')); },
  49.         mouseEnter: function(){ this.set('hover', true); },
  50.         mouseLeave: function(){ this.set('hover', false); }
  51.       })
  52.     });



  53.     /********************
  54.     controlle
  55.     ********************/
  56.     App.todoStore = Ember.ArrayController.create({
  57.       content: []
  58.     });
  59.     
  60.     App.selectController = Ember.Object.create({
  61.       selected: '低',
  62.       content: ['高','中','低']
  63.     });

  64. </script>
  65. </head>

  66. <body>
  67.   <script type="text/x-handlebars">
  68.     <span>请输入待办事项:</span>{{view App.AddItemView}}<br/>
  69.     <span>请选择优先级:</span>{{view Ember.Select
  70.                   contentBinding="App.selectController.content"
  71.                   selectionBinding="App.selectController.selected"}}
  72.                               {{view App.ListView}}
  73.   </script>

  74.   <script type="text/x-handlebars" data-template-name="itemTemplate">
  75.     {{view.content.title}} {{#if view.hover}}<a href="#" {{action removeItem target="this"}} >X</a>{{/if}}
  76.   </script>
  77. </body>
  78. </html>

阅读(598) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~