黑马ajax学习笔记02--art-template模板,自动提示,防抖,三级联动,fromData传参及传文件,同源,jsonp,天气预报,CROS,服务器桥接,withCredential跨域登录

1、模板引擎概述

作用:使用模板引擎提供的模板语法,可以将数据和HTML拼接起来
实际上是实现在客户端做数据拼接
art-template模板引擎
官网:http://aui.github.io/art-template/zh-cn/

2、art-template模板引擎使用步骤
  • 1、下载art-template模板引擎库文件并在html页面中引入库文件
  <script src="./js/template-web.js"></script>
  • 2、准备art-template模板
    模板实际是一个代码片段
    注意这个奇怪的使用方法,使用了‘text/html’的type,浏览器就会将相应所处的script标签内的内容当作html代码来解析了
 <script id="tp1" type="text/html">
  <div class="box"></div>
</script>
  • 3、告诉模板引擎将哪一个模板和哪个数据进行拼接
var html=template('tp1',{username:'zhangsan',age:'20'})
  • 4、将拼接好的html字符串添加到页面中
    获取html中的容器,并将拼接好的html字符串放入容器内的innerHtml中即可
document.getElementById('container').innerHTML=html
  • 5、通过模板语法(mustache语法)告诉模板引擎,数据和html字符串要如何拼接
<script id="tp1" type="text/html">
  <div class="box">{{username}}</div>
</script>

案例代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--1、将模板引擎的库文件引入当前页面-->
  <script src="./js/template-web.js"></script>
  <title>Title</title>
</head>
<body>
here is my server
<div id="container"></div>
<!--2、准备art-template模板,实际就是代码段,没有单独的文件-->
<script id="tpl" type="text/html">
  <div class="box">{{username}}</div>
  <div class="box">{{age}}</div>
</script>
<script type="text/javascript">
  //3、告诉模板引擎将哪个数据和哪个模板进行拼接
  //1)模板id,2)数据 对象类型
  //方法的返回值就是拼接好的字符串
  var html=template('tpl',{username:'zhangsan',age:'20'})
  console.log(html)
  document.getElementById('container').innerHTML=html
</script>
</body>
</html>
3、验证邮箱地址唯一性
  • 1、获取文本框并未其添加离开焦点事件
  • 2、离开焦点时,检测用户输入的邮箱地址是否符合规则(使用正则)
  • 3、如果不符合规则,阻止程序向下执行,并给出提示信息
  • 4、想服务器端发送请求,检测邮箱地址是否被被人注册
  • 5、根据服务器端返回值决定客户端显示何种提示信息

案例代码
需要做三个准备工作

  • 1、提前封装好网络请求函数,笔记01里里面已经封装
  • 2、使用正则表达式验证邮箱的合规性
  • 3、在node里的app.js里面创建路由,并验证邮件地址是否唯一

app.js

//引入express框架
const express=require('express')

//引入路径处理模块
 const path=require('path')
//使用post方式传参必须的模块
const bodyParser= require('body-parser')
//引入文件读取模块
const fs=require('fs')
//创建web服务器
const app=express();

//静态资源访问服务器功能
app.use(express.static(path.join(__dirname,'public')))
//解析post请求头,调用json的解析方法
app.use(bodyParser.json())

//创建路由
app.get('/verifyEmailAdress',(req,res)=>{
  if (req.query.email=='zhangsan@126.com'){
    res.send('email is ok')
  }else{
    res.send('email is unlaw')
  }

})
//监听端口
app.listen(8848);

//控制台提示输出
console.log('服务器启动成功')

ajax.js(提前封装好的网络请求函数)

//封装一个ajax函数
function ajax(options){
  //声明一个默认参数对象,存储默认参数
  let defults={
    type: 'get',
    url:'',
    data:{},
    header:{
      'Content-Type':'application/x-www-form-urlencoded'
    },
    success:()=>{},
    error:()=>{}
  }

  //使用defaults覆盖options对象。用Object.assign()进行覆盖
  //两个参数,用第二个参数覆盖第一个参数,使用options对象中的属性覆盖defaults对象中的属性
  Object.assign(defults,options);

  //创建ajax对象
  let xhr=new XMLHttpRequest()
  //在get传参方式下,对json数据对象转换成字符串
  var params='';
  //将对象转换成字符串格式
  for (var attr in defults.data){
    params += attr+'='+defults.data[attr]+'&'
  }
  //截取多串的&符,从第一个到倒数第二个
  params=params.substr(0,params.length-1);
  //对请求方式进行判断,如果为get则,将params放入open方法的url字符串里,如果是post,则将params放入send方法中
  if (defults.type=='get'){
    defults.url = defults.url+'?'+params
  }
  //配置ajax对象
  xhr.open(defults.type,defults.url)

  if (defults.type=='post'){
    let contentType = defults.header['Content-Type'];
    //如果为post还要调用setRequestHeader方法,设置请求参数格式的类型
    xhr.setRequestHeader('Content-Type',contentType);//由于有横杠,所以对对象的访问不使用点句法,而使用[]+引号
    //判断传入的文件头是否为json对象
    if (contentType === 'applictaion/json'){
      xhr.send(JSON.stringify(defults.data));
    }else{
      //如果不是json格式,则send普通参数
      xhr.send(params);
    }
  }else{
    //发送请求
    xhr.send();
  }

  //处理响应信息
  xhr.onload=()=>{
    //xhr.getResponseHeader()获取响应头中的数据
    let contentType= xhr.getResponseHeader('Content-Type')
    //暂存服务器响应会的数据内容
    let responseText=xhr.responseText;
    //如果响应类型中包含'application/json'则说明服务器返回的是json数据
    if (contentType.includes('application/json')){
      responseText=JSON.parse(responseText)
    }
    //当http状态码等于200的时候
    if (xhr.status==200){
      //请求成功,调用处理成功情况的函数
      options.success(responseText,xhr);
    }else{
      //请求失败,调用处理失败情况的函数
      //把服务器返回的信息传给error函数
      options.error(responseText,xhr)
    }
  }

}

html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--1、将之前封装好的网络请求js导入-->
  <script src="./js/ajax.js"></script>
  <style type="text/css">
    .bg-danger{background-color:lemonchiffon; color: red}
    .bg-success{background-color:greenyellow; color: black}
  </style>
  <title>Title</title>
