1. 工作流程
- 产品经理提出需求-UI设计师完成设计稿psd-前端工程师切页面并且加各种动效,和后台人员进行数据交互;
- 产品经理提出需求-后台人员制作接口
-
前端与后台之间的交互详解
2. ajax请求
- 前端往后台的请求方式:(8种)
- GET:请求数据;
- POST:发送数据;隐秘;
- DELETE:删除数据;
- PUT:上传数据;
- 同步和异步:
- 同步:每次只能完成一次任务,必须等这个任务完成之后,才能开始下个任务;
- 异步:当前的任务没完成,不用等待,继续开始下个任务,也就是,可以多个任务并行;
- 回调函数;
- 事件;
- 定时器;
- ajax属于异步;
- 建立ajax请求实例
- 步骤:
- 1)创建一个xml对象;代码:
var xml=new XMLHttpRequest()
- 打开地址:三个参数,请求方式method:GET;请求地址,是否异步;
- 响应请求,添加事件
xml.onreadystatechange=function(){}
;判断条件:a.是否准备好:readyState等于4;;b.是否响应成功:status:状态码 2xx;
- 响应请求,添加事件
- 4)发送请求:
xml.send()
;
- 1)创建一个xml对象;代码:
- 代码:
<body> <script src="utils.js"></script> <script> //1.创建一个xml对象 var xml=new XMLHttpRequest(); //2.打开地址:三个参数,请求方式method:GET;请求地址,是否异步; xml.open("GET","data.txt",true);//默认情况下是true,异步;false指的是不异步,必须先获取地址,才能进行下面的步骤; //3.响应请求 xml.onreadystatechange=function () { //准备好:readyState:4; 响应成功:status:状态码 2xx if(xml.readyState==4 && /^2\d{2}/.test(xml.status)){ //解析后台返回的数据,后台返回的数据为字符串; //利用jsonParse来将字符串转化为数组对象; var data=utils.jsonParse(xml.responseText); console.log(data); } }; //4.发送请求 xml.send(null);//实际上是在第三步执行,先于响应请求执行,因响应请求为异步执行 </script> </body>
- 同步异步问题:
- 若在第二步中
xml.open("GET","data.txt",false)
,后面设置false,意思是不异步,即同步;这种情况下浏览器会报警告。其中,第四步中发送请求xml.send(null)
,必须放在响应请求的后面,才能得到data,放在响应请求的前面,不会得到data; - 若在第二步中
xml.open("GET","data.txt",true)
,后面设置为true,或者不写,即意思是异步;这种情况下,第四步发送请求的位置,在第三步响应请求的前面还是后面都没有影响,都会打印出data; 而且不会报警告;
- 若在第二步中
- 建立ajax请求的注意点:
- 在创建的txt文件中的数据格式,必须是一个JSON的格式文件,并且不能加双引号,其本身默认就是一个字符串;
- ajax运行需要运行环境,在webstorm中运行,它会自动提供一个环境,运行的时候会在地址栏中地址前面会显示有
localhost
,指本地运行;如果没有运行环境,会报错,不能拿到ajax;
3. http响应状态码
- 2xx 成功;
- 3xx 重定向;
- 4xx 请求错误
- 400 请求的参数错误
- 404 文件没找到
- 5xx 服务器错误;
4. 表格中元素的获取
<body>
<table id="tab" cellspacing="0" cellpadding="0">
<caption>武林排行榜</caption>
<thead>
<tr>
<th>name</th>
<th>age</th>
<th>level</th>
<th>sex</th>
</tr>
</thead>
<tbody>
<tr class="bg0">
<td>郭靖</td>
<td>18</td>
<td>98</td>
<td>0</td>
</tr>
<tr class="bg1">
<td>美女</td>
<td>18</td>
<td>198</td>
<td>10</td>
</tr>
</tbody>
</body>
- 知识点:
- 表格中只有一个表头thead标签;可以有多个表体tbody标签
- 获取thead标签元素的代码:
var otHead=oTab.tHead
,此时otHead是一个thead元素; - 获取tbody标签元素集合的代码:
var atBody=oTab.tBodies
,此时atBody是所有tbody元素组成的集合;
- 获取thead标签元素的代码:
- 表头和每个表体中都可以有多行,每一行中可以有多列;
- 获取表头中第一行的所有列标签
- 代码:
var aCells=otHead.rows[0].cells;
,此时获取的是表头中第一行所以列标签元素所组成集合;
- 代码:
- 获取所有表体的第一个表体中的所有行元素标签
- 代码:
var aRows=atBody[0].rows;
- 代码:
- 表格中只有一个表头thead标签;可以有多个表体tbody标签
5. 表格排序实例题
- 实例需求及思路:
- 需求:获取后台数据,按顺序插入到表格中,添加各行换色,对表头中的每一列添加点击事件,事件目的排序
- 思路:
- 获取后台数据(4步)
- a.新建一个ajax对象
- b.添加地址;
- c.发送地址;
- d.添加准备事件,获取后台响应数据,获取JSON格式对象data;
- 获取表格元素
- 表头中的每一列aCells;--为了添加点击事件;
- 表体中第一个的所有行aRows;--为了排序;
- 将data对象中的数据插入到DOM页面
- 字符串拼接、innerHTML插入页面;
- 新建元素、DOM动态插入、联合文档碎片进行优化;
- 添加隔行换色函数
- 通过添加className来设置,可以利用%取余;
- 表格排序
- 思路:先对其中一列进行排序然后再给多列添加
- 此给其中一列添加点击事件,事件内容为表格排序;
- a.先对age列进行排序,排序就要用到数组类原型上的sort的公有属性方法,所以必须要把aRows类数组转化数组,才能享用这个方法;
- b.转化完后,使用sort()方法排序,里面的参数a,b获取的是每一行元素节点,但是比较是aCeils[1]中的内容,所以需要对a,b进行重新赋值;赋值里面的数字字符串;然后利用a-b隐式类型转换来升序排列;
- 知识点:在sort()中升序降序排列,可以通过-1来实现;
- c.以上两步已经获得了一个排好序的新数组,里面每一项都是行元素节点,然后需要重新插入到tbody中,所以需要遍历新数组,用appendChild()方法,插入到页面,但是会有弊端,会频繁对DOM页面进行操作,性能不好,所以可以新建一个文档碎片,来解决这个问题,文档碎片相当于一个元素节点,把数组中的每一项先插入到文档碎片中,然后把文档碎片再作为一个节点插入到tbody元素节点中,然后释放frg空间,进行性能优化;
- d.插入页面中,appendChild()此时的功能相当于剪切,实质就是DOM映射;
- 以上步骤是对其中一列(age列)进行的表格排序,现在想要对其他的列进行排序,所以要将函数进行改造,把私有的参数,换成公有的参数,然后进行重写构造;此例中的公有参数是每列的索引值,所以在sort()函数中要添加形参n,传入实参i,在点击事件中怎么保存i,可以利用自定义属性,或者是闭包;
- 给所有列添加点击事件,就需要遍历aCells类数组,但是需要添加条件,排除我不想添加点击事件的那列,也就是sex列,它无需排序,所以就在添加点击事件之前,进行if判断;筛选;此处的条件是
if(aCells[i].className=="cursor")
,即只给添加className为cursor的元素,添加点击事件; - 添加点击事件中,存在不同的排列方法,在name列中,需要通过汉字拼音排序,所以需要在排序方法中,再次添加if条件判断,判断特殊情况下的新排序规则;此处的条件是
if(isNaN(a) || isNaN(b))
,即判断a,b是否为汉字,如果为汉字那就利用localeCompare()方法来进行拼音顺序排序; - 当排完序之后,还要重新添加隔行换色,再次调用隔行换色函数即可;
- 获取后台数据(4步)
- 注意点:
- 每一步都要新建一个独立的函数,可以重复调用函数;
- 获取后台数据时,准备事件为异步运行,所以后面的插入页面的函数,要在事件中执行;其中data后台数据设置为全局变量,不能作为准备事件的私有变量,这样会导致bind函数对应堆地址的开辟空间中找不到data;所以必须设置为全局变量;
- 调用隔行换色函数,也必须在bind函数中调用,也是因为异步与同步关系;
- 排完序之后,需要重新设置各行换色,再次调用隔行换色函数即可;
- 问题:用户体验问题,当点击其中一列之后,会正序排列,然后去点击其他列,再回到当前列点击的时候,点击会发生倒序排列;所以需要解决问题,就是当点击当前列的时候,即i==n时,让当前列中的aCells[i].fig*=-1,其他列的aCells[i].fig变回初始值-1;如代码
aCells[i].fig=i==n?aCells[i].fig*-1:-1;
,强调一点,一定是给aCells[i].fig赋值,而不是aCells[n].fig;
- 代码:
<head>
<meta charset="UTF-8">
<title>表格排行榜4</title>
<style>
*{
margin:0;
padding: 0;
}
table{
width: 500px;
text-align: center;
margin: 100px auto;
border-radius: 10px;
padding: 10px;
box-shadow: 0 0 10px darkgreen;
}
table caption{
font-size: 30px;
font-weight: bold;
margin-bottom: 10px;
}
table thead{
height: 40px;
line-height: 40px;
background-color: darkgreen;
color: #ffffff;
}
table thead tr{
-webkit-user-select: none;
}
table thead tr th.cursor{
cursor:pointer;
}
table tbody tr{
height: 30px;
line-height: 30px;
}
table tbody tr.bg0{
background-color: lightsalmon;
}
table tbody tr.bg1{
background-color: lightskyblue;
}
</style>
</head>
<body>
<table id="tab" cellspacing="0" cellpadding="0">
<caption>武林排行榜</caption>
<thead>
<tr>
<th class="cursor">name</th>
<th class="cursor">age</th>
<th class="cursor">level</th>
<th>sex</th>
</tr>
</thead>
<tbody>
<!-- <tr class="bg0">
<td>郭靖</td>
<td>18</td>
<td>98</td>
<td>0</td>
</tr>
<tr class="bg1">
<td>美女</td>
<td>18</td>
<td>198</td>
<td>10</td>
</tr>-->
</tbody>
</table>
<script src="utils.js"></script>
<script>
//获取元素
var oTab=document.getElementById("tab");
var otHead=oTab.tHead;//thead元素
var atBody=oTab.tBodies;
var otBody=atBody[0];//第一个tbody元素
var aCells=otHead.rows[0].cells;
var aRows=otBody.rows;
//1.获取后台的数据
var data=null;
getData();
function getData() {
var xml=new XMLHttpRequest();
xml.open("GET","data2.txt",true);
xml.send(null);
xml.onreadystatechange=function () {
if(xml.readyState==4 && /^2\d{2}/.test(xml.status)){
data=utils.jsonParse(xml.responseText);
bind();
}
}
}
//2.插入页面
//1)字符串拼接插入
/*function bind() {
var str="";
for(var i=0; i<data.length; i++){
var cur=data[i];
cur.sex= cur.sex==0?"男":"女";
str+=" <tr><td>"+cur.name+"</td><td>"+cur.age+"</td><td>"+cur.level+"</td><td>"+cur.sex+"</td></tr>";
}
otBody.innerHTML=str;
}*/
//2)文档碎片,DOM动态插入,DOM映射
var frg=document.createDocumentFragment();
function bind() {
for(var i=0; i<data.length; i++){
var cur=data[i];
var otr=document.createElement("tr");
for(var attr in cur){
if(attr=="sex"){
cur[attr]=cur[attr]==0?"男":"女";
}
var otd=document.createElement("td");
otd.innerHTML=cur[attr];
otr.appendChild(otd);
}
frg.appendChild(otr);
}
otBody.appendChild(frg);
frg=null;
changeColor();
}
//3.隔行换色
function changeColor() {
for(var i=0; i<aRows.length; i++){
aRows[i].className="bg"+i%2;
}
}
//4.表格排序
function sort(n) {//n为传进来的索引值
//点击谁让谁*=-1,其他的所有都变为初始值-1;
for(var i=0; i<aCells.length; i++){
if(i==n){//点击谁,i的值就是n
aCells[i].fig*=-1;
}else{
aCells[i].fig=-1;
}
//三目写法:aCells[i].fig=i==n?aCells[i].fig*-1:-1;
}
var ary=utils.makeArray(aRows);
ary.sort(function (a, b) {
a=a.cells[n].innerHTML;
b=b.cells[n].innerHTML;
if(isNaN(a) || isNaN(b)){//判断a为汉字时,进行汉字拼音排序;
return a.localeCompare(b)*aCells[n].fig;//return返回值,并阻断程序执行;
}
return (a-b)*aCells[n].fig;
});//此时的ary为排好序的数组,里面是每一行的tr元素节点,想要插入到DOM操作中,所以要一项一项的插,要遍历;
var frg=document.createDocumentFragment();
for(var i=0; i<ary.length; i++){
frg.appendChild(ary[i]);
}
otBody.appendChild(frg);
frg=null;
changeColor();
}
//思路,先进行一列去排序,然后把通过其他列,去把公共的东西提成形参,然后传入实参,此时的实参就是索引值;
//此时的变量就是每一列的索引值;所以把索引值提成形参,然后实参传入;
/*aCells[1].fig=-1;
aCells[1].onclick=function () {
sort(1);
}*/
//所有的列添加事件
for(var i=0; i<aCells.length; i++){
if(aCells[i].className=="cursor"){//目的:就是排除掉我不想添加事件的列,所以需要添加条件
aCells[i].fig=-1;
aCells[i].index=i;//此时不能添加全局属性,要给各自添加私有的自定义属性;
aCells[i].onclick=function () {
//此时要往sort()函数中传索引值,所以必须用到自定义属性;
//此时的this代表当前元素,所以this.index就能获取到每个元素自己身上的自定义属性,也就是对应的索引值;
sort(this.index);
}
}
}
</script>
</body>
- data2.txt文件中内容
[{"name":"郭靖","age":18,"level":98,"sex":0},{"name":"黄蓉","age":16,"level":28,"sex":1},{"name":"洪七公","age":69,"level":100,"sex":0},{"name":"郭彬","age":26,"level":88,"sex":0},{"name":"梅超风","age":30,"level":98,"sex":1},{"name":"天空","age":15,"level":38,"sex":0}]