zoukankan      html  css  js  c++  java
  • 第八天-Ajax交互

     Symfony回顾

    在七个小时的工作之后,askeet程序已经很好了。主页显示问题列表,问题的详细内容显示其答案,用户具有一个配置页面,而各种主题列表也可以由每一页的侧边栏访问。我们社区加强的FAQ处在其正确的方向上,而现在用户还不可以修改数据。

    如果web中数据操作的基础是长长的表单,那么今天的AJAX技术可以改变程序的构建方式。而这也同样适用于askeet。在这个指南中,我们将会显示在askeet中添加加强的AJAX交互。其目标就是允许一个已注册的用户声明其对某一个问题的兴趣。

    在布局中添加一个指示器

    当一个异步请求发送时,AJAX网站的用户并不需要考虑通常的动作暂停,而结果会很快显示。这就是所有的AJAX交互页面应能够可以显示一个活动的指示器的原因。

    正因为如此,在全局的layout.php的<body>顶部添加下面的代码行:

    <div id="indicator" style="display: none"></div>

    尽管默认情况下这是隐藏的,但是当AJAX请求发送时,<div>就会显示。他是空的,但是main.css样式表指定其形状与内容:

    div#indicator
    {
      position: absolute;
      100px;
      height: 40px;
      left: 10px;
      top: 10px;
      z-index: 900;
      background: url(/images/indicator.gif) no-repeat 0 0;
    }

    添加AJAX交互来声明兴趣

    一个AJAX交互由三部分组成:调用者(一个链接,一个按钮或者是其他的用户启动动作的控件),一个服务器动作,以及页面中向用户显示动作结果的区域。

    调用者

    让我们回到显示的问题。如果我们还记得第四天,一个问题可以在一个问题列表中显示,也可以在问题详细中显示。

    这就是将问题标题与兴趣块重构到一个_interested_user.php片段中的原因。再次打开这个片段,添加一个链接允许用户声明其兴趣:

    <?php use_helper('User') ?>
     
    <div class="interested_mark" id="mark_<?php echo $question->getId() ?>">
      <?php echo $question->getInterestedUsers() ?>
    </div>
     
    <?php echo link_to_user_interested($sf_user, $question) ?>

    这个链接所做的不仅是重定向到另一个页面。事实上,如果一个用户已经指定了其对某一个问题的兴趣,他就不可以再一次声明。而且如果这个用户没有被认证,呃,这将是我们后面要讨论的情况。

    这个链接是在一个帮助器函数中编写的,这就需要在askeet/apps/frontend/lib/helper/UserHelper.php中创建:

    <?php
     
    use_helper('Javascript');
     
    function link_to_user_interested($user, $question)
    {
      if ($user->isAuthenticated())
      {
        $interested = InterestPeer::retrieveByPk($question->getId(), $user->getSubscriberId());
        if ($interested)
        {
          // already interested
          return 'interested!';
        }
        else
        {
          // didn't declare interest yet
          return link_to_remote('interested?', array(
            'url'      => 'user/interested?id='.$question->getId(),
            'update'   => array('success' => 'block_'.$question->getId()),
            'loading'  => "Element.show('indicator')",
            'complete' => "Element.hide('indicator');".visual_effect('highlight', 'mark_'.$question->getId()),
          ));
        }
      }
      else
      {
        return link_to('interested?', 'user/login');
      }
    }
     
    ?>

    link_to_remote()函数是AJAX交互的第一个元素:调用者。他声明了当用户点击链接时必须请求哪个动作(在这里为user/interested)以及页面中的哪个区域必须使用动作结果进行更新。两个事件处理器(loding与complete)被添加进来并且与原型javascript函数相关联。原型库提供了手动的javascript工具来使用简单的函数调用实现页面中的可视效果。唯一的不足是文档的缺乏,但是源码是相当直接的。

    我们选择使用帮助器而不是partial,是因为这个函数的PHP代码要多于HTML代码。

    不要忘记在question/_list片段中添加id id="block_<?php echo $question->getId() ?>"。

    <div class="interested_block" id="block_<?php echo $question->getId() ?>">
      <?php include_partial('interested_user', array('question' => $question)) ?>
    </div>

    结果区域

    link_to_remote() javascript帮助器的update属性指定了结果区域。在这个例子中,user/interested动作的结果将会替换id为block_XX的元素的内容。如果我们还感到迷惑,我们可以查看一下这个模板片段中所集成的内容:

    ...
    <div class="interested_block" id="block_<?php echo $question->getId() ?>">
      <!-- between here -->
      <?php use_helper('User') ?>
      <div class="interested_mark" id="mark_<?php echo $question->getId() ?>">
        <?php echo $question->getInterestedUsers() ?>
      </div>
      <?php echo link_to_user_interested($sf_user, $question) ?>
      <!-- and there -->
    </div>
    ...

    两段注释的中间区域即为结果区域。这个动作一旦执行,就会替换这些内容。

    第二个id(mark_XX)的兴趣是十分明显的。link_to_remote帮助器的完整事件处理器将高亮显示已点击的兴趣的interested_mark <div>层,在动作返回一个兴趣的增量数。

    服务器动作

    AJAX调用器指向user/interested动作。这个动作必须在Interest表中为当前的问题以及当前的用户创建新的记录。在Symfony中我们可以这样来做:

    public function executeInterested()
    {
      $this->question = QuestionPeer::retrieveByPk($this->getRequestParameter('id'));
      $this->forward404Unless($this->question);
     
      $user = $this->getUser()->getSubscriber();
     
      $interest = new Interest();
      $interest->setQuestion($this->question);
      $interest->setUser($user);
      $interest->save();
    }

    在这里我们要记住,Interest对象的->save()方法已经被修改来增加相关用户的interested_user域。所以对于当前问题感兴趣的用户数目会在动作调用之后自动增加。

    那么结果的interestedSuccess.php模板应如何显示呢?
    <?php include_partial('question/interested_user', array('question' => $question)) ?>

    他会再一次显示问题模块的_interested_user.php片段。这就是我们编写这个片段的最大好处。

    我们必须禁止这个模板的布局(modules/user/config/view.yml):

    interestedSuccess:
      has_layout: off

    最终测试

    AJAX兴趣的开发到现在就结束了。我们可以进行相应的测试,在登陆页面输入已存在的用户名与密码,显示问题列表,并且点击'interested?'链接。当请求发往服务器时就会显示指示器。然后,当服务器应答后增加的数目就会高亮显示。我们可以注意到初始的'interested?'链接现在变为'interested'并且没有链接,这样就是我们的link_to_interested帮助器所起的作用。

    添加一个内联'sign-in'表单

    我们在前面说到只有注册用户可以声明对某一个问题的兴趣。这就意味着如果一个未授权的用户点击一个'interested?'链接时,必须首先显示登陆页面。

    但是等一下。为什么用户要装入一个新的页面来登陆,而失去与他所声明的感兴趣的问题失去联系呢?一个更好的办法就是在页面上动态装入一个登陆页面。这就是我们将要做的工作。

    在布局中添加一个隐藏登陆表单

    打开全局布局(askeet/apps/frontend/templates/layout.php),添加下面的代码(header与content div之间的内容):

    <?php use_helper('Javascript') ?>
     
    <div id="login" style="display: none">
      <h2>Please sign-in first</h2>
     
      <?php echo link_to_function('cancel', visual_effect('blind_up', 'login', array('duration' => 0.5))) ?>
     
      <?php echo form_tag('user/login', 'id=loginform') ?>
        nickname: <?php echo input_tag('nickname') ?><br />
        password: <?php echo input_password_tag('password') ?><br />
        <?php echo input_hidden_tag('referer', $sf_params->get('referer') ? $sf_params->get('referer') : $sf_request->getUri()) ?>
        <?php echo submit_tag('login') ?>
      </form>
    </div>

    再一次说明,这个表单默认是隐藏的。referer隐藏标记包含referer请求参数,或者是当前的URI。

    当非授权用户点击interested链接时显示表单

    我们还记得在前面编写的User帮助器吗?现在我们将要来处理非授权用户的情况。打开askeet/lib/helper/UserHelper.php文件,将下面的代码行:

    return link_to('interested?', 'user/login');return link_to('interested?', 'user/login');

    改为:

    return link_to_function('interested?', visual_effect('blind_down', 'login', array('duration' => 0.5)));

    当用户为非授权时,'interested?'上的链接会载入一个原型javascript效果(blind_down)来为login id留出空间。

    登陆用户

    user/login动作已经在第五天编写完成了,并且在第六天进行了重构。我们需要再一次进行修改。

    public function executeLogin()
    {
      if ($this->getRequest()->getMethod() != sfRequest::POST)
      {
        // display the form
        $this->getRequest()->getParameterHolder()->set('referer', $this->getRequest()->getReferer());
     
        return sfView::SUCCESS;
      }
      else
      {
        // handle the form submission
        // redirect to last page
        return $this->redirect($this->getRequestParameter('referer', '@homepage'));
      }
    }

    现在的工作已经很完美了,保存的referer将会用户重定向到用户点击以前所在的页面。

    现在测试AJAX功能。一个未注册的用户点击时将会显示一个登陆页面而不离开当前页面。如果用户名与密码通过了认证,页面会进行刷新,用户可以点击他之前想要点击的'interested?'链接。

    明天见
  • 相关阅读:
    微信公众号内调用微信支付
    transform-translate3d
    Ubuntu16.04 install apache-flume-1.7.0-bin.tar.gz
    Ubuntu16.04 install apache-hive-2.X.X-bin.tar.gz
    Ubuntu16.04 install mysql5.X
    Ubuntu16.04 install hadoop-2.8.1.tar.gz伪分布式配置
    Ubuntu16.04 install jdk-8u144-linux-x64.tar.gz
    入门VMware Workstation下的Debian学习之Vim简单使用(三)
    入门VMware Workstation下的Debian学习之基本命令(二)
    Ubuntu16.04 install android-studio-ide-162.4069837-linux
  • 原文地址:https://www.cnblogs.com/dyllove98/p/2462008.html
Copyright © 2011-2022 走看看