</head>
<body>
here is my server
<div class="container">
  <div class="form-group">
    <label>邮箱地址</label>
    <input id="email" type="email" class="form-control" placeholder="请输入邮箱地址"/>
  </div>
  <!--错误的话添加bg-danger类名,正确添加bg-success类名-->
  <p id="info"></p>
</div>
<script type="text/javascript">
let email=document.getElementById("email")
let info=document.getElementById("info")

  email.onblur=function (){
  let email=this.value;
  //验证邮箱地址的正则表达式
  let reg=/^[A-Za-z\d]+([-_.][A-Za-z\d]+)*@([A-Za-z\d]+[-.])+[A-Za-z\d]{2,4}$/
  //验证用户输入的email是否正确
  if(!reg.test(email)){
    //阻止程序向下执行
    info.innerText='您输入的邮箱地址有误'
    info.className='bg-danger';
    return;
  }

  info.className='bg-success';

  //向服务器端发送请求
    ajax({
      type:'get',
      data:{
        email:email
      },
      url:'http://localhost:8848/verifyEmailAdress',
      success:(result)=>{
        console.log(result)
        info.innerHTML=result;
      },
      error:(result)=>{
        console.log(result)
        info.innerHTML=result;

      }

    });



  }
</script>
</body>
</html>
4、搜索框内容自动提示
  • 1、获取搜索框并为其添加用户事件
  • 2、获取用户输入的关键字
  • 3、向服务器端发送请求并携带关键字作为请求参数
  • 4、响应数据显示在搜索框底部
    案例:
    1、需要引入上例封装好的ajax网络请求函数
    2、需要引入auitemplate库
    3、node创建网络访问接口
    node的app.js
app.get('/serachAutoPrompt',(req,res)=>{
  let datas=['黑马程序员','黑马官网','黑马社区'];
  console.log(req.query.key)
  let thekey = req.query.key;
  if (thekey=='黑' || thekey=='黑马'){
    res.send(datas)
  }
})

html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--1、将之前封装好的网络请求js导入-->
  <script src="./js/ajax.js"></script>
  <script src="./js/template-web.js"></script>
  <style type="text/css">
    .bg-danger{background-color:lemonchiffon; color: red}
    .bg-success{background-color:greenyellow; color: black}
  </style>
  <title>Title</title>
</head>
<body>
here is my server
<div class="container">
  <div class="form-group">
    <label>邮箱地址</label>
    <input id="search" type="text" class="form-control" placeholder="请输入搜索关键字"/>
  </div>
  <ul class="list-group" id="list-box">

  </ul>
</div>
<!--创建模板-->
<script id="tpl" type="text/html">
  {{each resualt}}//模板语法
  <li class="list-group-item">{{$value}}</li>
  {{/each}}
</script>
<script type="text/javascript">
let serachInp=document.getElementById("search")
let listbox=document.getElementById("list-box")
//输入过程中触发
serachInp.oninput=function(){
  //获取用户输入的内容
  let key=this.value;
  //向服务器端发送请求,索取和用户输入关键字相关的内容
  ajax({
    type:'get',
    url:'http://localhost:8848/serachAutoPrompt',
    data:{
      key:key,
    },
    success:(result)=>{
      let html=template('tpl',{resualt:result})
      listbox.innerHTML=html;
      listbox.style.display='block';
    }

  })
}

</script>
</body>
</html>
5、使用定时器防抖(过于频繁访问服务器)
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--1、将之前封装好的网络请求js导入-->
  <script src="./js/ajax.js"></script>
  <script src="./js/template-web.js"></script>
  <style type="text/css">
    .bg-danger{background-color:lemonchiffon; color: red}
    .bg-success{background-color:greenyellow; color: black}
  </style>
  <title>Title</title>
</head>
<body>
here is my server
<div class="container">
  <div class="form-group">
    <label>邮箱地址</label>
    <input id="search" type="text" class="form-control" placeholder="请输入搜索关键字"/>
  </div>
  <ul class="list-group" id="list-box">

  </ul>
</div>
<!--创建模板-->
<script id="tpl" type="text/html">
  {{each resualt}}
  <li class="list-group-item">{{$value}}</li>
  {{/each}}
</script>
<script type="text/javascript">
let serachInp=document.getElementById("search")
let listbox=document.getElementById("list-box")
//存储定时器变量
let timer=null;

//输入过程中触发
serachInp.oninput=function(){
  //每次触发时先把上次的定时器清除掉
  clearTimeout(timer);
  //获取用户输入的内容
  let key=this.value;
  //如果用户没有在搜索框输入内容
  if(key.trim().length==0){
    //将提示下拉框隐藏
    listbox.style.display='none';
    //阻止程序向下执行
    return;
  }

  //使用定时器来防抖(过于频繁的访问服务器)
  timer=setTimeout(()=>{
    //向服务器端发送请求,索取和用户输入关键字相关的内容
    ajax({
      type:'get',
      url:'http://localhost:8848/serachAutoPrompt',
      data:{
        key:key,
      },
      success:(result)=>{
        console.log(result);
        let html=template('tpl',{resualt:result})
        listbox.innerHTML=html;
        listbox.style.display='block';
      }

    })
  },800)

}

</script>
</body>
</html>
6、省市区三级联动
  • 1、通过接口获取省份信息
  • 2、使用JavaScript获取到省市区下拉框元素
  • 3、将服务器返回的省份信息显示在下拉框中
  • 4、为下拉框元素添加表单值改变事件(onchange)
  • 5、当用户选择省份时,更具省份id获取城市信息

本例一部分运算放在服务器端完成,实际上可以一次性在访问省份路由的情况下就返回给一个全局变量,然后三级联动的逻辑全部在客户端完成,就可以有效地降低服务器端的压力

案例代码:
node里app.js编写数据和路由

 //----城市数据----
var mycities=[
  {
    pid:'001',
    provinceName:'北京市',
    cities:[
      {
        id:'101',
        cityName:'北京',
        areas:['东城区', '西城区', '崇文区']
      }
    ]
  },
  {
    pid:'002',
    provinceName:'天津市',
    cities:[
      {
        id:'201',
        cityName:'天津',
        areas:['和平区', '河东区', '河西区']
      }
    ]
  },
  {
    pid:'003',
    provinceName:'河北省',
    cities:[
      {
        id:'301',
        cityName:'石家庄',
        areas:['长安区', '桥东区', '桥西区']
      },
      {
        id:'302',
        cityName:'唐山',
        areas:['路南区', '路北区', '古冶区', '开平区', '丰南区']
      },
    ]

  }
]
//----省市区三级联动--之省份路由----
app.get('/province',(req,res)=>{
  res.send(mycities)
})

