分享,技术 创建于2014年06月25日 [1,179]
Typecho实现全站式Ajax的方法

我相信不懂jQuery和Ajax的朋友看到这篇文应该会挺高兴的,因为目前网络上关于Typecho的Ajax关键字全是willin kan做的AjaxComments插件。如果你对Typecho的全站化ajax有兴趣,那么你可以在这里得到想要的东西。

其实全站ajax已经不是什么新鲜的东西,做全站Ajax所需要的jQuery和Ajax知识非常地浅,对于没有系统地学习这两样技能的人来说只要琢磨一会马上就能掌握。Ajax有个缺点就是对搜索引擎不友好,它请求的页面是不存在真实地址的话,就不会被索引到。所以不少行业内认识唾弃它不利于ZEO(你看得懂就行了);另一方面他所带来的用户体验是非常好的,那么这两方面怎么取舍就看站长个人。

接下来我会通过其他方式了弥补缺点发扬优点在Typecho上合理使用Ajax。

上面说过对搜索引擎的问题,所以这里我们Ajax加载将会采用加载真实地址,不会通过后台函数输出想要的内容。这样搜索引擎会访问到真实的地址,而用户则会Ajax加载需要的内容。还有个问题就是Ajax真实地址后我们加载的数据跟直接访问会一样,再次加载了不需要的内容。当然我们可以从过在Ajax后删除不需要的内容,这些内容也仅仅是Html代码 还不回被真正执行。当时PHP后台还是会浪费资源输出这些。要想真正放弃加载需要内容之外的东西。这里会做个判断,当用户第一次进入网页 会加载head,sidebar,foot。当点击站内链接后。会在加载之前给这几个不需要加载的部分传值。让这些内容不输出。而搜索引擎是不会执行JS代码的,会正常访问页面。

另外个问题就是Ajax后,地址栏变化的问题。我们可以通过jQuery的history插件,或者使用html5自带的API:history.pushState和history.replaceState来实现。这个会在后面为大家详细介绍。

当然AJax的关键代码页很少,内容如下:

$.ajax({
url: ajaxUrl,
type: 'get-or-post',
error: function() {
//抛出错误
},
success: function() {
//抛出完成代码
}

Ajax其实比较比较泛指,最低层的应该是.ajax(); 基于这个底层方法 JQuery又有多种类型。比如 .load(); .getScprit(); .getJSON(); 之类的。想了解的话可以自己去看API文档。最简单的应该就是.load();方法了。有多简单呢?

$(".container").load("url .container");

这行代码的意思就是 在页面的.container div内载入地址为URL的页面,并且只取.container元素内容,其他丢弃。当然只靠这一句代码是完成不了所有动作的,那就需要你的想象力了,请看下面内容:

$('a[target!=_blank]').on('click',function(){                   //所有a链接不为新标签打开的链接 绑定click事件。
           var url = $(this).attr("href");                        //获取a链接的地址
           var title = $(this).attr("title");                     //获取新链接的title
           $('.container').fadeTo(500,0.3);                        //内容部分模糊
           #(".container").load("url .container",function(){        //开始加载
                          $('.container').fadeTo(200,1);           //完成后 内容部分重新显示
                          window.document.title = title;          //设置标题
           }); 
})

注意:全站Ajax要绑定每一个非_blank的a标签。
以上是使用.load()方法实现的异步加载。是不是很简单,如果你想使用底层的.ajax方法那就请继续往下看。

如果你使用了上面这个代码会产生一个问题,就是这个.container会把页面头部也加载了进来。用一句很流行的话来说,只要把头掐掉就能吃了(笑)。我的意思是,header和footer是全站Ajax不需要的东西。那么在index.php post.php page.php 自定义模版页做个判断,判断如果这是ajax请求则不读取header.php和footer.php就可以了,请看:

if(isset($_SERVER["HTTP_X_REQUESTED_WITH"]) && strtolower($_SERVER["HTTP_X_REQUESTED_WITH"])=="xmlhttprequest"){ 
    // ajax 请求的处理方式 
}else{ 
    $this->need('header.php');
    // 正常请求的处理方式 
};

加上这句以后,头部和尾部就不被Ajax加载了。
到这里,Ajax的核心代码已经完成 。其他动作那就要根据你自己来制定了。不如ajax过程中的动画,啥的小细节。我相信如果你对JQuery比较熟悉的话 应该也是很容易的一件事。

通过上面的方法,你会发现AJAX加载时没什么问题的,但是地址栏的URL是不会改变,有木有?URL会一直显示在你第一次进入网站的地址。这样的话 如果用户想分享地址的或者想保存地址的话 就不是当前文章所在的地址。还有返回前进不能使用,这样就造成了很尴尬的局面。

其实有两种方法解决这个问题,各有优缺点。

第一种方法是通过Jquery的一个插件jQuery Address实现的。优点就是兼容低版本的浏览器,缺点呢就是它是通过“#”锚点的方法来改变地址的,如果你直接复制AJAX后带锚点的地址打开的话,浏览器会先加载锚点之前的页面,然后才会执行你写的JS,再通过判断AJAX加载锚点的地址。当然也不能算是个很明显的缺点了。

