前后端交互01

前后端交互01

课堂目标

  1. 理解ajax基本使用
  2. 会使用XMLHttpRequest对象实现数据交互
  3. 了解onreadystatechange服务器响应信息
  4. 会使用FormData对象上传文件
  5. 了解upload事件对象

知识要点

  1. ajax使用
  2. XMLHttpRequest对象
  3. FormData对象
  4. upload 事件对象

登录简单回顾

1、提出ajax验证用户名需求;

2、如果通过跳转解决很麻烦;

利用ajax来解决验证用户名问题

  • ajax的前端实现

  • ajax后端实现

  • 利用ajax来解决验证用户名问题-demo

  • ajax是: Ajax 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML)
    XML: 和JSON一样是目前主流的两种返还格式

    ajax的特点: 无刷新,局部更新;

  • ajax的基本使用;

    • 新建XMLHttpRequest对象
    let xhr = new XMLHttpRequest();
    
    • 配置请求参数
    xhr.open("get","/checkUser",true); //true是异步,false是同步
    
    • 接收返还值
     xhr.onload = function(){
        let res = JSON.parse(xhr.responseText);
     }
    
    • 发送服务器
    xhr.send();
    

针对ajax的详细解释

get/post在ajax中的使用

  • ajax中的get请求
  • get注意点:
    • get和querystring的问题,通过url传参(?带参方式)
    xhr.open("get", `/checkUserName?username=${this.value}` ,true)
    
    • get通过parmas传参(跟querystring区别是不带参数会错误)必须给参数,否则地址错误。(? 之前)
    xhr.open("get",'/get/4',true)
    // 带个4的参数,在后台路由指定是什么,id
    // router.get("/get/:id",(ctx,next)=>{})
    
  1. query方式传参,则不会影响地址。(?之后)
  2. post也可以使用query方式,不是get独有的;

get.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <button>点击发送ajax</button>
</body>
<script>
    document.querySelector("button").onclick = function(){
        let xhr = new XMLHttpRequest();
        xhr.open("get","/get/4",true);
        xhr.onload = function(){
            console.log(xhr.responseText);
        }
        xhr.send();
    }
</script>
</html>

index.js(koa)

router.get("/get/:id",(ctx,next)=>{
    console.log(ctx.params);
    ctx.body = {
        status:1,
        info:"请求成功"
    }
})
  • post注意点:

    • post传参是没有数据量限制的,通常会是服务器限制;
    • post传参是正文区域传参所以需要设置编码格式,而get是在头部url中,所以不需要;
    • 发送数据时候需要设置http正文头格式:
    xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");  //默认编码
    xhr.setRequestHeader("Content-type","multipart/form-data");  //二进制编码
    xhr.setRequestHeader("Content-type","application/json");  //json编码
    
    • 获取头部信息;
      • getAllResponseHeaders 或者是 getResponseHeader
  • post.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <!-- <form action="" enctype="application/x-www-form-urlencoded"></form> -->
    <button>点击我发送ajax</button>
</body>
<script>
    document.querySelector("button").onclick = function () {
        let xhr = new XMLHttpRequest();
        xhr.open("post", "/post", true);
        xhr.onload = function () {
            console.log(xhr.responseText);
            // 获取返还头信息
         //    console.log(xhr.getAllResponseHeaders());
        // console.log(xhr.getResponseHeader("content-type"));
        }
        // xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
        // xhr.setRequestHeader("Content-Type","multipart/form-data"); //二进制编码
        xhr.setRequestHeader("content-type","application/json");
        // let data = "username=王五&age=20";
        let data = JSON.stringify({
            username:"王五",
            age:20
        })
        xhr.send(data);
    }
</script>

</html>
  • index.js(koa)
const koaBody = require("koa-body");

app.use(koaBody({
    multipart:true
}));

router.post("/post",(ctx,next)=>{
    console.log(ctx.request.body);
    ctx.body = {
        status:1,
        info:"post请求成功"
    }
})

onreadystatechange

onreadystatechange:存有处理服务器响应的函数,每当 readyState 改变时,onreadystatechange 函数就会被执行。

readyState:存有服务器响应的状态信息(老的方式,请求状态,可以不用)

  • 0: 请求未初始化(代理被创建,但尚未调用 open() 方法)

  • 1: 服务器连接已建立(open方法已经被调用)

  • 2: 请求已接收(send方法已经被调用,并且头部和状态已经可获得)

  • 3: 请求处理中(下载中,responseText 属性已经包含部分数据)

  • 4: 请求已完成,且响应已就绪(下载操作已完成)

  • readyStatus.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <button>点击</button>