//----省市区三级联动--之城市路由----
app.get('/cities',(req,res)=>{
  let pid=req.query.pid;
  for (var index in mycities){
    if (mycities[index].pid==pid){
      res.send(mycities[index].cities)
    }
  }
})
//----省市区三级联动--之区县路由----
app.get('/areas',(req,res)=>{
  let id=req.query.id;
  for(var index1 in mycities){
    for (var index2 in mycities[index1].cities){
      if (mycities[index1].cities[index2].id==id){
        res.send(mycities[index1].cities[index2].areas)
      }
    }

  }

})

html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--1、将之前封装好的网络请求js导入-->
  <script src="./js/ajax.js"></script>
  <script src="./js/template-web.js"></script>
  <style type="text/css">
    .form-inline{display: flex}
    .form-group{flex: 1;}
    .bg-success{background-color:greenyellow; color: black}
  </style>
  <title>Title</title>
</head>
<body>
here is my server
<div class="form-inline">
  <div class="form-group">
    <select class="from-control" id="province">
    </select>
  </div>
  <div class="form-group">
    <select class="from-control" id="city">
      <option>请选择城市</option>
    </select>
  </div>
  <div class="form-group">
    <select class="from-control" id="area">
      <option>请选择县市</option>
    </select>
  </div>
</div>
<!--创建省份模板-->
<script type="text/html" id="provinceTpl">
  <option>请选择省份</option>
  {{each resualtProvince}}
  <option value="{{$value.pid}}">{{$value.provinceName}}</option><!--$value表示循环过程的当前项-->
  {{/each}}
</script>
<!--创建城市模板-->
<script type="text/html" id="cityTpl">
  <option>请选择城市</option>
  {{each resualtCity}}
  <option value="{{$value.id}}">{{$value.cityName}}</option><!--$value表示循环过程的当前项-->
  {{/each}}
</script>
<!--创建区县模板-->
<script type="text/html" id="areaTpl">
  <option>请选择区县</option>
  {{each resualtArea}}
  <option>{{$value}}</option><!--$value表示循环过程的当前项-->
  {{/each}}
</script>
<script type="text/javascript">
  //获取省市区下拉框元素
  let province=document.getElementById('province');
  let city=document.getElementById('city');
  let area=document.getElementById('area');
//获取省份信息
  ajax({
    type:'get',
    url:'http://localhost:8848/province',
    success:(data)=>{
      let html=template('provinceTpl',{resualtProvince:data})
      //将拼接好的html字符串放入省份下拉框
      province.innerHTML=html;
      return;
    }
  })

  //为省份下拉框添加值改变事件
  province.onchange=function(){
    //获取省份id
    var pid=this.value;
    //清空线程下拉框的数据
    let html=template('areaTpl',{resualtArea:[]})
    area.innerHTML=html;
    //根据省份pid获取城市信息
    ajax({
      data: {
        pid:pid
      },
      url:'http://localhost:8848/cities',
      success:(cities)=>{
        let html=template('cityTpl',{resualtCity:cities})
        city.innerHTML=html;
      }
    })

  }

  //为城市下拉框添加值改变事件
  city.onchange=function(){
    //获取城市id
    var id=this.value;
    //根据城市id获取城市信息
    ajax({
      data: {
        id:id,
      },
      url:'http://localhost:8848/areas',
      success:(areas)=>{
        let html=template('areaTpl',{resualtArea:areas})
        area.innerHTML=html;
      }
    })
  }


</script>
</body>
</html>
7、formData对象的作用
  • 1、模拟html表单,相当于将html表单映射成表单对象,自动将表单对象中的数据拼接成请求参数的格式。
  • 2、异步上传二进制文件

步骤

  • 1、准备html表单
<form id="form">
  <input type="text" name="username"/>
  <input type="text" name="password"/>
  <input type="button" />
</form>
  • 2、将html表单转换为fromData对象
    使用formData构造函数就可以将表单转换为formdata对象
let form=document.getElementById('form')
let fromData=new FormData(form)
  • 3、提交表单对象
   xhr.send(fromData)

ps:不能使用get请求,只能使用post请求

8、formData读写模块 formidable的安装
cpm install --save formidable
9、简单的formdata传参案例

1、node的app.js中引入formidable及相关路由
app.js

//引入express框架
const express=require('express')

//引入路径处理模块
 const path=require('path')
//使用post方式传参必须的模块
//const bodyParser= require('body-parser')

//引入formdata处理模块
const formidable=require('formidable')
//引入文件读取模块
const fs=require('fs')
//创建web服务器
const app=express();

//静态资源访问服务器功能
app.use(express.static(path.join(__dirname,'public')))
//解析post请求头,调用json的解析方法
//app.use(bodyParser.json())

//配置formdata路由
app.post('/fromData',(req,res)=>{
  //创建formidable表单解析对象
  const form=new formidable.IncomingForm();
  //解析客户端传递过来的FormData对象
  form.parse(req,(err,fields,files)=>{
    res.send(fields)

  })
})
//监听端口
app.listen(8848);

//控制台提示输出
console.log('服务器启动成功')

html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--1、将之前封装好的网络请求js导入-->
  <script src="./js/ajax.js"></script>
  <script src="./js/template-web.js"></script>
  <style type="text/css">
  </style>
  <title>Title</title>
</head>
<body>
here is my server
<div>
<form id="form">
  <input type="text" name="username"/><br/>
  <input type="password" name="password"/><br/>
  <input type="button" id="btn" value="提交">
</form>
</div>
<script>
  let form=document.getElementById('form')
  let btn=document.getElementById('btn')

  btn.onclick=function(){

    let fromData=new FormData(form)//内置构造函数创建一个formdata对象
    //创建ajax对象
    let xhr=new XMLHttpRequest();
    //对ajax对象进行配置
    xhr.open('post','http://localhost:8848/fromData')
    //发送ajax请求
    xhr.send(fromData)

    //监听ahr的onload时间
    xhr.onload=function(){
      //对http状态码进行判断
      if (xhr.status==200){
        console.log(xhr.responseText)
      }

    }
  }


</script>
</body>
</html>
10、FormData对象的实例方法
  • 1、获取表单对象中属性的值
