本页目录
很多人喜欢 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 就没有问题了。