初识Ajax
- Ajax 的作用
获取服务器的数据
- Ajax 的效果
在不刷新整个页面的情况,通过一个url地址获取服务器的数据,然后进行页面的局部刷新
- 一些熟悉的场景
-
评论加载效果
-
用户名验证
局部 异步 刷新
Ajax 的全称: Asyncchronous Javascript And XML , 就是使用JS代码获取服务器数据
基础知识铺垫
服务器与客户端
A. 概念层面:
a. 服务器:能够提供某种服务的电脑
b. 客户端:想使用服务器所提供服务的电脑
B. 硬件层面:
a. 服务器:由于要给千千万万个客户端提供服务,因此一般来说,服务器的硬件配置更高一些
b. 客户端:个人电脑、手机、平板等都可以称为客户端
注意:服务器与客户端在硬件层面上并没有明显的划分,配置很差的个人电脑依然可以当作服务器使用,只不过速度慢一点而已。
C. 服务器能提供什么服务?
一些我们日常使用的功能,其实都是服务器所提供的服务。比如网页服务、邮箱服务、文件上传与下载服务、聊天服务等等…
D. 服务器软件
服务器能提供服务由于在服务器操作系统上安装了很多软件,由于这些软件对外提供服务,比如:
HTTP网页服务:Apache、Tomcat、IIS等
文件上传下载服务:VsFtp等
邮箱服务:SendMail等
数据存储服务:MySql、Oracle等
小结:服务器就是提供服务的,客户端就是使用服务器所提供的服务。
网络相关概念
a. IP地址
通过ip地址就能找到特定的服务器,比如百度服务器的IP地址为:123.125.114.144
b. 域名
域名就相当于地名一样,方便人们查找到服务器
比如说:www.baidu.com
查看本机ip : ipconfig
c. DNS 域名解析服务器
DNS 提供域名与ip地址的映射关系
访问服务器的流程:本机hosts文件 ——> DNS 服务器 ——> 服务器
本机host 文件的路径为:C\Windows\System32\drivers\etc\HOSTS
d. 端口
前面我们说过,服务器就是提供服务的。ip地址是用来查找某一台服务器的。域名是方便人们记忆的。DNS维护着域名和ip地址的映射关系。
所以通过域名是可以找到一台服务器的
但是一台服务器可能提供多种服务,我们找到这台服务器时,究竟是想使用这台服务器的什么服务呢?这就使用端口号来区分。
其实我们每次访问网页,最完整的写法应该是:http://www.baidu.com:80 80这个端口比较特殊,可以省略不写
小结:ip地址是用来查找某一台服务器的。域名是方便人们记忆的。DNS维护着域名和ip地址的映射关系。端口是用来区分一台服务器上提供的不同服务的。
通信协议
通信协议就是事先规定好的规则。(机器与机器之间的交流)
常见的协议:
HTTP、HTTPS、超文本传输协议
FTP文件传输协议
SMTP简单邮件传输协议
在HTTP协议中,需要大致了解的是:请求头、响应头、请求体、响应体。
Wamp的安装
为什么要安装Wamp
将我们写的 html 界面以服务的方式分享给别人看,否则别人的电脑是无法看到我们所写的界面的
Wamp是什么
Wamp 指的是:Windows、appache、mysql、php 几个服务器软件的缩写,类似的还有Lamp:linux、apache、mysql、php
Wamp的安装与简单配置
a. 配置访问权限,默认情况下,apache提供的网页服务只允许Localhost和127.0.0.1 进行访问,我们需要对配置进行修改。配置文件位于 D:\Application program\wamp\bin\apache\Apache2.4.4\conf 将268行的Deny from all 改为Allow from all
b. 网站根路径的配置,默认情况下,网站的根路径为 C:\wamp\www 此目录可以修改。将 D:\Application program\wamp\bin\apache\Apache2.4.4\conf 中的239行的DocumentRoot 进行修改即可
比如在D盘下创建一个myweb文件夹,添加一个test.html 测试界面,然后在另一台电脑的浏览器地址栏输入 http://192.168.213.1/test.html (这里的ip地址是利用 ipconfig 命令查询到的本地计算机的ip) 运行显示出测试界面 表示运行没问题。
虚拟主机的配置
如果一台服务器想提供多个站点,那么就需要对虚拟主机进行配置。
更改配置文件时,首先备份一份。找到C:\Windows\System32\drivers\etc 里的hosts文件,增加IP地址的映射
然后在 D:\Application program\wamp\bin\apache\Apache2.4.4\conf 下的 httpd.conf 文件里 去掉这行注释符号
最后再对 D:\Application program\wamp\bin\apache\Apache2.4.4\conf\extra 下的 httpd-vhosts.conf 文件进行修改(增加需要的虚拟站点即可)。
PHP 基本语法
-
网站的分类:静态网站和动态网站
a.静态网站
全部由HTML代码格式页面组成的网站,没有数据库的支持,在网站制作和维护方面工作量较大
b.动态网站
动态网站并不是指具有动画功能的网站,而是指网站内容可根据不同情况动态变更的网站。一般情况下动态网站通过数据库进行架构。一般动态网站体现在网页一般是以 asp,jsp,php,aspx等结尾,动态网页以数据库为基础,可以大大降低网站维护的工作量,维护方便。 -
PHP 语法的基本结构
a.所有的PHP代码都要写到 <?php...?> 里面
b.PHP文件可以和HTML相互结合进行使用
c.PHP文件的默认默认文件扩展名是".php"
d.PHP代码必须在服务器上执行 -
echo 的使用
echo 的作用就是向页面中输入字符串
print_r 输出复杂类型
var_dump 输出复杂类型 -
变量的声明和变量的使用
无论是变量的声明还是变量的使用都需要使用$符号 -
字符串的拼接
字符串的拼接使用 . 进行连接 -
php 的执行原理
浏览器是不识别PHP代码的,PHP代码必须在服务器中执行,双击打开 php文件是达不到效果的。
- 数组相关
a.一维数组
数组的定义:
$arr = array("zhangsan","lisi","wangwu");
echo $arr[2]; // 只能输出字符串
print_r($arr); // 可以输出复杂类型
var_dump($arr); // 可以输出复杂类型
// echo json_encode($arr); // 将数组转化为json格式的字符串
// 可以拆分成以下这样
$result = json_encode($arr);
echo $result;
PHP当中数组的特点:下标可以自定义
$arr = array("zhangsan","name1"=>"lisi","wangwu");
// 可以对数组的下标索引自定义
var_dump($arr);
二维数组:
// 二维数组
$arr = array();
$arr["zhangsan"] = array("age"=>19,"sex"=>"male","height"=>"180");
$arr["lisi"] = array("age"=>18,"sex"=>"female","height"=>"160");
$arr["wangwu"] = array("age"=>17,"sex"=>"male","height"=>"190");
var_dump($arr);
$result = json_encode($arr);
echo $result;
在浏览器中显示如下(json格式,后续会经常用到):
数组遍历:
// 数组遍历
// 1. 普通for循环
$arr1 = array("zhangsan","wangwu","lisi");
for($i=0;$i<count($arr1);$i++){
$arr1[$i];
$temp = $arr1[$i];
echo $temp . "<br>";
}
// 2. foreach,这种方式更常用
foreach($arr as $key => $value) {
echo $key . ">>>" . $value . "<br>";
}
- PHP中的函数
a. json_encode php中将数组转化为json格式的字符串
b. var_dump 输出复杂的数据类型
c. print_r 输出复杂的数据类型
d. count 得到数组的长度
- 预定义变量
A. 请求类型
请求有时候是需要携带参数的,用来标识特定的要求,根据参数携带位置的不同可以简单的把请求分为 Get请求 和 Post请求
a. Get请求:参数在URL后面,多个参数用&进行连接
b. Post请求:参数在请求体中
B. 获取请求参数的值
a. $_GET[]
b. $_Post[]
AJAX 的使用
Ajax 简单来说,就是一个异步的javascript 请求,用来获取后台服务端的数据,而并不是整个界面进行跳转。
在原生 JS 中来实现Ajax主要的类就是XMLHttpRequest,它的使用一般有四个步骤:
-
创建XMLHttpRequest 对象
-
准备发送网络请求
-
开始发送网络请求
-
指定回调函数
下面通过代码来实现这四个步骤:
window.onload = function(){
var btn = document.getElementById("btn");
btn.onclick = function(){
var username = document.getElementById("username").value;
// console.log(username);
// 使用js代码进行checkUsername.php这个文件的访问,将username传递给这个文件
var xhr = new XMLHttpRequest();
xhr.open("get","checkUsername.php?username=" + username,true);
xhr.send(null);
xhr.onreadystatechange = function(){
var result = xhr.responseText;
// console.log(result);
document.getElementById("result").innerText = result;
};
};
}
html代码:
<body>
<h1>注册界面</h1>
<form action="register.php" method="post">
用户名:<input type="text" name="username" id="username">
<input type="button" value="验证用户名" id="btn">
<span id="result"></span>
<br>
密码:<input type="password" name="password"><br>
<input type="submit" value="提交">
</form>
</body>
chechUsername.php 文件代码:
$uname = $_GET["username"];
// 按道理来说,这里应该是要查询数据库 此处简单模拟
if($uname == "zhangsan") {
echo "username exists";
} else {
echo "username ok";
}
下面对 post请求 作详细讲解
window.onload = function(){
var btn = document.getElementById("btn");
btn.onclick = function(){
var username = document.getElementById("username").value;
// console.log(username);
// 使用js代码进行checkUsername.php这个文件的访问,将username传递给这个文件
// 1. 创建XMLHttpRequest这个对象
var xhr = null;
if(window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
// IE6浏览器 这边是针对ie6做的兼容处理
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
// 2. 准备发送
// xhr.open("get","checkUsername.php?username=" + username,true); // 这里true代表异步(不写默认异步)
xhr.open("post","checkUsername.php",true);
// 3. 执行发送
var param = "username=" + username;
// 对于post请求来说的话,我们的参数应该放到请求体中
// 设置xhr的请求头信息,这个步骤仅仅是针对于post请求才有的
xhr.setRequestHeader("Content-type","application/x-www-form-urlencode");
xhr.send(param);
// 4. 设置回调函数
xhr.onreadystatechange = function(){
if(xhr.readyState == 4) {
if(xhr.status == 200) {
// 得到数据
// xhr.responseXML
var result = xhr.responseText;
console.log(result);
document.getElementById("result").innerText = result;
}
}
};
};
};
html 页面代码:
<body>
<h1>注册界面</h1>
<form action="register.php" method="post">
用户名:<input type="text" name="username" id="username">
<input type="button" value="验证用户名" id="btn">
<span id="result"></span>
<br>
密码:<input type="password" name="password"><br>
<input type="submit" value="提交">
</form>
</body>
chechUsername.php 文件代码:
$uname = $_POST["username"];
// 按道理来说,这里应该是要查询数据库 此处简单模拟
if($uname == "zhangsan") {
echo "username exists";
} else {
echo "username ok";
}
在用户名输入框输入 zhangsan
注册界面案例讲解
当前端界面需要从服务器获取数据的时候,其实就只要访问一个url地址,制定特定的参数即可。这个url地址所对应的jsp也好,php也好 其实服务器开发人员已经开发好了。服务器开发人员开发好相关的接口之后,会提供一份接口文档,在文档中会详细的说明你要获取什么数据的时候,访问什么地址,传入什么参数等等。
以下是注册界面案例完整代码展示
<title>注册界面</title>
<script>
window.onload = function() {
var username = document.querySelector("#username");
var email = document.querySelector("#email");
var phone = document.querySelector("#phone");
username.onblur = function() {
var usernameValue = username.value;
// 将 usernameValue 提交给服务器,有服务器进行唯一性的校验
// 1. 创建对象 兼容处理
var xhr = null;
if(window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
// 2. 准备发送
xhr.open("get","./server/checkUsername.php?uname=" + usernameValue,true);
// 3. 执行发送
xhr.send(null);
// 4. 指定回调函数
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
if(xhr.status == 200) {
var result = xhr.responseText;
// console.log(result);
var username_result = document.querySelector("#username_result");
if(result == "ok") {
username_result.innerText = "用户名可用";
} else {
username_result.innerText = "用户名已被注册";
}
}
}
}
}
email.onblur = function() {
var emailValue = email.value;
var xhr = null;
if(window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
var param = "e=" + emailValue;
xhr.open("post","./server/checkEmail.php",true);
// post 方法需要设置请求头 关于请求头里的内容不用强行记忆
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xhr.send(param);
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
if(xhr.status == 200) {
var result = xhr.responseText;
var email_result = document.querySelector("#email_result");
if(result == 0) {
// 邮箱可用
email_result.innerText = "邮箱可用";
} else {
// 邮箱不可用
email_result.innerText = "邮箱不可用";
}
}
}
}
};
phone.onblur = function() {
var phoneValue = phone.value;
// 1 2 3 4
var xhr = null;
if(window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
xhr.open("post","./server/checkPhone.php",true);
var params = "phonenumber=" +phoneValue;
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xhr.send(params);
xhr.onreadystatechange = function() {
if(xhr.readyState == 4){
if(xhr.status == 200) {
// xhr.responseText就是一个字符串
var result = xhr.responseText;
// 希望将result这样一个字符串转化为对象,方便我们获取里面的一些值
result = JSON.parse(result); // 只有是json格式的字符串才能使用这个转化方法
var phone_result = document.querySelector("#phone_result");
if(result.status == 0) {
// 代表手机号可用
phone_result.innerText = result.message.tips + "," + result.message.phonefrom;
} else if(result.status == 1){
// 代表手机号码不可用
phone_result.innerText = result.message;
}
}
}
}
}
}
</script>
</head>
<body>
<h1>注册界面</h1>
<form action="">
用户名:<input type="text" id="username"><span id="username_result"></span><br>
邮箱:<input type="text" id="email"><span id="email_result"></span><br>
手机号:<input type="text" id="phone"><span id="phone_result"></span><br>
</form>
</body>
此处发现验证唯一性的代码大量类似,应该想到封装的思想
同步和异步的理解
- 将Ajax请求改为同步请求
xhr.open("get","./server/checkUsername.php?uname=" + usernameValue,false);
这样做的话,会有两个问题:
第一:界面卡顿,卡顿多长时间,取决于网络速度
第二:xhr.onreadyStatechange 的回调函数不会被执行,需要修改代码才能获取到数据,将回调去掉即可
- 异步的底层原理
js中的异步的实现的原理是单线程加事件队列,js的代码执行是单线程的,所谓的单线程的含义是js的代码是从上往下按顺序依次执行的,一定是上一行代码执行完再执行下一行代码,事件队列可以认为是一个容器,这个容器中存储一些回调函数。这些回调函数只有在js代码全部执行完成之后,才有可能会去调用,因为js是单线程的,一次只能做一件事情。
sync_async 举例
Ajax 的执行步骤图解:
数据格式
- 什么是数据格式
将数据通过一定的规范组织起来,叫做数据格式,例如 张三%19%男-李四%23%男-王五%30%女 这就是一种数据格式,这种自定义的数据格式组成的规则不通用
- Xml 数据格式
Xml 数据格式是将数据以标签的方式进行组装,必须以 <?xml version="1.0" encoding="utf-8" ?> 开头,标签必须成对出现,也就是有开始标签就一定要有结束标签。xml 是一个通用的标准,任何人都知道该如何解析它。
缺点:体积太大,传输慢,元数据太多,解析不方便,目前使用的很少。
- Json 数据格式
Json 数据格式类似于js中的对象方式,通过key-value 的形式组装,是一个通用的标准,任何人都知道如何解析它。
Ajax 的使用——解析xml数据格式
<head>
<meta charset="UTF-8">
<title>书籍列表</title>
<style>
div{
width: 800px;
margin: 20px auto;
}
table{
width: 800px;
margin: 20px auto;
border-collapse: collapse;
}
th{
background-color: #0094ff;
color:white;
font-size: 16px;
padding: 5px;
text-align: center;
border: 1px solid black;
}
td{
padding: 5px;
text-align: center;
border: 1px solid black;
}
</style>
<script>
window.onload = function() {
var xhr = new XMLHttpRequest();
xhr.open("get","./server/getBooks.php",true);
xhr.send(null);
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
if(xhr.status == 200) {
var result = xhr.responseXML; }
console.log(result.getElementsByTagName("booklist")[0].getElementsByTagName("book"));
var books = result.getElementsByTagName("booklist")[0].getElementsByTagName("book");
var newHtml = document.getElementById("bookContainer").innerHTML;
for(var i = 0; i < books.length; i++) {
var itemBook = books[i];
var name = itemBook.getElementsByTagName("name")[0].textContent;
var author = itemBook.getElementsByTagName("author")[0].textContent;
var desc = itemBook.getElementsByTagName("desc")[0].textContent;
var tempHtml = "<tr><td>"+name+"</td><td>"+author+"</td><td>"+desc+"</td></tr>";
// console.log(tempHtml);
newHtml += tempHtml;
}
document.getElementById("bookContainer").innerHTML = newHtml;
}
}
}
</script>
</head>
<body>
<div>
<table id="bookContainer">
<tr>
<th>书名</th>
<th>作者</th>
<th>描述</th>
</tr>
<tr>
</tr>
</table>
</div>
</body>
php 文件如下
<?php
header("Content-Type:text/xml;");//这里设置响应头信息,保证浏览器可以把相应内容识别为xml文件类型
$arr = array();
$arr[0] = array("name"=>"三国演义","author"=>"罗贯中","desc"=>"一个杀伐纷争的年代");
$arr[1] = array("name"=>"水浒传","author"=>"施耐庵","desc"=>"108条好汉的故事");
$arr[2] = array("name"=>"西游记","author"=>"吴承恩","desc"=>"佛教与道教斗争");
$arr[3] = array("name"=>"红楼梦","author"=>"曹雪芹","desc"=>"一个封建王朝的缩影");
?>
<?xml version="1.0" encoding="utf-8" ?>
<booklist>
<?php
foreach ($arr as $key => $value) {
?>
<book>
<name><?php echo $value['name'] ?></name>
<author><?php echo $value['author'] ?></author>
<desc><?php echo $value['desc'] ?></desc>
</book>
<?php
}
?>
</booklist>
Ajax 的使用——解析json数据格式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>学生列表</title>
<style>
div{
width: 800px;
margin: 20px auto;
}
table{
width: 800px;
margin: 20px auto;
border-collapse: collapse;
}
th{
background-color: #0094ff;
color:white;
font-size: 16px;
padding: 5px;
text-align: center;
border: 1px solid black;
}
td{
padding: 5px;
text-align: center;
border: 1px solid black;
}
</style>
<script>
window.onload = function() {
var xhr = new XMLHttpRequest();
xhr.open("get","./server/getStudents.php",true);
xhr.send(null);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status == 200){
var result = xhr.responseText;
// 这里的responseText 只是一个字符串 需要把JSON格式的字符串转化为对象之后才能方便我们进行值的获取
result = JSON.parse(result);
var newHtml = document.getElementById("container").innerHTML;
for(var i =0; i < result.length; i++) {
var item = result[i];
var name = item.name;
var sex = item.sex;
var age = item.age;
var tempHtml = "<tr><td>"+name+"</td><td>"+age+"</td><td>"+sex+"</td></tr>";
newHtml += tempHtml;
// console.log(newHtml);
}
document.getElementById("container").innerHTML = newHtml;
}
}
};
}
</script>
</head>
<body>
<div>
<table id="container">
<tr>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
</tr>
</table>
</div>
</body>
</html>
php 文件如下
<?php
$arr = array();
$arr[0] = array("name"=>"张三","age"=>"19","sex"=>"男");
$arr[1] = array("name"=>"李四","age"=>"23","sex"=>"男");
$arr[2] = array("name"=>"王五","age"=>"30","sex"=>"女");
echo json_encode($arr);
?>
封装Ajax
对于封装方法,我们主要考虑几个方面:
- 哪些东西是变的
- 哪些东西是不变的
- 如何将结果通知调用者
- 如何调用方便
根据之前的案例经验,我们知道,不同场景的ajax调用,调用方法get还是post这个是有可能发送改变的,调用url地址也是会变的,请求参数也是会变的,返回数据的类型也是会变的。对于发生改变的东西可以通过参数传递的方式实现。
基础代码例如创建 XMLHttpRequest 对象,准备发送,执行发送,响应回调中有些代码也是固定不变的。
将结果通知调用者也可以通过在调用时传入一个方法就可以实现。
综上所述,代码可以封装成以下形式;
function myAjax(type,url,params,dataType,callback,async) {
// 1 2 3 4
var xhr = null;
if(window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
// 如果不传参 为null 得到的是 ?null 这里需要进行判断
if(type == "get") {
if(params && params != "") {
url += "?" + params;
}
}
xhr.open(type,url,async);
if(type == "get") {
xhr.send(null);
} else if(type == "post") {
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xhr.send(params);
}
if(async) {
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
if(xhr.status == 200) {
var result = null;
if(dataType == "json") {
result = xhr.responseText;
result = JSON.parse(result);
} else if(dataType == "xml") {
result = xhr.responseXML;
} else {
result = xhr.responseText;
}
// 考虑 callback 存在
if(callback){
callback(result);
}
}
}
}
} else {
if(xhr.readyState == 4) {
if(xhr.status == 200) {
var result = null;
if(dataType == "json") {
result = xhr.responseText;
result = JSON.parse(result);
} else if(dataType == "xml") {
result = xhr.responseXML;
} else {
result = xhr.responseText;
}
// 考虑 callback 存在
if(callback){
callback(result);
}
}
}
}
}
现在还差最后一个步骤,如何调用方便。对于目前的封装,我们可以很容易发现这个封装方法的两个缺点:
1. 参数的顺序不可以改变
2. 参数没有默认值,每次都得传递
这两个缺点可以通过一个小技巧就可解决,我们将封装的参数变为一个对象即可。得到如下代码:
function myAjax2(obj) {
var defaults = {
type:"get",
url:"#",
dataType:"json",
data:{},
async:true
};
// obj中的属性,覆盖到defaults中的属性
// 1. 如果有一些属性只存在obj中,会给defaults中增加属性
// 2. 如果有一些属性在obj和defaults中都存在,会将defaults中的默认值覆盖
// 3. 如果有一些属性只在defaults中存在,在obj中不存在,这时候defaults中将保留预定义的默认值
for(var key in obj) {
defaults[key] = obj[key];
};
}
优化过后的封装代码为:
function myAjax2(obj) {
var defaults = {
type:"get",
url:"#",
dataType:"json",
data:{},
async:true,
success:function(){console.log(result);}
};
// obj中的属性,覆盖到defaults中的属性
// 1. 如果有一些属性只存在obj中,会给defaults中增加属性
// 2. 如果有一些属性在obj和defaults中都存在,会将defaults中的默认值覆盖
// 3. 如果有一些属性只在defaults中存在,在obj中不存在,这时候defaults中将保留预定义的默认值
for(var key in obj) {
defaults[key] = obj[key];
};
var xhr = null;
if(window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
// 得到params
// data:{
// uname:"zhangsan",
// age:"18"
// } // uname=zhangsan&age=18
var params = "";
for(var attr in defaults.data){
params += attr + "=" + defaults.data[attr] + "&";
}
if(params) {
params = params.substring(0,params.length - 1);
}
if(defaults.type == "get"){
defaults.url += "?" + params;
}
xhr.open(defaults.type,defaults.url,defaults.async);
if(defaults.type == "get"){
xhr.send(null);
} else if (defaults.type == "post") {
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xhr.send(params);
}
if(defaults.async) {
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
if(xhr.status == 200) {
if(defaults.dataType == "json") {
result = xhr.responseText;
result = JSON.parse(result);
} else if(defaults.dataType == "xml") {
result = xhr.responseXML;
} else {
result = xhr.responseText;
}
defaults.success(result);
}
}
}
} else {
if(xhr.readyState == 4) {
if(xhr.status == 200) {
if(defaults.dataType == "json") {
result = xhr.responseText;
result = JSON.parse(result);
} else if(defaults.dataType == "xml") {
result = xhr.responseXML;
} else {
result = xhr.responseText;
}
defaults.success(result);
}
}
}
}
然后 调用 Ajax2 完成注册页面案例:
<script type="text/javascript" src="myutils.js"></script>
<script>
window.onload = function() {
var username = document.querySelector("#username");
var email = document.querySelector("#email");
var phone = document.querySelector("#phone");
username.onblur = function() {
var usernameValue = username.value;
var type = "get";
var url = "./server/checkUsername.php";
var params = "uname=" + usernameValue;
var dataType = "text";
myAjax2({
url:url,
// type:"get", 可以不写 默认为get
data:{uname:usernameValue},
dataType:"text",
success:function(result){
var username_result = document.querySelector("#username_result");
if(result == "ok") {
username_result.innerText = "用户名可用";
} else {
username_result.innerText = "用户名已被注册";
}
},
async:false
});
}
email.onblur = function() {
var emailValue = email.value;
var type = "post";
var url = "./server/checkEmail.php";
var params = "e=" + emailValue;
var dataType = "text";
myAjax2({
url:url,
type:"post",
dataType:"text",
data:{
e:emailValue
},
success:function(result){
var email_result = document.querySelector("#email_result");
if(result == 0) {
// 邮箱可用
email_result.innerText = "邮箱可用";
} else {
// 邮箱不可用
email_result.innerText = "邮箱不可用";
}
},
async:true
});
phone.onblur = function() {
var phoneValue = phone.value;
var type = "post";
var url = "./server/checkPhone.php";
var params = "phonenumber=" +phoneValue;
var dataType = "json";
myAjax2({
url:url,
type:"post",
data:{
phonenumber:phoneValue
},
success:function(result){
var phone_result = document.querySelector("#phone_result");
if(result.status == 0) {
// 代表手机号可用
phone_result.innerText = result.message.tips + "," + result.message.phonefrom;
} else if(result.status == 1){
// 代表手机号码不可用
phone_result.innerText = result.message;
}
}
});
}}
}
</script>
<body>
<h1>注册界面</h1>
<form action="">
用户名:<input type="text" id="username"><span id="username_result"></span><br>
邮箱:<input type="text" id="email"><span id="email_result"></span><br>
手机号:<input type="text" id="phone"><span id="phone_result"></span><br>
</form>
</body>
jQuery 中使用ajax
对于jQuery中关于ajax的封装,它提供了很多方法供开发者调用。不过这些封装都是基于一个方法的基础上进行的修改。这个方法就是$.ajax()
我们主要关注以下3个方法:
- $.ajax()
username.onblur = function() {
var usernameValue = username.value;
var type = "get";
var url = "./server/checkUsername.php";
var params = "uname=" + usernameValue;
var dataType = "text";
$.ajax({
url:url,
type:type,
data:{
uname:usernameValue
},
async:false,
dataType:"text",
success:function(result){
var username_result = document.querySelector("#username_result");
if(result == "ok") {
username_result.innerText = "用户名可用";
} else {
username_result.innerText = "用户名已被注册";
}
}
});
}
- $.get()
username.onblur = function() {
var usernameValue = username.value;
var type = "get";
var url = "./server/checkUsername.php";
var params = "uname=" + usernameValue;
var dataType = "text";
$.get(url+"?"+params,function(result){
console.log(result);
});
}
- $.post()
email.onblur = function() {
var emailValue = email.value;
var type = "post";
var url = "./server/checkEmail.php";
var params = "e=" + emailValue;
var dataType = "text";
$.post(url,{e:emailValue},function(result){
console.log(result);
});
}
跨域
- 跨域的概念:
下面介绍一个知识叫做跨域,这个知识点是源于一个叫同源策略的东西。
同源策略是浏览器上为安全性考虑实施的非常重要的安全机制。Ajax默认是能获取到同源的数据,对于非同源的数据,ajax是获取不到的。
下面举一个例子,来看看什么叫同源
比如有一个页面,它的地址为 http://www.example.com.dir/page.html 这个网址,在这个网址中,要去获取服务器的数据,获取数据的地址如下所示:
所谓的同源就是协议、端口、域名三者都完全一样,如果我们使用ajax来请求非同源路径下的数据,那么将会报如下错误:
在之前的案例中,我们都能够成功的获取到服务器的数据,那是因为服务器的接口地址和前端界面都处于同源状态下。
那我们需要处理获取非同源数据获取的情况吗?答案是肯定的。因为前端界面访问非同源的服务器的这种需求是非常常见的,比如在前端界面中获取天气数据,天气数据肯定是存在于别人的服务器上的,我们如果不能使用ajax进行访问的话,那么该怎么办呢? 这里就需要用到跨域了。
所以,先把概念理解清楚,不管是ajax还是跨域,都是为了访问服务器数据。简单来说:Ajax 是为了访问自己服务器的数据,跨域是为了访问别人服务器的数据。
- 跨域的实现
XMLHttpRequest 对象默认情况下是无法获取到非同源服务器下的数据。那么怎么获取别人服务器的数据呢?使用 XMLHttpRequest 是达不到的,我们只能另辟蹊径。
我们可以通过script标签,用script标签的src属性引入一个外部文件,这个外部文件是不涉及到同源策略的影响的。
例如:
<script type="text/javascript" src="http://www.lisi.com/test.js"></script>
-
引入外部js文件
-
访问外部php文件
-
动态创建script标签传入动态参数
-
前端界面决定方法名称
-
给window 增加属性进行方法定义
<!--<script>
// 跨域的本质,其实就是服务器返回了一个方法调用,这个方法是我们事先定义好的,而方法中的参数就是我们想要的数据
function foo2(data) {
console.log(data);
}
</script> -->
<!-- <script type="text/javascript" src="http://www.zhujin.com/data.php?city=beijing"></script> -->
<script>
window.onload = function() {
var btn = document.querySelector("#btn");
btn.onclick = function() {
var cityName = document.querySelector("#city").value;
// 动态创建script标签,动态指定src属性的值
var script = document.createElement("script");
script.src = "http://www.zhujin.com/data.php?city="+cityName+"&callback=foo2";
// 这行代码就相当于注释掉的script部分代码 给window增加了一个属性
window["foo2"] = function(data) {
console.log(data);
};
var head = document.querySelector("head");
head.appendChild(script);
};
}
</script>
</head>
<body>
<h1>天气信息查询</h1>
<input type="text" id="city" placeholder="请输入城市名称">
<input type="button" id="btn" value="查询">
</body>
lisi 文件夹下的data.php文件代码如下:
<?php
$cbName = $_GET["callback"];
$city = $_GET["city"];
if($city == "beijing") {
echo $cbName."('北京天气🌤')";
} else {
echo $cbName."('没有查询到天气情况')";
}
// echo "var str = 'haha'";
?>
小案例:淘宝提示词接口、百度提示词接口
!()[D:\前端学习\images\41.png]
<script>
window.onload = function() {
var btn = document.querySelector("#btn");
btn.onclick = function() {
var keywordValue = document.querySelector("#keyword").value;
console.log(keywordValue);
var script = document.createElement("script");
script.src = "https://suggest.taobao.com/sug?q="+keywordValue+"&callback=haha";
window["haha"] = function(data) {
var liTag = "";
for(var i=0;i<data.result.length;i++){
var temp = data.result[i];
var tempSug = temp[0];
liTag += "<li>" +tempSug+ "</li>"
}
var ulTag = document.querySelector("ul");
ulTag.innerHTML = liTag;
// console.log(data);
};
var head = document.querySelector("head");
head.appendChild(script);
}
}
</script>
<body>
<input type="text" id="keyword" placeholder="请输入相关的关键字">
<input type="button" id="btn" value="查询">
<ul>
</ul>
</body>
百度提示词案例:
<script>
window.onload = function() {
var btn = document.querySelector("#btn");
btn.onclick = function() {
var keywordValue = document.querySelector("#keyword").value;
console.log(keywordValue);
var script = document.createElement("script");
script.src = "http://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd="+keywordValue+"&cb=hehe";
window["hehe"] = function(data) {
var liTag = "";
for(var i=0;i<data.s.length;i++){
var temp = data.s[i];
liTag += "<li>" + temp + "</li>";
}
var ulTag = document.querySelector("ul");
ulTag.innerHTML = liTag;
// console.log(data);
};
var head = document.querySelector("head");
head.appendChild(script);
}
}
</script>
</head>
<body>
<input type="text" id="keyword" placeholder="请输入相关的关键字">
<input type="button" id="btn" value="查询">
<ul>
</ul>
</body>
可以发现两个案例中出现了很多重复代码,可对其进行 跨域部分的封装
myutils.js 文件代码如下:
// "https://suggest.taobao.com/sug?q="+keywordValue+"&callback=haha"
// obj = {
// url:"https://suggest.taobao.com/sug",
// data:{q:"123",pwd:"123456"},
// success:function(data){}
// }
function myAjax(obj) {
var defaults = {
type:"get",
url:"#",
data:{},
success:function(data){},
jsonp:"callback",
jsonpCallback:"haha"
};
for(var key in obj) {
defaults[key] = obj[key];
}
var params = "";
for(var attr in defaults.data) {
params += attr + "=" + defaults.data[attr] + "&";
}
if(params) {
params = params.substring(0,params.length-1);
defaults.url += "?" + params;
}
defaults.url += "&"+defaults.jsonp+"=" + defaults.jsonpCallback;
console.log(defaults.url);
var script = document.createElement("script");
script.src = defaults.url;
window[defaults.jsonpCallback] = function(data){
defaults.success(data);
};
var head = document.querySelector("head");
head.appendChild(script);
}
封装之后引用js文件即可:
<script type="text/javascript" src="myutils.js"></script>
<script>
window.onload = function() {
var btn = document.querySelector("#btn");
btn.onclick = function() {
var keywordValue = document.querySelector("#keyword").value;
// console.log(keywordValue);
myAjax({
url:"http://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su",
data:{wd:keywordValue},
success:function(data){
// console.log(data);
var liTag = "";
for(var i=0;i<data.s.length;i++){
var temp = data.s[i];
liTag += "<li>" + temp + "</li>";
}
var ulTag = document.querySelector("ul");
ulTag.innerHTML = liTag;
},
jsonp:"cb",
jsonpCallback:"xixi"
});
}
}
</script>
</head>
<body>
<input type="text" id="keyword" placeholder="请输入相关的关键字">
<input type="button" id="btn" value="查询">
<ul>
</ul>
</body>
使用jQuery获取跨域数据
<script type="text/javascript" src="jquery.js"></script>
<script>
window.onload = function() {
var btn = document.querySelector("#btn");
btn.onclick = function() {
var keywordValue = document.querySelector("#keyword").value;
console.log(keywordValue);
$.ajax({
url:"http://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su",
data:{wd:keywordValue},
success:function(data){
// console.log(data);
var liTag = "";
for(var i=0;i<data.s.length;i++){
var temp = data.s[i];
liTag += "<li>" + temp + "</li>";
}
var ulTag = document.querySelector("ul");
ulTag.innerHTML = liTag;
},
dataType:"jsonp",
jsonp:"cb",
// jsonpCallback:"haha" 这个就是改变调用的函数名称而已
});
}
}
</script>
<body>
<input type="text" id="keyword" placeholder="请输入相关的关键字">
<input type="button" id="btn" value="查询">
<ul>
</ul>
</body>
模板引擎的使用
无论是Ajax还是跨域,目的都是为了获取服务器的数据,获取数据之后将前端界面进行渲染。怎么渲染前端界面呢?前端界面都是由标签构成的,所以前端界面的渲染主要做的就是生成html标签。
生成html标签我们可以通过拼接字符串的方式来实现。这种方式在标签结构比较复杂的情况之下很不好操作和后期的维护,并且容易出错。接下来就介绍一种技术叫做模板引擎,通过模板引擎我们可以很方便的生成html标签。
模板引擎的本质:将数据和模板结合起来生成html片段。所以模板引擎需要两个组成部分:模板和数据,通过数据,将模板指定的标签动态生成,方便维护。
常见的模板引擎有很多,这里介绍一个效率最高的模板引擎artTemplate,这是腾讯公司出品的开源的模板引擎,在github上可以下载到源代码。
使用步骤如下:
-
引入js文件
-
定义模板
-
将数据和模板结合起来生成html片段
-
将html片段演染到界面中
基本语法:
得到数据中的值{{value}}
循环操作 {{each result as value i}}{{/each}}
转义:#的使用{{#value}}
条件判断 {{if xxx}}{{/if}}
技巧:有时候有可能需要对原始数据进行加工操作
例如:
<script type="text/javascript" src="./template.js"></script>
<!-- data.data -->
<script id="test" type="text/html">
<ul>
{{each arr as value i}}
<li>{{value}}</li>
{{/each}}
</ul>
</script>
<script>
window.onload = function(){
var data = ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他'];
var temp = {};
temp.arr = data;
var html = template("test",temp);//data.xxx
document.querySelector("#content").innerHTML = html;
}
</script>
</head>
<body>
<div id="content">
<ul>
<li>文艺</li>
<li>博客</li>
</ul>
</div>
</body>
<!-- 1、模板的type 2、给模板配一个id
data.s
-->
<script type="text/html" id="resultTemplate">
<ul>
{{each s as value i}}
<li>
<div>
<span>结果{{i+1}}:</span>
<span>{{value}}</span>
</div>
</li>
{{/each}}
</ul>
</script>
<title>Document</title>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="template.js"></script>
<script>
window.onload = function() {
var btn = document.querySelector("#btn");
btn.onclick = function() {
var keywordValue = document.querySelector("#keyword").value;
console.log(keywordValue);
$.ajax({
url:"http://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su",
data:{wd:keywordValue},
success:function(data){
console.log(data);
// template方法的含义就是将数据和模板结合起来,生成html片段
var html = template("resultTemplate",data);
console.log(html);
var ulTag = document.querySelector("ul");
ulTag.innerHTML = html;
var divResult = document.querySelector("#resultDiv");
divResult.innerHTML = html;
},
dataType:"jsonp",
jsonp:"cb"
});
}
}
</script>
<body>
<input type="text" id="keyword" placeholder="请输入相关的关键字">
<input type="button" id="btn" value="查询">
<div id="resultDiv">
<ul>
<li>
<div>
<span>结果1:</span>
<span>1</span>
</div>
</li>
</ul>
</div>
</body>
最终运行结果为这样:
- 天气查询案例
接口文档如下:
完整源码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>获取天气信息</title>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="template.js"></script>
<script type="text/html" id="weatherTemplate">
{{each weather as value i}}
<div>
<span>{{value.date}}</span>
<ul>
<li>白天天气:{{value.info.day[1]}}</li>
<li>白天温度:{{value.info.day[2]}}</li>
<li>白天风向:{{value.info.day[3]}}</li>
<li>白天风速:{{value.info.day[4]}}</li>
</ul>
<ul>
<li>夜间天气:{{value.info.night[1]}}</li>
<li>夜间温度:{{value.info.night[2]}}</li>
<li>夜间风向:{{value.info.night[3]}}</li>
<li>夜间风速:{{value.info.night[4]}}</li>
</ul>
{{if value.info.dawn}}
<ul>
<li>黎明天气:{{value.info.dawn[1]}}</li>
<li>黎明温度:{{value.info.dawn[1]}}</li>
<li>黎明风向:{{value.info.dawn[1]}}</li>
<li>黎明风速:{{value.info.dawn[1]}}</li>
</ul>
{{/if}}
</div>
{{/each}}
</script>
<script type="text/javascript">
$(function(){
$("#query").click(function(){
//将用户所选择的城市信息的天气预报情况查询出来
var code = $("#city").val();
console.log(code);
$.ajax({
url:"http://cdn.weather.hao.360.cn/sed_api_weather_info.php",
data:{
app:"360chrome",
code:code
},
jsonp:"_jsonp",
dataType:"jsonp",
success:function(data){
console.log(data);
var html = template("weatherTemplate",data);
$("#info").html(html);
}
});
});
});
</script>
<style type="text/css">
#container{
width: 400px;
min-height: 300px;
background-color: lightgreen;
margin: auto;
padding: 10px;
text-align: center;
}
ul{
list-style: none;
text-align: left;
}
</style>
</head>
<body>
<div id="container">
<select id="city">
<option value="101010100">北京</option>
<option value="101020100">上海</option>
<option value="101280101">广州</option>
<option value="101280601">深圳</option>
<option value="101210101">杭州</option>
<option value="101200101">武汉</option>
<option value="101110101">西安</option>
<option value="101190401">苏州</option>
<option value="101220101">合肥</option>
<option value="101220606">宿松</option>
<option value="101220201">蚌埠</option>
<option value="101270201">攀枝花</option>
<option value="101310218">珊瑚岛</option>
<option value="101340102">台北</option>
</select>
<input type="button" value="查询" id="query">
<div id="info">
</div>
</div>
</body>
</html>
- 手机号码查吉凶
使用 www.mob.com 提供的数据服务来得到我们想要的数据。
第三方接口的使用一般来说,都是需要注册、创建应用、申请appkey 这几个步骤,然后按照文档中的要求进行api接口的调用即可。
获取服务器数据小结:
首先需要获取API接口文档:
访问www.mob.com
进入mobAPI --找到手机号码查询吉凶
获得到了API信息。其中key的值需要用户申请,点击右上角申请之后会获得一个申请码即可使用该接口。
注意访问得到的仅仅是一个json数据,并没有回调函数,所以无法跨域得到数据,该接口与我们的地址非同源,也无法使用正常的ajax,所以我们先访问自己的服务器,再由服务器去访问此接口,返回数据给我们前端界面
完整源码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>获取手机吉凶信息</title>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(function(){
$("#btn").click(function(){
var phoneNumber = $("#phonenumber").val();
console.log(phoneNumber);
$.ajax({
url:"./server/getphoneinfo.php",
data:{mobile:phoneNumber},
dataType:"json",
success:function(data){
console.log(data);
if(data.retCode == 200) {
var info = data.result.conclusion;
document.querySelector("#result").innerHTML = info;
} else {
document.querySelector("#result").innerHTML = "信息获取失败,请检查输入";
}
}
});
});
});
</script>
</head>
<body>
<div id="container">
<input type="text" id="phonenumber" placeholder="请输入手机号码">
<input type="button" id="btn" value="查询">
<span id="result">结果信息</span>
</div>
</body>
</html>
getphoneinfo.php 文件代码:
<?php
// 在php中,获取一个链接中的数据
// 设置编码
header("Content-Type:text/plain;charset=utf-8");
// 拿到前端的数据
$phoneNumber=$_GET["mobile"];
// 使用curl进行网络数据访问
$ch=curl_init();
// 网络访问的url地址
$url="http://apicloud.mob.com/appstore/lucky/mobile/query?key=216e720443bb8&mobile=".$phoneNumber;
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
// 执行HTTP请求
curl_setopt($ch,CURLOPT_URL,$url);
// 得到数据
$res=curl_exec($ch);
echo $res;
?>