使用 JQuery Mobile 和 LocalStorage 创建 CRUD Web 应用






4.98/5 (20投票s)
创建一个使用 JQuery Mobile 和 Localstorage 来创建、读取、更新和删除记录的 Web 应用
引言
本文旨在演示如何使用 JQuery Mobile 框架和 HTML5 创建一个可以在桌面和移动设备上运行的 Web 应用程序。该应用程序的目的是存储和检索用户的笔记。本文将展示一种简单的方法来存储和检索 LocalStorage 中的记录。这个示例应用程序最终将有 4 个屏幕,它们是:
- 启动屏 - 提供访问笔记的选择
- 笔记 - 以列表视图显示您的笔记,并提供添加新笔记和返回启动屏的功能
- 添加笔记 - 一个用于添加新笔记并保存的屏幕
- 编辑笔记 - 一个用于更新和删除笔记的屏幕
请注意:我假设您对 JQuery Mobile、LocalStorage、JavaScript 和 HTML5 有一定的了解,但我已经为您提供了上面关于从网络获取它们的部分信息的链接。
背景
我一直想用移动框架开发 CRUD 应用程序。我想要一些易于应用的东西,通过 Google 我找到了 JQuery Mobile。JQuery Mobile 是一个使用最新版 HTML5 开发移动应用程序的框架。您可以在网上找到关于这些框架的大量信息,但对我来说,访问 JQuery Mobile 的官方网站非常有启发性。对我来说,最有用的网站之一是 W3School,您可以在那里找到关于各种 Web 开发框架的大量信息。
虽然这个 Web 应用程序(我将称之为 NoteKeeper)可以使用 PhoneGap Build 轻松编译为混合应用,但这一步将不包含在本文中。
我读过的大多数关于 JQuery Mobile 的书籍更多的是关于设计用户界面,而不是操作用户界面的 API,比如读取和保存记录。通过阅读 JQuery 相关的书籍,我才了解到如何能够执行像存储和检索记录到本地存储这样简单的操作。我希望展示如何为不同的控件完成这项操作,以及用户如何在运行时更新它们。
这将展示如何绑定和执行按钮和链接的点击事件,使用元素的 data-* 属性,在运行时更新列表视图,在运行时定义消息框并根据最终用户的选择执行代码,使用 jquery 获取和设置元素属性,使用对象和 json 等。
使用代码
开发 NoteKeeper 的第一步是定义用户界面,即最终用户将看到的屏幕。如上所述,我们有四个屏幕:列出笔记、添加新笔记、编辑现有笔记和启动屏。您可以通过查看附加的源代码获得更多内容,因为我在这里只涉及主要功能以及它的作用。我还会解释幕后的代码,以处理当保存按钮被点击等事件时。
这个 Web 应用遵循 单页应用 框架,所有页面都在一个 HTML 页面内设计,并通过 ID 进行引用。从现在开始,我将快速解释每个页面的 HTML 定义以及该定义的最终输出。在查看 HTML 定义时,请将其与生成的输出屏幕关联起来。如上所述,我假设您具备 JQuery Mobile、HTML5 和 Javascript 的一些知识,才能完全理解本文。
启动屏 - HTML 定义和页面输出,这是 Web 应用启动时您看到的第一个屏幕。
<div id="pgMenu" data-role="page" data-theme="b" class="my-page">
<header id="pgMenuheader" data-role="header" data-position="fixed">
<h1>NoteKeeper
</h1>
</header>
<div id="pgMenucontent" data-role="content" class="content">
<ul data-role="listview" data-inset="true" id="sbItems">
<li data-icon="false">
<a data-transition="slide" id="sbNote" href="#pgNote">
<h2>Notes
</h2>
<p>Maintain Notes
</p>
<img height="200" width="100%" src="apps80.png" alt="Notes" class="ui-li-thumb">
</img>
</a>
</li>
</ul>
</div>
<footer id="pgMenufooter" data-role="footer" data-position="fixed">
<h1>Powered by JQM.Show © Anele Mbanga 2015
</h1>
</footer>
</div>
启动屏页面有一个带有 NoteKeeper 标题的头部。页面的内容是一个列表视图,其中包含一个名为 Notes 的项目。该项目有一个描述:维护笔记。上面 HTML 定义的结果设计如下面图 1 所示。选择“笔记”后,用户将被带到笔记列表,在那里将列出可用的笔记。
该屏幕实现的功能 - 这是笔记和最终用户之间的链接。如果将来向此 Web 应用添加其他页面,此启动屏可用于提供指向 Web 应用其他部分的链接。例如,如果此 Web 应用具有存储用户详细信息的函数,则可以在现有项目列表中添加一个项目来访问用户列表。
笔记列表 - HTML 定义和页面输出
笔记列表屏幕显示已保存到 Web 应用本地存储中的笔记列表。所有可用列表都从 LocalStorage 读取,然后在屏幕显示之前更新列表视图。稍后我将解释 JavaScript 中是如何做到的,现在让我们看看笔记列表的定义。
<div id="pgNote" data-role="page">
<header id="pgNoteheader" data-role="header" data-position="fixed">
<h1>Notes</h1>
<a data-role="button" id="pgNoteBack" data-icon="arrow-l" class="ui-btn-left">Back</a>
<a data-role="button" id="pgNoteNew" data-icon="plus" data-theme="b" class="ui-btn-right">New</a>
</header>
<div id="pgNotecontent" data-role="content" class="content">
<ul data-role="listview" data-inset="true" id="pgNoteList" data-autodividers="true" data-filter="true" data-filter-placeholder="Search Notes" data-filter-reveal="false">
<li data-role="list-divider">NoteHdr</li>
<li id="noNote">You have no notes</li>
</ul>
</div>
</div>
笔记列表屏幕有一个返回按钮,按下该按钮可让用户返回启动屏,该按钮定义为 pgNoteBack
。此处还有一个标题中的按钮用于添加新笔记,由 pgNoteNew
定义。我本可以在其元素定义中定义这些按钮点击时的操作,但我希望通过 JavaScript 代码来处理,稍后我将演示这一点。通过代码处理这些简单的点击事件的缺点是会使我的应用臃肿,因为它们只执行诸如从一个页面移动到另一个页面之类的简单功能。但是,如果需要在按钮事件触发时执行其他功能,最好在点击该按钮时调用一个函数。
此笔记列表定义的最终结果如下面图 2 所示。当 Web 应用首次启动时,它会显示“无笔记”,直到用户输入一些笔记并保存它们。每删除一条笔记,也会从 LocalStorage 中删除,并列出剩余的笔记。
当列表中的某个元素被选中时,会显示一个笔记更新屏幕,其中用户可以更新笔记的详细信息。一些元素的设置将如 JavaScript 中所述。
从上面的列表中,列表视图将具有自动数据分隔符,这意味着笔记将按字母分组,并且由于列表视图定义中存在 data-filter="true"
属性,因此它们是可搜索的。
该屏幕实现的功能 - 列出 LocalStorage 中存储的所有可用笔记。当用户选择一个笔记时,会提示他们进行更新和保存。它还提供了一个添加新笔记的链接。
新笔记 - HTML 定义和页面输出
接下来的屏幕旨在解释新笔记屏幕的设计和最终输出。
<div id="pgAddNote" data-role="page">
<header id="pgAddNoteheader" data-role="header" data-position="fixed">
<h1>Add Note</h1>
<a data-role="button" id="pgAddNoteBack" data-icon="arrow-l" class="ui-btn-left">Back</a>
</header>
<div id="pgAddNotecontent" data-role="content" class="content">
<form action="#" method="post" id="pgAddNoteForm" name="pgAddNoteForm">
<div data-role="fieldcontain">
<label for="pgAddNoteTitle" id="lblpgAddNoteTitle">Title<span style='color:red;'>*</span></label>
<input type="text" required="required" title="Enter title here." name="pgAddNoteTitle" id="pgAddNoteTitle" placeholder="Enter title here." autocomplete="off" data-clear-btn="true">
</input>
</div>
<div data-role="fieldcontain">
<label for="pgAddNoteDetail" id="lblpgAddNoteDetail">Details<span style='color:red;'>*</span></label>
<textarea name="pgAddNoteDetail" id="pgAddNoteDetail" placeholder="Enter details here." data-clear-btn="true" required="required"></textarea>
</div>
<div><button type="submit" id="pgAddNoteSave" class="ui-btn ui-corner-all ui-shadow ui-btn-b">Save Note</button>
</div>
</form>
</div>
</div>
下面图 3 中描绘的添加笔记屏幕具有上述定义。当用户从笔记列表页面选择“新建”按钮时,将显示一个提示用户创建新笔记的新屏幕。为了在移动设备上漂亮地排列表单内容,元素被放置在字段容器内,由 data-role="fieldcontain"
定义。笔记的所有必需字段都用红星标出,符合每个元素的样式定义。对于每条笔记,用户应输入标题和详细信息,然后点击“保存笔记”。
该屏幕实现的功能 - 为最终用户提供添加新笔记并将其保存到本地存储的功能,还可以返回笔记列表。标题将显示一个删除图标,以便快速清除标题内容。这使用了文本字段的 data-clear-btn="true"
属性。
编辑笔记 - HTML 定义和页面输出
编辑笔记屏幕与添加笔记屏幕相同,但它不添加新笔记,而是更新现有笔记。当用户选择更新现有笔记时,由于笔记的标题是唯一的,因此用于提示用户的标题文本框将被设置为只读。此屏幕还在标题中具有删除笔记的功能。
<div data-url="Title" id="pgEditNote" data-role="page">
<header id="pgEditNoteheader" data-role="header" data-position="fixed">
<h1>Edit Note</h1>
<a data-role="button" id="pgEditNoteBack" data-icon="arrow-l" class="ui-btn-left">Back</a>
<a data-role="button" data-href="ID" id="pgEditNoteDelete" data-icon="delete" data-theme="b" class="ui-btn-right">Delete</a>
</header>
<div id="pgEditNotecontent" data-role="content" class="content">
<form action="#" method="post" id="pgEditNoteForm" name="pgEditNoteForm">
<div data-role="fieldcontain">
<label for="pgEditNoteTitle" id="lblpgEditNoteTitle">Title<span style='color:red;'>*</span></label>
<input readonly="readonly" data-clear-btn="true" autofocus="true" type="text" required="required" title="Enter title here." name="pgEditNoteTitle" id="pgEditNoteTitle" placeholder="Enter title here." autocomplete="off"></input>
</div>
<div data-role="fieldcontain">
<label for="pgEditNoteDetail" id="lblpgEditNoteDetail">Details<span style='color:red;'>*</span></label>
<textarea name="pgEditNoteDetail" id="pgEditNoteDetail" placeholder="Enter details here." data-clear-btn="true" required="required"></textarea>
</div>
<div><button type="submit" id="pgEditNoteUpdate" class="ui-btn ui-corner-all ui-shadow ui-btn-b">Update Note</button>
</div>
</form>
</div>
</div>
上面定义的相应用户界面屏幕如下面图 4 所示。
该屏幕实现的功能 - 为最终用户提供编辑现有笔记以及带有提示删除它的功能。
我应该提到的另一件事是,当用户选择删除笔记时,应该提示他们是否要删除该笔记,如果 Web 应用中的某些信息不正确,则需要告知用户。为此,我定义了两个页面,一个作为 MessageBox
,另一个作为 Alert。
消息框 - HTML 定义和页面输出
使用页面元素向用户发出提示对我来说有点棘手,我仍在寻找其他方法来提供它们。我也不想使用插件,但想要 JQuery Mobile 提供的相同功能。为了使其工作,需要进行一些设置。
<section data-transition="pop" id="msgbox" data-role="dialog">
<header id="msgboxheader" data-role="header" data-position="fixed">
<h1>Confirm</h1>
</header>
<div id="msgboxcontent" data-role="content" class="content">
<div id="msgboxtitle">
</div>
<br><div id="msgboxprompt">
<p>Are you sure you want to delete this record?</p>
</div>
<br><div style="text-align: center;" id="msgboxbuttons" class="ui-grid-a">
<div class="ui-block-a">
<a data-method="" data-id="" data-topage="" id="msgboxyes" data-role="button" data-icon="check">Yes</a>
</div>
<div class="ui-block-b">
<a data-method="" data-id="" data-topage="" id="msgboxno" data-role="button" data-icon="delete" data-theme="b">No</a>
</div>
</div>
</div>
</section>
消息框的性质是动态的,取决于输入到它们的内容。这包括它们显示的标题、提示和按钮。在此示例中,上面的定义有两个按钮,一个“是”和一个“否”。消息框的标题以及显示给用户的提示都会改变。这两个描绘的按钮位于一个网格元素内。我还使用 data
- 元素,如 data-id、data-topage 和 data-method,来传递变量,指示当用户点击“是”或“否”按钮时应用程序应该做什么,这取决于这些 data- 属性。
例如,data-method
会指示执行哪个数据方法,data-id
指示处理哪个笔记 ID,data-topage
指示执行完所有操作后转到哪个页面。
这些按钮被命名为 msgboxyes
和 msgboxno ,因为我们还有一个警报框定义。
下面图 5 是当 Web 应用运行时,此消息框定义的输出。
该屏幕实现的功能 - 为最终用户提供提示,询问他们是否要删除笔记。
警报 - HTML 定义和页面输出
<section data-transition="pop" id="alertbox" data-role="dialog">
<header id="alertboxheader" data-role="header" data-position="fixed">
<h1>Error</h1>
</header>
<div id="alertboxcontent" data-role="content" class="content">
<div id="alertboxtitle">
</div>
<br><div id="alertboxprompt">
<p>An error has been encountered!</p>
</div>
<br><div style="text-align: center;" id="alertboxbuttons" class="ui-grid-solo">
<div class="ui-block-a">
<a data-method="" data-id="" data-topage="" id="alertboxok" data-role="button" data-icon="check" data-theme="b">Ok</a>
</div>
</div>
</div>
</section>
当用户输入了不正确的用户名和密码组合时,例如在登录 NoteKeeper 应用时,警报框会运行。在本练习中,这只是说明如何定义一个带有“确定”按钮的警报框。上面解释的消息框的相同数据元素也适用。我将在下面解释如何配置消息框提示,但请注意,这些相同的原则也可以应用于此警报框,以提示用户并稍后执行操作。
我们已经完成了 Web 应用 HTML 的定义,现在我们将深入研究使之工作的粘合剂。这将是 JavaScript 和本地存储访问。
NoteKeeper - JavaScript(代码在文件中按顺序解释)
$(function(){
// define the application
var NoteKeeper = {};
(function(app){
// variable definitions go here
var NoteLi = '<li ><a href="#pgEditNote?Title=LINK">ID</a></li>';
var NoteHdr = '<li data-role="list-divider">NoteHdr</li>';
var noNote = '<li id="noNote">You have no notes</li>';
我们正在定义一个具有命名空间的 NoteKeeper 应用程序,如 var NoteKeeper = {}
所定义的。
NoteLi
定义了笔记列表页面内列表视图的每个项目。当每个笔记被选中时,它应该打开 pgEditNote
页面,使用每个笔记的标题来编辑页面。当从本地存储读取笔记时,此变量将用于生成每个列表项。
NoteHdr
变量是显示在列表视图上的标题,它被定义为一个显示标题的分隔符。
noNote
- 是一个定义当没有笔记时显示的文本的变量。
接下来,我们定义所有 Web 应用运行时应触发的事件的绑定。
app.init = function(){
FastClick.attach(document.body);
app.Notesbindings();
app.checkForNotesStorage();
当应用初始化时,使用 FastClick,我们通过将 FastClick JavaScript 分配给应用程序的文档来确保在点击按钮时不会出现点击延迟。有关 FastClick 的更多详细信息,请访问此处。物理点击和单击事件之间有 300 毫秒的延迟,这旨在消除这种延迟。
其次,我们绑定所有笔记相关的事件,如列表视图点击、返回按钮点击、新笔记的“新建”按钮点击、保存按钮点击等。绑定事件告诉系统这些事件应该触发,但并不实际触发它们。我们只是让 Web 应用了解对元素有什么期望,例如,对于“保存”按钮,将发生点击事件,并且在该点击发生时应该做什么。
第三,我们希望系统运行 checkForNotesStorage
。这基本上表示,打开本地存储,检查笔记是否存在,如果存在,则加载它们。稍后我将解释绑定函数。
然后我们定义消息框的链接。
$('#msgboxyes').on('click', function(e){
e.preventDefault();
e.stopImmediatePropagation();
var yesmethod = $('#msgboxyes').data('method');
var yesid = $('#msgboxyes').data('id');
app[yesmethod](yesid);
});
当点击 msgboxyes (即消息框上的“是”按钮)时,阻止点击链接时的默认操作,并阻止事件在页面上冒泡,分别为
e.preventDefault
和 e.stopImmediatePropagation
。
var yesmethod = $('#msgboxyes').data('method');
获取要执行的方法的名称,该方法已分配给 msgboxyes 元素的 data-method 属性。
var yesid = $('#msgboxyes').data('id');
从 msgboxyes 元素的 data-id 属性中获取要处理的元素的 ID,最后。
app[yesmethod](yesid);
执行应用程序的关联方法,并将要处理的标题传递给它。
我们还在此处绑定启动屏的点击事件。
$(document).on('click', '#sbItems a', function(e){
e.preventDefault();
e.stopImmediatePropagation();
var href = $(this).attr('href');
$.mobile.changePage(href, {transition: 'slide'});
});
每个启动屏项目都是一个带有 href 属性的列表项。在这里,我们基本上从 href 属性中获取要跳转到的页面的详细信息,并使用 jquery 的 changePage
方法滑动到该页面。这只是展示了如何操作列表视图项目的点击事件。列表视图的名称是 sbItems,每个项目都是列表中的一个锚点项。
app.Notesbindings
用户已从列表视图中的可用笔记中选择了一个笔记。
app.Notesbindings = function(){
$(document).on('click', '#pgNoteList a', function(e){
e.preventDefault();
e.stopImmediatePropagation();
var href = $(this)[0].href.match(/\?.*$/)[0];
var Title = href.replace(/^\?Title=/,'');
$.mobile.changePage('#pgEditNote', {transition: 'slide'});
app.editNote(Title);
});
从这里开始,当从笔记列表屏幕选择一个笔记时,1. 获取所选项目的 href,2. 切换到 pgEditNote 屏幕,即用户可以更新笔记的地方,3. 执行
app.EditNote(Title) 方法。方法 3 基本上从本地存储读取笔记,并通过更新编辑屏幕的文本框和文本区域将其显示在屏幕上。
在显示笔记列表页面之前,我们希望显示现有笔记,因此我们添加此函数。
在显示笔记列表页面之前,使用可用笔记更新列表视图。
$(document).on('pagebeforechange', function(e, data){
var toPage = data.toPage[0].id;
if(toPage == 'pgNote'){
// restart the storage check
app.checkForNotesStorage();
}
});
我们将要显示的页面与托管笔记的页面(即 pgNote
)进行比较,如果是,则执行 checkForNotesStorage
。
在笔记列表页面,当用户点击返回按钮时。
$('#pgNoteBack').on('click', function(e){
e.preventDefault();
e.stopImmediatePropagation();
// move to the add new record screen
$.mobile.changePage('#pgMenu', {transition: 'slide'});
});
当用户按下笔记列表上的返回按钮时,Web 应用应该显示启动屏。如上所示,这只会使代码臃肿,并且可以通过在笔记列表标题的“返回”按钮定义中添加属性 href='#pgMenu' data-transition='slide
'
来轻松实现。但是,如果您可能想在点击返回按钮时执行其他操作,而不仅仅是转到另一个页面,那么您将编写类似的代码。我将在下面通过“新建”按钮来演示执行其他操作。
标题上的“新建”按钮与返回按钮功能相同,但它转到 pgAddNote 屏幕。如果您注意到此按钮,我们想存储访问
pgAddNote 页面的名称。
在笔记列表页面,当用户点击“新建”按钮时。
$('#pgNoteNew').on('click', function(e){
e.preventDefault();
e.stopImmediatePropagation();
$('#pgAddNote').data('from', pgNote);
// move to the add new record screen
$.mobile.changePage('#pgAddNote', {transition: 'slide'});
});
pgNoteNew 的这一部分,即添加新笔记时点击的按钮。
$('#pgAddNote').data('from', pgNote);
这告诉应用程序,对于 AddNote 屏幕,将一个名为“from”的数据属性设置为
pgNote ,告诉 Web 应用将此信息分配给页面以供以后处理。
当用户在“添加笔记”页面上并点击“返回”时,Web 应用应读取打开“添加笔记”页面的页面并相应地执行。
在“添加笔记”页面上,当用户点击返回按钮时。
$('#pgAddNoteBack').on('click', function(e){
e.preventDefault();
e.stopImmediatePropagation();
//which page are we coming from, if from sign in go back to it
var pgFrom = $('#pgAddNote').data('from');
switch (pgFrom) {
case "pgSignIn":
$.mobile.changePage('#pgSignIn', {transition: 'slide'});
break;
default:
// go back to the listing screen
$.mobile.changePage('#pgNote', {transition: 'slide'});
}
});
在“添加笔记”页面上,当用户点击“保存笔记”按钮时。
$('#pgAddNoteSave').on('click', function(e){
e.preventDefault();
e.stopImmediatePropagation();
// save the Note
var NoteRec;
NoteRec = pgAddNoteGetRec();
app.addNote(NoteRec);
});
pgAddNoteGetRec() 是一个函数,它从屏幕读取标题和详细信息,并将它们分配给一个对象,然后将该对象传递给
app.addNote 以将新笔记保存到本地存储。
在“编辑笔记”页面,当用户点击返回按钮时。
$('#pgEditNoteBack').on('click', function(e){
e.preventDefault();
e.stopImmediatePropagation();
// go back to the listing screen
$.mobile.changePage('#pgNote', {transition: 'slide'});
});
当用户从“编辑笔记”屏幕点击返回按钮时,将显示笔记列表页面。
在“编辑笔记”屏幕上,当用户点击“更新笔记”按钮时。
// click update when editing a record
$('#pgEditNoteUpdate').on('click', function(e){
e.preventDefault();
e.stopImmediatePropagation();
// save the Note
var NoteRecNew;
NoteRecNew = pgEditNoteGetRec();
app.updateNote(NoteRecNew);
});
当用户点击更新按钮时,标题和详细信息的原始内容将保存在一个对象中,该对象将传递给 app.updateNote 以使用笔记的新详细信息更新本地存储。笔记的标题是只读的,此时无法更改。这确保了标题的详细信息是防篡改的,因为它是唯一的。
接下来的部分需要进一步解释,因为它处理了上面定义的消息框。
在“更新笔记”屏幕上,当用户点击“删除”按钮时。
$('#pgEditNoteDelete').on('click', function(e){
e.preventDefault();
e.stopImmediatePropagation();
var Title = $('#pgEditNoteTitle').val();
Title = Title.replace(/-/g,' ');
$('#msgboxheader h1').text('Confirm Delete');
$('#msgboxtitle').text(Title);
$('#msgboxprompt').text('Are you sure that you want to delete this note?');
$('#msgboxyes').data('method', 'deleteNote');
Title = Title.replace(/ /g,'-');
$('#msgboxyes').data('id', Title);
$('#msgboxno').data('topage', 'pgEditNote');
$.mobile.changePage('#msgbox', {transition: 'pop'});
});
};
当用户在编辑笔记时点击“删除”按钮时,我们希望出现一个消息框,询问他们是否要删除该笔记。我们希望消息框是动态的,因为它可能被 notekeeper 应用中的其他模型使用。
当用户选择删除时,会发生以下情况。
1. 从屏幕读取标题。标题是唯一的。
var Title = $('#pgEditNoteTitle').val();
2. 标题中的任何空格都替换为 -。
Title = Title.replace(/-/g,' ');
3. 消息框的标题将变为“确认删除”。
$('#msgboxheader h1').text('Confirm Delete');
4. 我们设置一个标题来显示要删除的笔记,使用标题。
$('#msgboxtitle').text(Title);
5. 我们设置消息框的提示。
$('#msgboxprompt').text('Are you sure that you want to delete this note?');
6. 如果用户选择删除该笔记,我们希望 Web 应用运行 app.deleteNote 方法。这是通过为 msgboxyes 按钮分配 data-method 元素来实现的。
$('#msgboxyes').data('method', 'deleteNote');
7. 我们将“是”按钮的 data-id 设置为笔记的标题。
$('#msgboxyes').data('id', Title);
8. 如果用户在消息框中选择“否”,我们则返回“编辑笔记”页面。
$('#msgboxno').data('topage', 'pgEditNote');
9. 我们向用户显示新更新的消息框,使其在屏幕上弹出。
$.mobile.changePage('#msgbox', {transition: 'pop'});
您可以在上面图 5 中找到关于消息框如何定义的说明。笔记的绑定到此结束。以下是 Web 应用使用的一些其他有用函数,并附有注释。
//get the record to be saved and put it in a record array
function pgAddNoteGetRec(){
//define the new record
var NoteRec
NoteRec = {};
NoteRec.Title = $('#pgAddNoteTitle').val();
NoteRec.Detail = $('#pgAddNoteDetail').val();
return NoteRec;
}
//get the record to be saved and put it in a record array
function pgEditNoteGetRec(){
//define the new record
var NoteRec
NoteRec = {};
NoteRec.Title = $('#pgEditNoteTitle').val();
NoteRec.Detail = $('#pgEditNoteDetail').val();
return NoteRec;
}
//clear the forms for new data entry
function pgAddNoteClear(){
$('#pgAddNoteTitle').val('');
$('#pgAddNoteDetail').val('');
}
//clear the forms for new data entry
function pgEditNoteClear(){
$('#pgEditNoteTitle').val('');
$('#pgEditNoteDetail').val('');
}
当用户添加新笔记时,将执行此函数。先前从屏幕内容读取的 NoteRec 被传递给它以保存到本地存储。当保存新笔记时,Web 应用会通过执行
app.getNotes 来读取本地存储中的现有笔记。这将返回一个 json 对象。然后,新笔记将被添加到现有笔记中并保存到本地存储。
屏幕内容将被清除。Web 应用将停留在同一页面,直到点击“返回”。在后续的文章中,我们将更新 NoteKeeper,添加登录和注册屏幕,以便用户可以保护他们的笔记。
将笔记保存到本地存储。
app.addNote = function(NoteRec){
// get Note records.
var NotesObj = app.getNotes();
// define a record object to store the current details
var Title = NoteRec.Title;
Title = Title.replace(/ /g,'-');
NotesObj[Title] = NoteRec;
localStorage['notekeeper-notes'] = JSON.stringify(NotesObj);
// clear the form fields
pgAddNoteClear();
//which page are we coming from, if from sign in go back to it
var pgFrom = $('#pgAddNote').data('from');
switch (pgFrom) {
case "pgSignIn":
$.mobile.changePage('#pgSignIn', {transition: 'slide'});
break;
}
};
如前所述,当用户从列表视图中的现有笔记中选择一个笔记时,它将被编辑。此函数从指定的笔记标题中,从本地存储的现有笔记中读取笔记,然后使用笔记的保存内容更新标题文本框和详细信息文本区域。
从本地存储读取后,在屏幕上显示保存的笔记。
app.editNote = function(Title){
// get Note records.
var NotesObj = app.getNotes();
// lookup specific Note
Title = Title.replace(/ /g,'-');
var NoteRec = NotesObj[Title];
$('#pgEditNote').data('url', Title);
$('#pgEditNoteDelete').data('href', Title);
$('#pgEditNoteTitle').attr('readonly', 'readonly');
$('#pgEditNoteTitle').attr('data-clear-btn', 'false');
$('#pgEditNoteTitle').val(NoteRec.Title);
$('#pgEditNoteDetail').val(NoteRec.Detail);
};
更新现有笔记并持久化到本地存储。
app.updateNote = function(NoteRecNew){
// get Note records.
var NotesObj = app.getNotes();
// lookup specific Note
var Title = NoteRecNew.Title;
Title = Title.replace(/ /g,'-');
var NoteRec = NotesObj[Title];
// assign new values to read record
NoteRec.Title = NoteRecNew.Title;
NoteRec.Detail = NoteRecNew.Detail;
NotesObj[Title] = NoteRec;
localStorage['notekeeper-notes'] = JSON.stringify(NotesObj);
// clear the form fields
pgEditNoteClear();
// show the page to display after a record is deleted
$.mobile.changePage('#pgNote', {transition: 'slide'});
};
笔记详细信息已从“更新笔记”屏幕读取并分配给一个对象,该对象传递给上述方法。笔记从本地存储读取,如果该笔记已存在于本地存储中,则会被覆盖。更新页面的内容将被清除,用户将被带到笔记列表页面。
从本地存储中删除笔记。
app.deleteNote = function(Title){
// clear the set values// get the Note records from localStorage
var NotesObj = app.getNotes();
// delete selected Note
delete NotesObj[Title];
// write it back to localStorage
localStorage['notekeeper-notes'] = JSON.stringify(NotesObj);
// show the page to display after a record is deleted
$.mobile.changePage('#pgNote', {transition: 'slide'});
};
上述方法使用笔记标题作为键,从本地存储中删除现有笔记。首先从本地存储中读取笔记,如果具有该标题的笔记存在,则通过执行 delete NotesObj[Title]; 脚本将其删除。
以下是从本地存储获取所有笔记的方法。所有读取的笔记都被分配一个 json 对象。
从本地存储获取笔记。
app.getNotes = function(){ // get Note records var NotesObj = localStorage['notekeeper-notes']; if (!NotesObj){ NotesObj = {}; localStorage['notekeeper-notes'] = JSON.stringify(NotesObj); } else { NotesObj = JSON.parse(NotesObj); } return NotesObj; };
存储笔记的记录存储在名为 notekeeper-notes 的本地存储键中。由于我们可能还有其他要为 notekeeper 存储的详细信息,例如用户及其密码,因此将这些元素分开是一个显而易见的选择。如果没有现有笔记,一个空对象将被存储在存储中并作为空返回。
在笔记列表中显示笔记。
下面的代码读取本地存储中的所有可用笔记,遍历每个笔记,并将每个笔记的标题显示到笔记列表列表视图。这是运行时更新列表视图。
app.displayNotes = function(){
// get Note records.
var NotesObj = app.getNotes();
// create an empty string to contain html
var html = '';
// make sure your iterators are properly scoped
var n;
// loop over notes
for (n in NotesObj){
var nLnk = n.replace(/-/g,' ');
html += NoteLi.replace(/ID/g,nLnk).replace(/LINK/g,n);
}
$('#pgNoteList').html(NoteHdr + html).listview('refresh');
};
这是我一直想学习的最重要的事情之一。此过程获取本地存储中的所有笔记,并迭代每个笔记,在列表视图中创建一个新的可点击元素。当我们开始时,我们定义了几个参数,包括 NoteLi ,它是一个列表项。在这里,我们使用相同的项目,只需用每个笔记的标题更新它。列表视图项目元素只是基本的,但您可以添加计数气泡、侧边内容和项目描述。在紧随其后的文章中,我们将通过将用户添加到此 NoteKeeper 来更深入地探讨列表视图。
当所有笔记都读取完毕后,列表视图将用标题和新元素详细信息一次性更新。运行时更新元素的推荐功能之一不是通过使用 document 点符号创建元素,而是通过像这样创建元素并一次性更新项目的 .html 元素。
另一个重要事实是 .listview('refresh') 方法。这确保了我们的更改反映在列表视图中。
图 6 在这里显示了捕获到的笔记列表。此列表将根据添加的笔记数量而动态变化。在“搜索笔记”中键入内容将在您的列表视图中列出所有符合您搜索条件的笔记。
图 7,当没有列表存在时。
检查存储。
app.checkForNotesStorage = function(){
var NotesObj = app.getNotes();
// are there existing Note records?
if (!$.isEmptyObject(NotesObj)) {
// yes there are. pass them off to be displayed
app.displayNotes();
} else {
// nope, just show the placeholder
$('#pgNoteList').html(NoteHdr + noNote).listview('refresh');
}
};
我们希望 Web 应用在启动时检查本地存储,并向最终用户显示适当的通知或显示现有笔记。如果笔记存在,它们将通过调用 app.DisplayNotes 来显示,否则用户将被告知“无笔记”。
App Script 结束。
app.init();
})(NoteKeeper);
});
最后这三行代码结束了我们的应用定义,我们的应用程序已准备好执行。您可以将所有这些脚本保存在一个单独的文件中,并在主 html 文件中引用它,或者将其包含在 html 文件本身中。
离线工作。
作为本文的一部分,源代码中包含了一个 index.appcache 文件,该文件使此应用程序能够离线工作。
关注点
在开发 NoteKeeper 的过程中,我学会了如何创建消息框的行为,并根据用户的选择捕获“是”或“否”按钮并执行代码。这包括将数据项存储在元素的 data-* 属性中。从本地存储存储和检索数据也大开眼界,特别是将数据读取到 json 对象以及将其写回为文本。
屏幕导航也很重要,决定如何创建页面滑动效果以获得漂亮的用户界面。发现 FastClick 也有助于使 Web 应用的性能更快。在运行时处理列表视图并对其进行更新非常棒。
出于某种原因,主题对我来说仍然是一个严峻的挑战,因为它似乎在模拟器中不起作用,例如,当我将其更改为“e”时,没有任何反应。我将进一步研究如何在此处实现它。我打算探索 PhoneGap,了解如何将信息存储在设备文件中,并可能添加备份和恢复数据的功能,因为这可以用于任何其他通用工具。