jQuery Address

为提升用户体验,改善前端页面效果,越来越多的 Web 应用以及企业或个人团体网站,采用了全站动态不刷新页面的方式加载内容,各种加载效果也层出不穷。特别是手机网站,对前端的设计更是要求偏高。刷新页面所产生的等待时间和展现方式严重地影响了网站整体的设计效果和使用体验。

本文详细介绍如何利用 jQuery 框架以及 jQuery Address 插件实现最基本的全站 AJAX 动态加载页面内容的功能的方法。

案例目标

以常见基本结构的网站为案例,实现全站链接 AJAX 加载页面内容,不刷新页面,不影响搜索引擎收录。同时兼容 WordPress。

功能实现

需要提供给 jQuery Address 的有三个常量,分别是:

var baseurl          = 'http://www.example.com/test/blog',
    request_uri      = '/test/blog',
    request_uri_host = 'http://www.example.com';

当网站根目录处于域名根目录时,三个常量的定义为:

var baseurl          = 'http://www.example.com',
    request_uri      = '/',
    request_uri_host = 'http://www.example.com';

以上定义这几个常量数据中的斜杠符非常重要,有误将导致通站 AJAX 链接不能工作。

主体功能实现程序如下:

/**
 * 标记初始化完成
 * @type {Boolean}
 */
var is_init = true;

/**
 * 标记浏览器是否支持 Push State
 * @type {Boolean}
 */
var is_state = ( window.history.pushState !== undefined );

jQuery(document).ready( function() {

  jQuery.address
    // 指定 URL 前缀
    .state( baseurl.replace( request_uri_host, '' ) )
    // 初始化
    .init( function() {
      // 绑定所需的链接,此处筛除了 WordPress 内部功能链接、Feed 订阅链接,以及新窗口链接
      jQuery("a[href^='"+baseurl+"']:not([href^='"+baseurl+"/wp-']):not([href$='/feed/']):not([target='_blank'])")
        .address( function() {
          // 返回相对路径
          return jQuery(this).attr('href').replace( request_uri_host, '' );  
        } );
    } )
    // 初始化为当前 URL
    .path( request_uri )
    // 当 URL 发生改变时的事件
    .change( function( event ) {
      // 防止初始化时重复 AJAX 加载当前页面
      if ( is_state && is_init ) {
        is_init = false;
      } else if ( 0 === jQuery.active ) {
        // 当 AJAX 请求队列为空时
        url = jQuery.address.state().replace( /^\/$/, '' ) + event.path;
        // AJAX 加载所点击的页面内容
        my_load_page_ajax( url );
      }
    } );

  // 页面初始化 JS 程序
  my_init_after_ajax();

} );

/**
 * 通过 AJAX 获取新页面内容
 * @param {String} url 页面 URL
 */
function my_load_page_ajax( url ) {
  // 调用 jQuery AJAX
  jQuery.ajax( {
    url: url,
    type: 'GET',
    dataType: 'html',
    beforeSend: function() {
      // 添加 loading 标记类
      jQuery('body').addClass('loading');
    },
    success: function( data, textStatus, jqXHR ) {
      // 滚动至页面顶部
      jQuery('html, body').scrollTop(0);
      // 替换 #all 层内容
      jQuery('#all').children().remove();
      jQuery('#all').append( jQuery( data ).find('#all').children() );
      jQuery.address.title( />([^<]*)<\/title/.exec( data )[1] );
      // 页面初始化 JS 程序
      my_init_after_ajax();
    },
    complete: function( jqXHR, textStatus ) {
      // 去除 loading 标记类
      jQuery('body').removeClass('loading');
    }
  } );
}

/**
 * 页面初始化 JS 程序
 */
function my_init_after_ajax() {
  // ... 各种页面初始化 JS 程序
}

WordPress + jQuery Address

应用于 WordPress 中,除了主体 JS 程序可以直接放入 Theme 的 JS 文件中,常量的定义需要 WordPress Theme PHP 传递给前台。实现方法如下:

// WordPress 加载 JS/CSS 文件回调过程,一般位于 Theme 的 functions.php 或其它包含文件
function _enqueue_scripts_frontend() {

  wp_enqueue_script( 'jquery' );
  wp_enqueue_script( 'jquery.address', get_stylesheet_directory_uri() . '/js/jquery.address.min.js', array( 'jquery' ) );
  wp_enqueue_script( 'web',            get_stylesheet_directory_uri() . '/js/web.js', array( 'jquery' ), false, true );

  // 传递 JS 变量给已加载的名为 'web' 的 JS 程序文件,并封装在 'theme' 对象中
  wp_localize_script( 'web', 'theme', array(
    'baseurl'          => home_url(),
    'request_uri'      => '/' . trim( $_SERVER['REQUEST_URI'], '/' ),
    'request_uri_host' => ( ( isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] == 'on' ) ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'],
    // 此处仍可传递其它实际需要的参数,如调用 WordPress 内置 AJAX 功能、调用 Theme 元素文件 URI 等
    // 'ajaxurl' => admin_url( 'admin-ajax.php' ),
    // 'tplurl'  => get_stylesheet_directory_uri(),
    // ...
  ) );

  // ...

}
add_action( 'wp_enqueue_scripts', '_enqueue_scripts_frontend' );

此 WordPress 案例 Theme 前端 /js/web.js 程序如下:

if ( 'undefined' !== typeof theme )
  var baseurl          = theme.baseurl,
      request_uri      = theme.request_uri,
      request_uri_host = theme.request_uri_host;

// ...