Mojito项目实战:构建复合Mojit应用
前言
本文将深入探讨如何使用Mojito框架构建包含多个Mojit组件的复合应用。我们将创建一个图片浏览应用,包含图片列表和详情两个Mojit组件,实现组件间的交互和数据共享。
项目概述
我们将构建一个Flickr图片浏览应用,主要包含两个核心功能:
- 图片列表Mojit:显示Flickr图片缩略图,支持分页浏览
- 图片详情Mojit:显示选中图片的详细信息
这两个Mojit将协同工作,当用户点击列表中的缩略图时,详情Mojit将展示对应图片的详细信息。
环境准备
在开始之前,请确保已经完成Mojito的安装和基础配置。如果尚未完成,请参考相关文档进行设置。
创建基础应用
首先创建一个新的Mojito应用:
mojito create app flickr-list
cd flickr-list
构建图片列表Mojit
1. 创建Mojit
mojito create mojit simple PagedFlickr
mkdir mojits/PagedFlickr/lang
mkdir mojits/PagedFlickr/assets
2. 控制器实现
控制器主要负责处理业务逻辑,这里我们需要实现分页功能和图片数据获取:
YUI.add('PagedFlickr', function(Y, NAME) {
var PAGESIZE = 6;
Y.mojito.controllers[NAME] = {
index: function(ac) {
// 处理分页参数
var page = ac.params.getFromMerged('page');
var start = (page-1) * PAGESIZE;
// 获取图片数据
ac.models.get('ModelFlickr').getFlickrImages('mojito', start, PAGESIZE, function(err, images) {
// 构建视图数据
var data = {
images: images,
// 分页控制
prev: { url: selfUrl(ac, 'flickr', { page: page-1 } ) },
next: { url: selfUrl(ac, 'flickr', { page: page+1 } ) }
};
// 为图片添加详情链接
Y.Array.each(images, function(image) {
image.detail_url = '/detail/image/' + image.id;
});
ac.done(data);
});
}
};
// 辅助函数:生成URL
function selfUrl(ac, mojitType, mods) {
var params = Y.mojito.util.copy(ac.params.getFromMerged());
for (var k in mods) {
params[k] = mods[k];
}
return ac.url.make(mojitType, 'index', Y.QueryString.stringify(params));
}
}, '0.0.1', {requires: ['mojito-models-addon', 'mojito-util', 'querystring-stringify', 'ModelFlickr']});
3. 共享模型实现
我们使用共享模型来获取Flickr图片数据:
YUI.add('ModelFlickr', function(Y, NAME) {
Y.mojito.models[NAME] = {
getFlickrImages: function(queryString, start, count, callback) {
// 使用YQL查询Flickr API
var q = 'select * from flickr.photos.search(' + start + ',' + count + ') where text="' + queryString + '"';
Y.YQL(q, function(rawYqlData) {
// 处理返回数据
var photos = [];
Y.Array.each(rawYqlData.query.results.photo, function(rawPhoto) {
photos.push({
id: rawPhoto.id,
title: rawPhoto.title || "[" + queryString + "]",
url: buildFlickrUrlFromRecord(rawPhoto)
});
});
callback(null, photos);
});
}
};
// 辅助函数:构建Flickr图片URL
function buildFlickrUrlFromRecord(record) {
return 'http://farm' + record.farm + '.static.flickr.com/' +
record.server + '/' + record.id + '_' + record.secret + '.jpg';
}
}, '0.0.1', {requires: ['yql', 'jsonp-url']});
4. 视图模板
使用Mustache模板引擎渲染图片列表:
<div id="{{mojit_guid}}">
<ul class="pics">
{{#images}}
<li class="pic">
<a href="{{detail_url}}">
<img src="{{url}}" alt="{{title}}"/>
</a>
</li>
{{/images}}
</ul>
<div id="paginate">
{{#prev}}<a href="{{{url}}}">{{title}}</a>{{/prev}}
{{#next}}<a href="{{{url}}}">{{title}}</a>{{/next}}
</div>
</div>
5. 样式设计
为图片列表添加基本样式:
.pics .pic img {
height: 60px;
width: 60px;
}
ul.pics {
list-style-type: none;
}
ul.pics .pic {
padding: 1px;
}
#paginate span {
margin:1em;
}
构建图片详情Mojit
1. 创建Mojit
mojito create mojit simple FlickrDetail
mkdir mojits/FlickrDetail/lang
mkdir mojits/FlickrDetail/assets
2. 控制器实现
详情Mojit控制器处理图片详情请求:
YUI.add('FlickrDetail', function(Y, NAME) {
Y.mojito.controllers[NAME] = {
index: function(ac) {
var imageId = ac.params.getFromMerged('image') || '0';
// 参数验证
if (!imageId.match(/^\d+$/)) {
return ac.done({ type: 'error', message: 'Invalid image ID' });
}
// 获取图片详情
ac.models.get('ModelFlickr').getFlickrDetail(imageId, function(err, details) {
if (err) return ac.error(err);
// 处理详情数据
details.intl = {
DATE_POSTED: ac.intl.lang('DATE_POSTED'),
// 其他国际化字段
};
ac.done(details);
});
}
};
}, '0.0.1', {requires: ['mojito-models-addon', 'mojito-intl-addon', 'ModelFlickr']});
3. 扩展共享模型
在原有模型基础上添加获取详情的方法:
getFlickrDetail: function(imageId, callback) {
var q = 'select * from flickr.photos.info where photo_id="' + imageId + '"';
Y.YQL(q, function(rawYqlData) {
var photo = rawYqlData.query.results.photo;
photo.urls.image = {
type: 'image',
content: buildFlickrUrlFromRecord(photo)
};
callback(null, photo);
});
}
4. 视图模板
详情页模板展示图片信息:
<div class="FlickrDetail">
<div class="img">
<img src="{{urls.image.content}}" alt="{{title}}"/>
</div>
<table>
<tr class="title">
<th>{{intl.TITLE}}</th>
<td>{{#title}}{{.}}{{/title}}{{^title}}{{intl.TITLE_NONE}}{{/title}}</td>
</tr>
<tr class="description">
<th>{{intl.DESCRIPTION}}</th>
<td>{{#description}}{{.}}{{/description}}{{^description}}{{intl.DESCRIPTION_NONE}}{{/description}}</td>
</tr>
<!-- 其他信息展示 -->
</table>
</div>
应用配置
1. 路由配置
定义应用的路由规则:
[
{
"settings": ["master"],
"flickr_by_page": {
"verbs": ["get"],
"path": "/flickr/page/:page",
"call": "flickr.index"
},
"flickr_base": {
"verbs": ["get"],
"path": "/flickr",
"param": "page=1",
"call": "flickr.index"
},
"detail": {
"verbs": ["get"],
"path": "/detail/image/:image",
"call": "detail.index"
}
}
]
2. 应用配置
注册Mojit组件:
[
{
"settings": ["master"],
"specs": {
"flickr": {
"type": "HTMLFrameMojit",
"config": {
"child": {
"type": "PagedFlickr"
}
}
},
"detail": {
"type": "HTMLFrameMojit",
"config": {
"child": {
"type": "FlickrDetail"
}
}
}
}
}
]
运行与测试
启动应用服务器后,可以访问以下URL测试应用:
- 图片列表页:
/flickr - 图片详情页:
/detail/image/{image_id}
进阶优化
- 客户端渲染优化:可以添加客户端JavaScript实现无刷新加载详情
- 错误处理增强:完善各种边界情况的错误处理
- 性能优化:添加缓存机制减少YQL请求
- 响应式设计:使界面适配不同设备屏幕
总结
通过本文,我们学习了如何在Mojito框架中:
- 创建包含多个Mojit的复合应用
- 实现Mojit间的数据共享和交互
- 使用共享模型减少代码重复
- 配置路由和应用结构
这种架构模式可以扩展到更复杂的应用场景,为构建模块化、可维护的Web应用提供了良好基础。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