fromData.get('key')//fromData是FormData的一个实例,key是表单控件中的属性名称(name属性的值)
  • 2、设置表单对象中属性的值
    如果set设置的表单属性值是原本存在的,则会覆盖手动提交的值,如果表单属性值是不存在的,则会额外多建立一个属性值进行提交
fromData.set(key,value)
  • 3、删除表单对象中属性的值
fromData.delete('key')
  • 4、向表单对象中追加值
fromData.append('key','value')
  • 5、set和append的区别
    set方法与append方法的区别是,在属性名已存在的情况下,set会覆盖已有键名的值,append会保留两个值。但服务器只能接收最后一个,如果需要同时接受两个或以上的同名属性,需要在服务器中进行设置(如何设置老师没讲,也不想研究)

案例

<div>
<form id="form">
  <input type="text" name="username"/><br/>
  <input type="password" name="password"/><br/>
  <input type="button" id="btn" value="提交">
</form>
</div>

<script>
  let form=document.getElementById('form')
  let btn=document.getElementById('btn')

  btn.onclick=function(){

    let fromData=new FormData(form)//内置构造函数创建一个formdata对象
    let uname=fromData.get('username')
    console.log(uname)
    fromData.set('password','666666')
    fromData.set('gender','male')
    fromData.delete('gender')
    fromData.append('key','value')//也可以从空的formData上进行append(添加)
	fromData.append('password','8888')
    fromData.append('password','9999')
  }
</script>  
11、FormData二进制文件上传
<input type="file" id="file"/>
//创建空表单formdata对象
    let fromData = new FormData(form)
    //将用户的二进制文件追加到表单对象中
    fromData.append('myfile', this.files[0])//从fiels数组中选择

案例代码
1、创建node的app.js中的路由逻辑,仍然需要使用formidable模块

//配置upload路由
app.post('/upload',(req,res)=>{
  //创建formidable表单解析对象
  const form=new formidable.IncomingForm();
  //设置上传文件的存储路径,需要使用path默认模块这里使用参数形式拼接文件路径
  form.uploadDir=path.join(__dirname,'public','uploads')
  //保留上传文件的后缀,使用fromidable对象的keepExtensions属性
  form.keepExtensions=true;
  //解析客户端传递过来的FormData对象
  form.parse(req,(err,fields,files)=>{
    res.send('file is upload successed')

  })
})

2、html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--1、将之前封装好的网络请求js导入-->
  <script src="./js/ajax.js"></script>
  <script src="./js/template-web.js"></script>
  <style type="text/css">
  </style>
  <title>Title</title>
</head>
<body>
here is my server
<div>
<form id="form">
  <input type="file" id="file"/>
  <input type="button" id="btn" value="提交">
</form>
</div>
<script>
  let form=document.getElementById('form')
  let file=document.getElementById('file')
  //let btn=document.getElementById('btn')

  //当用户选择文件时
  file.onchange=function() {
    //创建空表单formdata对象
    let fromData = new FormData()
    //将用户的二进制文件追加到表单对象中
    fromData.append('myfile', this.files[0])//从fiels数组中选择
    //创建ajax对象
    let xhr=new XMLHttpRequest();
    //对ajax对象进行配置
    xhr.open('post','http://localhost:8848/upload')
    //发送ajax请求
    xhr.send(fromData)

    //监听ahr的onload时间
    xhr.onload=function(){
      //对http状态码进行判断
      if (xhr.status==200){
        console.log(xhr.responseText)
      }

    }
  }


</script>
</body>
</html>
12、FormData文件上传进度展示

文件上传过程中持续触发onprogress事件,具体位置为xhr.upload.onprogress
核心代码

  file.onchange=function() {
//文件上传过程中持续触发onprogress事件
    xhr.upload.onprogress=function(event){
      //当前上传文件大小/文件总大小,再将结果转换为百分数
      //将结果赋值给进度条的宽度属性
      bar.style.width=(event.loaded/event.total)*100+'%';
    }
}

案例代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--1、将之前封装好的网络请求js导入-->
  <script src="./js/ajax.js"></script>
  <script src="./js/template-web.js"></script>
  <style type="text/css">
    .progress{width: 100%; height: 20px; border: 1px solid gray;}
    .progress_bar{height: 20px;  background-color: cornflowerblue}
  </style>
  <title>Title</title>
</head>
<body>
here is my server
<div>
<form id="form">
  <input type="file" id="file"/><br/>
  <div class="progress">
    <div class="progress_bar" style="width: 0;" id="bar">0%</div>
  </div>
</form>
</div>
<script>
  let file=document.getElementById('file')
  let bar=document.getElementById('bar');

  //当用户选择文件时
  file.onchange=function() {
    //创建空表单formdata对象
    let fromData = new FormData()
    //将用户的二进制文件追加到表单对象中
    fromData.append('myfile', this.files[0])//从fiels数组中选择
    //创建ajax对象
    let xhr=new XMLHttpRequest();
    //对ajax对象进行配置
    xhr.open('post','http://localhost:8848/upload')
    //文件上传过程中持续触发onprogress事件
    xhr.upload.onprogress=function(event){
      console.log(event)
      //当前上传文件大小/文件总大小,再将结果转换为百分数,大小有默认的属性(load,total)
      //将结果赋值给进度条的宽度属性
      let result=event.loaded/event.total*100+'%';
      bar.style.width=result;
      //将百分比显示在进度条中
      bar.innerText=result;
    }

    //发送ajax请求
    xhr.send(fromData)

    //监听ahr的onload时间
    xhr.onload=function(){
      //对http状态码进行判断
      if (xhr.status==200){
        console.log(xhr.responseText)
      }

    }
  }


</script>
</body>
</html>
13、FormData文件上传图片即时预览

在我们将图片上传到服务器端以后,服务器端通常都会将图片地址作为响应数据传递到客户端,客户端可以从响应数据获取图片地址,然后将图片再显示在页面中。

1、改造原有node的app.js的原有路由

//配置upload路由
app.post('/upload',(req,res)=>{
  //创建formidable表单解析对象
  const form=new formidable.IncomingForm();
  //设置上传文件的存储路径,需要使用path默认模块这里使用参数形式拼接文件路径
  form.uploadDir=path.join(__dirname,'public','uploads')
  //保留上传文件的后缀,使用fromidable对象的keepExtensions属性
  form.keepExtensions=true;
  //解析客户端传递过来的FormData对象
  form.parse(req,(err,fields,files)=>{
    //将客户端传递过来的文件地址响应到客户端
    //这里的attrName是从客户端的fromdata里append过来的
    res.send(
      {
        path:files.attrName.path.split('public')[1]
      })

  })
})