</body>
<script>
    document.querySelector("button").onclick = function () {
        let xhr = new XMLHttpRequest();
        xhr.open("get", "/get/4", true);
        xhr.onload = function () {
            console.log(xhr.responseText);
            console.log(xhr.readyState);
            console.log(xhr.status);
        }
        // xhr.onreadystatechange = function () {
        //     if (xhr.readyState == 4) {
        //         if (xhr.status == 200) {
        //             console.log(xhr.responseText);
        //         }
        //     }
        // }
        xhr.send();
    }
</script>

</html>

status常用状态码

        HTTP                状态码描述

        100                    继续。继续响应剩余部分,进行提交请求

        200                    成功

        301                    永久移动。请求资源永久移动到新位置

        302                    临时移动。请求资源零时移动到新位置

        304                    未修改。请求资源对比上次未被修改,响应中不包含资源内容

        401                    未授权,需要身份验证

        403                    禁止。请求被拒绝

        404                    未找到,服务器未找到需要资源

        500                    服务器内部错误。服务器遇到错误,无法完成请求

        503                    服务器不可用。临时服务过载,无法处理请求
  • 返还数据类型

    • 服务器返还json数据

      xhr.responseText  //来获取 文本
      
    • 服务器返还xml数据

      xhr.responseXML //获取值 页面
      
      • 重写response里的content-type内容
      • xhr.overrideMimeType(‘text/xml; charset = utf-8’)
      • 服务端若返回xml格式数据需设置响应头(koa中)
        ctx.set(“content-type”,“text/xml”)
  • xml.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <button>点击我获取xml</button>
</body>
<script>
        document.querySelector("button").onclick = function(){
            let xhr = new XMLHttpRequest();
            xhr.open("get","/xml",true);
            // 重写content-type;
            xhr.overrideMimeType("text/xml");
            xhr.onload = function(){
                // console.log(xhr.responseText);
                // console.log(xhr.responseXML);
                // console.log(xhr.response)
                let name =  xhr.responseXML.getElementsByTagName("name")[1].innerHTML;
                console.log(name);
            }
            xhr.send();
        }
    </script>
</html>
  • index.js(koa)
router.get("/xml",(ctx,next)=>{
    // ctx.set("content-type","text/xml");
    ctx.body = `<?xml version='1.0' encoding='utf-8' ?>
                    <books>
                        <nodejs>
                            <name>nodejs实战</name>
                            <price>56元</price>
                        </nodejs>
                        <react>
                            <name>react入门</name>
                            <price>50元</price>
                        </react>
                    </books>
                `
})
  • 同步及异步ajax;

    • 设置true和false区别;
      1.异步,任务不需等待不受影响
      2.同步,等待其他任务完成
  • async.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <button>按钮一</button>
    <button>按钮二</button>
</body>
<script>
    let btns = document.querySelectorAll("button");
    btns[0].onclick = function () {
        let xhr = new XMLHttpRequest();
        xhr.open("get", "/get/4", true);
        xhr.onload = function () {
            console.log(xhr.responseText);
        }
        xhr.send();
    }
    btns[1].onclick = function(){
        console.log("我是按钮二");
    }
</script>

</html>

ajax的封装使用

封装步骤:

  1. 使用Object.assign()函数将默认配置和传递配置参数进行合并;
  2. 传递的method中,需要判断get/post,get传参需要使用queryString即使用?进行拼接url;post也要凭借成参数并通过send()进行传递;
  3. 封装拼接url方法(Object.keys(obj)和Object.values(obj)),map循环key=value并使用join("&")进行拼接(这种方式如果数据对象为多层数据,需要递归解决);
  4. onload()方法获取返回数据,xhr.responseText()
  5. 判断get/post方法,不同请求方式,send()方法不同。
  6. 需要给出默认headers配置,用户也可以自定义设置,通过for in设置头部setRequestHeader();设置头部后,需要switch判断头部,只有为JSON时,才能以封装的数据格式以post方式传递数据,如果是json格式,需要转为json再发送
  7. onload()时也需要判断返还数据类型,或者直接使用JSON.parse()直接数据转为对象

封装成类似下面形式:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <!-- <form enctype="application/x-www-form-urlencoded"></form> -->
</body>
<script>
    ajax({
        url: "/test",
        method: "post",
        data: {
            hello: "你好",
            height: "178cm"
        },
        success(res) {
            console.log(res)
        }
    })

