源码网,源码论坛,源码之家,商业源码,游戏源码下载,discuz插件,棋牌源码下载,精品源码论坛

 找回密码
 立即注册
查看: 243|回复: 20

[JavaScript] 探索Emberjs制作一个简单的Todo应用

[复制链接]

7万

主题

861

回帖

32万

积分

论坛元老

Rank: 8Rank: 8

积分
329525
发表于 2012-11-7 11:08:10 | 显示全部楼层 |阅读模式
使用Emberjs制作一个简单的Todo应用,需要的朋友可以参考下 目标
使用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="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="http://cloud.github.com/downloads/wycats/handlebars.js/handlebars-1.0.rc.1.js"></script>
<script type="text/javascript" src="http://cloud.github.com/downloads/emberjs/ember.js/ember-1.0.0-pre.2.min.js"></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模板的方法是<script type="text/x-handlebars">/*视图助手*/</script>,还可以指定模板名称,在data-template-name属性里定义,待会我们添加列表项目时会需要用到。

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

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

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

{{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模板,并且会用到上面给出的模板名称,代码如下:

复制代码 代码如下:
<script type="text/x-handlebars" data-template-name="itemTemplate">

</script>


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

复制代码 代码如下:
<script type="text/x-handlebars" data-template-name="itemTemplate">
{{view.content}}
</script>


完成后,刷新页面,现在终于把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,顺便给个文字提示,然后添加到文本框模板的下面,修改后的代码如下:

复制代码 代码如下:
<script type="text/x-handlebars">
<span>请输入待办事项:</span>{{view App.AddItemView}}<br/>
<span>请选择优先级:</span>{{view Ember.Select contentBinding="App.selectController.content" selectionBinding="App.selectController.selected"}}
{{view App.ListView}}
</script>


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

要想让列表项也出现这个优先级,还得花点功夫啊。是时候用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值来显示,代码如下:

复制代码 代码如下:
<script type="text/x-handlebars" data-template-name="itemTemplate">
{{view.content.title}}
</script>


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

好了,最后一个功能,删除。跟添加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代码如下:

复制代码 代码如下:
<script type="text/x-handlebars" data-template-name="itemTemplate">
{{view.content.title}} <a href="#" {{action removeItem target="this"}} >X</a>
</script>


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

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

复制代码 代码如下:
full code
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Ember--第一个应用</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="http://cloud.github.com/downloads/wycats/handlebars.js/handlebars-1.0.rc.1.js"></script>
<script type="text/javascript" src="http://cloud.github.com/downloads/emberjs/ember.js/ember-1.0.0-pre.2.min.js"></script>
<script>

/********************
application
********************/

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

/********************
model
********************/

App.TodoModel = Em.Object.extend({
status:'',
value:'',
title:function(){
return '['+this.get('status')+']'+this.get('value');
}.property('status','value')
});

/********************
view
********************/
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','');
}
});

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' ));},
mouseEnter:function(){this.set('hover',true);},
mouseLeave:function(){this.set('hover',false);}
})
});



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

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

</script>
</head>
<body>
<script type="text/x-handlebars">
<span>请输入待办事项:</span>{{view App.AddItemView}}<br/>
<span>请选择优先级:</span>{{view Ember.Select contentBinding="App.selectController.content"
selectionBinding="App.selectController.selected"}}
{{view App.ListView}}
</script>
<script type="text/x-handlebars" data-template-name="itemTemplate">
{{view.content.title}} {{#if view.hover}}<a href="#" {{action removeItem target="this"}} >X</a>{{/if}}
</script>
</body>
</html>
回复

使用道具 举报

3

主题

2万

回帖

172

积分

注册会员

Rank: 2

积分
172
发表于 2022-8-14 02:13:11 | 显示全部楼层
谢谢分享,先下来用用
回复 支持 反对

使用道具 举报

0

主题

2万

回帖

186

积分

注册会员

Rank: 2

积分
186
发表于 2022-12-16 19:40:43 | 显示全部楼层
66666666666666666666
回复 支持 反对

使用道具 举报

12

主题

2万

回帖

431

积分

中级会员

Rank: 3Rank: 3

积分
431
发表于 2023-6-23 15:44:25 | 显示全部楼层
那三门,你们谁寂寞才快乐撒
回复 支持 反对

使用道具 举报

2

主题

2万

回帖

73

积分

注册会员

Rank: 2

积分
73
发表于 2023-8-30 02:03:46 | 显示全部楼层
看看怎么样再说
回复 支持 反对

使用道具 举报

4

主题

2万

回帖

262

积分

中级会员

Rank: 3Rank: 3

积分
262
发表于 2023-8-30 19:42:30 | 显示全部楼层
天天源码社区。。。。
回复 支持 反对

使用道具 举报

1

主题

2万

回帖

319

积分

中级会员

Rank: 3Rank: 3

积分
319
发表于 2023-9-1 10:33:47 | 显示全部楼层
好东西一定要看看!
回复 支持 反对

使用道具 举报

0

主题

2万

回帖

55

积分

注册会员

Rank: 2

积分
55
发表于 2023-11-5 12:55:19 | 显示全部楼层
的沙发水电费水电费
回复 支持 反对

使用道具 举报

4

主题

2万

回帖

303

积分

中级会员

Rank: 3Rank: 3

积分
303
发表于 2023-11-15 12:55:32 | 显示全部楼层
额UI废物iuhfujewfiewnnfen
回复 支持 反对

使用道具 举报

0

主题

2万

回帖

0

积分

中级会员

Rank: 3Rank: 3

积分
0
发表于 2023-12-10 15:40:06 | 显示全部楼层
1312315458748777
回复 支持 反对

使用道具 举报

高级模式
B Color Image Link Quote Code Smilies

本版积分规则

手机版|小黑屋|网站地图|源码论坛 ( 海外版 )

GMT+8, 2024-11-22 17:08 , Processed in 0.083646 second(s), 26 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表