我们在应用中添加了许多可靠的功能。然而,有一些缺失的特性,有些人可能会认为“好的 T1”有重要意义,对我们来说很重要,这样我们的应用就有了良好的用户体验。

在本章中,我们将:

  • 将 jQuery 添加到项目中,并使用它简化删除按钮
  • 通过使用 CouchDB 视图和 jQuery 向用户帖子添加基本分页
  • 使用 Gravatar 的 web 服务为所有用户添加配置文件图像

这些特性很有趣,只是添加了一些小功能,当您将其他库与 CouchDB 和 PHP 相结合时,它们也会让您看到可能的情况。

将 jQuery 添加到我们的项目中

尽管这本书主要是关于用 PHP 编写应用的,但 JavaScript 已经成为开发人员在构建伟大应用时工具带中几乎必不可少的工具。我们已经在 CouchDB 视图中使用了 JavaScript,但在本章中,我们将在最常见的用例中使用 JavaScript——改善用户体验。为了编写更简单的 JavaScript,我们将使用一个名为jQuery的流行库。如果您以前没有使用过 jQuery,您会惊喜地发现它在多大程度上简化了 JavaScript 中常见和复杂的操作。

安装 jQuery

幸运的是,jQuery 在任何项目中都非常简单。我们可以从下载 http://www.jquery.com ,但是,因为我们想关注速度,我们实际上可以使用它,而无需在存储库中安装任何东西。

行动时间-将 jQuery 添加到我们的项目中

由于使用 jQuery 的人大量涌入,谷歌已经建立了一个内容交付网络,为我们提供 jQuery 库,而我们的项目中不需要任何东西。让我们告诉我们的 layout.php文件在哪里可以找到 jQuery。

打开 layout.php文件,在 body部分末尾前添加以下代码:

<script type="text/javascript" src= "//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js">
</script>
</body>
</html>

刚才发生了什么事?

我们只是在 layout.php文件中的 body标记末尾之前添加了一行代码。这就是在我们的项目中使用 jQuery 所需要的全部!您可能想知道为什么我们决定将 jQuery 库一直放在文件的底部。最简单的解释是,当浏览器加载代码时,它一次加载一行代码。通过将 JavaScript 放在页面底部,它允许其他元素(如 CSS 和 HTML 标记)加载得更快,给用户一种加载速度快的印象。

该采取行动了——创建 master.js 并连接 Boostrap 的 JavaScript 文件

随着应用的增长,我们希望能够将 JavaScript 添加到外部文件中。让我们创建一个名为 master.js的文件,它将保存我们应用的所有 JavaScript,然后连接我们在第 6 章建模用户中下载的 Bootstrap 的 JavaScript 文件。

  1. 在 public/js文件夹中创建一个名为 master.js的新文件。
  2. 打开 layout.php文件,在 body部分末尾前添加以下代码:
    <script type="text/javascript" src= "//ajax.googleapis.com/ajax/libs/jquery /1.7.2/jquery.min.js">
    <script type="text/javascript" src= "//ajax.googleapis.com/ajax/libs/jquery /1.7.2/jquery.min.js">
    </script>
    <script type="text/javascript" src="<?php echo $this- >make_route('/js/bootstrap.min.js') ?>">
    </script>
    <script type="text/javascript" src="<?php echo $this- >make_route('/js/master.js') ?>">
    </script> 
    </body>
    </html>

    

刚才发生了什么事?

我们创建了一个名为 master.js的空白文件,我们的应用的所有 JavaScript 都将在该文件中运行。接下来,我们再次调整了我们的 layout.php文件,允许我们包括我们在第 6 章中下载的 boostrap.min.js文件,以及我们新创建的 master.js文件。

注

在编写 JavaScript 时,加载文件的顺序很重要。在本章后面编写 jQuery 时,浏览器必须首先加载 jQuery 文件,这样它才能知道什么是 jQuery 以及语法是如何工作的。

使用 jQuery 改进我们的网站

