JavaScript内功功法AJAX的详解

ajax的介绍

AJAX是属于javascript的一个应用,可以说是一个扩展,它只是一个哥们“发明”的缩写:Asynchronous JavaScript and XML,意思就是用JavaScript执行异步网络请求。

那么什么是异步网络请求呢?说白了就是多种事情一起做,相互之间并不互相影响。就像我们在网上填写表单时,当我们输入的信息和规定的标准不一样时,就是实时的提示你输入错误,而不是在最后提交的时候才告诉你,这里的实时的提示就是异步操作。

ajax解决的问题

我们在使用表单向后台提交数据的时候,通常都是跳转到一个新的页面,然后在新页面里告诉你操作是成功了还是失败了。也就是一次HTTP请求对应一个页面。

使用ajax解决的问题:如果要让用户留在当前页面中,同时发出新的HTTP请求,就必须用JavaScript发送这个新请求,接收到数据后,再用JavaScript更新页面,这样一来,用户就感觉自己仍然停留在当前页面,但是数据却可以不断地更新。也就是在不重新加载整个网页的情况下,对网页的某部分进行更新。比如当我们访问百度的时候,输入关键字就会自动的出现和关键字相关的内容。同时使用ajax可以实现分页的效果。

用JavaScript写一个完整的AJAX代码并不复杂,但是需要注意:AJAX请求是异步执行的,也就是说,要通过回调函数获得响应。在响应函数中对数据进行操作。

ajax对象的创建和使用

在现代的大多数浏览器中创建ajax对象使用的类是XMLHttpRequest对象,但是当我们在低版本的IE中创建ajax对象的时候,就会发现,这个类是不能使用的,要使用到ActiveXObject类。
这里写图片描述
而我们可以在控制台看到输出的ajax对象的内容:
这里写图片描述

创建完对象,我们就可以使用对象里面的方法和后台进行连接进行数据的查询等操作。我们一般使用到的是三个方法。

  1. xhr.open(method,url,flag);使用这个方法,可以和后台建立连接。里面有三个参数

    • 第一个参数是请求的方法,可以是get或post请求。
    • 第二个参数是请求的地址,一般指向后台的某个地址
    • 第三个参数是一个布尔类型的值,当为true时,表示我们是异步请求,默认是true,如果是false时,表示异步请求,但是当我们尝试去把这个参数修改成false后,会报一个错误,大致意思是说主线程上的同步XMLHttpRequest因其对最终用户体验的不利影响而被弃用。所以一般我们都是写true
      这里写图片描述
  2. xhr.send();当我们使用open方法后,建立连接,然后就是发送数据,对于发送数据,当我们使用不同的请求方式有不同的发送方式。

    1. 如果是get请求,请求的数据是在url上进行传输的,这是我们可以直接调用send()方法进行发送,不需要参数的传递
    2. 如果是post请求,请求的数据是在http协议的请求实体中,并不在url上。这时就需要单独的设置。注意,使用get方式时,不需要设置请求头,传递的数据直接写在url上。
      这里写图片描述
  3. xhr.onreadystatechange = function(){};当上面的两步执行完后,我们可以对请求的情况进行监听。
    这里写图片描述
    我们获取后台的数据一般是通过ajax的responseText方法得到。而一般后台传过来的数据都是json格式的数据。在这里我们可以模拟后台传输的数据。
    这里写图片描述
    我们在后台通过使用php定义一个数组,并把数组转换成json格式类型。通过echo输出。这样在前台就可以正确的接受到json数据。
    这里写图片描述
    我们可以把json数据格式转换成对象的格式,方便我们的获取。
    这里写图片描述
    这里写图片描述
    当我们转换成对象后,就可以使用对象的访问形式进行数据的填充。

ajax的get请求方式和特殊字符的处理

get方式缓存处理

在我们和后台进行连接的时候,如果使用get方式请求,很容易的产生缓存,当我们再次访问的时候,有可能访问的是本地缓存的网页,并没有进行连接,对于此问题,我们通过的方法是在url连接上传递一个随机数参数,这样每次访问的时候,都是一个最新的连接。

这里写图片描述

