很多人喜欢Pjax 的魅力,我收集了一个博客的教程,将他们整合到一起。
这里只做备份用,很推荐去原文看看,尤其是评论区,说不定会有意想不到的收获。
此系列文章更新于2015年2月
- 原文来源:INLOJV
第一部分
教程写给自己的,所以日后可能有补充。首先这个pjax的代码有好几部分,来自网络不同作者,经过本人封装,教程就是按这几个部分来进行的。这是第一部分,我把自己理解的大致原理说一下,pjax是 pushstate + ajax,分别百度可以得到相关资料,在此就不赘述了。
Ajax
ajax直白的理解就是请求一个链接所指向的页面的其中一部分来替换当前页面的一部分,比如我用的wordpress,典型的博客页面,有页面头部、主体部分、侧栏部分、页面底部四个主要部分。
ajax请求的过程是如何的呢?比如我现在打开的是页面A
,页面A
中有一个a标签,正常情况下点击a标签的链接会打开一个页面B
,那么整个页面A就会被替换成页面B。然而,页面A和页面B有些结构是完全一样的,比如头部,底部,甚至是侧栏,其实要替换的仅仅是主体部分而已,ajax就提供了这样一个功能,它控制你在点击a标签的链接时,只抓取页面B的主体部分来替换页面A的主体部分,而头部、底部、侧栏不用替换(也就不用刷新)。
PushState
以上是最直白的理解,而pushstate则是干嘛的?HTML5里引用了新的API,history.pushState和history.replaceState,就是通过这个接口做到无刷新改变页面URL的。因为用ajax替换局部页面时,浏览器的地址是不会改变的,你替换为页面B的主体,地址栏的url还是页面A的,而且点击浏览器的后退或前进按钮地址栏url也是不会改变的,pushstate的作用则用来改变地址栏url的状态。
那么PJAX就是以上两者的结合。
开始我们必须对 被请求的页面进行请求前的处理,这个处理非常重要,如果把被请求的页面想象成一张图片,那么这个处理就相当于对图片进行剪裁,没有处理之前,被请求的页面B是完整的,请求过来就首先要预读取一边页面B,而其实我们不必要将整个页面都读取,我们只需要读取主体部分,所以我们可以把头部、侧栏和底部都先剪掉,只剩下主体部分,然后再请求过来替换页面A中的主体部分。
这个剪裁的方法如下:
在对应的php页面进行
<?php if( $_GET['ajx'] != 'container' ) { ?> //被剪裁掉的部分,比如: //<?php get_header(); ?> //<?php get_sidebar(); ?> //<?php get_footer(); ?> <?php } ?>
这个方法非常重要,包括评论分页也需要这样的处理,对pjax的速度是一大影响。了解了这个其实剩下的只需要把剩下的代码超过去就可以了。当然,你不剪裁也是可以的,那也可以替换,但那就不算是真正的ajax了。目前大多数pjax的代码都不会有这样的处理。下面一篇是pjax的核心代码以及一些说明。
第二部分
原文来源: http://www.inlojv.com/4967.html
处理过程
上篇我们提到了“剪裁”,本篇我们先来实际体验一下被剪裁掉的页面是如何的,这方便我们对接下来的页面请求过程有一个感性的认识。
假设我的index.php首页是这个结构:头部、主题、侧栏、底部 四大结构组成。
<?php get_header(); ?> <div id="container"> </div> <?php get_sidebar(); ?> <?php get_footer(); ?>
现在我先把头部剪掉
<?php if( $_GET['ajx'] != 'container' ) { ?> <?php get_header(); ?> <?php } ?> <div id="container"> </div> <?php get_sidebar(); ?> <?php get_footer(); ?>
可以看到我用第一篇中所说的代码将头部包住了,这意味着我把头部剪掉了。
原本首页是 http://127.0.0.1/
,现在我们以这样的链接形式来访问首页 http://127.0.0.1/?ajx=container
打开这个链接你会发现,首页的头部不见了,由于头部加载了css,你首页的样式也会消失,这个状态就是我们想要ajax请求的,我们不需要头部,把它给剪掉了,接着我们可以用同样的方法剪掉侧栏和底部,最后就会只剩下主体部分,如下:
<?php if( $_GET['ajx'] != 'container' ) { ?> <?php get_header(); ?> <?php } ?> <div id="container"> </div> <?php if( $_GET['ajx'] != 'container' ) { ?> <?php get_sidebar(); ?> <?php } ?> <?php if( $_GET['ajx'] != 'container' ) { ?> <?php get_footer(); ?> <?php } ?>
这就是真正需要ajax请求的页面了。
我们需要把http://127.0.0.1/?ajx=container
这样的链接传递给ajax方法进行异步请求,
比如在页面A http://127.0.0.1/page-a
中要请求页面B,页面A中的a标签中指向页面B的链接就应该是这样的 http://127.0.0.1/page-b?ajx=container
,
利用两个js函数来对点击的链接进行处理,加上后面的?=ajx=container
参数,在必要的时候后再去掉它们。
完整的PJAX代码
var ajx_content = "#ajx_content"; function rerun() {} $(function() { rerun(); a(); }); function show_loading(e) { if ($("#loading_box").length == 0) { var div = "<div id='loading_box'></div><div id='loading'></div><div id='loading-text'></div></div>"; } if (e === true) { $("body").append(div); } else { $("#loading_box,#loading,#loading-text").fadeOut(400, function() { $(this).remove(); }); } } function body_am(id) { id = isNaN(id) ? $("#" + id).offset().top : id; $("body,html").animate({ scrollTop: id }, 600); return false; } function pluginRerun() { var plugin_scripts = $('script[src*="plugins"]'); plugin_scripts.each(function() { var url = $(this).attr("src"); $.getScript(url); }); } function addUrlPara(url, para) { var strArray = new Array(); strArray = url.split("?"); if (strArray.length == 1) { if (url.indexOf("#") != -1) { strArray = url.split("#"); return strArray[0] + "?" + para + "#" + strArray[1]; } return url + "?" + para; } else { if (url.indexOf(para) != -1) return url; return strArray[0] + "?" + para + "&" + strArray[1]; } } function removeUrlPara(url, para) { var strArray = new Array(); strArray = url.split(para); if (strArray.length == 1) { strArray = url.split("?" + para); return strArray[0]; } else { if (strArray[1].indexOf("&") != -1) { strArray = url.split(para + "&"); return strArray[0] + strArray[1]; } else { strArray = url.split("?" + para); return strArray[0] + strArray[1]; } } } function l() { history.replaceState({ url: window.document.location.href, title: window.document.title, html: $(document).find(ajx_content).html() }, window.document.title, document.location.href); } function a() { window.addEventListener("popstate", function(e) { if (e.state) { document.title = e.state.title; $(ajx_content).html(e.state.html); rerun(); } }); } function ajax(reqUrl, msg, data) { if (msg == "pagelink" || msg == "search") { show_loading(true); $(ajx_content).fadeTo("normal", 0); $("body,html").animate({ scrollTop: $("body").offset().top }, 810); var paraUrl = addUrlPara(reqUrl, "ajx=container"); } else if (msg == "comtpagenav") { to_anchor("#post-comment-list", 0); $("#comment_list").fadeTo(500, .2, function() { $("#comment_list").css("position", "relative"); }); reqUrl = removeUrlPara(reqUrl, "ajx=container"); paraUrl = addUrlPara(reqUrl, "ajx=comts"); } $.ajax({ url: paraUrl, data: data, beforeSend: function() { l(); }, success: function(data) { if (msg == "pagelink" || msg == "search") { $(ajx_content).replaceWith($(data).filter(ajx_content)); $(ajx_content).fadeTo(500, 1, function() { rerun(); }); show_loading(false); } else if (msg == "comtpagenav") { var content = $(data).find("#comment_list").html(); $("#comment_list").animate({ opacity: 0, top: 35 }, 200, function() { $("#comment_list").html(content); $("#comment_list").animate({ opacity: 1, top: 0 }, 400, function() { $("#comment_list").css("position", "inherit"); }); rerun(); }); } document.title = $(data).filter("title").text(); reqUrl = removeUrlPara(reqUrl, "ajx=comts"); var state = { url: reqUrl, title: $(data).filter("title").text(), html: $(data).filter(ajx_content).html() }; window.history.pushState(state, $(data).filter("title").text(), reqUrl); }, complete: function() {}, timeout: 5e3, error: function(request) { if (msg == msg == "pagelink" || msg == "search") { show_loading(false); location.href = reqUrl; } else if (msg == "comtpagenav") { $("#comment_list").fadeTo("normal", 1); $("#comt_svg").css("display", "none"); $("#comments_paginate").css("display", "block"); } else { location.href = reqUrl; } } }); } function check_x(url) { var url_string = new String(" , comment-page-, #respond, #comment, javascript:, oauth2, .jpg, .gif, .png"); var url_x = url_string.split(", "); for (var i in url_x) { if (url.indexOf(url_x[i]) >= 0) { return true; } } return false; } $("body").on("click", "a[target!=_blank]:not(.noajx)", function() { url = $(this).attr("href"); if (check_x(url) == true) return; ajax(url, "pagelink"); return false; }); $("body").on("submit", "#search .s-form", function() { ajax(this.action + '?=' + $(this).find("#s").val(), 'search', $(this).serialize()); return false; }); $("body").on("click", "#comments_paginate a", function() { ajax($(this).attr("href"), "comtpagenav"); return false; });
核心就是ajax(reqUrl, msg, data)函数了,还有两个函数需要说明一下
1、check_x(url)函数 —— 这是检查a标签的链接中是否有需要排除的字符,有时候某些a标签是不需要ajax请求的,比如/wp-login.php,图片链接带有.jpg、.gif、.png 等等,都不需要ajax请求,我们得把它们排除掉,加入到check_x(url)内的排除列表内。
2、rerun()函数 —— 这个函数方便我们对其他js脚本进行重新加载,相当于一个回调函数,比如有的站用了多说评论系统,ajax请求时是不会请求css和js的,只抓取html结构,所以ajax加载后多说需要的js就不会一起加过来,这时候就需要把多说的js放进rerun()函数进行重新加载。
好了,PJAX教程就介绍到这里,适合有一定js基础的朋友看,如果连js都不懂,那只能靠百度了。
第三部分
原文来源: http://www.inlojv.com/5011.html
全站pjax教程一和二已经将重点与核心代码呈现过了,还有一些执行上的问题在此补充一下
1、并不是所有的pjax代码都相同?
网上有很多所谓的全站ajax代码,其实仅仅是页面ajax,全站还要兼顾很多东西,搜索、评论、重载回调等等,另外有一些pushstate的使用也不相同,有的pjax后退是没有缓存的,这样这些代码的前进和后退,就会重新请求一次push进去的历史链接,所以你会发现有的后退是重新执行一遍代码会有loading效果,而有的不是,是很干脆地切换回去。教程[二]提供的代码属于后者。
2、ajax替换页面容器所用的函数不同
比如教程[二]中ajax执行成功后有这么一句$(ajx_content).replaceWith($(data).filter(ajx_content));
,有一些代码则不同,有可能是这样的:$(ajx_content).html($(data).filter(ajx_content).html());
,还有的用的不是filter()
而是find()
。这两个函数是有区别的,一个是针对同级元素,一个是针对子元素;当对请求页面进行剪裁时,容器可能暴露在最外面,此时就需要用filter;当没有剪裁时就只能用find。
3、“剪裁”的方式
有的小伙伴可能对“剪裁”并不熟悉,只是生搬硬套,这也导致了后面需要做很多工作,比如:ajax请求后浏览器的页面标题需要通过修改页面结构来组合获取。其实剪裁的时候保留title标签,title就可以直接用document.title = $(data).filter("title").text();
来获取了。
4、重载回调
这个算是个很大的难题,因为解决这样的问题其实相当于把jquery的基础给学了一遍,我不是专业的,现在也还不是很明白这些代码的执行到底应该怎么描述。ajax请求不会请求到容器之外的脚本文件,除非你把js写在容器之内,比如之前我试过把百度分享代码写在footer.php
,但ajax始终不加载,只能把它写在single.php
的容器里面。 还有很多插件会加载额外的js脚本,比如多说评论、某虾米音乐插件、图片灯箱、代码高亮 等等,它们在ajax请求过来后都会失效,这时候就需要为ajax提供一个回调函数,方便在ajax过程执行完毕之后重新加载这些模块的js脚本。
有的插件提供了执行函数,比如slimbox灯箱,会有一个slimbox()
函数;Google prettify语法高亮,会有一个prettify()
函数,这些都可以在ajax回调时放进去重新加载,使得加载后这些功能不失效。
有的插件则不会提供这种函数,比如多说,它只有一整个js脚本,加载方式可以看这里两种方式执行外部插件挂载的js脚本
下面我就以最典型的Willin Kan版的ajax评论来举个例子,因为很多小伙伴完成页面ajax之后,评论ajax总是失效,下面先看看这个评论ajax代码:
var theme_dir = $('head #default-css').attr('href').split('style.css')[0]; // 主题路径 ,以style.css分割href,第一段就是主题路径 /** * WordPress jQuery-Ajax-Comments v1.3 by Willin Kan. * URI: http://kan.willin.org/?p=1271 */ var commentform = '#comment_form', // ××× form表单id comment = 'c_tarea', // ××× textarea 的id 不带# commentlist = 'comment-list', // ××× 评论列表ul或ol的class,不带点 respond = '#respond', // ××× 评论插入位置,插入在这个id之前 homeUrl = document.location.href.match(/http:\/\/([^\/]+)\//i)[0], // 主页地址,用于下面的提交函数 txt1 = '<div id="loading" class="text-info"> 正在提交, 请稍候...</div>', txt2 = '<div id="error">#</div>', txt3 = '"><div class="text-success"> OK !', edt1 = ' 刷新页面之前您可以<a rel="nofollow" class="comment-reply-link" href="#edit" onclick=\'return addComment.moveForm("', edt2 = ')\'>再次编辑评论</a></div>', cancel_edit = '取消编辑', edit, num = 1, $comments = $('#response'), // 评论数 $cancel = $('#cancel-comment-reply-link'), cancel_text = $cancel.text(), $submit = $(commentform+ '#submit'); $submit.attr('disabled', false), $body = (window.opera) ? (document.compatMode == "CSS1Compat" ? $('html') : $('body')) : $('html,body'), comm_array = []; comm_array.push(''); $('#'+comment).after(txt1 + txt2); // ××× textarea的id或class $('#loading').hide(); $('#error').hide(); // 评论提交 // $(commentform).submit( // 非动态绑定 $(document).on("submit", commentform, //动态绑定 function() { if (edit) $('#'+comment).after('<input type="text" name="edit_id" id="edit_id" value="' + edit + '" style="display:none;" />'); $submit.attr('disabled', true).fadeTo('slow', 0.5); $('#loading').slideDown(); $.ajax({ url: theme_dir + '/comt-ajax.php', data: $(this).serialize() , type: $(this).attr('method'), error: function(request) { $('#loading').slideUp(); $("#error").slideDown().html(request.responseText); setTimeout(function() { $submit.attr('disabled', false).fadeTo('slow', 1); $('#error').slideUp(); }, 3000); }, success: function(data) { $('#loading').hide(); comm_array.push($('#'+comment).val()); $('textarea').each(function() { this.value = '' }); var t = addComment, cancel = t.I('cancel-comment-reply-link'), temp = t.I('wp-temp-form-div'), respond = t.I(t.respondId), post = t.I('comment_post_ID').value, parent = t.I('comment_parent').value; // 增加评论数 if (!edit && $comments.length) { n = parseInt($comments.text().match(/\d+/)); // 匹配数字 $comments.text($comments.text().replace(n, n + 1)); } // 评论显示 new_htm = '" id="new_comm_' + num + '"></'; new_htm = (parent == '0') ? ('\n<ol style="clear:both;" class="'+commentlist+'" ' + new_htm + 'ol>') : ('\n<ul class="children' + new_htm + 'ul>'); ok_htm = '\n<div class="ajax-notice" id="success_' + num + txt3; div_ = (document.body.innerHTML.indexOf('div-comment-') == -1) ? '': ((document.body.innerHTML.indexOf('li-comment-') == -1) ? 'div-': ''); ok_htm = ok_htm.concat(edt1, div_, 'comment-', parent, '", "', parent, '", "respond", "', post, '", ', num, edt2); ok_htm += '</span><span></span>\n'; ok_htm += '</div>\n'; if($('#comments .comment-list').length>0){ // ××××××××××××××××××××非嵌套评论时,新评论显示插入的位置(按自己的喜好修改显示位置) $('#comments .comment-list').before(new_htm); } else{ $('#respond').after(new_htm); } $('#new_comm_' + num).append(data); $('#new_comm_' + num + ' li').append(ok_htm); $body.animate({scrollTop: $('#new_comm_' + num).offset().top - 200},900); countdown(); num++; edit = ''; $('*').remove('#edit_id'); cancel.style.display = 'none'; cancel.onclick = null; t.I('comment_parent').value = '0'; if (temp && respond) { temp.parentNode.insertBefore(respond, temp); temp.parentNode.removeChild(temp) } } }); return false; }); addComment = { moveForm: function(commId, parentId, respondId, postId, num) { var t = this, div, comm = t.I(commId), respond = t.I(respondId), cancel = t.I('cancel-comment-reply-link'), parent = t.I('comment_parent'), post = t.I('comment_post_ID'); if (edit) exit_prev_edit(); num ? (t.I(comment).value = comm_array[num], edit = t.I('new_comm_' + num).innerHTML.match(/(comment-)(\d+)/)[2], $new_sucs = $('#success_' + num), $new_sucs.hide(), $new_comm = $('#new_comm_' + num), $new_comm.hide(), $cancel.text(cancel_edit)) : $cancel.text(cancel_text); t.respondId = respondId; postId = postId || false; if (!t.I('wp-temp-form-div')) { div = document.createElement('div'); div.id = 'wp-temp-form-div'; div.style.display = 'none'; respond.parentNode.insertBefore(div, respond) } ! comm ? (temp = t.I('wp-temp-form-div'), t.I('comment_parent').value = '0', temp.parentNode.insertBefore(respond, temp), temp.parentNode.removeChild(temp)) : comm.parentNode.insertBefore(respond, comm.nextSibling); $body.animate({scrollTop: $('#respond').offset().top - 180},400); if (post && postId) post.value = postId; parent.value = parentId; cancel.style.display = ''; cancel.onclick = function() { if (edit) exit_prev_edit(); var t = addComment, temp = t.I('wp-temp-form-div'), respond = t.I(t.respondId); t.I('comment_parent').value = '0'; if (temp && respond) { temp.parentNode.insertBefore(respond, temp); temp.parentNode.removeChild(temp); } this.style.display = 'none'; this.onclick = null; return false; }; try { t.I(comment).focus(); } catch(e) {} return false; }, I: function(e) { return document.getElementById(e); } }; function exit_prev_edit() { $new_comm.show(); $new_sucs.show(); $('textarea').each(function() { this.value = '' }); edit = ''; } var wait = 15, submit_val = $submit.val(); function countdown() { if (wait > 0) { $submit.val(wait); wait--; setTimeout(countdown, 1000); } else { $submit.val(submit_val).attr('disabled', false).fadeTo('slow', 1); wait = 15; } } function grin(a) { var b; a = " " + a + " "; if (document.getElementById(comment) && document.getElementById(comment).type == "textarea") { b = document.getElementById(comment) } else { return false } if (document.selection) { b.focus(); sel = document.selection.createRange(); sel.text = a; b.focus() } else if (b.selectionStart || b.selectionStart == "0") { var c = b.selectionStart; var d = b.selectionEnd; var e = d; b.value = b.value.substring(0, c) + a + b.value.substring(d, b.value.length); e += a.length; b.focus(); b.selectionStart = e; b.selectionEnd = e } else { b.value += a; b.focus() } }
上面的代码有些选择器是针对我自己的主题的,所以仅供参考,这个不重要。重点是当各种变量赋值完毕后,那一句$(document).on("submit", commentform,
,这个是关键,意思是这个on方法把submit事件冒泡绑定到了document上,这个时候submit事件里面的所有动作就不会受到页面ajax加载的影响。你可以注意到上面有一句$('#'+comment).after(txt1 + txt2);
这个是在提交评论时显示的loading提示文字,它没有被包含在submit事件里面,所以它是受到页面ajax加载影响的!也就是说:页面ajax加载后,你点击评论提交按钮,此时不会显示loading提示文字,但却能进行ajax评论提交。如果你把这段提示放进submit里面去,那么整个评论ajax就和页面ajax完全相互独立了,它们可以互不影响,完全兼容。
另外,你可能注意到在$(document).on("submit", commentform,
上一句注释是这样的$(commentform).submit(
,这表示你没有用on方法将submit冒泡到document之上,此时这就和上面那个loading提示文字是一样的,整个评论ajax就会受到页面ajax的影响。那么如果不用on方法,应该怎么兼容?看下面的代码:
var theme_dir = $('head #default-css').attr('href').split('style.css')[0]; // 主题路径 ,以style.css分割href,第一段就是主题路径 /** * WordPress jQuery-Ajax-Comments v1.3 by Willin Kan. * URI: http://kan.willin.org/?p=1271 */ $(document).ready(function() { ajaxComt(); }); function ajaxComt(){ var commentform = '#comment_form', // ××× form表单id comment = 'c_tarea', // ××× textarea 的id 不带# commentlist = 'comment-list', // ××× 评论列表ul或ol的class,不带点 respond = '#respond', // ××× 评论插入位置,插入在这个id之前 homeUrl = document.location.href.match(/http:\/\/([^\/]+)\//i)[0], // 主页地址,用于下面的提交函数 txt1 = '<div id="loading" class="text-info"> 正在提交, 请稍候...</div>', txt2 = '<div id="error">#</div>', txt3 = '"><div class="text-success"> OK !', edt1 = ' 刷新页面之前您可以<a rel="nofollow" class="comment-reply-link" href="#edit" onclick=\'return addComment.moveForm("', edt2 = ')\'>再次编辑评论</a></div>', cancel_edit = '取消编辑', edit, num = 1, $comments = $('#response'), // 评论数 $cancel = $('#cancel-comment-reply-link'), cancel_text = $cancel.text(), $submit = $(commentform+ '#submit'); $submit.attr('disabled', false), $body = (window.opera) ? (document.compatMode == "CSS1Compat" ? $('html') : $('body')) : $('html,body'), comm_array = []; comm_array.push(''); $('#'+comment).after(txt1 + txt2); // ××× textarea的id或class $('#loading').hide(); $('#error').hide(); // 评论提交 $(commentform).submit( // 非动态绑定 // $(document).on("submit", commentform, // 动态绑定 function() { if (edit) $('#'+comment).after('<input type="text" name="edit_id" id="edit_id" value="' + edit + '" style="display:none;" />'); $submit.attr('disabled', true).fadeTo('slow', 0.5); $('#loading').slideDown(); $.ajax({ url: theme_dir + '/comt-ajax.php', data: $(this).serialize() , type: $(this).attr('method'), error: function(request) { $('#loading').slideUp(); $("#error").slideDown().html(request.responseText); setTimeout(function() { $submit.attr('disabled', false).fadeTo('slow', 1); $('#error').slideUp(); }, 3000); }, success: function(data) { $('#loading').hide(); comm_array.push($('#'+comment).val()); $('textarea').each(function() { this.value = '' }); var t = addComment, cancel = t.I('cancel-comment-reply-link'), temp = t.I('wp-temp-form-div'), respond = t.I(t.respondId), post = t.I('comment_post_ID').value, parent = t.I('comment_parent').value; // 增加评论数 if (!edit && $comments.length) { n = parseInt($comments.text().match(/\d+/)); // 匹配数字 $comments.text($comments.text().replace(n, n + 1)); } // 评论显示 new_htm = '" id="new_comm_' + num + '"></'; new_htm = (parent == '0') ? ('\n<ol style="clear:both;" class="'+commentlist+'" ' + new_htm + 'ol>') : ('\n<ul class="children' + new_htm + 'ul>'); ok_htm = '\n<div class="ajax-notice" id="success_' + num + txt3; div_ = (document.body.innerHTML.indexOf('div-comment-') == -1) ? '': ((document.body.innerHTML.indexOf('li-comment-') == -1) ? 'div-': ''); ok_htm = ok_htm.concat(edt1, div_, 'comment-', parent, '", "', parent, '", "respond", "', post, '", ', num, edt2); ok_htm += '</span><span></span>\n'; ok_htm += '</div>\n'; if($('#comments .comment-list').length>0){ // ××××××××××××××××××××非嵌套评论时,新评论显示插入的位置(按自己的喜好修改显示位置) $('#comments .comment-list').before(new_htm); } else{ $('#respond').after(new_htm); } $('#new_comm_' + num).append(data); $('#new_comm_' + num + ' li').append(ok_htm); $body.animate({scrollTop: $('#new_comm_' + num).offset().top - 200},900); countdown(); num++; edit = ''; $('*').remove('#edit_id'); cancel.style.display = 'none'; cancel.onclick = null; t.I('comment_parent').value = '0'; if (temp && respond) { temp.parentNode.insertBefore(respond, temp); temp.parentNode.removeChild(temp) } } }); return false; }); addComment = { moveForm: function(commId, parentId, respondId, postId, num) { var t = this, div, comm = t.I(commId), respond = t.I(respondId), cancel = t.I('cancel-comment-reply-link'), parent = t.I('comment_parent'), post = t.I('comment_post_ID'); if (edit) exit_prev_edit(); num ? (t.I(comment).value = comm_array[num], edit = t.I('new_comm_' + num).innerHTML.match(/(comment-)(\d+)/)[2], $new_sucs = $('#success_' + num), $new_sucs.hide(), $new_comm = $('#new_comm_' + num), $new_comm.hide(), $cancel.text(cancel_edit)) : $cancel.text(cancel_text); t.respondId = respondId; postId = postId || false; if (!t.I('wp-temp-form-div')) { div = document.createElement('div'); div.id = 'wp-temp-form-div'; div.style.display = 'none'; respond.parentNode.insertBefore(div, respond) } ! comm ? (temp = t.I('wp-temp-form-div'), t.I('comment_parent').value = '0', temp.parentNode.insertBefore(respond, temp), temp.parentNode.removeChild(temp)) : comm.parentNode.insertBefore(respond, comm.nextSibling); $body.animate({scrollTop: $('#respond').offset().top - 180},400); if (post && postId) post.value = postId; parent.value = parentId; cancel.style.display = ''; cancel.onclick = function() { if (edit) exit_prev_edit(); var t = addComment, temp = t.I('wp-temp-form-div'), respond = t.I(t.respondId); t.I('comment_parent').value = '0'; if (temp && respond) { temp.parentNode.insertBefore(respond, temp); temp.parentNode.removeChild(temp); } this.style.display = 'none'; this.onclick = null; return false; }; try { t.I(comment).focus(); } catch(e) {} return false; }, I: function(e) { return document.getElementById(e); } }; function exit_prev_edit() { $new_comm.show(); $new_sucs.show(); $('textarea').each(function() { this.value = '' }); edit = ''; } var wait = 15, submit_val = $submit.val(); function countdown() { if (wait > 0) { $submit.val(wait); wait--; setTimeout(countdown, 1000); } else { $submit.val(submit_val).attr('disabled', false).fadeTo('slow', 1); wait = 15; } } function grin(a) { var b; a = " " + a + " "; if (document.getElementById(comment) && document.getElementById(comment).type == "textarea") { b = document.getElementById(comment) } else { return false } if (document.selection) { b.focus(); sel = document.selection.createRange(); sel.text = a; b.focus() } else if (b.selectionStart || b.selectionStart == "0") { var c = b.selectionStart; var d = b.selectionEnd; var e = d; b.value = b.value.substring(0, c) + a + b.value.substring(d, b.value.length); e += a.length; b.focus(); b.selectionStart = e; b.selectionEnd = e } else { b.value += a; b.focus() } } } // end Ajax评论
代码的核心内容和前面是一样的,只不过我将整段评论代码写成了一个ajaxComt()
函数,也就是将代码用function ajaxComt(){...}
包住,可以看到,此时submit事件并非动态绑定,只要这样
$(document).ready(function() { ajaxComt(); });
就和原来不用函数包住的时候没什么区别了。那么这个ajaxComt()
函数,就是我们放在页面ajax回调里面重新加载的东西。ajax方法里面会有几个执行先后的参数,beforeSend、success、complete ,我们可以把它放在complete里面:
complete: function() { // 页面ajax完成后加载 ajaxComt(); }
这样就和动态绑定没什么区别了。说法的区别从我个人角度来看就是:前者属于冒泡绑定,页面ajax和评论ajax是互不影响的;后者属于先后执行,页面ajax先执行完毕再执行一遍评论ajax 。
第四部分
原文来源: http://www.inlojv.com/5026.html
教程进行到第四已然显得有些罗嗦了,本篇主要是本人记录自己遇到的一些细节问题和网上的各种pjax代码版本,权当补充篇来看吧。
搜索ajax表单序列化
最近想把主题换成经典的twentytwelve
,也试着把它pjax化,其中遇到一个搜索ajax的问题,按理说其他主题能实现,没问题,这个也应该可以,但我把代码搬上去之后,发现搜索ajax返回没有返回正确的页面,这里首先要说的就是WordPress正常情况下的搜索请求链接应该是这样的http://127.0.0.1/?=xxx
,xxx表示你搜索的关键字,而由于有后端的处理(也就是教程[一]中的“剪裁”),发送给ajax的请求链接一般是类似?ajx=container
这样的后缀(其他版本有可能是这样?action=pjax
),那么搜索ajax的请求链接能不能这样http://127.0.0.1/?=xxx?ajx=container
?答案是不能。只能把?号换成&号,变成这样http://127.0.0.1/?=xxx&ajx=container
,所以在搜索ajax的请求链接上要加一些判断,如果是搜索,那么得改一改链接附加的参数形式。
以上只是一个细节,我在修改twentytwelve时没有返回应有的页面,把搜索链接http://127.0.0.1/?=xxx&ajx=container
直接输入到浏览器打开,发现也不是搜索结果页面,找了半天才发现是form表单序列化的问题,$.ajax()
方法有几个参数,其中我们要把序列化的表单信息放入到ajax方法的data参数内。赋值 data = $('#searchform').serialize();
。其中#searchform是form表单的id
以上只是一个例子,条件判断可以按自己的思路来做改变。如此一来,搜索ajax就没有问题了。