2、html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--1、将之前封装好的网络请求js导入-->
  <script src="./js/ajax.js"></script>
  <script src="./js/template-web.js"></script>
  <style type="text/css">
    .progress{width: 100%; height: 20px; border: 1px solid gray;}
    .progress_bar{height: 20px;  background-color: cornflowerblue}
  </style>
  <title>Title</title>
</head>
<body>
here is my server
<div>
<form id="form">
  <input type="file" id="file"/><br/>
  <div class="progress">
    <div class="progress_bar" style="width: 0;" id="bar">0%</div>
  </div>
  <div id="inputimg"></div>
</form>
</div>
<script>
  let file=document.getElementById('file')
  let bar=document.getElementById('bar');
  let inputimg=document.getElementById('inputimg');
  //当用户选择文件时
  file.onchange=function() {
    //创建空表单formdata对象
    let fromData = new FormData()
    //将用户的二进制文件追加到表单对象中
    fromData.append('attrName', this.files[0])//从fiels数组中选择
    //创建ajax对象
    let xhr=new XMLHttpRequest();
    //对ajax对象进行配置
    xhr.open('post','http://localhost:8848/upload')
    //文件上传过程中持续触发onprogress事件
    xhr.upload.onprogress=function(event){
      console.log(event)
      //当前上传文件大小/文件总大小,再将结果转换为百分数,大小有默认的属性(load,total)
      //将结果赋值给进度条的宽度属性
      let result=event.loaded/event.total*100+'%';
      bar.style.width=result;
      //将百分比显示在进度条中
      bar.innerText=result;
    }

    //发送ajax请求
    xhr.send(fromData)

    //监听ahr的onload时间
    xhr.onload=function(){
      //对http状态码进行判断
      if (xhr.status==200){
        let result=JSON.parse(xhr.responseText)
        //动态创建img表单
        let img=document.createElement('img');
        //给图片标签设置src属性
        img.src=result.path;
        console.log(img.src)

        //img加载时,才将img加载带盒子里
        img.onload=function(){
          inputimg.appendChild(img)
        }

      }

    }
  }


</script>
</body>
</html>
14、同源政策之ajax请求限制(跨域问题)

ajax只能想自己的服务器发送请求,不能同时向两个服务器发送请求。即A、B两个网站,A站的html不能同时向A、B网站发送请求,只能请求A网站(跨域问题)

1、什么是同源:
如果两个页面拥有相同的协议、域名和端口,那么这两个页面就属于同一个源,其中只要有一个不相同,就是不同源
在这里插入图片描述

2、同源政策的目的:
同源政策是为了保护用户信息的安全,防止恶意的网站窃取数据。如a客户端的cookie,b网站不能访问

此外,无法想飞同源地址发送ajax请求,如果请求,浏览器就会报错(报CROS错误)

15、使用JSONP解决同源限制问题

jsonp是json with padding的缩写,不属于ajax请求,但它可以模拟ajax请求,用于向非同源客户端发送请求

  • 1、将不同源的服务器端请求卸载script表情的src属性中
    因为script标签不受同源政策的约束,可以请求非同源地址
<script  src='www.example.com'></script>
  • 2、服务器端响应数据必须是一个函数的调用,真正要发送给客户端的数据需要作为函数调用的参数
 const data='fn({name:'zhangsan',age:'20'})'
  res.send(data)
  • 3、要在客户端全局作用域下定义函数fn
 function fun(data){ }
  • 4、在fn函数内部对服务器返回的数据进行处理
 function fn (data){ console.log(data)}

案例代码
服务器1(端口号8848)html代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--1、将之前封装好的网络请求js导入-->
  <script src="./js/ajax.js"></script>
  <script src="./js/template-web.js"></script>
  <style type="text/css">
    .progress{width: 100%; height: 20px; border: 1px solid gray;}
    .progress_bar{height: 20px;  background-color: cornflowerblue}
  </style>
  <title>Title</title>
</head>
<body>
here is my server
<div>
<form id="form">

</form>
</div>
<script>
  //这里是全局作用的处理函数,用来处理服务器返回的数据(函数调用及实参共同组成的字符串)
  function fn(data){
    console.log('客户端的函数被调用了')
    console.log(data)
  }
</script>
<!--将非同源服务器端的请求地址卸载script标签的src属性中-->
<script src="http://localhost:8888/test">

</script>
</body>
</html>

服务器2(端口号8888)app.js代码

//创建路由
app.get('/test', (req, res) => {
  //将函数调用写在字符串中,返回给1号客户端,由1号客户端来调用这个函数
  //函数放在字符串里的同时,可以给函数一个实参
  const resualt='fn({name:"zhangsan",age:"25"})'
  res.send(resualt)
})
//监听端口
app.listen(8888);
16、jsonp代码优化----客户端需要将函数名称传递到服务器端。

服务器1(端口号8848)html代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--1、将之前封装好的网络请求js导入-->
  <script src="./js/ajax.js"></script>
  <script src="./js/template-web.js"></script>
  <style type="text/css">
    .progress{width: 100%; height: 20px; border: 1px solid gray;}
    .progress_bar{height: 20px;  background-color: cornflowerblue}
  </style>
  <title>Title</title>
</head>
<body>
here is my server
<div>
<form id="form">

</form>
</div>
<script>
  //这里是全局作用的处理函数,用来处理服务器返回的数据(函数调用及实参共同组成的字符串)
  function fn(data){
    console.log('客户端的函数被调用了')
    console.log(data)
  }
</script>
<!--将非同源服务器端的请求地址卸载script标签的src属性中-->
<script src="http://localhost:8888/better?callback=fn">

</script>
</body>
</html>

服务器2(端口号8888)app.js代码

app.get('/better', (req, res) => {
  //接收客户端传递过来的函数名
  const fnName = req.query.callback;
  //将函数调用写在字符串中,返回给1号客户端,由1号客户端来调用这个函数
  //函数放在字符串里的同时,可以给函数一个实参
  //将函数名称对应的函数调用代码返回给客户端
  const resualt=fnName+'({name:"zhangsan",age:"25",address:"beijing"})'
  res.send(resualt)
})
//监听端口
app.listen(8888);
17、jsonp代码优化----将script请求的发送变成动态请求。