特殊字符的处理

当我们在向后台传输数据的时候,有时候我们可能会遇见这样的参数,比如一个人的名字是 ajax&js 或者ajax?java,这时候,我们如果还是使用上面的方式,没有处理而直接传递到后台,你会发现,会发生意料之外的事情,针对像&或?中文等的特殊字符的处理。我们一般是把特殊字符进行转换。使用encodeURIComponent方法。
这里写图片描述
这里写图片描述
从上面的代码中可以看到,完美的解决了特殊字符的问题。

ajax跨站请求

我们在上面使用open方法时,都是指定文件名的,也就是相对路径,就就是请求的资源和当前文件的域名地址和端口号是一样的,如果我们把地址尝试的修改成百度的地址,你会发现,在浏览器会报一个错误。

这里写图片描述

这是因为浏览器的同源策略导致的。默认情况下,JavaScript在发送AJAX请求时,URL的域名必须和当前页面完全一致。完全一致的意思是,域名要相同(www.php.com和php.com不同),协议要相同(http和https不同),端口号要相同(默认是:80端口,它和:8080就不同)。

那是不是用JavaScript无法请求外域(就是其他网站)的URL了呢?方法还是有的,我们可以使用jsonp,它有个限制,只能用GET请求,并且要求返回JavaScript。这种方式跨域实际上是利用了浏览器允许跨域引用JavaScript资源

我们先来看一个简单的访问函数的案列:

 <script>
        //定义一个方法,传递过来的参数是一个对象格式的数据
        function getData(obj){
            //输出传递过来的数据
            console.log(obj);
        }
    </script>
    <script>
        //对上面js中的函数进行访问,并传递过去一个对象格式的数据
        getData({
            name:'张三',
            age:23,
            sex:'男',
            class:2
        })
    </script>

这里写图片描述

在第二个js代码中进行访问函数。我们再次对上面的代码进行修改,我们访问函数的js代码单独的写到一个文件中。
这里写图片描述

封装过后我们通过引入这个js文件。

 <script>
        //定义一个方法,传递过来的参数是一个对象格式的数据
        function getData(obj){
            //输出传递过来的数据
            console.log(obj);
        }
    </script>
    <script src = './getData.js'></script>

这时我们可以看到结果是和原来的一样的。就像上面说的这种方式跨域实际上是利用了浏览器允许跨域引用JavaScript资源:当引入外部的js资源文件后,当我们文件里面有资源定义的函数,就会自动的调用。

在百度有一个连接https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=ajax&cb=JSON_CALLBACK,它会自动的返回一个js代码

JSON_CALLBACK({q:"ajax",p:false,s:["ajax提交form表单","ajax 同步","ajax教程","ajax post","ajax error","ajax async","ajax json","ajax 上传文件","ajax跨域请求","ajax 跨域"]});

我们可以在自己的代码中定义JSON_CALLBACK方法接受数据。

function JSON_CALLBACK(obj){
     console.log(obj);
}

这里写图片描述

使用上面方式我们就可以进行跨站的访问数据。当然跨站访问有很多方式,这种方式只是其中的一种。

ajax实现分页

在开发中分页功能是很常见的一种功能,而ajax也是可以实现分页的效果,并且这种效果是在在页面中小范围的刷新数据。

ajax功能的封装

我们在使用ajax时,每次都是定义对象,连接,发送,监听回调。其实我们可以把ajax一些公共的代码进行封装,使用的时候,只需要传递一些参数就能自动的进行请求,并通过回调函数进行返回。我们传递的参数格式是一个对象:

    {
         method:'get',//访问的方法
         url:'data.php',
         data:'name=ajax',//传递的参数
         callback:function(res){//当返回数据后调用的回调函数,可以在这里面刷新页面数据
            console.log(res);
         }
    }

封装的ajax方法,使用传递过来的对象属性。

