在 第一部分 中,我们开发了 Firefox OS 待办事项应用的用户界面。在本部分中,我们将使用 Backbone 编写 JavaScript 代码使其具有功能。
待办事项应用的源代码可在 GitHub 上获得
注意:我建议您在继续之前回顾一下 第一部分,因为我在 #view-todos
中为每个待办事项添加了一个编辑按钮,并且按钮 CSS 模块进行了少量更改以使其更易于重用。
所需库
第一步是使用 volo 添加所需的 js 库。在项目的根目录 (/fos-todo-app
) 中执行以下所有 volo
命令。
添加 Requirejs/Text
Text 是一个加载程序插件,用于加载文本资源,如模板文件、CSS 等。
volo add requirejs/text
添加 Backbone.js
以下命令将添加 Backbone 及其依赖项,即 Underscore 和 jQuery。
volo add backbone
添加 Zepto.js
正如我在第一部分中提到的,我们将使用 Zepto 而不是 jQuery,因此我们需要添加 Zepto 并用它替换 jQuery。
volo add zepto
现在打开 /fos-todo-app/package.json
文件并从中删除以下行
"jquery": "github:jquery/jquery/2.0.2",
这将从我们的 volo 项目中删除 jQuery 依赖项。现在从 fos-todo-app/www/js/lib
目录中删除 jquery.js
文件。最后,我们需要告诉 Require.js 在请求 jQuery 时加载 Zepto。我们可以通过在 /fos-todo-app/www/js/app.js
中的 Require.js 配置中添加 map
属性来做到这一点。
requirejs.config({
baseUrl: 'js/lib',
// Map jquery to zepto
map: { '*': { 'jquery': 'zepto' } },
paths: {
app: '../app'
}
});
Backbone IndexedDB 适配器
在本教程中,我将使用 superfeedr 的 indexeddb 适配器。
volo add superfeedr/indexeddb-backbonejs-adapter/master/backbone-indexeddb.js
添加路径
再次,打开 /fos-todo-app/www/js/app.js
文件以将以下路径添加到 Require.js 配置中。
paths: {
app: '../app',
models: '../app/models',
collections: '../app/collections',
views: '../app/views',
templates: '../app/templates',
db: '../app/db',
}
现在在 www/js/app
目录中创建上面路径中提到的所有目录(模型、集合、视图、模板、db)。此外,删除 www/js/app/main.js
文件,因为我们不会使用它。
注意:对于移动应用,路由并不像 Web 应用那样重要。因此,我们不会在本应用中使用 Backbone 路由。
IndexedDB 配置
在 www/js/app/db
中创建一个 TodosDB.js 文件,该文件返回一个包含 IndexedDB 相关配置的对象。
define(['backbone', 'backbone-indexeddb'], function (Backbone, idxdb) {
Backbone.sync = idxdb.sync;
return {
id: 'todos-db',
migrations: [{
version: 1,
migrate: function (transaction, next) {
var store = transaction.db.createObjectStore('todos');
next();
}
}]
};
});
请注意,Backbone.sync
方法已替换为从 IndexedDB 适配器返回的 sync 方法。现在,它将与本地 IndexedDB 同步,而不是与服务器同步。
返回的对象中的 id
是数据库的唯一 ID。migrations
属性包含 version
和 migrate
方法。一旦执行 migrate
,数据库版本将更改为指定的值(在我们的例子中为 1)。migrate
方法由驱动程序调用以执行迁移。有关更多详细信息,请参阅 实现 标题下的内容。
待办事项模型
现在创建 www/js/app/models/Todo.js
文件并在其中添加以下代码。
define(['backbone', 'db/TodosDB'],
function (Backbone, TodosDB) {
var Todo = Backbone.Model.extend({
database: TodosDB,
storeName: 'todos',
defaults: {
task: 'my task',
completed: false,
created_on: new Date()
},
validate: function (attrs) {
if (!attrs.task) {
return 'Task can't be empty';
}
}
});
return Todo;
});
在上面的模型中需要注意的只有 database
和 storeName
属性。您只需将从 TodosDB 返回的数据库配置分配给 database
属性,而 storeName 是用于此模型对象的存储的名称。请记住,它与数据库配置中定义的唯一 ID 不同。
其余部分都是非常常规的 Backbone 内容。如果您了解 Backbone,则可以轻松理解正在发生的事情。
待办事项集合
现在在 www/app/js/collections/todos.js
中添加以下集合。
define(['backbone', 'models/Todo', 'db/TodosDB'],
function (Backbone, Todo, TodosDB) {
var Todos = Backbone.Collection.extend({
database: TodosDB,
storeName: 'todos',
model: Todo,
comparator: function (m) {
return m.get('created_on').getTime();
}
});
var todos = new Todos();
//fetch all records from IndexedDB
todos.fetch();
return todos;
});
每当模块返回实例时,我都会编写该文件以小写字母开头的名称,例如上面集合的 todos.js
。
确保在此集合和先前创建的模型中使用相同的 storeName
。除此之外,我们希望我们的集合根据创建时间排序,因此添加了 comparator
方法,该方法使用 getTime
方法返回自 1970 年 1 月 1 日以来的毫秒数。
创建集合后,将创建一个新实例,并使用 todos.fetch()
获取所有记录,并返回 todos
。
待办事项模板
现在创建一个模板文件 www/js/app/templates/todo.htm
并在其中添加以下代码。
这与我们为任务编写的 HTML 代码相同,只有一个区别。添加了 Underscore 模板相关的代码以检查模型的 completed
属性并在 span
元素中打印 task
属性。
显示待办事项列表
现在,我将向您展示每个功能是如何实现的,而不是向您展示每个模块,因此您可能需要在不同的模块/文件之间切换。我们需要做的第一件事是使用 www/js/app/collections/todos.js
集合(从 IndexedDB 中获取)显示任务列表。
待办事项模型视图
要显示待办事项列表,我们首先需要为 www/js/app/models/Todo.js
模型创建一个视图。此视图将列表中的每个待办事项表示为 li
元素。创建一个新文件 www/js/app/views/Todo.js
。
define(['underscore', 'backbone', 'text!templates/todo.htm'],
function (_, Backbone, todoTempl) {
var TodoView = Backbone.View.extend({
tagName: 'li',
template: _.template(todoTempl),
//events: {},
initialize: function () {
this.$el.attr('role', 'listitem');
},
render: function () {
var self = this;
//--- render template ---//
self.$el.html(self.template( self.model.toJSON() ));
//--- cache DOM elements ---//
self.$taskEdit = self.$('input[type=text]');
self.$taskView = self.$('label');
self.$btnEdit = self.$('.btn.edit');
return self;
}
});
return TodoView;
});
上面的视图将创建一个包含 todo.htm
模板中所需 HTML 的 li
元素。在渲染时。请注意,在 initialize
方法中,将 listitem
的 role
应用于 li
元素。此外,在渲染方法中缓存了一些 DOM 元素,因为稍后我们需要重复使用它们。
待办事项集合视图
现在,我们将为待办事项集合创建视图,该视图将表示 section#view-todos
中的 ul#todo-list
。此视图将创建一个上面定义的 TodoView
的新实例并将其附加到自身。在 www/js/app/views/Todos.js
中添加以下代码
define(['backbone', 'views/Todo', 'collections/todos'],
function (Backbone, TodoView, todos) {
var TodosView = Backbone.View.extend({
tagName: 'ul',
id: 'todo-list',
className: 'todo-list reset-list',
initialize: function () {
this.collection = todos;
this.listenTo(this.collection, 'add', this.addTodo);
this.listenTo(this.collection, 'reset', this.render);
this.listenTo(this.collection, 'sort', this.render);
},
addTodo: function (todo) {
var todoView = new TodoView({model: todo}).render();
this.$el.append(todoView.el);
},
render: function () {
this.$el.html('');
this.collection.each(this.addTodo, this);
return this;
}
});
return TodosView;
});
在 initialize
方法中,todos
集合被分配给 this.collection
。请记住,此 todos
集合是从 app/collections/todos.js
模块返回的实例。现在,每当我们 require
此模块(在其他模块中)时,它将始终返回集合的相同实例。基本上它充当 单例。
addTodo
方法用于通过将 todo
模型作为参数传递给 addTodo
来创建 TodoView
(views/Todo.js) 的新实例。然后,它使用链中的 render
方法进行渲染,最后将其附加到 ul
元素。
Do render
方法重复调用 addTodo
以获取 this.collection
中的每个项目。
ViewTodos 视图
现在我们需要创建一个视图来表示 section#view-todos
区域。这是将 TodosView (app/views/Todos.js
) 附加到的视图,它包含 footer
中的“添加”和“删除”按钮。为此视图创建 app/views/ViewTodos.js
文件。
define(['backbone', 'views/Todos', 'collections/todos'],
function (Backbone, TodosView, todos) {
var ViewTodos = Backbone.View.extend({
el: '#view-todos',
//events: {},
setBtnDelDisabled: function () {
if (todos.length) {
this.$btnDel.removeAttr('disabled');
} else {
this.$btnDel.attr('disabled', 'disabled');
}
},
initialize: function () {
//init todo list
this.todosView = new TodosView().render();
this.listenTo(todos, 'add', this.setBtnDelDisabled);
},
render: function () {
this.$('.view-content').append(this.todosView.el);
this.$btnDel = this.$('footer .btn.del');
this.setBtnDelDisabled();
}
});
return ViewTodos;
});
上面的视图不会创建新元素,因为未使用 tagName
,而是使用 el
属性来选择现有的 DOM 元素 #view-todos
。
setBtnDelDisabled
方法非常简单。如果集合中不存在待办事项,它将禁用 this.$btnDel
。否则,它通过删除 disabled
属性来启用删除按钮。this.$btnDel
包含 'footer .btn.del'
元素(在 render
方法中缓存)。
在 initialize
方法中,创建了 TodosView
(待办事项列表视图)的新实例,对其进行了渲染,并将其分配给 this.todosView
。然后 this
视图 (ViewTodos
) 开始侦听 todos
集合上的 add
事件。每当在 todos
集合中添加新项目时,都会触发 setBtnDelDisabled
。
在 render
方法中,todosView
集合被附加到当前视图 (#view-todos
)。然后 .btn.del
在 $btnDel
中被缓存。最后,调用 setBtnDelDisabled
以根据 todos
集合中的项目数量启用或禁用 $btnDel
。
引导
现在我们需要创建一个 ViewTodos
的新实例并在 app.js
文件中对其进行渲染。将 requirejs(['app/main']);
语句替换为以下代码。
requirejs(['views/ViewTodos', 'collections/todos', 'zepto'], function (ViewTodos, todos, $) {
new ViewTodos().render();
//--- for testing only ---//
window.todos = todos; //todos collection
window.$ = $; //zepto
});
todos
集合被设置为全局变量,以便您可以轻松测试您的应用是否成功地在该集合上执行操作(读取、添加、编辑、删除)。
测试
现在,在向我们的应用添加任何新功能之前,我们需要确保我们的代码在控制台中没有错误地运行。如果您在 Firefox 浏览器中进行测试,请确保使用某些 Web 服务器 (http://localhost/fos-todo-app) 运行它,因为在您尝试使用 file:///
时,IndexedDB 会报错。
注意:我注意到,如果在“隐私”中将历史记录设置为“Firefox 将:记住历史记录”,则 Firefox 会抛出 IndexedDB InvalidStateError
。因此,请确保在测试之前设置“记住历史记录”。这在 Chrome 中不会发生。此外,IndexedDB 在隐私浏览窗口中也会出现相同的错误。
在我的控制台中,当我第一次运行测试时,得到了以下输出。
opening database todos-db in version #1 onupgradeneeded = 0 => 1 migrate begin version from #0 migrate begin before version #1 migrate done before version #1 migrate begin migrate version #1 migrate done migrate version #1 migrate begin after version #1 migrate done after version #1 Migrated to 1 migrate setting transaction.oncomplete to finish version #1 migrate done transaction.oncomplete version #1 Done migrating execute : read on todos for undefined
只有当版本号与 app/db/TodosDB.js
中定义的版本号不同时,您才会获得上述输出,否则您会在控制台中看到一条读取消息。
添加待办事项
让我们在实现编辑、删除或标记为已完成功能之前先实现添加待办事项功能,因为通过添加待办事项,我们可以正确测试从 IndexedDB 添加和获取待办事项列表的功能。
ViewAdd 视图
在实现此视图之前,让我们回顾一下我们想要在其中实现的功能。
我们希望通过使用 CSS3 动画打开此视图。很明显,我们希望此视图在点击页脚中的“完成”按钮时在 todos
集合中添加一个新的待办事项。但最重要的是,在用户在文本框中输入一些文本之前,保持“完成”按钮处于禁用状态。当待办事项成功添加到 todos
集合并保存在 IndexedDB 中时,我们希望使用 CSS3 动画关闭此视图,并在动画结束时使用 aria-hidden
属性将其隐藏。类似地,页脚中的取消(叉号)按钮将执行相同的功能,但不会保存待办事项。
现在创建一个新的视图文件 app/views/ViewAdd.js
,它将处理 section#view-add
区域。
define(['backbone', 'views/Todos', 'collections/todos'],
function (Backbone, TodosView, todos) {
var ViewAdd = Backbone.View.extend({
el: '#view-add',
//--- Replace click with tap before creating final build ---//
events: {
//we assigned id to .btn.done so why not select it using that
'click #btn-add-done' : 'addTodo',
//'tap #btn-add-done' : 'addTodo',
'click .btn.del' : 'cancel',
//'tap .btn.del' : 'cancel',
'keyup #task' : 'setAddBtnDisabled',
'keypress #task' : 'addTodo'
},
setAddBtnDisabled: function () {
var taskLen = this.$task.val().length;
taskLen ? this.$btnAdd.removeAttr('disabled')
: this.$btnAdd.attr('disabled', 'disabled');
},
addTodo: function (e) {
var task = this.$task.val();
console.log('ViewAdd:addTodo');
//if Done button is clicked or Enter key is pressed and
//task must have length greater than 0
if ((e.type === 'click' || e.keyCode === 13) && task.length) {
todos.create({task: task, created_on: new Date()});
this.cancel();
return false;
}
},
cancel: function () {
this.$el.removeClass('slide-up-in').addClass('slide-down-out');
},
hideView: function (e) {
var $target = $(e.target);
if (e.animationName === 'slide-down-out') {
$target.attr('aria-hidden', 'true');
}
},
initialize: function () {
this.$task = this.$('#task');
this.$btnAdd = this.$('#btn-add-done');
this.$el.on('animationend', this.hideView);
},
render: function () {
this.$el.removeAttr('aria-hidden').removeClass('slide-down-out').addClass('slide-up-in');
this.$task.val('');
this.$btnAdd.attr('disabled', 'disabled');
return this;
}
});
return ViewAdd;
});
在 initialize
方法中,缓存了 #task
文本框和 #btn-add-done
。在第三行,将 animationend
事件附加到当前视图的 DOM 元素 (#view-add)。每当 ViewAdd 上的动画结束时,它将触发 hideView
方法。
hideView
方法仅在 slide-down-out
动画结束时才使用 aria-hidden
隐藏视图,因为我们不希望在打开 (slide-up-in
) 动画时隐藏视图。
在 render
方法中,通过删除 aria-hidden
、slide-down-out
类并添加 slide-up-in
类来使视图可见,以通过对其进行动画处理来显示视图。然后清除 #task
中的文本,并禁用 $btnAdd
,因为我们希望用户在 #task
中输入一些内容。
cancel
方法是当用户点击/点击 .btn.del
时触发的事件处理程序。此方法使用动画类关闭视图。
setAddBtnDisabled
处理程序在 keyup
事件上触发。此方法仅根据 #task
中的字符长度启用/禁用 $btnAdd
。使用 keyup
事件是因为我们需要在用户释放键后获取字符串长度。
addTodo
处理程序在两个事件 ('click #btn-add-done'
和 'keypress #task'
) 上触发。在此方法中,仅当用户点击了 #btn-add-done
或按下了 Enter 键并且用户必须在 #task
中输入了一些文本时,才会保存新任务。在这种情况下,将在 todos
集合中添加新任务,并调用 cancel
方法以隐藏 #view-add
。
ViewAdd 渲染
如前所述,我们不会在我们的应用中使用路由。因此,我们需要在用户点击 ViewTodos
页脚中的添加按钮时从 ViewTodos
启动/渲染 ViewAdd
。为此,通过将其添加到作为 ViewTodos
中 define
的第一个参数传递的数组中来加载 ViewAdd
。
define(['backbone', 'views/Todos', 'views/ViewAdd', 'collections/todos'],
function (Backbone, TodosView, ViewAdd, todos) {
//body...
});
然后取消 ViewTodos
中 events
属性的注释并在其中添加点击事件处理程序。
events: {
//'tap footer .btn.add' : 'showAddView'
'click footer .btn.add' : 'showAddView'
},
现在添加 showAddView
处理程序,它将渲染 ViewAdd
。
showAddView: function () {
console.log('showAddView');
this.viewAdd = new ViewAdd().render();
//Redefine showAddView
this.showAddView = function () {
this.viewAdd.render();
};
//Remove existing events and reattach then
//using this.events hash
this.delegateEvents();
},
上面的视图创建了 ViewAdd
的一个新实例,调用 render
方法并将 ViewAdd
的实例分配给 this.viewAdd
。然后它重新定义自身 (showAddView
),其中仅调用 render
方法而无需创建其新实例。最后,修改后的方法需要重新绑定,这可以通过 Backbone 的 delegateEvents
方法来完成。
测试
现在尝试使用 ViewAdd 添加一些待办事项,并使用 console.log(todos.toJSON())
在控制台中测试 todos
集合。
注意:我注意到 Ubuntu 上的 Firefox 21 中存在一个错误。当渲染 ViewAdd
(#view-add
) 时,固定区域/视图中的固定 footer
无法正确动画处理。此外,有时它不会在 ViewAdd
中显示 footer
。相同的代码在 Firefox OS 模拟器中运行良好。
编辑待办事项
现在让我们使编辑功能正常工作,但首先回顾一下它将如何工作。当用户点击每个待办事项旁边的编辑图标时,将出现一个文本框,显示与非编辑模式下显示的相同的待办事项文本,如下所示。
用户现在可以编辑文本并点击/敲击键盘上的 Enter 键以保存更改,或按 Esc 键以撤消更改并退出编辑模式。当然,Esc 键功能对手机用户没有用,因为 Firefox OS 屏幕键盘上没有 Esc 键。
我们将在 app/views/Todo.js
中实现此功能,因为 Todo
视图表示待办事项列表中的每个项目。在 Todo
视图中为编辑按钮的 click
和文本框的 keypress
添加事件。
events: {
//'tap label' : 'editTodo',
'click .btn.edit' : 'editTodo',
'keypress input[type=text]' : 'saveTodo'
},
现在在 Todo
视图中添加 editTodo
方法。
editTodo: function () {
var self = this;
console.log('editTodo');
self.$taskEdit.val(self.$taskView.find('span').text());
self.$btnEdit.attr('aria-hidden', 'true');
self.$taskEdit
.removeAttr('aria-hidden')
.removeClass('slide-left-out')
.addClass('slide-right-in')
.focus();
self.$taskView.attr('aria-hidden', 'true');
return false;
},
在进入编辑模式之前,span
中的文本会被复制到文本框中。然后隐藏编辑按钮($btnEdit
)。使用CSS3动画使文本框($taskEdit
)可见,并使其获得焦点,以便用户可以直接编辑。最后,我们需要隐藏$taskView
,以便用户只看到$taskEdit
。现在用户处于编辑模式,可以编辑任务文本。
但是,当用户点击/按下回车键并返回查看模式时,我们也需要保存更改。类似地,按Esc键退出编辑模式而不保存更改。添加saveTodo处理程序来执行这些操作。
saveTodo: function (e) {
var self = this;
//save in case of enter/return
if (e.keyCode === 13) {
console.log('enter');
self.$taskView.find('span').text(self.$taskEdit.val());
self.model
.set({
task: self.$taskEdit.val()
})
.save();
}
//27 is for escape key
if (e.keyCode === 13 || e.keyCode === 27) {
self.$taskEdit
.removeClass('slide-right-in')
.addClass('slide-left-out');
self.$btnEdit.removeAttr('aria-hidden');
}
},
saveTodo
事件处理程序非常简单。如果按回车键,则将文本从文本框复制到span
并保存在模型中。如果按回车键或Esc键,则隐藏文本框($taskEdit
)并显示编辑按钮($btnEdit
)。但是您可能想知道为什么不显示$taskView
?是的,我们需要在$taskEdit
动画完成后显示它。为此,请在render
方法中的return false;
之前添加以下事件处理程序。
self.$taskEdit
.on('animationend', function (e) {
if (e.animationName === 'slide-left-out') {
self.$taskEdit.attr('aria-hidden', 'true');
self.$taskView.removeAttr('aria-hidden');
}
});
测试
尝试编辑不同的待办事项,并尝试刷新应用程序(在Firefox和Firefox OS模拟器中),以验证它是否保存在IndexedDB中。如果您正在测试Firefox浏览器,请记住强制刷新有时无法加载使用Require.js修改后的文件。
标记待办事项为已完成
我们还将在Todo
视图中实现“标记为已完成”功能,我们在其中实现了编辑功能。首先,在复选框上添加一个事件处理程序,该处理程序将待办事项标记为已完成。
//'tap input[type=checkbox]' : 'markCompleted',
'click input[type=checkbox]' : 'markCompleted',
现在在Todo
视图中添加markCompleted
处理程序。
markCompleted: function (e) {
var isCompleted = !this.model.get('completed');
console.log('markCompleted');
this.model
.set({
completed: isCompleted
})
.save();
},
在这里,completed
属性被反转并再次保存在模型中。
测试
尝试将不同的待办事项标记为已完成或未完成。然后在控制台中尝试todos.toJSON()
,以确保它正在更改completed
标志。
删除待办事项
我们将以动态的方式实现删除,为用户提供更多可能性。以下是删除的工作原理。如果用户将一个或多个待办事项标记为已完成,则删除按钮将充当“删除已完成项”,否则将充当“删除所有项”。
其实现将跨越多个文件。首先打开ViewTodos
并为删除按钮添加一个处理程序。
//'tap footer .btn.del' : 'delTodos',
'click footer .btn.del' : 'delTodos',
添加delTodos
处理程序。
delTodos: function () {
/**
* Other possible solution for following if condition is
* this.$('#todo-list input[type=checkbox]:checked').length
* But I didn't used it just to avoid DOM access
*/
if (todos.where({completed: true}).length) {
//function as Delete Completed
if (confirm('Delete Completed Tasks?')) {
this.todosView.delCompleted();
}
} else {
if (confirm('Delete All Tasks?')) {
//function as Delete All
this.todosView.delAll();
}
}
this.setBtnDelDisabled();
},
在此处理程序中,使用Backbone的where
方法检查已完成的待办事项总数。如果有已完成的项,它将调用TodosView
的delCompleted
方法(我们将在稍后实现)。否则,它将调用delAll
方法。最后,调用setBtnDelDisabled
,这在本教程中已讨论过。
现在打开app/view/Todos.js
并在其中添加delCompleted
方法。
delCompleted: function () {
this.collection.remove(
this.collection.where({completed: true})
);
},
上述方法简单地删除了所有completed
属性为true
的模型。现在在同一视图中添加delAll
方法。
delAll: function () {
/**
* We can remove all models using reset
* this.collection.reset([]);
*
* But I used remove method because I want remove
* event to get fired for each model
*/
this.collection.remove(this.collection.models);
},
delAll
简单地从集合中删除所有模型。
从DOM中删除
我们需要做的最后一件事是从其模型被删除的相应DOM元素中删除。在app/views/Todo.js
视图的initialize方法中添加以下语句。
this.listenTo(this.model, 'remove', this.destroy);
Todo
视图将开始监听其model
的remove
事件。如果模型触发remove
事件,则将调用destroy
方法。因此,在同一视图中添加destroy
方法。
destroy: function () {
this.$el.remove();
this.model.destroy();
},
它只是从DOM中删除自身,并且destroy
用于将其从IndexedDB中删除。
测试
尝试使用删除按钮删除一些待办事项。测试两种情况。添加一些待办事项并将其中一些标记为已完成。然后尝试使用删除按钮并确保通过刷新应用程序删除了这些项。类似地,尝试删除所有情况。不要将任何项目标记为已完成,然后按删除按钮。它必须删除列表中的所有项目。
添加/选择联系人Web活动
应用程序几乎完成了。我们已经实现了所有CRUD操作。最后我想向您展示的是Web活动。我们希望为用户提供一个选项,以便在ViewAdd
(#view-add
)中的文本框中插入联系人信息。当用户点击ViewAdd中的插入联系人链接时,将触发Web联系人pick
活动,因此我们需要为插入联系人链接添加一个事件处理程序。
'click #activities .add-contact' : 'addContact'
现在添加addContact
处理程序。
addContact: function () {
var self = this,
pick = new MozActivity({
name: 'pick',
data: {
type: 'webcontacts/contact'
}
});
pick.onsuccess = function () {
var res = this.result;
self.$task.val(self.$task.val() + res.name[0] + '(' + res.number + ')');
};
pick.onerror = function () {
alert('ERROR: Unable to add contact!');
};
return false;
},
在上面的处理程序中,使用MozActivity
触发pick
活动。如果有多个应用程序可以处理联系人类型,则列表中将显示所有可以处理类型webcontacts
的应用程序。如果成功选择了联系人,则将触发onsuccess处理程序,并且联系人信息将存储在this.result
中。从result
中,名称和号码信息将附加到#task
文本框中。
测试
您无法在Firefox浏览器中测试此功能。您需要Firefox OS模拟器或一部真机才能测试它。
就是这样。我希望您喜欢本教程。请在评论中提供反馈。
关于 Fawad Hassan
我是一名JavaScript开发者,我喜欢处理单页应用程序、Firefox OS、基于PhoneGap的移动应用程序以及Node.js/Express.js后端。目前我在PLUMgrid(SDN相关的创业公司)工作,并且正在开发基于HTML5的网络操作系统GUI。除此之外,我还是Mozilla的支持者,在我的空闲时间里,我会推广Mozilla的产品。
关于 Robert Nyman [荣誉编辑]
Mozilla Hacks的技术布道师和编辑。发表演讲和博客文章,内容涉及HTML5、JavaScript和开放网络。Robert是HTML5和开放网络的坚定支持者,自1999年以来一直从事网络前端开发工作——在瑞典和纽约市。他还在http://robertnyman.com上定期发表博客文章,并且热爱旅行和结识新朋友。
6条评论