amuropikin 发表于 2012-10-2 01:09:10

CI整合PJAX(pushstate+ajax)实现无刷新页面

本帖最后由 amuropikin 于 2012-10-2 14:27 编辑

PJAX效果

通过url可以跟踪ajax的动态加载内容。这种效果尤其在two step view布局的视图中有很大的好处。无刷新加载页面,意味着响应速度和用户体验得到了极大的提升,在静态脚本和通用模块比较多的情况下,最大程度上节省了重用部分的开销。应用例子可以参考现在的g plus、facebook和新版微博,同样是基于html5的pushState实现。g plus的表现最为明显,点击导航栏地址,箭头随目标移动,同时加载的页面淡入,效果很炫。

使用CI+jQuery实现PJAX
不需要从头编写基于pushState的javascript插件,因为jQuery已有项目把它开源出来

开始前的准备:1. jQuery libray http://code.jquery.com/jquery-1.8.2.min.js2. 基于jQ的pjax插件(github上的项目)https://github.com/defunkt/jquery-pjax3. PHP项目代码(本文使用codeigniter,开发中大同小异)
实际开发中包括前端和后端代码,关于前端插件的使用方法可参考github上的说明

php端需要处理的任务主要是两件:1.实现layout视图布局2.判断pjax过来的请求layout使每个视图的输出都是在一个公用模版之上。
第一步是实现CI中的layout。在application/libraries文件夹中新建文件Layout.php, 加入如下代码:


<?php
/*
*
* --------------------------------------------------------------------
*视图布局类
* --------------------------------------------------------------------
*
*@authors ekin.cen <weibo.com/2839892994>
*
*/
class Layout{

    public $obj;
    public $disable_layout = FALSE;
    protected $_layout;
    protected $_layout_dir = 'layout';
    protected $_template_dir = 'templates';
    protected $_data = array();

    public function __construct()
    {
      $this->obj = &get_instance();
    }

    public function set_layout($layout)
    {

      $this->_layout = $layout;
      return $this;
    }

    public function set_layout_dir($dirname)
    {
      $this->_layout_dir = $dirname;
      return $this;
    }

    public function set_template_dir($dirname)
    {
      $this->_template_dir = $dirname;
      return $this;
    }

    public function view($view, $data = NULL, $return = FALSE)
    {
      $view = $this->_template_dir . DIRECTORY_SEPARATOR . $view;
      $this->_layout = $this->_layout_dir . DIRECTORY_SEPARATOR . $this->_layout;

      if ($this->_data)
      {
            $data = $data ? array_merge($this->_data, $data) : $this->_data;
      }
      if ($this->disable_layout)
      {
            echo $this->obj->load->view($view, $data, TRUE);
      }
      else
      {
            $data = array('TEMPLATE_CONTENT' => $this->obj->load->view($view, $data, TRUE));
            $this->obj->load->view($this->_layout,$data,$return);
      }
    }

    public function assign($key, $value = null)
    {
      $data = is_array($key) ? $key : array($key => $value);
      $this->_data = array_merge($data, $this->_data);
      return $this;
    }
}
/* End of file */


第二步是构建自定义的控制器超类,通过判断请求是否来自pjax,来决定是否启用layout进行输出. 在application/core下创建MY_Controller:


<?php
/*
*
* --------------------------------------------------------------------
*控制器超类,加入pjax请求判断
* --------------------------------------------------------------------
*
*@authors ekin.cen <weibo.com/2839892994>
*
*/
class MY_Controller extends CI_Controller{

      protected $_layout='layout_default';

      public function __construct(){
                parent::__construct();
                $this->_initialize();
      }

      protected function _initialize(){
                $this->_set_layout();
                // check if is pjax request
               if (array_key_exists('HTTP_X_PJAX', $_SERVER) && $_SERVER['HTTP_X_PJAX'])
               {
                   $this->layout->disable_layout = TRUE;
               }
      }

      protected function _set_layout(){
      $this->load->library('layout');
      //set template
      $this->layout->set_layout($this->_layout);
      }
}
/* End of file */



现在创建view下的模版文件和相关的controller来进行测试

demo 的 welcome controller.php


<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Welcome extends MY_Controller {

      /**
         * Index Page for this controller.
         *
         * Maps to the following URL
         *               http://example.com/index.php/welcome
         *      - or -
         *               http://example.com/index.php/welcome/index
         *      - or -
         * Since this controller is set as the default controller in
         * config/routes.php, it's displayed at http://example.com/
         *
         * So any other public methods not prefixed with an underscore will
         * map to /index.php/welcome/<method_name>
         * @see http://codeigniter.com/user_guide/general/urls.html
         */
      public function index()
      {
               $this->layout->view('index');
      }

      public function test1(){
                $this->layout->view('test1');
      }

      public function test2(){
                $this->layout->view('test2');
      }
}

/* End of file welcome.php */


最后在模版文件中输出内容,详细的view文件可查看demo

打开支持html5的浏览器并观察网络请求,发现点击页面上的a标签会引起一个ajax请求,url跳转,而页面并没有重新载入,而且前进后退功能一切正常!

------------------------------------------------------------------

使用jquery-pjax插件需要注意的地方:

1 .返回的模版内容不能为纯文本,需要用html标签包裹2.插件的使用方法,详情参考github的项目说明,可能因为版本问题和demo有所出入3.对于不支持pushstate的低版本浏览器,pjax会自动判断或使用传统的页面加载模式4.当一个页面的pjax请求时间过长也会导致插件使用刷新加载,这时需要设定插件内的超时时间
最后附上此次演示的demo :)





姜梦林 发表于 2016-12-13 11:20:53

我设置完之后为什么没有发起ajax请求

一条咸鱼 发表于 2019-6-18 16:01:46

怎么看不到demo

bob 发表于 2014-5-24 17:02:41

谢谢分享,收藏了

gs129090 发表于 2012-10-8 20:18:27

支持 {:1_1:}{:1_1:}

终结者 发表于 2012-12-20 17:33:44

谢谢,pjax的确不错。

lh529 发表于 2013-4-19 16:08:25

学习学习

trynews 发表于 2013-4-21 12:27:38

好像也感觉到刷新呀

lh529 发表于 2013-4-28 15:44:37

xuexiele

zybo 发表于 2013-7-14 17:38:12

谢谢楼主

sdink 发表于 2013-8-7 13:49:15

{:soso_e145:}{:soso_e147:}{:soso_e146:}

1909264228 发表于 2014-2-4 09:09:29

好东西,存起来

shan199 发表于 2014-2-9 21:43:32

以后用到,收藏了。
页: [1] 2
查看完整版本: CI整合PJAX(pushstate+ajax)实现无刷新页面