如动态添加一个按钮,来决定是否发送动态请求

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--1、将之前封装好的网络请求js导入-->
  <script src="./js/ajax.js"></script>
  <script src="./js/template-web.js"></script>
  <style type="text/css">
    .progress{width: 100%; height: 20px; border: 1px solid gray;}
    .progress_bar{height: 20px;  background-color: cornflowerblue}
  </style>
  <title>Title</title>
</head>
<body>
here is my server<br/>
<button id="btn">点我发送请求</button>
<script>
  //这里是全局作用的处理函数,用来处理服务器返回的数据(函数调用及实参共同组成的字符串)
  function fn(data){
    console.log('客户端的函数被调用了')
    console.log(data)
  }
</script>

<script>
  var btn=document.getElementById('btn');
  btn.onclick=function(){
    //创建script标签
    var script=document.createElement('script')
    //设置src属性,并将非同源服务器端的请求地址卸载script标签的src属性中
    script.src="http://localhost:8888/better?callback=fn";
    //将script标签添加到页面中
    document.body.appendChild(script);
    //监听script标签的onload时间,一旦加载后就可以将script标签从body中删除
    script.onload=function(){
      //将body标签的script标签删除掉
      document.body.removeChild(script)
    }
  }

</script>
</body>
</html>
18、jsonp代码优化----封装jsonp函数,方便请求发送
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--1、将之前封装好的网络请求js导入-->
  <script src="./js/ajax.js"></script>
  <script src="./js/template-web.js"></script>
  <style type="text/css">
    .progress{width: 100%; height: 20px; border: 1px solid gray;}
    .progress_bar{height: 20px;  background-color: cornflowerblue}
  </style>
  <title>Title</title>
</head>
<body>
here is my server<br/>
<button id="btn">点我发送请求</button>
<script>
  //这里是全局作用的处理函数,用来处理服务器返回的数据(函数调用及实参共同组成的字符串)
  function fn(data){
    console.log('客户端的函数被调用了')
    console.log(data)
  }
</script>

<script>
  var btn=document.getElementById('btn');
  btn.onclick=function(){
    jsonp({
      //请求地址
      url:"http://localhost:8888/better?callback=fn"
    })

  }
  //封装jsonp函数,方便日后调用
  function jsonp(options){
    //动态创建script标签
    var script=document.createElement('script')
    //设置src属性,并将非同源服务器端的请求地址卸载script标签的src属性中
    script.src=options.url;
    //将script标签添加到页面中
    document.body.appendChild(script);
    //监听script标签的onload时间,一旦加载后就可以将script标签从body中删除
    script.onload=function(){
      //将body标签的script标签删除掉
      document.body.removeChild(script)
    }
   }


</script>
</body>
</html>
19、jsonp代码优化----随机函数名及函数作用域提升

函数作用域提升:将函数挂载到window上,

window.fnName=options.success

随机名:使用随机函数拼接

let fnName='myjsonp'+Math.random().toString().replace('.','')

案例代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--1、将之前封装好的网络请求js导入-->
  <script src="./js/ajax.js"></script>
  <script src="./js/template-web.js"></script>
  <style type="text/css">
    .progress{width: 100%; height: 20px; border: 1px solid gray;}
    .progress_bar{height: 20px;  background-color: cornflowerblue}
  </style>
  <title>Title</title>
</head>
<body>
here is my server<br/>
<button id="btn">11111点我发送请求</button>
<button id="btn2">2222点我发送请求</button>
<script>

</script>

<script>
  var btn=document.getElementById('btn');
  btn.onclick=function(){
    jsonp({
      //请求地址
      url:"http://localhost:8888/better",
      success:function (data) {
        console.log('123')
        console.log(data)
      }
    })

  }
  //封装jsonp函数,方便日后调用
  function jsonp(options){
    //动态创建script标签
    let script=document.createElement('script')
    //拼接随机函数名
    let fnName='myjsonp'+Math.random().toString().replace('.','')


    //options.success已经不是一个全局函数了,需要把他变为全部函数
    //解决办法是将其挂载到window对象上
    window[fnName]=options.success
    //设置src属性,并将非同源服务器端的请求地址卸载script标签的src属性中
    script.src=options.url+'?callback='+fnName;
    //将script标签添加到页面中
    document.body.appendChild(script);
    //监听script标签的onload时间,一旦加载后就可以将script标签从body中删除
    script.onload=function(){
      //将body标签的script标签删除掉
      document.body.removeChild(script)
    }
   }


</script>
</body>
</html>
21、jsonp代码优化----将需要传递的多个参数整合进jsonp函数里

使用遍历+拼接实参的方式

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--1、将之前封装好的网络请求js导入-->
  <script src="./js/ajax.js"></script>
  <script src="./js/template-web.js"></script>
  <style type="text/css">
    .progress{width: 100%; height: 20px; border: 1px solid gray;}
    .progress_bar{height: 20px;  background-color: cornflowerblue}
  </style>
  <title>Title</title>
</head>
<body>
here is my server<br/>
<button id="btn">11111点我发送请求</button>
<button id="btn2">2222点我发送请求</button>
<script>

</script>

<script>
  var btn=document.getElementById('btn');
  btn.onclick=function(){
    jsonp({
      //请求地址
      url:"http://localhost:8888/better",
      data:{
        name:'lisi',
        age:30,
        address:'hebei'
      },
      success:function (data) {
        console.log('123')
        console.log(data)
      }
    })

  }
  //封装jsonp函数,方便日后调用
  function jsonp(options){
    //动态创建script标签
    let script=document.createElement('script')
    //拼接字符串的变量,处理从服务器过来的对象,将对象转换成字符串(?key1=value1 &key2=value2形式)
    var params='';
    for (var attr in options.data){
      params += '&'+attr+'='+options.data[attr];
    }

    //拼接随机函数名
    let fnName='myjsonp'+Math.random().toString().replace('.','')


    //options.success已经不是一个全局函数了,需要把他变为全部函数
    //解决办法是将其挂载到window对象上
    window[fnName]=options.success
    //设置src属性,并将非同源服务器端的请求地址卸载script标签的src属性中
    script.src=options.url+'?callback='+fnName+params;
    //将script标签添加到页面中
    document.body.appendChild(script);
    //监听script标签的onload时间,一旦加载后就可以将script标签从body中删除
    script.onload=function(){
      //将body标签的script标签删除掉
      document.body.removeChild(script)
    }
   }
