不是原创哦,笔记是照着关注的微信公众号Web前端之巅记下来的,大家去关注吧!她的博客地址是https://blog.csdn.net/lvonve/,非常感谢她!
服务器和客户端
网路相关概念
IP地址:
通过IP地址可以找到特定的服务器。可以通过ipconfig
查看本机的IP。
域名:
由于IP地址是一串数字,比较难记,所以用域名代替IP地址。
DNS域名解析器:
DNS又叫做域名解析服务器,提供域名和ip地址的映射关系。
一台电脑访问服务器的过程如下:
比如访问百度服务器:当在地址栏输入www.baidu.com点击回车的时候,浏览器会将域名发送到DNS域名解析器,解析出www.baidu.com对应的ip是123.125.114.114,然后再将这个域名返回个浏览器,浏览器从这个ip访问百度服务器。
一般我们的电脑上有一个hosts文件,里面保存着域名和ip地址的映射关系,当我们访问百度的时候,现在hosts中读取是否有域名对应的ip,没有的话再通过DSN 域名解析器。
本机 hosts 文件的路径:C:\Windows\System32\drivers\etc\hosts
端口:
当我们电脑找到一台服务器时,这台服务器可能会提供很多服务,如何区分客户端需要哪种服务就需要端口来区分。
比如:我们在访问百度提供的网页服务时,完整的写法为:www.baidu.com:80
,80 这个端口就是百度提供网页服务的,但是80这个端口比较特殊,可以省略不写。
再比如我们在设置邮箱客户端的时候,也需要指定端口号。
通信协议
通信协议就是事先商量好的规则。而计算机之间的通信也需要规则。
常见的协议有:
HTTP、HTTPS:超文本传输协议
FTP:文件传输协议
SMTP:简单邮件传输协议
WAMP 的安装配置
什么是Wamp?
Wamp指的是:Windows、Apache、MySQL、PHP 几个服务器软件的缩写,类似的还有 LAMP,只不过把 Windows 换成了 Linux。
为什么要安装 Wamp?
以前我们写的 html 文件都是在本地执行的,现在我们想把我们的电脑变成一台服务器,然后将我们的 html 界面以服务的方式提供给别的客户机访问。
Wamp 的简单配置:
配置访问权限:
默认情况下,apache 提供的网页服务只允许 localhost 和 127.0.0.1 (其实这两个是一个映射关系,在 hosts 里面有写)访问,如果我们想让别的客户机访问,就需要对配置文件进行修改。配置文件位于:C:\wamp\bin\apache\Apache2.4.4\conf\httpd.conf 将 268 行的 Deny from all 改成 Allow from all。
注意:在修改所有配置文件之前,都应该先做备份。
网站根路径的配置
默认情况下,网站的根路径为 c:\wamp\www ,在此目录下的文件才可以以服务的方式提供给别人访问,如果想更改这个路径,也需要修改 C:\wamp\bin\apache\Apache2.4.4\conf\httpd.conf 文件,将 DocumentRoot 修改为自己想要的目录。
注意:修改之后,原路径 c:\wamp\www 将不可访问。
静态网站和动态网站
静态网站
所有的 HTML 代码全部都已经写好,任何人访问都是相同的。每次网页的改变,都需要修改 HTML 源码,而且如果有1000个 HTML 文件,就需要修改 1000 个 HTML代码,工作量巨大。
动态网站
一般动态网站通过数据库进行架构,动态网站的内容可以根据不同用户的不同需求展示不同的页面。一般是以 asp、jsp、php、aspx 等结尾。
php基础语法
基本结构
- 所有代码都要写在
<?php //内容 ?>
里面 - php文件可以和HTML文件结合进行使用
- php文件的扩展名是’.php’
- php代码必须在服务器上执行
打印语句
echo:在页面中输入字符串,只能打印字符串,数字等简单类型
print_r输出复杂类型
var_dump:输出复杂类型
<?php
echo 'hello lianlian.';
echo '<br>';
echo 123;
echo '<br>';
print_r([1,2,3,4,5]);
echo '<br>';
var_dump([1,2,3,4,5])
?>
打印结果:
hello lianlian.
123
Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 [4] => 5 )
array (size=5)
0 => int 1
1 => int 2
2 => int 3
3 => int 4
4 => int 5
变量的声明和使用
前面要加$
$str = 'Hello';
echo $str;
字符串拼接
使用’.’,不使用’+’
$str1 ="Hello";
$str2 ="world";
echo $str1." ".$str2;
php执行原理
浏览器是不识别PHP文件的,用浏览器打开php文件,之后显示php源代码,所以php文件必须在服务器中执行。其实Apache服务器也识别不了PHP文件,是Apache将php文件交给php模块处理的,最后Apache将处理之后的网页内容返回。
数组
一维数组的定义:
$arr = array();
$arr[0] = "10";
$arr[1] = "20";
$arr[2] = "30";
或者
$arr = array("10", "20", "30");
数组是复杂类型,不能食用echo打印,智能打印其中的某个元素,复杂类型使用print_r或者var_dump。
示例:
$arr1 = array();
$arr1[0] = "10";
$arr1[1] = "20";
$arr1[2] = "30";
$arr2 = array("40", "50", "60");
// echo $arr1; // 不能直接打印数组
print_r($arr1);
var_dump($arr2);
echo json_encode($arr1); // 将数组转化成 json 格式打印,转化后是 字符串格式,可以使用echo。
打印结果:
Array ( [0] => 10 [1] => 20 [2] => 30 )
array (size=3)
0 => string '40' (length=2)
1 => string '50' (length=2)
2 => string '60' (length=2)
["10","20","30"]
数组的下标索引自定义:
$arr = array("index1"=>"40", "index2"=>"50", "index3"=>"60");
或者只定义其中的几个:
$arr = array("40", "index"=>"50", "60");
此时,40的下标是0,60的下标是1.这种方式不可以使用for循环遍历数组,因为下标不是1,2,3了,要用foreach的方式(key索引,value为索引对应的值)
foreach($arr as $key => $value) {
echo $key . "---" . $value . "<br>";
}
二维数组的定义
$arr = array();
$arr[0] = array("1", "2", "3");
$arr[1] = array("4", "5", "6");
var_dump($arr);
echo json_encode($arr);
打印结果:
array (size=2)
0 =>
array (size=3)
0 => string '1' (length=1)
1 => string '2' (length=1)
2 => string '3' (length=1)
1 =>
array (size=3)
0 => string '4' (length=1)
1 => string '5' (length=1)
2 => string '6' (length=1)
[["1","2","3"],["4","5","6"]]
函数
系统函数
json_encode:php中将数组转化为json格式的字符串
var_dump:输出复杂的数据类型
print_r:输出复杂的数据类型
count:得到数组的长度
自定义函数
function add($num1,$num2){
return $num1+$num2;
}
预定义变量
我们知道,动态网页会根据不同的需求展示不同的页面,那么是怎么做到的呢?
请求类型
请求的时候是要携带参数的,用来表示不同的要求,根据参数的不同,而展示不同的界面。根据参数携带的位置不同,可以简单地把请求分为get和post。
get请求:跟在url后面,用?连接,多个参数之间用&连接
post请求:参数在请求体中
$_GET["属性名字"]
:获取get请求的属性的值
$_POST["属性名字"]
:获取post请求的属性的值
get请求
实例:php获取用户登录名和密码进行校验
<!--html代码-->
<!--省略代码-->
<body>
<h1>登录界面</h1>
<form action="check.php" method="GET">
用户名:<input type="text" name="username"> <br>
密 码:<input type="password" name="passwd"> <br>
<input type="submit" value="提交">
</form>
</body>
// php代码
<?php
$username = $_GET["username"];
$password = $_GET["passwd"];
if(($username == "Daotin") && ($password == "123")) {
echo "Login Success!";
} else {
echo "Login Failed!";
}
?>
在form表单中可以进行get请求和post请求
我们在输入账号和密码并点击提交之后,在地址栏可以看出,参数跟在了地址栏后,用?连接,参数之间用&连接
通过$_GET[]可以获取参数的值。
post请求
<!--HTML主要代码-->
<h1>登录界面</h1>
<form action="check.php" method="POST">
用户名:<input type="text" name="username"> <br>
密 码:<input type="password" name="passwd"> <br>
<input type="submit" value="提交">
</form>
<?php
$username = $_POST["username"];
$password = $_POST["passwd"];
if(($username == "Daotin") && ($password == "123")) {
echo "Login Success!";
} else {
echo "Login Failed!";
}
?>
可以看见在地址栏中没有显示请求参数
get请求和post请求的区别
- get请求会把请求参数放在url中,而post请求则放在请求体中,post更安全
- 所以,一般get请求数获取服务器的数据,post请求时向服务器提交一些数据
Ajax概述
Ajax全称是Asynchronous JavaScript and XML(异步的JavaScript和XML)。它可以在无需加载整个页面的情况下,能够更新部分网页。
我们可以通过以下几种方式让浏览器发出对服务端的请求,获得服务端的数据
* 地址栏输入地址,回车,刷新
* 特定元素的href或src属性
* 表单提交
web运作的原理:一次HTTP请求对应一个页面
Ajax请求时异步的,也就是说,腰痛过回调函数获得相应。
Ajax快速上手
使用Ajax的过程可以类比平常我们访问网页的过程
// 1.创建一个XMLHttpRequest类型的对象相当于打开了一个浏览器
var xhr = null;
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveObject("Microsoft.XMLHTTP");
}
// 2.打开与一个网址之间的连接,相当于在地址栏输入访问地址
xhr.open("get","checkusername.php?username="+uname,true);
// 3.通过连接发送一次请求相当于回车或者点击访问发送请求
xhr.send(null);
// 仅仅针对post请求
// xhr.setRequestHeader('Content-Type','application/x-www-from-urlencoded');
// 4.指定xhr状态变化事件处理函数相当于处理网页呈现后的操作
xhr.onreadystatechange = function(){
if(this.readtState == 4){
if(thid.status == 200){
console.log(this.responseText);
}
}
}
创建对象
在IE6及以下的时候,是不支持 XMLHttpRequest 对象的,那么与之对应写法为:
var xhr = new ActiveXObject("Microsoft.XMLHTTP");
所以为了兼容性,上面的创建对象的方式改为:
var xhr = null;
if(window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
open方法
第一个参数是请求的方式,是 get 请求还是 post 请求。一般取决后端开发的php文件里面写的是 get 还是 post。
第二个参数是需要请求的地址。如果是 get 请求,需要在地址后面加上 ? 进行连接操作,连接的是需要请求的你内容。(参考下面验证用户名示例),如果是 post 请求,只需要写请求的地址就可以了,它的请求内容是写在 send 中的。
第三个参数是同步或者异步,一般可以不写,不写默认异步,false:同步,true:异步。
send方法
对于 get 方式,参数为 null;
对于 post 方式,参数为请求的数据。
var param = "username=" + uname; // 和 get 地址后面 ? 链接请求内容一致
xhr.send(param);
对于 post 请求,还需要设置下请求头(post请求才有)
// 仅仅针对 post 请求才有
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
onreadystatechange 回调函数
之所以是回调函数,这样不会阻塞当前的操作,什么时候服务器返回数据,什么时候使用。这就是异步。
status:服务器返回的状态码
this.status == 200:表示响应成功;404 表示没有找到请求的资源;500 表示服务器端错误。
readyState:xhr对象的状态改变时,readyState的值也会相应的改变。具体数值的含义见下表:
readyState | xhr状态 | 说明 |
---|---|---|
0 | UNSENT | 代理(xhr)被创建,但尚未调用 open 方法 |
1 | OPENED | open 方法已经被调用,建立了连接 |
2 | HEADERS_RECEIVED | send 方法已经被调用,已经可以获取状态行和响应头 |
3 | LOADING | 响应体下载中,responseText 属性可能已经包含部分数据 |
4 | DONE | 响应体下载完成,可以直接调用 responseText 获取数据 |
当 readyState == 2 时,只获取到数据头,这时不能使用 responseText 获取,而是用 getResponseHeader 来获取数据头信息。
当 readyState == 3 时,可能已经获取部分数据体,但是处理数据是不可靠的,所以一般一般我们都是在 readyState 值为 4 时,执行响应的后续逻辑 。
案例:点击按钮验证用户名是否存在
<div>
<h1>用户注册</h1>
用户名:
<input type="text" name="username">
<input type="button" value="验证用户名" id="btn">
<span></span>
<br> 密码:
<input type="password" name="passwd">
<br>
<input type="submit" value="注册提交">
</div>
<script>
var spanObj = document.getElementsByTagName("span")[0];
document.getElementById("btn").onclick = function () {
// 获取用户名
var uname = document.getElementsByName("username")[0].value;
// 发送给服务器处理
var xhr = new XMLHttpRequest();
xhr.open("get", "tt.php?username=" + uname, true);
xhr.send(null);
xhr.onreadystatechange = function () {
if (this.readyState == 4) {
spanObj.innerText = xhr.responseText;
if (xhr.responseText == "用户名已存在!") {
spanObj.style.color = "red";
} else {
spanObj.style.color = "green";
}
}
};
};
</script>
后台php代码
<?php
$user = $_GET["username"];
if($user == "lvonve") { // 这里仅仅只判断一个用户名,实际上是由数据库提供
echo "用户名已存在!";
} else {
echo "用户名可以使用!";
}
?>
接口文档的使用
需求:使用接口文档验证用户名,邮箱,手机的唯一性
接口文档
当前端页面 要从服务器获取数据的时候,其实就是访问一个url地址,指定特定的参数即可。这个url对应的php或者jsp等都是服务器开发人员已经开发好的。服务器开发人员开发好相关的接口之后,会提供一份接口文档给前端人员,在接口中会详细说明你要获取什么数据,访问什么网址,传入什么参数等等内容,下面就是一个简单地接口文档内容:
验证用户唯一性的接口
地址 | /server/checkUsername.php |
---|---|
作用描述 | 验证用户是否可用 |
请求类型 | get 请求 |
参数 | uname |
返回的数据格式 | 普通字符串 |
返回数据说明 | 返回 ok:代表用户名可用; 返回 error:代表用户名不可用。 |
验证邮箱唯一性的接口
地址 | /server/checkEmail.php |
---|---|
作用描述 | 验证邮箱是否可用 |
请求类型 | post 请求 |
参数 | e |
返回的数据格式 | 数字 |
返回数据说明 | 返回 0:代表邮箱可用; 返回 1:代表邮箱不可用 |
验证手机号唯一性的接口
地址 | /server/checkPhone.php |
---|---|
作用描述 | 验证手机号是否可用 |
请求类型 | post 请求 |
参数 | phonenumber |
返回的数据格式 | json格式 |
返回数据说明 | 如下: |
//手机号可用情况下返回
{
"status":0,
"message":{
"tips":"手机号可用",
"phonefrom":"中国电信"
}
}
//手机号可用情况下返回
{
"status":1,
"message":"手机号已经被注册"
}
实例代码
// 获取所有元素
var userObj = document.getElementByName("username")[0];
var emailObj = document.getElementByName("email")[0];
var phoneObj = document.getElementByName("phone")[0];
var userSpanObj = document.getElementByName("user-span")[0];
var emailSpanObj = document.getElementByName("email-span")[0];
var phoneSpanObj = document.getElementByName("phone-span")[0];
// 用户名文本框失去焦点事件
userObj.onblur = function(){
// 获取文本内容
var userText = this.value;
var xhr = new XMLHttpRequest();
xhr.open("get","./server/checkUsername.php?username="+userText,true);
xhr.send(null);
xhr.onreadystatechange = function(){
if(this.readyState == 4){
if(this.status == 200){
if(this.responseText == "ok"){
userSpanObj.innerHTML = "用户名可用";
}else if(this.responseText = "error"){
userSpanObj.innerHTML = "用户名不可用";
}
}
}
}
}
// 密码文本框失去焦点事件
emailObj.onblur = function(){
// 获取文本内容
var emailText = this.value;
var xhr = new XMLHttpRequest();
xhr.open("post","./server/checkEmail.php",true);
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send("e="+emailText);
xhr.onreadystatechange = function(){
if(this.readyState == 4){
if(this.status == 200){
console.log(this.responseText);
if(this.responseText == 0){
emailSpanObj.innerHTML = "邮箱可用";
}else if(this.responseText == 1){
emailSpanObj.innerHTML = "邮箱不可用"
}
}
}
}
}
// 手机号文本框失去焦点事件
phoneObj.onblur = function(){
// 获取文本内容
var phoneText = this.value;
var xhr = new XMLHttpRequest();
xhr.open("post","./server/phoneEmail.php",true);
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send("phonenumber="+phoneText);
xhr.onreadystatechange = function(){
if(this.readyState == 4){
if(this.status == 200){
var val = JSON.parse(this.responseText);
if(val.status == 0){
phoneSpanObj.innerHTML = val.message.tips" "+val.message.phonefrom;
}else if(this.responseText == 1){
phoneSpanObj.innerHTML = val.message;
}
}
}
}
}
书写以上代码的过程中,完全不需要查看对应的php文件,只需要查看接口文档即可。
代码封装
上面的验证过程中,都是用到了Ajax的四部操作,有代码冗余,所以将Ajax的四部操作封装在一个函数内。
// Ajax的四部操作
function myAjax(type,url,param,async,dataType,callback){
var xhr = null;
// 兼容性处理
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
if((type=="get")||(type=="GET")){
if(param&¶m!=""){
url+="?"+param;
}
xhr.open(type,url,async);
xhr.send(null);
}else if((type=="post")||(type=="POST")){
xhr.open(type,url,async);
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
xhr.send(param);
}
if(async){
xhr.onreadystatechange = function(){
if(this.readyState == 4){
if(this.status == 200){
if(dataType == "xml"){
callback(this.responseXML);
}else if(dataType == "json"){
callback(JSON.parse(this.responseText));
}else{
callback(this.responseText);
}
}
}
}
}else{
if(this.readyState == 4){
if(this.status == 200){
if(dataType == "xml"){
callback(this.responseXML);
}else if(dataType == "json"){
callback(JSON.parse(this.responseText));
}else{
callback(this.responseText);
}
}
}
}
}
// 获取所有元素
var userObj = document.getElementByName("username")[0];
var emailObj = document.getElementByName("email")[0];
var phoneObj = document.getElementByName("phone")[0];
var userSpanObj = document.getElementByName("user-span")[0];
var emailSpanObj = document.getElementByName("email-span")[0];
var phoneSpanObj = document.getElementByName("phone-span")[0];
// 用户名文本框失去焦点事件
userObj.onblur = function(){
// 获取文本内容
var userText = this.value;
myAjax("get","./server/checkUsername.php","username="+userText,"true","text",function(result){
if(result == "ok"){
userSpanObj.innerHTML = "用户名可用";
}else if(result = "error"){
userSpanObj.innerHTML = "用户名不可用";
}
})
}
// 密码文本框失去焦点事件
emailObj.onblur = function(){
// 获取文本内容
var emailText = this.value;
myAjax("post","./server/checkEmail.php","e="+emailText,"true","true",function(result){
if(result == 0){
emailSpanObj.innerHTML = "邮箱可用";
}else if(result == 1){
emailSpanObj.innerHTML = "邮箱不可用"
}
})
}
// 手机号文本框失去焦点事件
phoneObj.onblur = function(){
// 获取文本内容
var phoneText = this.value;
myAjax("post","./server/checkPhone.php","e="+emailText,"true","true",function(result){
if(result.status == 0){
phoneSpanObj.innerHTML = val.message.tips" "+val.message.phonefrom;
}else if(result.responseText == 1){
phoneSpanObj.innerHTML = val.message;
}
})
}
仍存在的问题:
* 参数的顺序不可改变
* 参数没有设置默认值,所有的参数必须传递
代码进一步封装
将需要传递的参数做成一个对象,里面有所有参数的默认值,如果没有传入参数就使用默认值,如果传入了,覆盖掉默认参数。
function myAjax2(obj){
var defaults = {
type:"get",
url:"#",
dataType:"",
data:{}, //参数可能有多个,用对象保存
async:true,
success:function(result){
console.log(result);
}
};
for(var key in obj){
defaults[key] = obj[key];
}
var xhr = null;
// 兼容性处理
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
var param = "";
for(var attr in defaults.data){
param += attr + "=" +defaults.data[attr] + "&"
}
// 去掉最后一个&
if(param){
param = param.substring(0, param.length-1);
}
if((defaults.type=="get")||(defaults.type=="GET")){
defaults.url+="?"+param;
}
xhr.open(defaults.type,defaults.url,defaults.async);
if((defaults.type=="get")||(defaults.type=="GET")){
xhr.send(null);
}else if((defaults.type=="post")||(defaults.type=="POST")){
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send(param);
}
if(async){
xhr.onreadystatechange = function(){
if(this.readyState == 4){
if(this.status == 200){
if(dataType == "xml"){
callback(this.responseXML);
}else if(dataType == "json"){
callback(JSON.parse(this.responseText));
}else{
callback(this.responseText);
}
}
}
}
}else{
if(this.readyState == 4){
if(this.status == 200){
if(dataType == "xml"){
callback(this.responseXML);
}else if(dataType == "json"){
callback(JSON.parse(this.responseText));
}else{
callback(this.responseText);
}
}
}
}
}
// 获取所有元素
var userObj = document.getElementByName("username")[0];
var emailObj = document.getElementByName("email")[0];
var phoneObj = document.getElementByName("phone")[0];
var userSpanObj = document.getElementByName("user-span")[0];
var emailSpanObj = document.getElementByName("email-span")[0];
var phoneSpanObj = document.getElementByName("phone-span")[0];
// 用户名文本框失去焦点事件
userObj.onblur = function(){
myAjax2({
url:"./server/checkUsername.php",
type:"get",
data:{uname:this.value},
sucess:function(result){
if(result == "ok"){
userSpanObj.innerHTML = "用户名可用";
}else if(result = "error"){
userSpanObj.innerHTML = "用户名不可用";
}
}
})
}
// 密码文本框失去焦点事件
emailObj.onblur = function(){
myAjax2({
url:"./server/checkEmail.php",
type:"post",
data:{e:this.value},
sucess:function(result){
if(result == 0){
emailSpanObj.innerHTML = "邮箱可用";
}else if(result = 1){
emailSpanObj.innerHTML = "邮箱不可用";
}
}
})
}
// 手机号文本框失去焦点事件
phoneObj.onblur = function(){
myAjax2({
url:"./server/checkPhone.php",
type:"post",
dataType:"json",
data:{phonenumber:this.value},
sucess:function(result){
if(result.status == 0){
phoneSpanObj.innerHTML = result.message.tips" "+result.message.phonefrom;
}else if(result.status = 1){
phoneSpanObj.innerHTML = result.message;
}
}
})
}
进一步封装后的函数为:myAjax({}),里面是一个对象。使用默认的方式,不仅可以解决传入参数不一致的问题,还可以解决不传参数是默认值的问题。
同步请求和异步请求
同步请求:在用户发送请求之后,浏览器会一直等待服务器的数据返回,如果网络延迟比较高,浏览器就一直卡在当前的页面,直达服务器返回数据才进行其他的操作。
异步请求:在用户进行请求发送后,浏览器可以自由操作页面中的其他元素,当服务器返回数据的时候,才出发响应的是将,对返回的数据进行操作。
如果将Ajax请求改为同步的haul:
1.页面会卡顿,卡顿时间取决于网络的速度
2.xhr.onreadystatechange 的回调函数不会执行,因为在 xhr.send() 之后,xhr.readyState 就为 4 了,所以数据的处理,直接跟在xhr.send() 之后就可以了。
异步底层原理
js 中的异步实现原理是单线程+事件队列。js 的代码执行是单线程的,单线程的意思是代码从上到下按照顺序执行,而事件队列存储了一些回调函数,当 js 从上往下执行的时候,遇到回调函数就将其放到事件队列,在所有 js 代码执行完成之后处于空闲状态时,才会去事件队列看有没有回调函数达到触发条件,有的话就执行,没有的话就继续闲着。
Ajax 的四步操作中,同步和异步的区别:
如果是异步请求,在 send 的时候,会调用浏览器进行网络数据的请求,send 就执行完了,接着将第四步的回调函数存储在事件队列里面,浏览器数据请求完了,readyState 状态发生变化,触发第四步回调函数的执行。
而在同步请求中, send 时是自己进行网络数据的请求,这个时候非得请求到数据,才会接着将第四步的回调函数存储在事件队列里面,所以如果网络延时页面就会卡死,在 send 过后接受到数据的时候 readyState 已经为4了,不会再变化,所以第四步的回调函数不会执行。
数据格式
XML数据格式
XML数据格式是将数据以标签的凡是进行组装,必须以<? xml version="1.0" encoding="utf-8" ?>
开头,标签必须成对出现,也就是有开始标签就必须有结束标签。
<? xml version="1.0" encoding="utf-8" ?>
<students>
<student>
<name>张三</name>
<age>18</age>
<sex>男</sex>
</student>
</students>
缺点是体积太大,元数据(描述数据的数据)太多,解析不方便,目前很少使用
json数据格式
通过key-value的方式进行组装
{
"student" : [
{
"name": "张三",
"age": "18",
"sex": "男"
},
{
"name": "李四",
"age": "23",
"sex": "女"
}
]
}
优点是体积小,传输快,解析方便
案例:获取读书信息
接口文档:
地址 | /server/getBooks/php |
---|---|
作用描述 | 获取图书信息 |
请求类型 | get 请求 |
参数 | 无 |
返回数据格式 | xml 格式 |
返回数据说明 | 如下 |
<?xml version="1.0" encoding="utf-8"?>
<booklist>
<book>
<name>三国演义</name>
<author>罗贯中</author>
<desc>一个杀伐纷争的年代</desc>
</book>
<book>
<name>水浒传</name>
<author>施耐庵</author>
<desc>108条好汉的故事</desc>
</book>
<book>
<name>西游记</name>
<author>吴承恩</author>
<desc>佛教与道教斗争</desc>
</book>
<book>
<name>红楼梦</name>
<author>曹雪芹</author>
<desc>一个封建王朝的缩影</desc>
</book>
</booklist>
源代码:
<!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", "tt.php", true);
xhr.send(null);
xhr.onreadystatechange = function () {
if(this.readyState == 4) {
if(this.status = 200) {
var booklists = this.responseXML.getElementsByTagName("booklist")[0].getElementsByTagName("book");
for(var i=0; i<booklists.length; i++) {
var name = booklists[i].getElementsByTagName("name")[0].textContent;
var author = booklists[i].getElementsByTagName("author")[0].textContent;
var desc = booklists[i].getElementsByTagName("desc")[0].textContent;
var trObj = document.createElement("tr");
trObj.innerHTML = "<td>"+name+"</td><td>"+author+"</td><td>"+desc+"</td>";
document.getElementsByTagName("table")[0].appendChild(trObj);
}
}
}
};
};
</script>
</head>
<body>
<div>
<table>
<tr>
<th>书名</th>
<th>作者</th>
<th>描述</th>
</tr>
<!-- <tr>
<td>三国演义</td>
<td>罗贯中</td>
<td>一个杀伐纷争的年代</td>
</tr> -->
</table>
</div>
</body>
</html>
XML数据的格式主要是通过:getElementByTagName来获取的。
案例:获取学生信息
接口文档:
地址 | /server/getStudents.php |
---|---|
作用描述 | 获取学生信息 |
请求类型 | get 请求 |
参数 | 无 |
返回数据格式 | json 格式 |
返回数据说明 | 如下 |
[
{
"name":"张三",
"age":"18",
"sex":"男"
}
]
源代码:
<!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", "tt.php", true);
xhr.send(null);
xhr.onreadystatechange = function () {
if(this.readyState == 4) {
if(this.status = 200) {
var jsonObj = JSON.parse(this.responseText);
for(var i=0; i<jsonObj.length; i++) {
var name = jsonObj[i].name;
var age = jsonObj[i].age;
var sex = jsonObj[i].sex;
var trObj = document.createElement("tr");
trObj.innerHTML = "<td>"+name+"</td><td>"+age+"</td><td>"+sex+"</td>";
document.getElementsByTagName("table")[0].appendChild(trObj);
}
}
}
};
};
</script>
</head>
<body>
<div>
<table>
<tr>
<th>书名</th>
<th>作者</th>
<th>描述</th>
</tr>
<!-- <tr>
<td>张三</td>
<td>年龄</td>
<td>性别</td>
</tr> -->
</table>
</div>
</body>
</html>
只需要将获取的responseText转化为json格式的对象,使用
JSON.parse(this.responseText);
jQuery中的Ajax
$.ajax()
$.ajax()和上面的myAjax2()使用起开非常相似。同样是传入一个对象,有些参数不传递的话也有默认值。
userObj.blur(function(){
$.ajax({
url:"./server/checkUsername.php",
type:"get",
data:{uname:this.value},
success:functio(result){
if(result == "ok"){
userSpanObj.text("用户名可用");
}else if(result == "error"){
userSpanObj.text("用户名不可用");
}
}
})
})
.get()和 . g e t ( ) 和 .post
只需要传两个参数,第一个参数是url(带param的,里面有参数和值),第二个参数是回调函数
$.get(url+"?"+param,function(result){});
$.post(url,{参数:值},function(result){});
实例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>书籍列表</title>
<script>
// 获取所有元素
var userObj = $("input[name='username']");
var emailObj = $("input[name='email']");
var phoneObj = $("input[name='phone']");
var userSpanObj = $("#user-span");
var emailSpanObj = $("#email-span");
var phoneSpanObj = $("#phone-span");
//用户名文本框失去焦点事件
userObj.blur(function () {
$.get("./server/checkUsername.php?uname=" + $(this).val(), function (result) {
if (result == "ok") {
userSpanObj.text("用户名可用");
} else if (result == "error") {
userSpanObj.text("用户名不可用");
}
});
});
//邮箱文本框失去焦点事件
emailObj.blur(function () {
$.post("./server/checkEmail.php", {e: $(this).val()}, function (result) {
if (result == 0) {
emailSpanObj.text("邮箱可用");
} else if (result == 1) {
emailSpanObj.text("邮箱不可用");
}
});
});
//手机号文本框失去焦点事件
phoneObj.blur(function () {
$.post("./server/checkPhone.php", {phonenumber: $(this).val()}, function (result) {
result = JSON.parse(result);
if (result.status == 0) {
phoneSpanObj.text(result.message.tips + " " + result.message.phonefrom);
} else if (result.status == 1) {
phoneSpanObj.text(result.message);
}
});
});
</script>
</head>
<body>
<div id="dv">
<h1>用户注册</h1>
用户名:<input type="text" name="username"><span id="user-span"></span><br>
邮箱:<input type="text" name="email"><span id="email-span"></span><br>
手机:<input type="text" name="phone"><span id="phone-span"></span><br>
</div>
</body>
</html>
跨域
跨域这个概念来自一个叫“同源策略”的东西。同源策略是浏览器上为了安全考虑实施的非常重要的安全机制。
Ajax默认智能获取带同源的数据,对于非同源的数据,Ajax是获取不到的。
什么是同源?
协议,域名,端口全部相同。
比如一个界面地址为:http://www.example.com/dir/page.html ,在这个地址中取访问下面服务器的数据,会出现什么情况?
URL | 结果 | 原因 |
---|---|---|
https://www.example.com/dir/other.html | 不同源 | 协议不同,https 和 http |
http://en.example.com/dir/other.html | 不同源 | 域名不同 |
http://www.example.com:81/dir/other.html | 不同源 | 端口不同 |
http://www.example.com/dir/page2.html | 同源 | 协议,域名,端口都相同 |
http://www.example.com/dir2/page.html | 同源 | 协议,域名,端口都相同 |
如果使用Ajax获取非同源地址的数据,就要使用跨域。无论是Ajax还是跨域,都是为了访问服务器的数据(比如获取天气信息,航班信息等)
跨域的实现
引入外部js文件
我们可以通过script标签引入一个外部文件,这个外部文件是不涉及到同源策略的影响的。
<script src="http://www.example.com/dir/xxx.js"></script>
引入PHP文件
script引入的应该是js文件,如果我们要引入php文件的话,就要在php代码中,返回js格式的代码。
<?php
echo "var str = 'hello'";
echo "func(123)";
?>
在我们的html文件中:
<script>
function func(data){ // 就为了获取参数
console.log(data);
}
</script>
<script src="http://www.example.com/dir/xxx.php"></script>
在进一步,如果我们在PHP地址中传入了参数
<?php
$city = $_GET["city"];
if($city == "beijng"){
echo "func('获取到北京天气')"
}else{
echo "func('未获取到天气信息')"
}
?>
html文件
<script>
function func(data){ // 就为了获取参数
console.log(data);
}
</script>
<script src="http://www.example.com/dir/xxx.php?city=beijing"></script>
动态创建script标签
如果只是手动的在php问价后面传入参数,就太固定了,我们可以根据用户的输入来获取不同城市天气信息。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>天气查询</h1><br>
<input type="text" placeholder="请输入城市" id="txt"><br>
<input type="button" value="获取天气" id="btn">
<script>
function func(data) {
console.log(data);
}
document.getElementById("btn").onclick = function () {
var city = document.getElementById("txt").value;
var script = document.createElement("script");
script.src = "http://hr.pcebg.efoxconn.com/checkUsername.php?city=" + city;
document.getElementsByTagName("head")[0].appendChild(script);
};
</script>
</body>
</html>
动态指定回调函数名称
script.src = "http://hr.pcebg.efoxconn.com/checkUsername.php?city=" + city + "&callback=foo";
外部php代码:
<?php
$city = $_GET["city"];
$callback = $_GET["callback"];
if($city == "beijing") {
echo $callback . "('获取到北京天气')";
} else {
echo $callback . "('为获取到天气信息')";
}
?>
之后,再看我们在 script 里面写的 foo 函数的定义,会不会觉得很突兀?我们把它改成 window 的方法就可以了。
window["foo"] = function(data) { console.log(data); };
然后把它放到按钮的点击事件中,这样就和按钮的点击事件融为一体了。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>天气查询</h1><br>
<input type="text" placeholder="请输入城市" id="txt"><br>
<input type="button" value="获取天气" id="btn">
<script>
document.getElementById("btn").onclick = function () {
window["foo"] = function(data) { console.log(data); };
var city = document.getElementById("txt").value;
var script = document.createElement("script");
script.src = "http://hr.pcebg.efoxconn.com/checkUsername.php?city=" + city + "&callback=foo";
document.getElementsByTagName("head")[0].appendChild(script);
};
</script>
</body>
</html>
在修改回调函数的名称时,只需修改两个部分就可以了(window[“foo”] 和 “&callback=foo”;),php 的代码不需要修改。
淘宝提示词
淘宝提示词接口
地址 | https://suggest.taobao.com/sug |
---|---|
作用描述 | 获取淘宝提示词接口 |
请求类型 | get 请求 |
参数 | q:关键词; callback:回调函数名称 |
返回数据格式 | jsonp格式 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="dv">
<h1>淘宝提示词</h1>
<input type="text" placeholder="请输入关键词" id="txt">
<input type="button" value="查询" id="btn">
<ul id="uu"></ul>
</div>
<script>
document.getElementById('btn').onclick = function(){
var script = document.createElement("script");
var txt = document.getElementById('txt').value;
script.src = "https://suggest.taobao.com/sug?q="+txt+"&callback=sug";
window["sug"] = function(data){
var str = "";
if(data.result.length !== 0){
for(var i=0; i<data.result.length; i++){
str += "<li>" + data.result[i] + "</li>";
}
document.getElementById('uu').innerHTML = str;
}else{
str = "<li>未找到关键词</li>";
document.getElementById('uu').innerHTML = str;
}
}
document.querySelector("head").appendChild(script);
}
</script>
</body>
</html>
案例:百度提示词
百度提示词接口
地址 | http://suggestion.baidu.com/su |
---|---|
作用描述 | 获取百度提示词接口 |
请求类型 | get 请求 |
参数 | web:关键词; cb:回调函数名称 |
返回数据格式 | jsonp格式 |
我们将实现的代码封装成一个js文件
function myAjaxCross(obj){
var defaults = {
url:"#", //地址
data:{}, //业务逻辑参数
success:function(data){}, //参数传递回来的处理函数
jsonp:"callback", //获取方法名的key值,是一个回调函数,由后端接口文档指定
jsonpCallback:"sug" // 获取方法名的value值,也就是方法名字
}
//由obj传入的对象覆盖defaults
for(var key in obj){
defaults[key] = obj[key];
}
var script = document.createElement('script');
var params = "";
for(var attr in defaults.data){
params += attr + "=" + defaults.data[attr] + "&";
}
if(params&&(params!=="")){
params = params.substring(0,params.length-1);
}
script.src = defaults.url + "?" +params + "&" + defaults.jsonp + "=" +defaults.jsonpCallback;
console.log(script.src);
window[defaults.jsonpCallback] = function(data){
defaults.success(data);
}
document.querySelector("head").appendChild(script);
}
百度提示词使用这个封装好的js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="dv">
<h1>百度提示词</h1>
<input type="text" placeholder="请输入关键词" id="txt">
<input type="button" value="查询" id="btn">
<ul id="uu"></ul>
</div>
<script type="text/javascript" src="my-sug.js"></script>>
<script>
document.getElementById('btn').onclick = function(){
myAjaxCross({
url:"http://suggestion.baidu.com/su",
data:{wd:document.getElementById('txt').value},
success:function(data){
console.log(data);
var str = "";
if(data.s.length !== 0){
for(var i=0; i<data.s.length;i++){
str += "<li>"+data.s[i]+"</li>";
}
document.getElementById("uu").innerHTML = str;
}else{
str="<li>未找到关键词</li>";
document.getElementById("uu").innerHTML = str;
}
},
jsonp:"cb",
jsonpCallback:"sug"
})
}
</script>
</body>
</html>