//定义一个对象,来封装ajax.
var $$ = {
    //定义方法,传递一个对象类型的参数
    request:function(obj){
        //创建xmlhttprequest对象
        var xhr;
        if(window.XMLHttpRequest){
            xhr = new XMLHttpRequest();
        }else{
            xhr = new ActiveXObject("Microsoft.XMLHTTP");
        }

        //建立连接,通过传递过来的参数判断是什么请求。
        if(obj.method=='get'){
            xhr.open(obj.method,obj.url+'?'+obj.data+'&'+Math.random(),true);
            xhr.send();
        }else if(obj.method=='post'){
            xhr.open(obj.method,obj.url,true);
            xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
            xhr.send(obj.data);
        }
        //监视请求的状态
        xhr.onreadystatechange = function(){
            if(xhr.readyState==4 && xhr.status==200){
                    eval("var res = "+xhr.responseText);
                    //返回数据,调用回调函数。
                    obj.callback(res);
                }
            }
        }
    }
}

这里写图片描述

结果:

这里写图片描述

当我们封装后,使用起来就方便了很多。

ajax分页

上面我们已经封装了ajax的代码,在分页是我们就可以直接的时候,而不用每次的创建。

 <!--引入封装的ajax的js代码-->
<script type="text/javascript" src="js/ajax.js"></script>

在分页中当我们每次点击下一页或者上一页的时候,都会使用ajax请求后台获得数据,所以在JavaScript中写一个方法,同时把要获取那一页的页数通过参数传进去。

function getContent(page){
    $$.request({
        method:'post',
        url:'page.php',
        data:'page='+page,
        dataType:'text',
        callback:function(obj){
           //这是一个回调函数,当后台返回数据时,传递到这里
        }
    });
}

使用封装的ajax去请求后台,获取数据,因为我们在封装的代码中当获取数据后调用回调函数,callback这个方法就会在返回后调用,在这个方法中,我们可以动态的创建节点对象并把数据填充进去。我们从后台获取的数据可以是这种格式:
这里写图片描述

得到后台返回的数据,我们就可以动态的创建节点。填充数据,

callback:function(obj){
    if(obj.status){
        //得到当前页的数据
        var list = obj.result;
        //总的记录数
        total_rows = obj.total_rows;
        //总的页数
        total_pages = obj.total_pages;
        //创建节点对象并进行动态的填充数据。
        var oUl = document.getElementById('content');
        if(!oUl){
            var oUl = document.createElement('ul');
            oUl.id = 'content';
        }
        oUl.innerHTML = '';
        //根据结果创建对应的li标签
        for(var i=0;i<list.length;i++){
            var oLi = document.createElement('li');
            oLi.innerHTML = '<a href=""><img src="'+list[i].pic+'"><span>'+list[i].title+'</span></a>';
            oUl.appendChild(oLi);
        }

        document.getElementById('main').appendChild(oUl);

        //创建分页标签
        createPageBar(page);
    }
}

我们在创建节点对象的时候进行判断,是因为点击下一页或上一页的时候,就要把当前页的内容销毁掉,

if(!oUl){
    var oUl = document.createElement('ul');
    oUl.id = 'content';
}
oUl.innerHTML = '';

我们的下面的分页也是多变的数据
这里写图片描述

因此我们也可以在每次得到数据,创建节点对象后,创建分页显示条。

 //创建分页条
function createPageBar(now_page){
    //分页被div包裹
    var oDiv = document.getElementById('pagebar');
    //每点击一次,都要把上一页的销毁掉
    if(!oDiv){
        var oDiv = document.createElement('div');
        oDiv.id = 'pagebar';
    }
    //定义公共的部分
    oDiv.innerHTML = '';
    var page_str = '<span>共'+total_rows+'条记录'+now_page+'/'+total_pages+'</span>';
    //当前页是第一页的时候,上一页是不显示的。
    if(now_page==1){

        //当前是第一页的时候,显示下一页和尾页
        page_str += '<a href="javascript:getContent('+(now_page+1)+')">下一页</a><a href="javascript:getContent('+total_pages+')">尾页</a>';
    }else if(now_page==total_pages){

        //如果是尾页的时候,下一页是不显示的。
        page_str += '<a href="javascript:getContent(1)">首页</a><a href="javascript:getContent('+(now_page-1)+')">上一页</a>';
    }else{

        //其他形式,上一页和下一页都显示。
        page_str += '<a href="javascript:getContent(1)">首页</a><a href="javascript:getContent('+(now_page-1)+')">上一页</a><a href="javascript:getContent('+(now_page+1)+')">下一页</a><a href="javascript:getContent('+total_pages+')">尾页</a>';
    }
    oDiv.innerHTML = page_str;
    document.getElementById('main').appendChild(oDiv);
}

