jQuery+PHP 大话ajax免刷新提交表单与切换页面
昨天折腾了一个晚上,今天在抽空折腾的东西,不记下来未免太浪费了,于是我决定花晚上把它写下来。
Ajax是目前最流行的优化用户体验的方法,但在过去,他往往代表着牺牲SEO以及抛弃浏览器后退前进功能,但是现在,已经不是这样了。
现在的Ajax完全可以做到兼备,所以你可以看到,基本上,在你提交表单之后再也不用跳转之后才告诉你你的输入是否正确,甚至在搜索时,一边输入字符,一边进行检索。
这些都是Ajax所带来的便利,但是鉴于我还没有前后端整站写过(只有使用前后框架[PHP MVC]以及前端的经历),所以对整个流程还不能说熟悉。这次,我们从后端写到前端,一点点来解刨Ajax的套路。
首先,我们前端的核心当然是$.ajax
啦,没有他我们怎么实现ajax呢?在之前,我已经写过ajax的表单提交了,所以表单其实是很好上手的,相比之下,页面切换的处理要麻烦很多。
关于jQuery中的$.ajax
,这里有w3school和官方文档,w3school的参数不是很全,但是是中文的。中文文档不知道全不全:http://jquery.bootcss.com/jQuery.ajax/
好了,不多做介绍了,之后用到什么讲什么吧。
首先,我们用html建立一个传统意义上的表单,其中method="post"
:
1<form class="login" method="post">
2 <input type="password" placeholder="密码" name="password">
3 <input type="submit" value="提交">
4</form>
5
如果是PHP的话,应该还有action,但我们用ajax传输,就不用这么写了。
然后我们用jQuery写个点击事件:
$('.login>input[type="submit"]').click(function() {
$.ajax({
type: 'POST',
url: 'core/login.php',
data: $('.login').serialize(),
dataType: 'json',
beforeSend: function() {
$('.tip').html('Loading');
},
success: function(data) {
if (data == '200') {
$('.tip').html('Success');
$('.tip').css({color: 'green'});
setTimeout(function(){
pajax('microblog.php', 'Hello');
}, 300);
} else if (data == '403') {
$('.tip').html('Error Password');
$('.tip').css({color: 'red'});
} else {
$('.tip').css({color: '#000'});
$('.tip').html('Develop Error');
}
},
error: function() {
$('.tip').html('Something Wrong');
}
});
return false;
});
呀,进度好像过快了,但就是这样。$('.login').serialize()
把login
传过来的值序列化为对象了。这里剩下的似乎都没什么好说的,唯一要说的是return false
,这一点在于取消默认行为,默认来说,使用submit之后,页面会有一个跳转(或者说刷新)操作,跳转到action,但我们不需要这个多余的动作,所以用它阻止冒泡。
然后开始写PHP部分,也就是上文要传输过去的core/login.php
。
1<?php
2 session_start();
3
4 // array_key_exists('password', $_POST)
5 if (isset($_POST['password'])) {
6 $pass = md5($_POST['password']);
7
8 if ($pass == md5('Kurama')) {
9 $_SESSION['login'] = true;
10 echo json_encode('200');
11 } else {
12 echo json_encode('403');
13 }
14 } else {
15 echo json_encode('404');
16 }
17?>
18
是怎么回事呢?我们照理写我们的PHP部分,其实是不干扰的,只要传出json_encode()
转换为json对象就好了。
剩下的就跟PHP一样处理,包括写入session等部分。
如果要检测数组是否有某个值,也可以使用:array_key_exists('password', $_POST)
,其实我是嫌这货太长- -#
好了,表单讲完了,烦人的是,我们要开始试着做局部或者全局Ajax了,这个好麻烦呀,之前没有试过呀。
于是就有了下面的一大堆资料来学习,大致上是这样的。
首先我们来说说全局的ajax。
这一点其实并不难,我们需要在ajax
里type使用html来获取,并且加入就可以了,大致Like that.
1var pajax = function(targetUrl, targetTitle) {
2 $.ajax({
3 dataType: 'html',
4 type: 'GET',
5 url: targetUrl,
6 headers: {
7 Pjax: true
8 },
9 success: function(data) {
10 $('body').contents().remove();
11 $('body').append(data);
12 console.log(data);
13 $('title').html(targetTitle);
14 window.history.pushState({type:'url', url: targetUrl, title: targetTitle}, 'Hello', targetUrl);
15 }
16 });
17};
18
关于window.history的部分,之后在做解释。 我们可以看到,这样就把body里的部分移除了,然后在append过去,基本上是没什么问题的。
当然,这里我们需要PHP的配合,否则的话就会出现把全部页面重复加载到body里的问题。 在这里,我们在ajax时设定了一个header,之后就会用上了。
在PHP部分,通常我们会选择将网页分成三个部分,header.php, xxx.php, footer.php,这里,我们给header和footer加个判断(xxx.php存放的是差异部分,也是需要remove的部分)。
1<?php
2 if (!isset($_SERVER['HTTP_PJAX']))
3 include('common/header.php');
4?>
5
在这里,我们使用$_SERVER['HTTP_PJAX']
的存在与否来检查是否要载入header和footer,于是,就能分成:可以正常直接访问页面,以及可以正常ajax加载了。
接下来,我们前面说到,关于SEO的问题,也是为了刷新访问正常,我们需要在Ajax之后改变地址栏,这也就是后面一大堆参考的攻略点了。
我们需要用到的也就是操作历史记录(pushstate&popstate),pushState
可以做到免刷新修改url,这点就是和window.location的不同之处了。
1window.history.pushState({type:'url', url: targetUrl, title: targetTitle}, targetTitle, targetUrl);
2
这句话起到的作用也就在于此了。这里需要注意的是,传入的值都是相对于目标页面(也就是Ajax载入的页面)而言的,而不是原来的页面。所以我们这里用target来表示。
做到这里,还不够,因为我们还需要知道用户什么时候点击了后退前进按钮,这里需要使用到popstate监听:
1window.addEventListener('popstate', function(e){
2 var url;
3 var title;
4 if (window.history.state){
5 var state = e.state;
6 url = state.url;
7 title = state.title;
8 type = state.type;
9 }
10 if (type != 'page') {
11 $.ajax({
12 dataType: 'html',
13 type: 'GET',
14 url: url,
15 headers: {
16 Pjax: true
17 },
18 success: function(data) {
19 $('body').contents().remove();
20 $('body').append(data);
21 console.log(data);
22 $('title').html(title);
23 }
24 });
25 } else {
26 page.pjax = true;
27 page.switchPage(state.pageNumber);
28 }
29});
30
主要还是看这段:
1 if (window.history.state){
2 var state = e.state;
3 url = state.url;
4 title = state.title;
5 type = state.type;
6 }
7
这里储存了我们的保留数据:pushState的第一个参数。然后根据参数来判断就好了。
当然,这里有个坑:最开始直接访问的地址是没有window.history.state的,我本来想着保留第一次访问的数据,通过监听内判断有没有window.history.state来决定。
结果发现如果在别的地方我还要使用局部ajax的话,这种写法太渣了,根本不能用,于是我们这么做:
1 if (!history.state) {
2 window.history.replaceState({type: 'url', pageNumber: page.currentPage, title: 'microblog'}, 'Hello', 'microblog.php');
3 }
4
使用replaceState,我们覆盖历史记录,参数同pushState部分。计划通。
最后,我们来试试局部Ajax,其实理论上而言这会比全局简单,因为只要删除部分DOM,然后加上嘛~实际上还是在地址栏以及前进后退的问题。 如果我们不进行一些判断操作,那么很快就会陷入 读取数据 - back修改链接并写入相关信息 然后重复这个操作,于是如同上面的源码,我们通过设置一个pjax等不等于true来解决这个问题。同时,针对是局部还是全部加载,我们新设置了一个type属性。
对应判断:
1Page.prototype.switchPage = function(targetPageNumber) {
2 this.getPageNumber(function() {
3 message.getMessage(targetPageNumber);
4 this.changePages(targetPageNumber);
5 var targetUrl = 'microblog.php#' + targetPageNumber;
6 console.log(this.pjax);
7 if (!this.pjax) {
8 window.history.pushState({type: 'page', pageNumber: targetPageNumber, title: 'MicroBlog', url: targetUrl}, 'MicroBlog', targetUrl);
9 }
10 this.pjax = false;
11 });
12}
13
计划通在这里:
1 if (!this.pjax) {
2 window.history.pushState({type: 'page', pageNumber: targetPageNumber, title: 'MicroBlog', url: targetUrl}, 'MicroBlog', targetUrl);
3 }
4 this.pjax = false;
5
so,在此,我们实现了所有的Ajax免刷新操作,非常感谢各种文章提供的各种帮助wwww
感谢以下文章: HTML5之pushstate、popstate操作history,无刷新改变当前url 使用ajax和history.pushState无刷新改变页面URL jQuery Address 全站 AJAX (Deep Linking) 完整案例详解 HTML5 简介(三):利用 History API 无刷新更改地址栏 jquery ajax发送Post请求,如何添加请求头
评论 (0)