• 哈佛大学构建动态网站--第七讲ajax


    Ajax

    ajax举例:

    google maps其实是ajax应用,在地图上进行任意操作时,都无需刷新页面。ajax的实质就是让我们能够执行http请求而无需重载页面

    DOM的结构

    http://img.blog.csdn.net/20140212180241156

    通过js来修改html页面。

    1. <html>
    2. <head>
    3. <title></title>
    4. </head>
    5. <body>
    6. <script type="text/javascript">
    7. //<![CDATA[
    8. document.write("hello,world!");
    9. //]]
    10. </script>
    11. </body>
    12. </html>

    Ajax的含义

    异步jsxmlasynchronous javascript and xml,如今它不一定异步,也不一定用 js,不一定用xml,它如今是一个代名词,代指在浏览器客户端动态修改html的技术。所谓异步就是指一次可以执行多个请求,具体讲就是当执行某个请求时,它不会阻碍网页剩余部分的运作。而同步在需要获得服务器的回应后才会有其他动作。


    return false的用途

    意思就是返回false,这样会阻止提交的动作,因此页面不会提交,故不会跳转到另一个页面

    1. <form action="quote1.php" method="get" onsubmit="quote();return false;">
    2. <!--html 默认事件处理属性值里面放的是javascript-->
    3. <input id="symbol" name="symbol" type="text"/>
    4. <br/>
    5. <input type="submit" value="Get Quote" />
    6. </form>


    跨浏览器的ajax

    1. function quote()
    2. {
    3.    // instantiate XMLHttpRequest object
    4. try
    5. {
    6. xhr = new XMLHttpRequest();
    7. }
    8. catch (e)//catch块会捕获异常而不是直接报错,尝试IE的方式
    9. {
    10. xhr = new ActiveXObject("Microsoft.XMLHTTP");
    11. }
    12.     // handle old browsers
    13. if (xhr == null)
    14. {
    15. alert("Ajax not supported by your browser!");
    16. return;
    17. }
    18. // construct URL,即构造数据来源的URL,
    19. //这里的quote1.php表示在服务器端的与html文件相同路径下的一个php文件,是个相对路径
    20. var url = "quote1.php?symbol=" + document.getElementById("symbol").value;
    21.     // 打开XMLHttpRequest对象连接
    22. xhr.onreadystatechange = handler; //handler是后面的处理函数
    23. xhr.open("GET", url, true); //最后一个参数总为true,表示需要是异步的
    24. xhr.send(null);//此时数据才真正发送给quote1.php
    25. }
    26. /*
    27. * Handles the Ajax response.
    28. */
    29. function handler() //由XMLHttpRequest对象调用,只要状态改变则触发
    30. {
    31. // only handle loaded requests
    32. if (xhr.readyState == 4) //即请求完全载入状态
    33. {
    34. if (xhr.status == 200)
    35. //而且假设HTTP响应为200,即一切正常,而不是403权限错误或404文件未找到什么的
    36.     alert(xhr.responseText);
    37. //此时用弹窗方式显示返回结果,php文件给回的responseText信息
    38. }
    39. else
    40. {
    41. alert("Error with Ajax call!");
    42. }
    43. }
    1. //quote1.php
    2. <?php
    3. // get quote
    4. $handle = @fopen("http://download.finance.yahoo.com/d/quotes.csv?s={$_GET['symbol']}&f=e1l1", "r");
    5. if ($handle !== FALSE)
    6. {
    7. $data = fgetcsv($handle);
    8. if ($data !== FALSE && $data[0] == "N/A")
    9. print($data[1]);
    10. fclose($handle);
    11. }
    12. ?>

    为什么不直接从yahoo获得数据呢?

    这是因为为了安全的同源策略,我们只能在网页所在的位置使用 ajax获取信息,如果从其他不受信任的位置获取信息,信息源处的人会意识到并且可能故意发送恶意数据,以此来破坏你的网页,因为你允许了这些不受信任的数据进入你的页面。
    举例来讲就是ajax.html如果和quote1.php不在同一个服务器下面,那么就不能行。一般不会单独访问php文件,通常是在ajax.html中执行请求。

    XMLHttpRequest对象的实例化方法大概有四五种

    下面介绍了两种(虽然不全但能包括火狐,safari,chrome,ie),但基本上都是通过try-catch嵌套来尝试不同的实例化方法。在这一讲最后也会讲到使用库来进行实例化的方式状态也有很多种


    XMLHttpRequest的状态

    • onreadystatechange
      • 0 unitialized
      • 1 open
      • 2 sent
      • 3 receiving
      • 4 loaded
    • readyState
    • responseBody(IE only)
    • responseText
    • responseXML
    • status
      • 200 OK
      • 404 not found
      • 500 internal Server Error
    • statusText


    用DOM而不是弹窗显示数据

    1. document.getElementById("price").value = xhr.responseText;

    a标签,div标签,span标签等等只要我们给了id,都可以通过innerHTML修改其内容也即<span>标签之间的所有内容包括表示加粗的标签<b></b>也会被改掉。

    1. Price: <span id="price"><b>to be determined</b></span>

    9.上面这整个例子有点太简单化了,实际中我们要注意一些安全问题,也就是得到的数据要经过检验,看是否有危害,是否包含其他恶意js代码,当没有危害时我们才能将其注入到页面中。

    同时获得多个数据

    http://img.blog.csdn.net/20140212211043578 

    此时quote2.php打印了多个数据

    1. <?
    2. /*
    3. * quote2.php
    4. * Outputs price, low, and high of given symbol as plain/text.
    5. */
    6. // send MIME type
    7. header("Content-type: text/plain");
    8. // try to get quote
    9. $handle = @fopen("http://download.finance.yahoo.com/d/quotes.csv?s={$_GET['symbol']}&f=e1l1hg", "r");
    10. if ($handle !== FALSE)
    11. {
    12. $data = fgetcsv($handle);
    13. if ($data !== FALSE && $data[0] == "N/A")
    14. {
    15. print("Price: {$data[1]} ");
    16. print("High: {$data[2]} ");
    17. print("Low: {$data[3]}");
    18. }
    19. fclose($handle);
    20. }
    21. ?>

    如果不注明了换行,那么当注入到html页面中的时候不会换行,因此需要人为了的加入html的换行标签

    1. if ($data !== FALSE && $data[0] == "N/A")
    2. {
    3. print("Price: {$data[1]}");
    4. print("<br />");
    5. print("High: {$data[2]}");
    6. print("<br />");
    7. print("Low: {$data[3]}");
    8. }

    添加等待指示

    为了达到这个功能就需要处理XMLHttpRequest对象的不同状态。

    1. var url = "quote4.php?symbol=" + document.getElementById("symbol").value;
    2. // inform user 在数据发送前就更改了提示。
    3. document.getElementById("quote").innerHTML = "Looking up symbol...";

    当然也可以不用单调的文字提示而是使用动态gif图片


    方法就是首先在发送之前让图片块展示出来:

    1. // show progress
    2. document.getElementById("progress").style.display = "block"; //none
    3. //此处也发现了DOM的一大优点不但可以修改对象的html还可以修改元素的css样式
    4. // get quote

    在获得返回数据时,再把图片所在块去除开:

    1. function handler()
    2. {
    3. // only handle requests in "loaded" state
    4. if(xhr.readyState == 4)
    5. {
    6. // hide progress
    7. document.getElementById("progress").style.display = "none";
    8. if (xhr.status == 200)
    9. document.getElementById("quote").innerHTML = xhr.responseText;
    10. else
    11. alert("Error with Ajax call!");
    12. }
    13. }

    progress在页面文件中是一个层divid,在这个层中有gif图片

    1. <div id="progress" style="display: none;">
    2. <img alt="Please Wait" src="19-0.gif">
    3. <br />
    4. </div>

    课堂上为了更好地演示这个显示gif图的效果,于是人为的在quote.php开头加入了一个延迟函数sleep(5).让其延迟5

    通过XML方式来获得数据

    收到来自yahoo的返回数据,加上在quote5中自己打印的根元素quote以及对应的XML子元素,整个返回数据效果如下:

    1. <quote symbol="aapl">
    2. <price>304.18</price>
    3. <high>305.60</high>
    4. <low>302.20</low>
    5. </quote>

    1. //quote5.php
    2. <?
    3. // set MIME type
    4. header("Content-type: text/xml");
    5. // output root element's start tag
    6. print("<quote symbol='{$_GET['symbol']}'>");
    7. // try to get quote
    8. $handle = @fopen("http://download.finance.yahoo.com/d/quotes.csv?s={$_GET['symbol']}&f=e1l1hg", "r");
    9. if($handle !== FALSE)
    10. {
    11. $data = fgetcsv($handle);
    12. if ($data !== FALSE && $data[0] == "N/A")
    13. {
    14. print("<price>{$data[1]}</price>");
    15. print("<high>{$data[2]}</high>");
    16. print("<low>{$data[3]}</low>");
    17. }
    18. fclose($handle);
    19. }
    20. // output root element's end tag
    21. print("</quote>");
    22. ?>


    1. function handler()
    2. {
    3. // only handle requests in "loaded" state
    4. if (xhr.readyState == 4)
    5. {
    6. if (xhr.status == 200)
    7. {
    8. // get XML
    9. var xml = xhr.responseXML; //注意这里变为了XML
    10. // update price
    11. var prices = xml.getElementsByTagName("price");
    12. if (prices.length == 1)
    13. {
    14. var price = prices[0].firstChild.nodeValue;
    15. document.getElementById("price").innerHTML = price;
    16. }
    17. // update low
    18. var lows = xml.getElementsByTagName("low");
    19. if (lows.length == 1)
    20. {
    21. var low = lows[0].firstChild.nodeValue;
    22. document.getElementById("low").innerHTML = low;
    23. }
    24. // update high
    25. var highs = xml.getElementsByTagName("high");
    26. if (highs.length == 1)
    27. {
    28. var high = highs[0].firstChild.nodeValue;
    29. document.getElementById("high").innerHTML = high;
    30. }
    31. }
    32. else
    33. alert("Error with Ajax call!");
    34. }
    35. }

    对应的HTML页面代码中:

    1. <body>
    2. Price: <span id="price"></span>
    3. <br>
    4. Low: <span id="low"></span>
    5. <br>
    6. High: <span id="high"></span>
    7. </body>

    插入DOM元素


    它请求的页面是quote1.php,它只会返回一条文本html数据(即只有一条信息,价格),所以在ajax9中用的还是responseText

    使用DOM方法创建新节点然后插入数据。在html页面中有

    1. <div id="quotes"></div>

    但数据并非直接插入这里,innerHTML未用于此div,而是我们在代码中创建了新div元素,,然后在此div中创建新文本节点。


    下图是整个DOM的标签之间的关系图,new divsymbol:29.05(其中数字是请求返回的数据)就是我们自己创建的元素(标签),然后把symbol作为new div的子元素,最后再把new div作为div id=quote的子元素。可见通过DOM函数不仅可以修改已存在的元素还可以用于创建

    http://img.blog.csdn.net/20140213114803671  

    1. function quote()
    2. {
    3. // instantiate XMLHttpRequest object
    4. .... 省略
    5. // get symbol
    6. var symbol = document.getElementById("symbol").value;
    7. // construct URL
    8. var url = "quote1.php?symbol=" + symbol;
    9. // get quote
    10. xhr.onreadystatechange = function(){
    11. // 这里让onreadystatechange等于匿名函数(没有名字的函数),
    12. //由于不需要用在别处只用在这里所以不需要名字xhr.onreadystatechange字段并不需要函数有名字
    13. // only handle loaded requests
    14. if (xhr.readyState == 4)
    15. {
    16. if (xhr.status == 200)
    17. {
    18. // insert quote into DOM
    19. var div = document.createElement("div");
    20. var text = document.createTextNode(symbol + ": " + xhr.responseText);
    21. div.appendChild(text);
    22. document.getElementById("quotes").appendChild(div);
    23. }
    24. else
    25. alert("Error with Ajax call!");
    26. }
    27. }
    28. xhr.open("GET", url, true);
    29. xhr.send(null);
    30. }

    JSON

    XML不错,但使用起来还是有点麻烦,需要遍历树结构,这并不简洁。


    它能序列化数据,比如一个二维数组,它能将其序列化为一串数据,也即一个一维数组。


    JSON被大多数语言广泛支持,在PHP中通过内建的函数也能够简单创建JSON对象,比如说一个PHP数组可以轻松转化为JSON对象。


    PHP端,可以使用函数json_encode,传入一些变量比如数组(可以是关联数组或者二维数组),绝大多数PHP类型都能转为JSON然后发回到Ajax页面。


    唯一有点麻烦的是js端需要使用eval函数,使用该函数需要注意安全,因为不管你取的什么text内容,然后你对它求值,js将像代码一样实际执行,会有安全问题。


    使用了JSON后在本例子中获得的数据就是这么一串{price: 304.18, high: 305.60, low:302.20},下面来看看实际产生这个数据的quote文件:

    1. <?
    2. /*
    3. * quote6.php
    4. * Outputs price, low, and high of given symbol in JSON format.
    5. */
    6. // set MIME type
    7. header("Content-type: application/json");
    8. // try to get quote
    9. $handle = @fopen("http://download.finance.yahoo.com/d/quotes.csv?s={$_GET['symbol']}&f=e1l1hg", "r");
    10. if ($handle !== FALSE)
    11. {
    12. $data = fgetcsv($handle);
    13. if ($data !== FALSE && $data[0] == "N/A")
    14. {
    15. if (is_numeric($data[1]))
    16. $price = $data[1];
    17. if (is_numeric($data[2]))
    18. $high = $data[2];
    19. if (is_numeric($data[3]))
    20. $low = $data[3];
    21. }
    22. fclose($handle);
    23. }
    24. // output JSON
    25. print("{ price: $price, high: $high, low: $low }"); //直接输出原始JSON对象
    26. ?>

    优点在于在ajax10.html中可以发现获取JSON对象的值非常简单。

    1. function quote()
    2. {
    3. // instantiate XMLHttpRequest object
    4. ... 省略
    5. // get symbol
    6. var symbol = document.getElementById("symbol").value;
    7. // construct URL
    8. var url = "quote6.php?symbol=" + symbol;
    9. // get quote
    10. xhr.onreadystatechange =
    11. function()
    12. {
    13. // only handle loaded requests
    14. if (xhr.readyState == 4)
    15. {
    16. if (xhr.status == 200)
    17. {
    18. // evaluate JSON
    19. var quote = eval("(" + xhr.responseText + ")");
    20. //周围加上括号表示它是对象,求值结束后quote变量就成为了对象,然后就可以向JSON对象那样处理它了
    21. // show JSON in textarea
    22. document.getElementById("code").value = xhr.responseText;
    23. // insert quote into DOM
    24. var div = document.createElement("div");
    25. var text = document.createTextNode(symbol + ": " + quote.price);
    26. //此处我只想取得price数据,因此quote.price,可见这个功能非常强大易用,
    27. //而不用如XML那样还得遍历整棵XML树,直接用点符号获取数据就行了。
    28. div.appendChild(text);
    29. document.getElementById("quotes").appendChild(div);
    30. }
    31. else
    32. alert("Error with Ajax call!");
    33. }
    34. }
    35. xhr.open("GET", url, true);
    36. xhr.send(null);
    37. }

    对应用到的html页面body标签中的子元素:

    1. <div id="quotes"></div>
    2. <br>
    3. <textarea cols="80" id="code" rows="16">
    4. </textarea>

    最终获取数据效果如下图:

    http://img.blog.csdn.net/20140213122542250

    将php类转化为json

    之前说过可以任意使用数据类型,这里在php中模仿JSON对象,建立了一个叫Stock的类,用到了json_encode函数

    1. <?
    2. /*
    3. * quote7.php
    4. * Outputs price, low, and high of given symbol in JSON format using PHP's JSON extension.
    5. */
    6. // defines a stock
    7. class Stock
    8. {
    9. public $price;
    10. public $high;
    11. public $low;
    12. }
    13. // set MIME type
    14. header("Content-type: application/json"); //这个要注意,它的内容类型一定不要搞错了,要分清是JSON还是文本text还是XML
    15. // try to get quote
    16. $handle = @fopen("http://download.finance.yahoo.com/d/quotes.csv?s={$_GET['symbol']}&f=e1l1hg", "r");
    17. if ($handle !== FALSE)
    18. {
    19. $data = fgetcsv($handle);
    20. if ($data !== FALSE && $data[0] == "N/A")
    21. {
    22. $stock = new Stock();//创建一个新的stock实例
    23. if (is_numeric($data[1]))
    24. $stock->price = $data[1];
    25. if (is_numeric($data[2]))
    26. $stock->high = $data[2];
    27. if (is_numeric($data[3]))
    28. $stock->low = $data[3];
    29. }
    30. fclose($handle);
    31. }
    32. // output JSON
    33. print(json_encode($stock)); //json_encode将返回JSON编码后对象的字符串,不管是用于数组还是类都可以使用这个函数轻松应对
    34. ?>

    json_encode会在各个两边加上引号,这不用在意

    http://img.blog.csdn.net/20140213123906828

    使用了第三方框架YUI调用ajax

    例子中是使用的YUI库来减少代码量并且能支持更多浏览器。


    首先需要包含一些YUI js文件,然后和原来一样需要带上股票代码去连接quote7,然后告诉YUI执行异步请求,请求类型为get,传入URL,以及还有一个JSON对象,花括号表示JSON对象,键为success,值为handler


    这表示YUI中有这么个success字段,要求handler函数做些什么,这类似于前面讲过的onreadystatechange字段。


    handler函数传给它,所以状态值要改变,就会调用handler函数

    http://img.blog.csdn.net/20140213124733406

    这里handler函数中传入了一个对象参数o,其作用相当于前面的xhr,于是可以从quote7中得回responseText,并用evalJSON对象的值

    http://img.blog.csdn.net/20140213125338515

    使用JQuery库调用ajax

    总之使用第三方库能让Ajax请求变得更加容易。

    1. <head>
    2. <script src="http://code.jquery.com/jquery-latest.js">
    3. </script>
    4. <script>
    5. $(document).ready(function() {
    6. $("#form").submit(function() {
    7. $.ajax({
    8. url: "quote7.php",
    9. data: {
    10. symbol: $("#symbol").val()
    11. },
    12. success: function(data) {
    13. $("#price").html(data.price);
    14. $("#high").html(data.high);
    15. $("#low").html(data.low);
    16. }
    17. });
    18. return false;
    19. });
    20. });
    21. </script>
    22. <title></title>
    23. </head>


    使用google map中提供的api


    因此可以将谷歌地图用到我们的应用中,在initialize函数中创建对象设定参数,myLatlng是一个经纬度变量。


    myOptions是选项,可以确定缩放等级,zoom:8表示一般的缩放等级。


    mapTypeId是地图类型,然后后面一句话是实例化一张地图给既存的div,可以在html页面代码部分看到这个div,而在css中可以设置这个div大小,让地图以合适尺寸显示到网页,这样你可以把地图显示在一边而不用占据整个页面。

    http://img.blog.csdn.net/20140213130329812

    google maps API指南能查看到关于参数的信息。比如MapOptions. ,在课程项目中会把谷歌地图和BART提供的XML地铁数据整合起来做出一个实时地铁信息查询地图。


    同理整合两个资源做出一个网站的还有通过谷歌地图和WiFi热点数据之间来整合起来做出查询附近wifi热点。这类整合两个以上资源的应用称作mashup(整合






  • 相关阅读:
    python学习之——pip的安装与使用
    python学习之——django环境搭建
    python学习之——eclipse+pydev 环境搭建
    linux学习之——vim简明教程
    深度公式
    带宽、延时、吞吐率、PPS
    人脸应用:人脸检测、人脸对比、五官检测、眨眼检测、活体检测、疲劳检测
    非交互式人脸活体检测(002)
    活体检测记录(001)
    Learning Generalizable and Identity-Discriminative Representations for Face Anti-Spoofing
  • 原文地址:https://www.cnblogs.com/laiqun/p/5929123.html
Copyright © 2020-2023  润新知