jQuery Address只有十几K的体积,算是很比较小的插件了。(下载)在AJAX执行之前我们来使用插件做操作地址栏。代码如下:

var addresschanged=false;                                                   
$('a[rel="ajax"]').live("click",function(){      //所有rel=ajax的 A链接,
    var a=$(this),href=a.attr("href");
    _text=a.text();
    c=a.attr("title");
    if(c==""||c==null)c=_text;
    deeplink=href.replace("http://"+location.hostname+"/","");   //设置deeplink
    if(deeplink=="")deeplink="!";    //如果deeplink为空或带!
    addresschanged=true;                                         
    $.address.value(deeplink);
    window.document.title=c+;
    return false
});
$.address.change(function(event){   //监控地址栏变化
    var value=event.value,current=$("#content"),href;
    if(value.indexOf("comment")!==1){
        if(value=="/"){    //通过几步判断锚点是否需要加载
            href=location.href;
           }
        else {
            if(value=="/!"){href="http://"+location.hostname+"";
            addresschanged=true
             }
            else{
            href="http://"+location.hostname+""+value+"";
            addresschanged=true
            }
        }
        if(addresschanged==true){loadpage(href)}   //如果addresschanged为真  执行loadpage函数(loadpage函数就是AJAX加载代码)
    }
});

通过锚点变化里进行ajax操作,若是首页地址则变成 http://zhouzexin.cn/#/! 如果其它页面则变成http://zhouzexin.cn/#/ooxx.html。想了解更多详细问题可以去http://www.asual.com/jquery/address/了解。

如果你不想使用jquery插件,并且你只准备到支持html5的浏览器使用的话 可以使用下面的方法。HTML5中引进了2个API:history.pushState, history.replaceState。可以通过pushState和replaceState接口操作浏览器历史,并且改变当前页面的URL。pushState是将指定的URL添加到浏览器历史里,replaceState是将指定的URL替换当前的URL。

var state = {
    title: title,
    url: options.url,
    otherkey: othervalue
};
window.history.pushState(state, document.title, url);

调用方法如上。响应浏览器操作如下:

window.addEventListener('popstate', function(e){
  if (history.state){
    var state = e.state;
    //do something(state.url, state.title);
  }
}, false);

这样就可以结合ajax和pushState完美的进行无刷新浏览了。

到这里Typecho的全站AJAX加载 主要问题已经结束。剩下的应该都是一些根据自己的问题来操作的一些小问题。如果你对JS比较熟悉的话 应该是很简单的问题 当然对我写的这些也会这样认为。想更好的了解这些问题 还是多研究下js和jQuery 让你更得心应手。

实在懒得慢慢琢磨的,请看这边完整代码在这里:

   $("a:not(.comments a)[target!=_blank]").on("click",function(){ //针对装了AjaxComments插件的用户,需要指定非.comments区域的a标签
      var url = $(this).attr("href") ;
      $.ajax({
          url:url,
          type:"post",
         //加载前
          beforeSend:function(){
                $('.container').fadeTo(200,0.1);
            },
         //加载后
          complete:function(){ 
                $('.container').fadeTo(200,1);
            }
            ,
         //加载成功
          success:function(message){
                var ajaxtitle1 = $(message).find(".page-title a").text();
                var ajaxtitle2 = "zZz | zhouZExin's Blog";
                if (ajaxtitle1 == "") {
                    window.document.title = ajaxtitle2;
                }
                else {
                    window.document.title = ajaxtitle1 + " | zhouZExin's Blog";
                }
                $(".container").html(message);
            },
         //加载失败
           error: function() {//如果加载失败 报错内容
                $(".container").html("AJAX Error..."); 
            } , 
                });  
      return false; 
   })

未完待续

因发现pjax更方便且整合了PUSHSTATE,本文已弃坑。
更方便的方法请阅读:博客主题更新v1.1,完美全站化AJAX

已有 11 条评论
  1. 路过打酱油,我用的是PJAX

    1. 看了你的博客,非常棒

    2. 是吗,多谢:)
      PS:不能回复子评论?

    3. 我设置了单层嵌套,因为觉得这样比较美观。另外,托你的福,今天我了解了一下pjax,觉得相当的方便啊。再看回我这套复杂的做法,有点自惭形秽....尝试了下加入pjax,但跟我的部分js有冲突,这两天慢慢改..

    4. 你也可以把第二层的padding去掉,效果应该和单层差不多

    5. 谢谢你的提议。当初设计这套模版的时候我一心只想做成简单简洁的形式,目标就是像这样的单层嵌套。(虽然现在加了pjax后已经有点违背当初了)

    6. 119977 119977

      看看怎么实现ajax

  2. kuumaa kuumaa

    你们两个的网站都做得相当好啊

    1. 谢谢,你也可以的

  3. LTManito LTManito

    大神 请问下我做了全站Ajax 但是评论就不行 怎么解决

    1. 请问你遇到什么问题呢?不过 @Jimmy 好像已经在替你解决了。

添加新评论
登录管理
︿