现在我们有了 jQuery,让我们直接使用它来稍微改进我们的站点。有很多不同的方法可以编写 jQuery 和 JavaScript 代码,但我们将坚持本书中的绝对基础知识,并尽量保持简单。

修复了我们的 delete post 操作,实际使用 HTTP delete

在上一章的前面,您可能已经注意到,当我们编码从用户配置文件中删除帖子时,我们实际上使用了 GET HTTP方法而不是 DELETE方法。这是因为不使用 JavaScript 很难触发 DELETE路由。因此,在下一节中,我们将改进删除过程,以使其工作如下:

  1. 用户点击帖子上的删除。
  2. jQuery 向我们的应用发出 DELETE AJAX请求。
  3. 我们的应用将删除 post 文档,并向 jQuery 报告一切都按预期进行。
  4. 帖子将从视图中淡出,用户无需刷新页面。

这将是对我们的用户配置文件的一个很好的改进,因为我们不需要每次执行操作时都重新加载页面。

是时候采取行动了——通过使用 AJAX 删除帖子来改善我们的用户体验

让我们通过在 master.js文件中添加一些代码,让我们能够使用 JavaScript 删除帖子,从而让 jQuery 变得更加成熟。如果您一开始不熟悉 jQuery 的语法,请不要不知所措;坚持下去,我想你会对结果非常满意的。

  1. 打开 public/js/master.js,通过向文件中添加 $(document).ready事件,确保页面加载完成后 jQuery 代码将运行。这段代码意味着一旦页面完成加载,该函数中的任何 JavaScript 代码都将运行:
    $(document).ready(function() {
    });

    
  1. 现在,让我们添加一个事件,将 click事件绑定到 HTML 中具有 delete类的任何按钮。每次点击我们的一个删除帖子按钮时, function(event)括号内的所有代码都将运行:
    $(document).ready(function() {
    $('.delete').bind('click', function(event){ 
    });
    });

    
  1. 让我们防止链接将我们带到一个新页面,就像它通常做的那样,带有一段名为 event.preventDefault()的代码。然后,让我们将点击链接的 href属性保存到一个名为 location的变量中,以便我们可以在 AJAX 调用中使用它:
    $(document).ready(function() {
    $('.delete').bind( 'click', function(event){
    event.preventDefault();
    var location = $(this).attr('href'); 
    });
    });

    
  1. 最后,让我们创建一个基本的 AJAX 请求,它将调用我们的应用并为我们删除帖子:
    $(document).ready(function() {
    $('.delete').bind( 'click', function(){
    event.preventDefault();
    var location = $(this).attr('href');
    $.ajax({
    type: 'DELETE',
    url: location,
    context: $(this),
    success: function(){
    $(this).parent().parent().fadeOut();
    },
    error: function (request, status, error) {
    alert('An error occurred, please try again.'); }
    }); 
    });
    });

    

刚才发生了什么事?

