Web程序最初的目的就是将信息(数据)放到公共的服务器,让所有网络用户都可以通过浏览器访问。
在此之前,我们可以通过以下几种方式让浏览器发出对服务端的请求,获得服务端的数据:
●地址栏输入地址,回车,刷新
●特定元素的href或src属性
●表单提交
这些方案都是我们无法通过或者很难通过代码的方式进行编程(对服务端发出请求并且接受服务端返回的响应),如果我们可以通过JavaScript直接发送网络请求,那么Web的可能就会更多,随之能够实现的功能也会更多,至少不再是”单机游戏”。
AJAX( Asynchronous JavaScript and XML ) ,(先前是服务器返回XML,现在返回的是JSON格式,所以实际上该技术是AJAJ) 最早出现在2005年的Google Suggest (就是搜索框下的建议列表),是在浏览器端进行网络编程(发送请求、接收响应)的技术方案,它使我们可以通过JavaScript直接获取服务端最新的内容而不必重新加载页面。让Web更能接近桌面应用的用户体验。
AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
说白了, AJAX就是浏览器提供的一套API ,可以通过JavaScript调用,从而实现通过代码控制请求与响应。实现网络编程。能力不够,API来凑。
XMLHttpRequest:
程序必须先调用XMLHt tpRequest对象的responseText或responseXML来获取服务器响应,再通过DOM操作将服务器响应动态加载到当前页面中。
关于XMLHttpRequest最通用的定义是: XMLHttpRequest是一套可以在JavaScript、VBscript、JScript 等脚本语言中使用的API,它通过HTTP协议异步地向服务器发送请求,并获取从服务器返回的响应。
涉及到 ajax 操作的页面“不能”使用文件协议访问。(不能文件的方式访问)
(我放在了phpstudy_pro里www里的域名为ajax.learn 端口为8080的站点里
所以在网址输入ajax.learn:8080/ajax/ajax1.html就行了)
// 1.安装浏览器(浏览器相当于用户代理) // xhr 就类似于浏览器的作用(发送请求接收响应) var xhr = new XMLHttpRequest(); // 2. 打开浏览器,输入网址 xhr.open('GET', 'time.php'); // 3. 敲回车,开始请求 xhr.send(); //在检查里的network中all可查看向服务器请求回的
// 1.安装浏览器(浏览器相当于用户代理) // xhr 就类似于浏览器的作用(发送请求接收响应) var xhr = new XMLHttpRequest(); // 2. 打开浏览器,输入网址 xhr.open('GET', 'time.php'); // 3. 敲回车,开始请求 xhr.send(); // 4. 等待响应 // 因为响应需要时间,所以无法通过返回值的方式返回响应 即不能console.log(xhr.send()); // 因为客户端永远不知道服务端何时才能返回我们需要的响应 // 所以AJAX API采用事件的机制(通知的感觉) xhr.onreadystatechange = function () { //这个事件并不是只在响应时触发, 状态改变就触发,(状态改变即创建xhr、open、send) console.log(1); //所以打印了3个1 console.log(this.readyState); //2 3 4 因为每个状态对应一个数,0代表创建xhr,1代表open。。。 但是由于事件是后触发的,所以没有打印出全部, //如果需要捕获第一个状态的变化,需要注意代码执行顺序的问题(不要出现来不及的情况) }
time.php
<?php echo time(); ?>
readyState有五种可能的值:
0 (未初始化): (XMLHttpRequest)对象已经创建,但还没有调用open()方法。
1 (载入):已经调用open() 方法,但尚未发送请求。
2 (载入完成): 请求已经发送完成。
3 (交互):可以接收到部分响应数据。
4 (完成):已经接收到了全部数据,并且连接已经关闭。
// 1.安装浏览器(浏览器相当于用户代理) // xhr 就类似于浏览器的作用(发送请求接收响应) var xhr = new XMLHttpRequest(); console.log(xhr.readyState); // => 0 初始化,请求代理对象 // 2. 打开浏览器,输入网址 xhr.open('GET', 'time.php'); console.log(xhr.readyState); // => 1 open方法已经调用,建立一个与服务端特定端口的连接 // 3. 敲回车,开始请求 xhr.send(); // 4. 等待响应 // 因为响应需要时间,所以无法通过返回值的方式返回响应 即不能console.log(xhr.send()); // 因为客户端永远不知道服务端何时才能返回我们需要的响应 // 所以AJAX API采用事件的机制(通知的感觉) xhr.onreadystatechange = function () { //这个事件并不是只在响应时触发, 状态改变就触发,(状态改变即创建xhr、open、send) // console.log(1); //所以打印了3个1 // console.log(this.readyState); //2 3 4 // switch (this.readyState) { // case 2: // console.log(this.readyState); // // => 2 已经接受到了响应报文的响应头,即服务器名称信息等,但没有接受到响应体 // console.log(this.getAllResponseHeaders()); //打印响应头 // break; // case 3: // console.log(this.readyState); // // => 3 正在下载响应报文的响应体,有可能为空、或不完整、或完整。 // break; // case 4: // console.log(this.readyState); // // => 4 响应体下载完成 // break; // } if (this.readyState !== 4) return; //若状态是4,则获取响应的内容 // console.log(this.readyState); //4 console.log(this.responseText); //1618626395 ,即我们请求的time.php中返回的数据 }
var xhr = new XMLHttpRequest(); xhr.open('GET', 'time.php'); xhr.send(); // onl oad是HTML5 中提供的XMLHttpRequest version 2.0定义的,跟上述一样的功能 xhr.onload = function () { console.log(this.readyState); //4 console.log(this.responseText); //1618630324 }
var xhr = new XMLHttpRequest(); xhr.open('POST', 'add.php'); //设置请求行 xhr.setRequestHeader('Foo', 'Bar'); //设置一个请求头 // 一定注意 如果请求体是urlencoded格式必须设置这个请求头 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send('key1=value1&key2=value2'); //以urlencoded 格式设置请求体
add.php
<?php var_dump($_POST); ?>
users1.php
<?php // 返回的响应就是一个JSON 内容(返回的就是数据) // 对于返回数据的地址一般我们称之为接口(形式上是Web信息) $data = array( array( 'id' => 1, 'name' => '束文波' ), array( 'id' => 2, 'name' => '小夏' ), array( 'id' => 3, 'name' => '米卡' ), array( 'id' => 4, 'name' => '邢克垒' ) ); if (empty($_GET['id'])) { // 没有传ID,则获取全部 // 因为HTTP中约定报文的内容就是字符串,而我们需要传递给客户端的信息是-个有结构的数据 // 这种情况下我们一般采用JSON作为数据格式 $json = json_encode($data);// 格式:[{"id":1,"name":"束文波"},{...}] echo $json; } else { // 传递了ID,只获取一条 foreach ($data as $item) { //循环遍历, if ($item['id'] != $_GET['id']) continue; //找到对应的id对应的数组 $json = json_encode($item); echo $json; //在地址栏设id=1,则打印出{"id":1,"name":"\u675f\u6587\u6ce2"} ,其中汉字是Unicode格式 } }
var xhr = new XMLHttpRequest(); // 这里仍然是使用URL中的问号参数传递数据 xhr.open('GET', 'users.php?id=3'); //users.php在上面 在这里填京东啊,爱奇艺什么的相关数据接口,在下面即可获取内容 xhr.send(null); xhr.onreadystatechange = function () { if (this.readyState !== 4) return; console.log(this.responseText); //{"id":3,"name":"\u7c73\u5361"} }
user2.php
<?php // 返回的响应就是一个JSON 内容(返回的就是数据) // 对于返回数据的地址一般我们称之为接口(形式上是Web信息) $data = array( array( 'id' => 1, 'name' => '束文波', 'age' => 26 ), array( 'id' => 2, 'name' => '小夏', 'age' => 24 ), array( 'id' => 3, 'name' => '米卡', 'age' => 23 ), array( 'id' => 4, 'name' => '邢克垒', 'age' => 29 ) ); if (empty($_GET['id'])) { // 没有传ID,则获取全部 // 因为HTTP中约定报文的内容就是字符串,而我们需要传递给客户端的信息是-个有结构的数据 // 这种情况下我们一般采用JSON作为数据格式 $json = json_encode($data); // 格式: [{"id":1,"name":"张三"},{...}] echo $json; } else { // 传递了ID,只获取一条 foreach ($data as $item) { //循环遍历, if ($item['id'] != $_GET['id']) continue; //找到对应的id对应的数组 $json = json_encode($item); echo $json; //在地址栏设id=1,则打印出{"id":1,"name":"\u675f\u6587\u6ce2"} ,其中汉字是Unicode格式 } }
实现:点击名字,弹出相应年龄。
<body> <ul id="list"></ul> <script> var listElement = document.getElementById('list'); // 发送请求获取列表数据呈现在页面 var xhr1 = new XMLHttpRequest(); xhr1.open('GET', 'users1.php'); xhr1.send(); xhr1.onreadystatechange = function () { if (this.readyState !== 4) return; //使用 JSON.parse() 方法将请求到的 JSON 数据转换为 JavaScript 对象 var data = JSON.parse(this.responseText); //循环遍历,为每个li注册点击事件 for (var i = 0; i < data.length; i++) { // 创建多个元素li var liElement = document.createElement('li'); // 给li标签设置内容为传过来的name的值 liElement.innerHTML = data[i].name; liElement.id = data[i].id; // 把li添加到ul中 listElement.appendChild(liElement); // 为li注册点击事件 listElement.children[i].addEventListener('click', function () { // 需要再请求个数据,返回本次点击的响应的数据 var xhr2 = new XMLHttpRequest(); // id为本次点击的名字的id xhr2.open('GET', 'users2.php?id=' + this.id); xhr2.send(); xhr2.onreadystatechange = function () { if (this.readyState !== 4) return; var data2 = JSON.parse(this.responseText); // 弹出相应名字的年龄 alert(data2.age); } }) } } </script> </body>
POST请求过程中,都是采用请求体承载需要提交的数据。
如: xhr.send(‘username=KaTeX parse error: Expected 'EOF', got '&' at position 11: {username}&̲password={password}’);
login.php
<?php // 接收用户提交的用户名和密码 if (empty($_POST['username']) || empty($_POST['password'])) { exit('请提交用户名和密码'); } //校验 $username = $_POST['username']; $password = $_POST['password']; if ($username == '蜡笔小新' && $password == 'ilovexiaogege') { exit('成功登录'); } exit('用户名或密码错啦'); ?>
实现 点击登录按钮,显示加载层,加载完成后,打印结果
<style> .loading { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgb(128, 125, 125); opacity: 0.5; text-align: center; line-height: 500px; font-size: 50px; display: none; } .loading::after { /*::after用来创建一个伪元素,作为已选中元素的最后一个子元素。这个虚拟元素默认是行内元素。 */ content: '加载中...'; color: #fff; } </style> </head> <body> <div class="loading" id="loading"></div> <table border="1"> <tr> <td>用户名</td> <td><input type="text" name="" id="username"></td> </tr> <tr> <td>密码</td> <td><input type="password" name="" id="password"></td> </tr> <tr> <td></td> <td><button id="btn">登录</button></td> </tr> </table> <script> var btn = document.getElementById('btn'); var txtUsername = document.getElementById('username'); var txtPassword = document.getElementById('password'); var loading = document.getElementById('loading'); // 找一个合适的时机,做一件合适的事情 btn.onclick = function () { //点击登录显示加载中。。。 loading.style.display = 'block'; // 1.获取界面上的元素 value var username = txtUsername.value; var password = txtPassword.value; // 2.通过 XHR 发送一个 POST 请求 var xhr = new XMLHttpRequest(); xhr.open('POST', 'login.php'); // 一定注意 如果请求体是urlencoded格式必须设置这个请求头 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send('username=${username}&password=${password}'); // 3.根据服务端的反馈 做出界面提示 xhr.onreadystatechange = function () { if (this.readyState !== 4) return; //加载完成 loading.style.display = 'none'; console.log(this.responseText); // 用户名或密码错啦 } } </script> </body>
**同步:**一个人在同一个时刻只能做一件事情,在执行一些耗时的操作 ( 需要看管)不去做别的只是等待
**异步:**在执行一些耗时的操作(不需要看管)去做别的事,而不是等待
一般很少用同步。
//异步 console.time('aa'); var xhr = new XMLHttpRequest(); // open 方法的第三个参数是async异步 可以传入一个布尔值, 默认为true xhr.open('GET', 'time.php', true); xhr.send(); console.log(xhr.responseText); // 为空 因为异步是同时干好多事,send后的事在执行send时也在做 // 所以需要:xhr.onreadystatechange = function () 获得完整数据 console.timeEnd('aa'); // aa: 0.64208984375 ms //同步 console.time('bb'); var xhr2 = new XMLHttpRequest(); // open 方法的第三个参数是async异步 可以传入一个布尔值, 默认为true xhr2.open('GET', 'time.php', false); xhr2.send(); // 同步是依次执行,所以不用xhr.onreadystatechange = function () 就能完整接收数据 console.log(xhr2.responseText); // 打印出1618828035 console.timeEnd('bb'); // bb: 21.026123046875 ms
所以很少用到 同步模式。
一种数据描述手段
老掉牙的东西,简单演示一下,不在这里浪费时间,基本现在的项目不用了。
淘汰的原因:数据冗余太多
JSON
也是一种数据描述手段,类似于JavaScript字面量方式
服务端采用JSON格式返回数据,客户端按照JSON格式解析数据。
不管是JSON也好,还是XML,只是在AJAX请求过程中用到,并不代表它们之间有必然的联系,它们只是数据协议罢了
处理响应数据渲染
模板引擎:
artTemplate : https://aui.github.io/art-template/
模板引擎实际上就是一个API, 模板引擎有很多种,使用方式大同小异,目的为了可以更容易的将数据渲染到HTML中
兼容方案:
XMLHttpRequest在老版本浏览器( IE5/6 )中有兼容问题,可以通过另外-种方式代替
var xhr = window. XMLHttpRequest ? new XMLHttpRequest() : new ActiveXobject(‘Mi crosoft.XMLHTTP’)
<body> <table> <tbody id="content"></tbody> </table> <script> var xhr = new XMLHttpRequest(); xhr.open('GET', 'test.php'); xhr.send(); xhr.onreadystatechange = function () { if (this.readyState !== 4) return; var res = JSON.parse(this.responseText); var data = res.data; for (var i = 0; i < data.length; i++) { var tr = document.createElement('tr'); var td = document.createElement('td'); //下面方式太麻烦,我们采用模板引擎将数据呈现 artTemplate:https://aui.github.io/art-template/ 模板引擎实际上就是一个API td.innerHTML = '<td>' + data[i].id + '</td>' } } </script> </body>