function ajax(opts) {
    let newOpts = Object.assign({          //方法用于对象的合并
        url: "",
        method: "get",
        data: "",
        async: true,
        headers: {
            "content-type": "application/x-www-form-urlencoded"
        },
        success() { }
    }, opts);
    let xhr = new XMLHttpRequest();
    // get 是通过querystring方式传参数;            
    // post :send(data)       data:name=zhangsan&age=20
    // get url: /xml     
    // data:{name:zhangsan,age:20}--->/xml?name=zhangsan&age=20&height=178            
    // querystring是查询参&连接,不加引号
    if (newOpts.method.toLowerCase() === "get") {             //不管大写小写
        xhr.open(newOpts.method, newOpts.url + "?" + o2u(newOpts.data), newOpts.async);
    } else {
        xhr.open(newOpts.method, newOpts.url, newOpts.async);
    }
    xhr.setRequestHeader("content-type", newOpts.headers['content-type']);
    xhr.οnlοad = function () {
        newOpts.success(JSON.parse(xhr.responseText));
    }
    let sendData = null
    if (newOpts.method.toLowerCase() === "post") {
        // name=zhangsan&age=20&height=178
        sendData = o2u(newOpts.data);
    }
    xhr.send(sendData);
    // let obj = {
    //     name:"张三",
    //     age:20
    // }
    // console.log(o2u(obj));
    function o2u(obj) {
        // ["hello","height"] --> 0,1
        let keys = Object.keys(obj);
        let values = Object.values(obj);
        return keys.map((key, k) => {
            console.log(k)
            return key + "=" + values[k];
        }).join("&");
    }
}
</script>

</html>

利用FormData来实现文件上传

利用FormData来实现文件上传-demo

  • 创建FormData对象

  • 监控上传进度

    upload 事件

    上传文件事件钩子

    • onloadstart 上传开始
    • onprogress 数据传输进行中
      • evt.total :需要传输的总大小;
      • evt.loaded :当前上传的文件大小;
    • onabort 上传操作终止
    • onerror 上传失败
    • onload 上传成功
    • onloadend 上传完成(不论成功与否)
  • formdata.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <input type="file" class="myfile" />
    <button>点击我上传文件</button>
</body>
<script>
    document.querySelector("button").onclick = function(){
        let file = document.querySelector(".myfile").files[0];
        // console.log(files);
        let form = new FormData();
        form.append("img",file);
        form.append("name","张三");
        let xhr = new XMLHttpRequest();
        xhr.open("post","/upload",true);
        xhr.onload = function(){
            console.log(xhr.responseText);
        }
        xhr.send(form);
    }
</script>
</html>
  • index.js(koa)
const koaBody = require("koa-body");
const fs = require("fs");

app.use(koaBody({
    multipart:true
}));

router.post("/upload",(ctx,next)=>{
    console.log(ctx.request.body);
    console.log(ctx.request.files.img);
     let fileData =  fs.readFileSync(ctx.request.files.img.path);
    fs.writeFileSync("static/imgs/"+ctx.request.files.img.name,fileData);
    ctx.body = "请求成功";
})

qq空间批量上传图片案例

通过formData实现《qq空间批量上传图片》
需求确定:相册内容显示相册

nodejs搭建后台

分析上传元素
登录区分不同用户
创建上传对象
上传图片
获取上传后的最新图片数据

一、需求确定
1. 相册内容显示相册
点击上传(可选择多张图片),上传成功后,会显示相册图片;
上传时,有上传进度显示

二、nodejs搭建后台
使用nunjucks加载页面

三、分析上传元素
1. 登录区分不同用户
2. 创建上传对象
上传图片可以有多张图片:input中使用multiple="multiple"即可选择多张上传图片;
获取并显示待上传图片:通过原生this.files可以获取所有图片对象。根据文件对象循环创建HTML(createElement(“div”))放入对应容器中;

通过FileReader读取上传文件。let fileReader = new FileReader(file);fileReader.readAsDataURL(file);fileReader.onload()时将图片转为base64,并将base64作为临时路径(即在onload时再创建HTML);
继续添加时,继续创建HTML;
3. 上传图片
上传:监控上传进度,后台转存;此处上传是一个接一个进行上传,将需要上传时将html中对象一个一个添加到数组中,上传时将每个图片抽象成图片类(每张图片都有自己的创建HTML,监控上传进度,上传等方法);
将创建的节点进行保存,用于监控上传进度;

通过FormData进行上传
通过unload中的onprogress监控上传进度,onload()处理上传成功后的处理;
点击上传时,遍历存储的图片数组,并进行上传
使用Promise监控一个一个上传:调用时返回Promise对象,在每一个上传的函数中,使用async await处理即可
4. 获取上传后的最新图片数据

四、完整案例展示

回顾

1.ajax基本使用

2.get/post在ajax中的使用

3.ajax中成功的返还

4.返还数据格式

5.FormData对象

6.upload事件对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值