我们刚刚学习了如何在几行代码中使用 JavaScript 发出 AJAX 请求。我们首先将代码包装在一个 $(document).ready函数中,该函数在页面完全加载后运行。然后,我们添加了一个函数,用于捕获应用中任何 delete post链接的点击。最后,脚本中最复杂的部分是我们的 AJAX 调用。让我们稍微讨论一下,这样它才有意义。jQuery 有一个名为 $.ajax的函数,它有多种选项(在这里都可以看到:http://api.jquery.com/jQuery.ajax/))。让我们浏览一下我在前面给出的代码中使用的每个选项,确保您知道它们的含义。

  • type: 'DELETE'表示我们希望对我们的请求使用 DELETE HTTP方法。
  • url: location表示我们将使用点击链接的 href属性进行请求。这将确保删除正确的帖子。
  • context: $(this)是将用于所有 AJAX 回调的对象。因此,在本例中,此调用的 success选项中的所有代码都将使用单击的链接作为所有调用的上下文。
  • 无论何时 AJAX 请求完成,都会调用success: function()is。我们在此函数中放置了以下代码: $(this).parent().parent().fadeOut();。这意味着我们将从单击的链接中查找两个 HTML 级别。这意味着我们将寻找帖子的``,并将其淡出视野。
  • 只要代码中出现错误,就会运行error: function (request, status, error)。现在,我们只是显示一个警报框,这并不是最优雅的方法,特别是因为我们没有向用户提供所发生事件的详细信息。这将为我们现在的工作,但如果你想要一些额外的积分,发挥一点这个功能,看看你是否可以使它更优雅一点。

令人惊叹的我们刚刚添加了一些代码,这将真正改善用户体验。随着应用的增长,以及向其添加更多功能,请务必记住 jQuery 的 AJAX方法,这肯定会使事情变得更简单。

更新路由使用删除 HTTP 方法

现在我们通过 AJAX 调用正确地使用了 DELETE作为 HTTP方法,我们需要更新路由,这样我们的代码就知道如何处理路由。

  1. 打开 index.php,查找上一章创建的 post/delete/:id/:rev路由:
    get('/post/delete/:id/:rev', function($app) {
    $post = new Post();
    $post->_id = $app->request('id');
    $post->_rev = $app->request('rev');
    $post->delete();
    $app->set('success', 'Your post has been deleted');
    $app->redirect('/user/' . User::current_user());
    });

    
  1. 让我们通过将 get更改为 delete来将路线更改为使用 delete方法。然后,删除 success变量和重定向代码,因为我们不再需要它们:
    delete('/post/delete/:id/:rev', function($app) {
    $post = new Post();
    $post->_id = $app->request('id');
    $post->_rev = $app->request('rev');
    $post->delete();
    });

    

让我们来测试一下!

在测试此功能时,请确保停止并欣赏所有协同工作以解决某个复杂问题的技术。

  1. 进入 http://localhost/verge/login,以 johndoe身份登录应用。
  2. 点击我的个人资料。
  3. 点击你帖子旁边的 (Delete)。
  4. 被删除的帖子将淡出视图,其他帖子将在页面上弹出。

使用 jQuery 添加简单分页

随着应用的增长,帖子将开始填满用户的个人资料。如果我们的应用成功了,人们开始使用它,会发生什么?每次页面加载时,数百篇文章将打印到纵断面图。当应用开始增长时,这样的事情可能会严重影响应用。

考虑到这一点,我们将在个人资料页面上创建一些分页。我们的简单分页系统将按如下方式工作:

  1. 默认情况下,我们将在一个页面上显示 10 篇文章。当用户想要看到更多内容时,他们会点击加载更多链接。
  2. 当点击显示更多链接时,jQuery 将计算出要跳过多少项,并告诉 Bones 要检索哪些文档。
  3. Bones 将使用 Sag 调用 CouchDB 并通过 posts_by_user视图获得更多帖子。
  4. Bones 将把结果加载到一个局部视图中,该视图包含我们的 HTML 布局,用于设置帖子的格式。此 HTML 将返回 jQuery 以显示在我们的页面上。

这方面的工作相当多,但这种类型的功能在大多数应用中都很常见。那么,让我们跳进去看看我们是否能把这一切拼凑起来。

是时候采取行动了——从 profile.php 中删除帖子,并将其放在自己的局部视图中

用于列出帖子的代码直接位于 profile.php页面中,到目前为止,该页面还不错。然而,过一会儿,我们希望能够通过 Javascript 中的 callback显示帖子,如果我们不小心,这可能意味着重复的代码或不一致的布局。让我们通过将代码移动到一个可以轻松重用的局部视图来保护我们自己。

  1. 在视图/用户中创建名为 _posts.php的新文件。
  2. 复制并粘贴 views/user/profile.php中列出帖子的 foreach代码,并将其粘贴到我们的新文件 _posts.php中。 _posts.php的最终结果如下:
    <?php foreach ($posts as $post): ?>
    <div class="post-item row">
    <div class="span7">
    <strong><?php echo $user->name; ?></strong>
    <p>
    <?php echo $post->content; ?>
    </p>
    <?php echo $post->date_created; ?>
    </div>
    <div class="span1">
    <?php if ($is_current_user) { ?>
    <a href="<?php echo $this->make_route('/post/delete/' . $post->_id . '/' . $post->_rev)?>" class="delete">
    (Delete)
    </a>
    <?php } ?>
    </div>
    <div class="span8"></div>
    </div>
    <?php endforeach; ?>

    
  1. 现在,让我们从 views/user/profile.php中删除相同的 foreach语句,并将其替换为对新创建的 _posts文件的 include调用。然后,让我们在列表的 h2元素中添加一个 span,以便通过 jQuery 轻松访问它。
    <h2>
    Posts (<span id="post_count"><?php echo $post_count; ?></span>)
    </h2>
    <div id="post_list">
    <?php include('_posts.php'); ?>
    </div> 

    

刚才发生了什么事?

我们从 profile.php中取出所有列出帖子的代码,并将其移动到一个名为 _posts.php的新部分。我们在文件名开头加了一个下划线,就是为了告诉大家,当我们浏览源代码时,它与普通视图不同。所谓局部视图,我的意思是它应该被加载到另一个页面,它本身可能没有任何用处。从表面上看,我们的应用的功能将与我们将代码移动到局部视图之前完全相同。

然后,我们修改了 profile.php中的代码,以便更容易使用 jQuery。我们在 h2元素内部添加了一个 ID 为 post_count的 span元素。这个 span元素只包含总帖子数。我们很快就会用它来告诉我们是否已经将所有需要的帖子加载到我们的列表中。然后我们用一个 ID 为 post_list的 div来包装我们的帖子列表。我们将使用此标识符从分页控件向列表中追加新帖子。

添加分页后端支持

分页不需要其他函数。让我们改进一下 Post类的 get_posts_by_user函数。我们所需要做的就是添加 skip和 limit选项,然后将其传递到 CouchDB 中的 posts_by_user视图。将 skip传递给该视图将使我们能够跳过它发送给我们的结果中一定数量的记录, limit将允许我们一次只显示一定数量的帖子。通过组合这两个变量,我们将支持分页!

行动时间-调整我们的 get_posts by_user 功能以跳过和限制帖子

现在我们知道该做什么了,让我们直接开始编辑我们的 classes/post.php文件并调整 get_posts_by_user函数,以便我们可以添加 $skip和 $limit作为参数。

  1. 通过打开名为 classes/post.php的文件打开 Post类。
  2. 找到我们的 get_posts_by_user函数,添加 $skip的默认值为 0,添加 $limit的默认值为 10。
    public function get_posts_by_user($username, $skip = 0, $limit = 10) { 
    $bones = new Bones();
    $posts = array();
    ...
    }

    
  1. 更新我们对 Sag 的 get调用,以便它将 $skip和 $limit的值传递到查询中。
    public function get_posts_by_user($username, $skip = 0, $limit = 10) {
    $bones = new Bones();
    $posts = array();
    foreach ($bones->couch-> get('_design/application/_view/posts_by_user?key="' . $username . '"&descending=true&reduce=false&skip=' . $skip . '&limit=' . $limit)->body->rows as $_post) { 
    ...
    }

    
  1. 现在我们已经更新了我们的函数,包括了 skip和 limit,让我们在 index.php中创建一个新的路由,它类似于 user/:username路由,但引入了一个路由变量 skip来驱动分页。在这条路线中,我们只返回 _posts部分,而不是整个布局:
    get('/user/:username/:skip', function($app) {
    $app->set('user', User::get_by_username($app-> request('username')));
    $app->set('is_current_user', ($app->request('username') == User::current_user() ? true : false));
    $app->set('posts', Post::get_posts_by_user($app-> request('username'), $app->request('skip')));
    $app->set('post_count', Post::get_post_count_by_user($app-> request('username')));
    $app->render('user/_posts', false);
    });

    

刚才发生了什么事?

我们刚刚在 get_posts_by_user函数中添加了额外的 $skip和 $limit选项。我们还进行了一些设置,以便当前调用在不更改任何内容的情况下运行,因为我们为每个变量设置了默认值。我们在用户配置文件中现有的调用现在也将显示前 10 个帖子。

然后我们创建了一个名为 /user/:username/:skip的新路由,其中 skip是查询时要跳过的项目数。此函数中的所有其他内容都与 /user/:username路由中的内容完全相同,只是我们将结果返回到我们的分部中,并且布局为 false,因此没有布局包装器。我们这样做是为了让 jQuery 可以调用这个路由,它将只返回需要添加到页面列表末尾的帖子列表。

让我们来测试一下!

让我们通过直接在浏览器中使用 /user/:username/:skip路线,以确保我们的 /user/:username/:skip路线按预期运行。

  1. 转到 http://localhost/verge/user/johndoe/0(或任何拥有大量帖子的用户)。
  2. Your browser will return a big list of posts using views/user/_posts.php as a template. Notice that it's showing us 10 total posts, starting with the most recent post.

Let's test it out!

  1. Now, let's try to skip the first 10 posts (as our pager will eventually do) and retrieve the next 10 posts by going to: http://localhost/verge/user/johndoe/10

Let's test it out!

  1. 我们的代码希望工作得很好。我只有 12 篇关于这个帐户的帖子,所以这个视图跳过了前 10 篇,显示了最后两篇。

这一切的功能都完全符合我们的预期,但我们的代码中还有一些需要清理的地方。

是时候采取行动了——重构我们的代码,使其不再冗余

虽然我们的代码工作得很好,但您可能已经注意到我们的代码 in /user/:username和 /user/:username/:skip几乎相同。我们可以通过将所有冗余代码移动到一个函数中并从每个路由调用它来减少代码膨胀。让我们这样做,这样我们就可以保持代码整洁的习惯。

  1. 打开 index.php,创建一个名为 get_user_profile的函数,该函数以 $app为参数,并将其放置在 /user/:username路由上方。
    function get_user_profile($app) {
    }

    
  1. 将 /user/:username/:skip中的代码复制到此函数中。但是,这次,让我们检查一下它是否存在,而不仅仅是 passing $app->request('skip')。如果它存在,让我们将其传递给 get_posts_by_user函数。如果它不存在,我们就通过它 0。
    function get_user_profile($app) {
    $app->set('user', User::get_by_username($app-> request('username')));
    $app->set('is_current_user', ($app->request('username') == User::current_user() ? true : false));
    $app->set('posts', Post::get_posts_by_user($app-> request('username'), ($app->request('skip') ? $app-> request('skip') : 0)));
    $app->set('post_count', Post::get_post_count_by_user($app-> request('username')));
    } 

    
  1. 最后,让我们清理两个 profile 函数,以便它们都只调用 get_user_profile函数。
    get('/user/:username', function($app) {
    get_user_profile($app); 
    $app->render('user/profile');
    });
    get('/user/:username/:skip', function($app) {
    get_user_profile($app); 
    $app->render('user/_posts', false);
    });

    

刚才发生了什么事?

我们只是通过将大部分逻辑移到一个名为 get_user_profile的新函数中,简化了我们的用户配置文件路由。两条路线之间唯一不同的功能是 request变量 skip。因此,我们在对函数 Posts::get_posts_by_user的调用中放入了一个简写的 if语句,该语句将传递 skip请求变量(如果存在的话);但如果没有,我们就通过了 0。添加这一小部分功能允许我们对两条不同的路线使用相同的代码。最后,我们将全新的函数插入到路由中,并准备好享受代码的简单性。所有的东西都会像以前一样工作,但是它更容易阅读,将来也更容易更新。

在开发过程中,重构和一致地清理代码是一个重要的过程;以后你会感谢自己这么做的!

行动时间-为分页添加前端支持

我们几乎完全支持分页。我们现在需要做的就是在我们的项目中添加一点 HTML 和 JavaScript,我们会有一个很好的体验。

  1. 让我们先在 master.css文件中添加一行 CSS,这样加载更多按钮看起来会很漂亮。
    #load_more a {padding: 10px 0 10px 0; display: block; text-align: center; background: #e4e4e4; cursor: pointer;}

    
  1. 现在我们已经准备好 CSS,让我们在 profile.php视图的 post列表底部添加加载更多按钮的 HTML。
    <h2>
    Posts (<span id="post_count"><?php echo $post_count; ?></span>)
    </h2>
    <div id="post_list">
    <?php include('_posts.php'); ?>
    </div>
    <div id="load_more" class="row">
    <div class="span8">
    <a id="more_posts" href="#">Load More...</a>
    </div>
    </div>

    
  1. 现在,让我们打开 master.js,在 $(document).ready函数的结束括号内创建一个函数。此函数将针对 ID 为 more_posts的任何元素的 click事件。
    $('#more_posts').bind( 'click', function(event){
    event.preventDefault();
    }); 
    });

    
  1. 为了调用 /user/:username/:skip路由,我们需要使用名为 window.location.pathname的 JavaScript 函数获取页面的当前 URL。然后,我们将在字符串的末尾追加 post 项目的数量,以便跳过页面上当前显示的 post 数量。
    $('#more_posts').bind( 'click', function(event){
    event.preventDefault();
    var location = window.location.pathname + "/" + $('.post-item') .size(); 
    });

    
  1. 现在我们已经知道了位置,让我们填写 AJAX 调用的其余部分。这一次,我们将使用 GET HTTP方法,并使用 ID 为 post_list的帖子列表作为上下文,这将允许我们在 success事件中引用它。然后,我们只需添加一个通用的 error事件,以便在出现错误时让用户知道发生了什么错误。
    $('#more_posts').bind( 'click', function(event){
    event.preventDefault();
    var location = window.location.pathname + "/" + $('#post_list').children().size();
    $.ajax({
    type: 'GET',
    url: location,
    context: $('#post_list'),
    success: function(html){
    // we'll fill this in, in just one second
    },
    error: function (request, status, error) {
    alert('An error occurred, please try again.');
    }
    }); 
    });

    
  1. 最后,让我们用一些代码来填充 success函数,这些代码将 AJAX 调用返回的 HTML 附加到 post_list div的末尾。然后,我们将检查是否有其他帖子要加载。如果没有更多的帖子要加载,我们将隐藏加载更多按钮。为了获得帖子的数量,我们将查看我们用 post_count作为 ID 创建的 span,并将其转换为一个带有 parseInt:
    $('#more_posts').bind( 'click', function(event){
    event.preventDefault();
    var location = window.location.pathname + "/" + $('#post_list').children().size();
    $.ajax({
    type: 'GET',
    url: location,
    context: $('#post_list'),
    success: function(html){
    $(this).append(html);
    if ($('#post_list').children().size() <= " parseInt($('#post_count').text())) {
    $('#load_more').hide();
    } 
    },
    error: function (request, status, error) {
    alert('An error occurred, please try again.');
    }
    });
    });

    