22、jsonp代码优化----服务器端代码优化

服务器2app.js代码

app.get('/better', (req, res) => {
  
  //直接使用jsonp方法把客户端需要的数据返回回去
  res.jsonp({name:"zhangsan",age:"25",address:"beijing",university:'pku'})
})
//监听端口
app.listen(8888);
23、腾讯天气案例

请求地址:https://wis.qq.com/weather/common
请求方式:get 支持jsonp
参数名:
source:string类型 pc xw
weather_type:string类型,forecast_1h未来48小时,forecast_24h 未来7天
province:string类型 省份
city:string类型,城市
返回值:

{
    "data":{
      //48小时天气预报
      "forecast_1h":{
        '0':{
          "degree":"9",//温度
          "update_time":"20210220200000",//时间
          "weather":"阴",//天气名称
          "weather_code":"02",//天气码
          "weather_short":"阴",//天气简要名称
          "wind_direction":"微风",//风向
          "wind_power":"3"//风力级别
        }
      }
    },
    "message":"OK",
    "status":200
}

PS:这里需要提前封装好的jsop跨域访问js(上例)和网络请求ajax.js昨天的例子
在这里可以下载到:
ajax.js
jsonp.js
案例代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--1、将之前封装好的网络请求js导入-->
  <script src="./js/ajax.js"></script>
  <script src="./js/template-web.js"></script>
  <script src="./js/jsonp.js"></script>
  <style type="text/css">
    .wholebox{width:600px; border: 1px solid gray;}
    .table{width:100%;}
    .myth{ background-color: #ccc }
    #box{ border-collapse:collapse; text-align: center }
  </style>
  <title>Title</title>
</head>
<body>
here is my server<br/>
<div class="wholebox">
  <table class="table" align="center" id="box"  border="1">

  </table>
</div>
<!--表格模板-->
<script type="text/html" id="tpl">
  <tr class="myth">
    <th>时间</th><th>温度</th><th>天气</th><th>风向</th><th>风力</th>
  </tr>
  {{each info}}
    <tr>
      <td>{{dateFormat($value.update_time)}}</td>
      <td>{{$value.degree}}</td>
      <td>{{$value.weather}}</td>
      <td>{{$value.wind_direction}}</td>
      <td>{{$value.wind_power}}</td>
    </tr>
  {{/each}}
</script>

<script>
  //获取box控件
  let box=document.getElementById('box')
  //自定义日期格式化函数
  function dateFormat(date){
    let year=date.substr(0,4);
    let month=date.substr(4,2)
    let day=date.substr(6,2)
    let hour=date.substr(8,2)
    return year+'年'+month+'月'+day+'日'+hour+'时';
  }
  //向模板开放外部变量
  template.defaults.imports.dateFormat=dateFormat;//dateFormat是自己定义的函数

  //向服务器端获取天气信息
  jsonp({
    url:'https://wis.qq.com/weather/common',
    data:{
      source:'pc',
      weather_type:'forecast_1h',
      province:'北京市',
      city:'北京'
    },
    success:(data)=>{
      let html = template('tpl',{info:data.data.forecast_1h})
      box.innerHTML=html;
    }
  })


</script>
</body>
</html>

在这里插入图片描述

24、CROS跨域资源共享

CORS:全称为Cross-origin resource sharing,即跨域资源共享,它允许浏览器向跨域服务器发送ajax请求,克服了ajax只能同源使用的限制。
在这里插入图片描述
说白了就是在服务器端开始一个access-control-access-origin白名单,这个白名单在 ‘Access-Control-Allow-Origin’ header 头里

因此只需要编辑node里的路由拦截逻辑就可以了

app.use((req, res,next) => {
  //1、允许那些客户端访问我,都是设置在响应头里,第一个参数是响应名称,第二个参数响应名称对应的值
  //'*'星号代表所有的客户端都可以访问我
  res.header('Access-Control-Allow-Origin','*')
  //2、允许客户端使用哪些方法访问我,使用逗号分割方法
  res.header('Access-Control-Allow-Methods','get,post')
  res.send('成功实现跨域访问')

 })

案例代码
node的app.js设置路由拦截逻辑

//设置拦截所有请求,这样就不用再在每个路由里面单独编写跨域逻辑
app.use((req, res,next) => {//nex是下一个路由
  //1、允许那些客户端访问我,都是设置在响应头里,第一个参数是响应名称,第二个参数响应名称对应的值
  //'*'星号代表所有的客户端都可以访问我
  res.header('Access-Control-Allow-Origin','*')

  //2、允许客户端使用哪些方法访问我,使用逗号分割方法
  res.header('Access-Control-Allow-Methods','get,post')
  next();
  res.send('成功实现跨域访问')

 })
//监听端口
app.listen(8888);

html代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--1、将之前封装好的网络请求js导入-->
  <script src="./js/ajax.js"></script>
  <script src="./js/template-web.js"></script>
  <script src="./js/jsonp.js"></script>
  <style type="text/css">
  </style>
  <title>Title</title>
</head>
<body>
here is my server<br/>
<div >
  <button id="btn">点我发送请求</button>
</div>

<script>
  //获取按钮
let btn=document.getElementById('btn')
  //为按钮添加点击事件
btn.onclick=function(){
  ajax({
    type:'get',
    url:'http://localhost:8888/cross',
    success:function(data){
      console.log(data)
    }
  })
}
</script>
</body>
</html>
25、访问非同源数据(跨域问题)的另一种服务器端解决方案

同源政策是浏览器给与ajax技术的限制,服务器端是不存在同源政策的限制。

以下方法实际上就是用服务器做数据桥
在这里插入图片描述
需要使用request第三方模块(名字就叫request)
添加该模块

npm install request

案例代码

1号服务器(8848端口)html代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--1、将之前封装好的网络请求js导入-->
  <script src="./js/ajax.js"></script>
  <script src="./js/template-web.js"></script>
  <script src="./js/jsonp.js"></script>
  <style type="text/css">
  </style>
  <title>Title</title>
</head>
<body>
here is my server<br/>
<div >
  <button id="btn">点我发送请求</button>
</div>

<script>
  //获取按钮
let btn=document.getElementById('btn')
  //为按钮添加点击事件
btn.onclick=function(){
  ajax({
    type:'get',
    url:'http://localhost:8848/server',
    success:function(data){
      console.log(data)
    }
  })
}
</script>
</body>
</html>

1号服务器(8848端口)服务器端node的app.js代码

//引入向其他数据库请求数据的模块request
const request=require('request');

app.get('/server',(req,res)=>{
  //向2号服务器请求数据
  //request有两个参数,第一个参数是访问的第2号服务器的路由地址,第二个参数是处理反馈的回调函数
  //回调函数有三个参数,err是错误信息,response是服务器响应信息,body是2号服务器响应的信息体
  request('http://localhost:8888/cross',(err,response,body)=>{
    res.send(body)
  })

})
//监听端口
app.listen(8848);

2号服务器(8888端口)服务器端node的app.js代码
一定要在路由拦截那写next方法

//设置拦截所有请求,这样就不用再在每个路由里面单独编写跨域逻辑
app.use((req, res, next) => {
  //1、允许那些客户端访问我,都是设置在响应头里,第一个参数是响应名称,第二个参数响应名称对应的值
  //'*'星号代表所有的客户端都可以访问我
  res.header('Access-Control-Allow-Origin','*')
  //2、允许客户端使用哪些方法访问我,使用逗号分割方法
  res.header('Access-Control-Allow-Methods', 'get,post')
  //next不写的话,不会往下访问一个路由,非常重要
  next();
  //res.send('跨域成功')
})
 
app.get('/cross', (req, res) => {
  
  res.send('我是2号服务器的corss路由')
})
//监听端口
app.listen(8888);

26、cookie复习

cookie实际就是一个身份识别技术
在这里插入图片描述

27、withCredentials属性实现跨域登录

在使用ajax技术发送跨域请求时,默认情况下不会在请求中携带cookie信息‘’

withCredentials:指定在涉及到跨域请求时,是否携带cookie信息,默认值为false

需要在node服务器端设置:
Access-Control-Allow-Credentials:true允许客户端发送请求时携带cookie
客户端也需要做响应的修改

PS:由于这里使用到了express-session,需要提前引入express-session模块,安装模块使用:

npm install express-session -S

并引入这个模块

const session = require('express-session')

案例代码

- 1、第2台服务器node的app.js文件

注意跨域设置里没有使用*星号,而是使用了整个域名头部: res.header(‘Access-Control-Allow-Origin’,‘http://localhost:8848’)

ps:checklogin的服务器端代码没有找到,自己写不出来,唉

//设置拦截所有请求,这样就不用再在每个路由里面单独编写跨域逻辑
app.use((req, res, next) => {
  //1、允许那些客户端访问我,都是设置在响应头里,第一个参数是响应名称,第二个参数响应名称对应的值
  //'*'星号代表所有的客户端都可以访问我
  res.header('Access-Control-Allow-Origin','http://localhost:8848')
  //2、允许客户端使用哪些方法访问我,使用逗号分割方法
  res.header('Access-Control-Allow-Methods', 'get,post')
  //3、设置跨域登录响应头,允许客户端请求携带跨域信息
  res.header('Access-Control-Allow-Credentials',true)//设置前一个参数的值为true
  //next不写的话,不会往下访问一个路由,非常重要
  next();
  //res.send('跨域成功')
})
 
app.get('/cross', (req, res) => {
  
  res.send('我是2号服务器的corss路由')
})


app.post('/login', (req, res) => { 
  //创建表单解析对象
  let form = formidable.IncomingForm();
  //解析表单
  form.parse(req, (err, fields, file) => { 
    //接收客户端传递过来的用户名和密码
    const { username, password } = fields;
    //用户名密码比对
    if (username == 'zhangsan' && password == '123456') {
      //设置session
      session.isLogin = true;//要引入express-session,使用创建的session变量,而不是req.session
      res.send({ message: '登录成功' })
    } else { 
      res.send({ message: '登录失败,用户名或密码错误' })
    }
  })
})
app.get('/checklogin', (req, res) => {
  /*
  if (req.session.username == 'zhangsan' && req.session.password == '123456') {
    res.send({ message: '检测登录成功' })
  } else { 
    res.send({ message: '检测登录失败,用户名或密码错误' })
  }
  */
})
//监听端口
app.listen(8888);

- 2、第1台服务器html文件

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <!--1、将之前封装好的网络请求js导入-->
  <script src="./js/ajax.js"></script>
  <script src="./js/template-web.js"></script>
  <script src="./js/jsonp.js"></script>
  <style type="text/css">
  </style>
  <title>Title</title>
</head>
<body>
here is my server<br/>
<div >
  <form id="loginFrom">
    <div class="form-group">
      <label>用户名</label>
      <input type="text" name="username" class="from-control" placeholder="请输入用户名">
    </div>
    <div class="form-group">
      <label>密码</label>
      <input type="password" name="password" class="from-control" placeholder="请输入密码">
    </div>
    <input type="button" class="btn" value="登录" id="loginbtn"/>
    <input type="button" class="btn" value="检测用户登录状态" id="checklogin"/>
  </form>
</div>

<script>
  //获取按钮
let loginbtn=document.getElementById('loginbtn')
let checklogin=document.getElementById('checklogin')
let loginFrom=document.getElementById('loginFrom')
  //为登录按钮添加点击事件
  loginbtn.onclick=function(){
    //使用formData打包表单数据
    let formData=new FormData(loginFrom)
    //创建ajax对象
    let xhr=new XMLHttpRequest();
    //对ajax对象进行设置,向第2台服务器发送登录请求
    xhr.open('post','http://localhost:8888/login')
    //设置跨域登录属性,当发送跨域请求时,携带cookie信息
    xhr.withCredentials=true;
    //发送请求,并传递请求参数
    xhr.send(formData)
    //监听服务器端的响应内容
    xhr.onload=function(){
      console.log(xhr.responseText)
    }
  }
  //为检测用户登录状态按钮添加点击事件
  checklogin.onclick=function(){
    //创建ajax对象
    let xhr=new XMLHttpRequest();
    //对ajax对象进行设置,向第2台服务器发送登录请求
    xhr.open('get','http://localhost:8888/checklogin')
    //设置跨域登录属性,当发送跨域请求时,携带cookie信息
    xhr.withCredentials=true;
    //发送请求,并传递请求参数
    xhr.send()
    //监听服务器端的响应内容
    xhr.onload=function(){
      console.log(xhr.responseText)
    }
  }
</script>
</body>
</html>
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值