因为页数不同,显示的内容不同,所以进行判断。

最后我们因为默认的显示第一页的内容,所以在js代码中调用一次getContent(1)方法。

我们分页出来的结果:

这里写图片描述

分页源代码

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
    <style type="text/css">
        *{margin:0;padding: 0}
        li{list-style: none;}
        a{text-decoration: none;}
        body{font-family: Arial,"微软雅黑";font-size: 14px}
        #main{width:440px;margin:50px auto;}
        #main ul li{width:220px;float: left;text-align: center;}
        #main li img{width:220px;height:220px;}
        #pagebar{padding-top:15px;clear: both;text-align: center;}
    </style>
    <script type="text/javascript" src="js/ajax.js"></script>
</head>
<body>
<div id="main">
    <!--显示内容部分-->
</div>
<script type="text/javascript">
    //上面的数据应该是根据当前的页数查询出来的
    //默认查询第一页的数据
    getContent(1);
    function getContent(page){
        $$.request({
            method:'post',
            url:'page.php',
            data:'page='+page,
            dataType:'text',
            callback:function(obj){
                console.log(obj);
                if(obj.status){
                    //得到当前页的数据
                    var list = obj.result;
                    //总的记录数
                    total_rows = obj.total_num;
                    //总的页数
                    total_pages = obj.pageSum;
                    //创建节点对象并进行动态的填充数据。
                    var oUl = document.getElementById('content');
                    if(!oUl){
                        var oUl = document.createElement('ul');
                        oUl.id = 'content';
                    }
                    oUl.innerHTML = '';
                    //根据结果创建对应的li标签
                    for(var i=0;i<list.length;i++){
                        var oLi = document.createElement('li');
                        oLi.innerHTML = '<a href=""><img src="'+list[i].pic+'"><span>'+list[i].title+'</span></a>';
                        oUl.appendChild(oLi);
                    }

                    document.getElementById('main').appendChild(oUl);

                    //创建分页标签
                    createPageBar(page);
                }
            }
        });
    }
    //创建分页条
    function createPageBar(now_page){
        //分页被div包裹
        var oDiv = document.getElementById('pagebar');
        //每点击一次,都要把上一页的销毁掉
        if(!oDiv){
            var oDiv = document.createElement('div');
            oDiv.id = 'pagebar';
        }
        //定义公共的部分
        oDiv.innerHTML = '';
        var page_str = '<span>共'+total_rows+'条记录'+now_page+'/'+total_pages+'</span>';
        //当前页是第一页的时候,上一页是不显示的。
        if(now_page==1){

            //当前是第一页的时候,显示下一页和尾页
            page_str += '<a href="javascript:getContent('+(now_page+1)+')">下一页</a><a href="javascript:getContent('+total_pages+')">尾页</a>';
        }else if(now_page==total_pages){

            //如果是尾页的时候,下一页是不显示的。
            page_str += '<a href="javascript:getContent(1)">首页</a><a href="javascript:getContent('+(now_page-1)+')">上一页</a>';
        }else{

            //其他形式,上一页和下一页都显示。
            page_str += '<a href="javascript:getContent(1)">首页</a><a href="javascript:getContent('+(now_page-1)+')">上一页</a><a href="javascript:getContent('+(now_page+1)+')">下一页</a><a href="javascript:getContent('+total_pages+')">尾页</a>';
        }
        oDiv.innerHTML = page_str;
        document.getElementById('main').appendChild(oDiv);
    }
</script>
</body>
</html>

后台数据

我们使用ajax把页数传到后台,后台时候的是php进行处理。默认每页显示的信息是四个。php文件访问数据库得到数据,然后封装传到前台。注意把代码放到服务器运行

整个文件的打包地址ajax分页源代码下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值