的整数

刚才发生了什么事?

在本节中,我们完成了分页!我们首先为我们的加载更多链接创建了一个快速 CSS 规则,这样它看起来更友好一些,并添加了显示在个人资料页面上所需的 HTML。我们通过对当前用户配置文件的 URL 调用一个 AJAX 函数来结束分页,并附加了 #post_list div中当前存在的帖子数量。通过将这个数字传递给我们的路线,我们告诉我们的路线传递这个数字并忽略所有这些项目,因为我们已经显示了它们。

接下来,我们添加了一个 success函数,使用 _posts部分的布局从我们的路线返回 HTML。此 HTML 将附加在 #post_list div的末尾。最后,我们通过比较 #post_list的大小和 reduce函数返回到 #post_count span配置文件顶部的帖子数量来检查是否还有其他项目需要加载。如果两个值相等,则意味着无法加载更多的帖子,我们可以安全地隐藏Load more链接。

是时候采取行动了-修复我们的 delete post 函数以使用分页

当我们添加分页时,我们还破坏了删除通过 AJAX 加载的帖子的功能。这是因为我们正在使用 bind事件处理程序将 click事件绑定到我们的链接,这只发生在页面加载时。因此,我们需要考虑通过 AJAX 加载的链接。谢天谢地,我们可以使用 jQuery 的 live事件处理程序来实现这一点。

  1. 打开 master.js,将 delete邮政编码改为 live代替 bind:
    $('.delete').live( 'click', function(event){ 
    event.preventDefault();
    var location = $(this).attr('href');

    
  1. 如果您开始删除帖子列表中的一组项目,则当前不会更改使用 JavaScript 绑定到用户帐户的帖子数量。在这里,让我们修改 success函数,这样它也会更新帖子列表顶部的帖子数量:
    $('.delete').live( 'click', function(event){
    event.preventDefault();
    var location = $(this).attr('href');
    $.ajax({
    type: 'DELETE',
    url: location,
    context: $(this),
    success: function(html){
    $(this).parent().parent().parent().fadeOut();
    $('#post_count').text(parseInt($('#post_count').text()) - 1); 
    },
    error: function (request, status, error) {
    alert('An error occurred, please try again.');
    }
    });
    });

    

刚才发生了什么事?

我们刚刚更新了删除按钮,使用 live事件处理程序而不是 bind事件处理程序。通过使用 live,jQuery 允许我们定义一个选择器,并将规则应用于与该选择器匹配的所有当前和未来项目。然后,我们将 #post_count元素设置为动态元素,以便每次删除帖子时,帖子数量都会相应地发生变化。

测试我们完整的分页系统

我们的分页终于结束了。让我们返回并测试所有内容,以确保分页按预期工作。

  1. 进入 http://localhost/verge/login,以 johndoe身份登录应用。
  2. 点击我的个人资料。
  3. 滚动至页面底部,点击加载更多。接下来的 10 个帖子将返回给您。
  4. 如果您的帐户中的帖子少于 20 篇,加载更多按钮将从页面中消失,显示您已加载帐户中的所有帖子。
  5. 尝试并单击通过 AJAX 加载的列表中的最后一篇文章,它将消失,正如它应该消失一样!

太神了我们的分页系统工作正常;我们可以删除帖子,每次删除帖子时,我们的帖子数量都会更新。

使用重力仪

在这一点上,我们的个人资料看起来有点无聊,只有一堆文本,因为我们不支持将图像上传到我们的系统中。为了时间,也为了用户的利益,我们将在本书中避免这个话题。让用户在每次加入服务时上传一张新的个人资料图片会有相当大的摩擦。相反,有一项服务可以让我们的生活更轻松一些:Gravatar(http://www.gravatar.com )。Gravatar 是一种 web 服务,允许用户将配置文件图像上载到单个位置。从那里,其他应用可以使用用户的电子邮件地址作为映像的标识符来获取概要文件映像。

行动时间-向我们的应用添加 Gravatar

通过我们的用户类添加对 Gravatar 的支持就像添加几行代码一样简单。之后,我们将在整个应用中添加 gravatar函数。

  1. 打开 user/profile.php和一个名为 gravatar的 public函数,该函数接受一个名为 size 的参数;我们将给它一个默认值 50。
    public function gravatar($size='50') {
    }

    
  1. 为了获取用户的 Gravatar,我们只需要创建一个用户电子邮件地址的 md5散列,作为 gravatar_id。然后,我们将使用 $size变量设置大小,并将所有这些附加到 Gravatar 的 web 服务 URL。
    public function gravatar($size='50') {
    return 'http://www.gravatar.com/avatar/?gravatar_id=' .md5(strtolower($this->email)).'&size='.$size;
    }

    
  1. 就这样!现在我们的应用中有 Gravatar 支持。我们只需要开始将其添加到任何我们想要查看配置文件图像的地方。让我们首先在 views/user/profile.php文件顶部的用户信息部分添加一个大的 Gravatar。
    <div class="span4">
    <div class="well sidebar-nav">
    <ul class="nav nav-list">
    <li><h3>User Information</h3></li>
    <li><img src="<?php echo $user->gravatar('100'); ?>" /></li> 
    <li><b>Username:</b> <?php echo $user->name; ?></li>
    <li><b>Email:</b> <?php echo $user->email; ?></li>
    </ul>
    </div>
    </div>

    
  1. 接下来,让我们更新 views/user/_posts.php文件中的帖子列表,这样我们可以很好地显示我们的 Gravatar。
    <?php foreach ($posts as $post): ?>
    <div class="post-item row">
    <div class="span7">
    <div class="span1">
    <img src="<?php echo $user->gravatar('50'); ?>" />
    </div>
    <div class="span5">
    <strong><?php echo $user->name; ?></strong>
    <p>
    <?php echo $post->content; ?>
    </p>
    <?php echo $post->date_created; ?>
    </div>
    </div> 
    <div class="span1">
    <?php if ($is_current_user) { ?>
    <a href="<?php echo $this->make_route('/post/delete/' . $post->_id . '/' . $post->_rev)?>" class="deletes">(Delete)</a>
    <?php } ?>
    </div>
    <div class="span8"></div>
    </div>
    <?php endforeach; ?>

    

刚才发生了什么事?

我们在User类中添加了一个名为gravatar的函数,该函数接受一个参数$size,默认值为 50。从那里,我们对该对象的电子邮件地址和$size进行了md5散列,并将其固定到 Gravatar 的 web 服务的末尾。结果是一个链接到一个好的,易于显示的 Gravatar 图像。

随着我们的 Gravatar 系统就位,我们将其添加到了views/user/profile.php和views/user/_posts.php页面中。

测试我们的孕妇

我们的 Gravatar 应该在我们的个人资料页面上启动并运行。如果用户的电子邮件地址未绑定图像,则会显示一个简单的保留图像。

  1. Go to http://localhost/user/johndoe, and you will see Gravatar's placeholder on each post and in the User Information section.

Testing our Gravatars

  1. Now, let's associate a Gravatar with your e-mail by going to http://www. gravatar.com and clicking on Sign up.

Testing our Gravatars

  1. Type in your e-mail, and click on Signup. You'll receive a verification e-mail to your address, so go check it and click on the activation link.

Testing our Gravatars

  1. Next, you will be taken to a page that shows your current account and images tied to your account. You will not have anything tied to your account yet, so click on Add one by clicking here!.

Testing our Gravatars

  1. After you have uploaded the image to the account and added any e-mail addresses you want to use, you can go back to the profile associated with your e-mail address (for me it's http://localhost/user/tim), and you will see a Gravatar in place!

Testing our Gravatars

将所有内容添加到 Git

我希望在本章中,您已经将代码提交到 Git;如果你没有,这是你的提醒。一定要早做,经常做!

总结

我希望你喜欢这一章!虽然这些功能对于我们的应用来说都不是“任务关键型”功能,但随着应用的增长,用户会要求这些功能。

具体地说,我们学习了如何安装 jQuery 并使用它来帮助创建一些基本的 JavaScript,并使用它使帖子的删除和分页更加干净。接下来,我们将 Gravatar 图像添加到个人资料和帖子列表中,以使我们的个人资料看起来更有趣。

就这样!我们的申请已经准备好了。在下一章中,我们将保护应用的最后部分,并部署所有内容,以便全世界都能看到您构建的内容。