01-原生Ajax

7/25/2022

本课程用到的依赖

"dependencies": {
    "@koa/router": "^12.0.0",
    "axios": "^0.27.2",
    "body-parser": "^1.19.0",
    "cookie-parser": "^1.4.5",
    "express": "^4.17.1",
    "express-session": "^1.17.2",
    "koa": "^2.13.4",
    "koa-body": "^5.0.0",
    "koa-logger": "^3.2.1",
    "koa-static": "^5.0.0",
    "koa2-cors": "^2.0.6",
    "mongodb": "^4.4.0",
    "nprogress": "^0.2.0",
    "qs": "^6.11.0"
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 1. 原生Ajax经典步骤

AJAX: 全称为Asynchronous Javascript And XML,就是异步的 JS 和 XML

  • 它可以使用 JSON,XML,HTML 和 text 文本等格式发送和接收数据
  • AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式

Ajax发送请求的经典步骤

  • 第一步:创建网络请求的AJAX对象(使用XMLHttpRequest)
  • 第二步:监听XMLHttpRequest对象状态的变化,或者监听onload事件(请求完成时触发)
  • 第三步:配置网络请求(通过open方法)
  • 第四步:发送send网络请求

XMLHttpRequest的state(状态)

在一次网络请求中看到状态发生了很多次变化,这是因为对于一次请求来说包括如下的状态

  • 0       UNSENT       代理被创建,但尚未调用 open() 方法。
  • 1       OPENED       open() 方法已经被调用。
  • 2       HEADERS_RECEIVED       send() 方法已经被调用,并且头部和状态已经可获得。
  • 3       LOADING       下载中, responseText 属性已经包含部分数据。
  • 4       DONE       下载操作已完成。

注意

  • 这个状态并非是HTTP的相应状态,而是记录的XMLHttpRequest对象的状态变化
  • http响应状态通过status获取

前端代码

<!-- 
    前端能发请求的方式:
        // =================  get 
            浏览器的地址栏
            a标签的href
            img标签src
            script标签的src
            link标签的href
            postman工具也可以发请求
            表单
            ajax
        // =================  post
            postman工具也可以发请求
            表单
            ajax

    AJAX:Asynchronous Javascript And XML(异步JavaScript和XML)
        并不是一个新技术,是多门技术的结合体,如:js bom json...

        作用:向后端发出请求,后端给出响应

    XML:
        HTML:
            <div>  <p>   <span> ... 
        XML:
            <pig>   <dog>   <student>...
            在10年前,是前后端通信的一种数据格式
            现在,前后端通信主要是以json为主
    
    -----------------------------------
    ajax发请求的经典步骤:
        1)创建一个ajax对象   XMLHttpRequest
        2)监听ajax对象的状态变化    或     监听onload事件
        3)配置网络请求
        4)发出请求
-->

<script>
    // 1)创建一个ajax对象   XMLHttpRequest   属于BOM中的内容
    let xhr = new XMLHttpRequest();
    console.log(xhr);
    console.log(xhr.readyState); // ajax刚创建出来的时状态是0

    // 2)监听ajax对象的状态变化 
    xhr.onreadystatechange = function() {
        // console.log("==>", xhr.readyState);
        // if(xhr.readyState === 4){
        //     console.log("-------------");
        //     console.log(xhr.response);
        //     console.log("-------------");
        // }

        if (xhr.readyState === XMLHttpRequest.DONE) {
            console.log("-------------");
            console.log(xhr.response);
            console.log("-------------");
        }
    }

    // 3)配置网络请求
    xhr.open("get", "http://127.0.0.1:3000/get")
    console.log(xhr.readyState); // 调用完open方法后,ajax的状态就变成1

    // 4)发出请求  send(请求体)  请求体就是给后端传递数据
    // get请求没有所谓的请求体  只有post请求才能请求体
    // 你发出了get请求,send()  ()中不需要写任何内容 
    xhr.send()
    console.log(xhr.readyState); // ajax的状态就变成1
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

后端代码

const Koa = require("koa");
const cors = require("koa2-cors");
const logger = require("koa-logger");
const Router = require("@koa/router");
const koaBody = require("koa-body");
const app = new Koa();
const router = new Router();

app.use(cors());
app.use(logger());
app.use(koaBody());

router.get("/get", async (ctx, next) => {
    ctx.status = 200;
    ctx.body = "hello Ajax";
});

app.use(router.routes())
router.allowedMethods();

app.listen(3000, () => {
    console.log("running in http://127.0.0.1:3000");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 2. xhr对象的load事件

除了onreadystatechange还有其他的事件可以监听

  • loadstart:请求开始
  • progress: 一个响应数据包到达,此时整个 response body 都在 response 中
  • abort:调用 xhr.abort() 取消了请求
  • error:发生连接错误,例如,域错误。不会发生诸如 404 这类的 HTTP 错误
  • load:请求成功完成,我们也可以使用load来获取数据
  • timeout:由于请求超时而取消了该请求(仅发生在设置了 timeout 的情况下)
  • loadend:在 load,error,timeout 或 abort 之后触发

前端代码

<script>
    let xhr = new XMLHttpRequest();

    // xhr.onreadystatechange = function () {
    //     if (xhr.readyState === 4) {
    //         console.log(xhr.response);
    //     }
    // }

    xhr.onload = function() {
        console.log(xhr.response);
    }

    xhr.open("get", "http://127.0.0.1:3000/get");
    xhr.send();
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

后端代码同上

# 3. 响应JSON数据, 指定响应类型

XMLHttpRequest response 属性返回响应的正文内容

  • 返回的类型取决于responseType的属性设置
  • 通过responseType可以设置获取数据的类型
  • 早期通常服务器返回的数据是普通的文本和XML,所以我们通常会通过responseText、 responseXML来获取响应结果
  • 目前服务器基本返回的都是json数据,直接设置为json即可

前端代码

<script>
    let xhr = new XMLHttpRequest();

    xhr.onload = function() {
        console.log(xhr.response);
        console.log(xhr.response.name);
        console.log(xhr.response.culture);
        console.log(typeof xhr.response);
    }
    // 期望后端返回json数据,如果不作这样的配置,得到的是纯文本字符串
    xhr.responseType = "json";

    xhr.open("get", "http://127.0.0.1:3000/json");
    xhr.send();
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

后端代码

const Koa = require("koa");
const cors = require("koa2-cors");
const logger = require("koa-logger");
const Router = require("@koa/router");
const koaBody = require("koa-body");
const app = new Koa();
const router = new Router();

app.use(cors());
app.use(logger());
app.use(koaBody());

router.get("/json", async (ctx, next) => {
    ctx.status = 200;
    ctx.type = "json";
    ctx.body = {
        name: "码路教育",
        culture: "为学员服务",
    };
});

app.use(router.routes())
router.allowedMethods();

app.listen(3000, () => {
    console.log("running in http://127.0.0.1:3000");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 4. 响应XML数据

前端代码

<script>
    let xhr = new XMLHttpRequest();

    xhr.onload = function() {
        // console.log(xhr.response); 

        // 得到xml数据
        console.log(xhr.responseXML);
    }

    // xhr.responseType = "xml"  // 不OK

    xhr.open("get", "http://127.0.0.1:3000/xml");
    xhr.send();
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

后端代码

const Koa = require("koa");
const cors = require("koa2-cors");
const logger = require("koa-logger");
const Router = require("@koa/router");
const koaBody = require("koa-body");
const app = new Koa();
const router = new Router();

app.use(cors());
app.use(logger());
app.use(koaBody());

router.get("/xml", async (ctx, next) => {
    ctx.status = 200;
    ctx.type = "xml"
    ctx.body = `
        <content>
            <name>码路教育</name>
            <culture>为学员服务</culture>
        </content>
    `;
});

app.use(router.routes())
router.allowedMethods();

app.listen(3000, () => {
    console.log("running in http://127.0.0.1:3000");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 5. 响应的状态status

  • XMLHttpRequest的state是用于记录xhr对象本身的状态变化,并非针对于HTTP的网络请求状态
  • 如果我们希望获取HTTP响应的网络状态,可以通过status和statusText来获取

前端代码

<script>
    let xhr = new XMLHttpRequest();

    xhr.onload = function() {
        // console.log(xhr.response);

        // xhr.status,得到响应的状态码
        console.log(xhr.status);
    }

    // xhr.open("post", "http://127.0.0.1:3000/status/500");
    // xhr.open("post", "http://127.0.0.1:3000/status/503");
    xhr.open("post", "http://127.0.0.1:3000/status/404");
    xhr.send();
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

后端代码

const Koa = require("koa");
const cors = require("koa2-cors");
const logger = require("koa-logger");
const Router = require("@koa/router");
const koaBody = require("koa-body");
const app = new Koa();
const router = new Router();

app.use(cors());
app.use(logger());
app.use(koaBody());

router.post("/status/500", async (ctx, next) => {
    ctx.status = 500;
    ctx.body = 500;
});

router.post("/status/503", async (ctx, next) => {
    ctx.status = 503;
    ctx.body = 503;
});

router.post("/status/403", async (ctx, next) => {
    ctx.status = 403;
    ctx.body = 403;
});

router.post("/status/404", async (ctx, next) => {
    ctx.status = 404;
    ctx.body = {
        ok: 1
    };
});

app.use(router.routes())
router.allowedMethods();

app.listen(3000, () => {
    console.log("running in http://127.0.0.1:3000");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# 6. GET请求传递参数

在开发中,我们使用最多的是GET和POST请求,在发送请求的过程中,我们也可以传递给服务器数据

常见的传递给服务器数据的方式有如下几种

  • 方式一:GET请求的query参数
  • 方式二:POST请求 x-www-form-urlencoded 格式
  • 方式三:POST请求 FormData 格式
  • 方式四:POST请求 JSON 格式

前端代码

<script>
    let xhr = new XMLHttpRequest();

    xhr.onload = function() {
        console.log(xhr.response);
    }

    xhr.responseType = "json"

    // query传参  在谷歌浏览器的控制台有一个payload  表示query传递的参数
    //  querystring  查询字符串
    // xhr.open("get", "http://127.0.0.1:3000/get?name=wc&age=18&address=bj");
    // xhr.send();

    // params传参
    // 在谷歌浏览器的控制台中没有payload  但是也给后端传递了参数
    xhr.open("get", "http://127.0.0.1:3000/get/wc/18/bj");
    xhr.send();
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

后端代码

const Koa = require("koa");
const cors = require("koa2-cors");
const logger = require("koa-logger");
const Router = require("@koa/router");
const koaBody = require("koa-body");
const app = new Koa();
const router = new Router();

app.use(cors());
app.use(logger());
app.use(koaBody());

router.get("/get", async (ctx, next) => {
    ctx.status = 200;
    ctx.body = ctx.query;
});

router.get("/get/:name/:age/:address", ctx => {
    ctx.status = 200;
    ctx.body = ctx.params;
})

app.use(router.routes())
router.allowedMethods();

app.listen(3000, () => {
    console.log("running in http://127.0.0.1:3000");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 7. post请求传递参数

前端代码

<script>
    let xhr = new XMLHttpRequest();

    xhr.onload = function() {
        console.log(xhr.response);
    }

    // xhr.responseType = "json"

    xhr.open("post", "http://127.0.0.1:3000/post");

    // 如果不设置请求求,默认Content-Type是text/plain
    // 此时谷歌浏览器调度面板中的payload显示Request Data
    // Content-Type: text / plain; charset = UTF - 8

    // 如果配置了请求头是application/x-www-form-urlencoded
    // 此时谷歌浏览器调度面板中的payload显示Form Data
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")

    // post传参,需要放在请求体中
    // ()中请求体
    xhr.send("name=xq&age=28&address=zz");
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

后端代码

const Koa = require("koa");
const cors = require("koa2-cors");
const logger = require("koa-logger");
const Router = require("@koa/router");
const koaBody = require("koa-body");
const app = new Koa();
const router = new Router();

app.use(cors());
app.use(logger());
app.use(koaBody());

router.post("/post", async (ctx, next) => {
    ctx.status = 200;
    ctx.body = ctx.request.body;
});

app.use(router.routes())
router.allowedMethods();

app.listen(3000, () => {
    console.log("running in http://127.0.0.1:3000");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 8. formData传递参数

前端代码

<meta charset="utf-8">
<form class="info">
    <input type="text" name="username">
    <input type="text" name="pwd">
</form>
<button class="send">发送请求</button>

<script>
    let formEle = document.querySelector(".info")
    let sendEle = document.querySelector(".send")
    sendEle.onclick = function() {
        let xhr = new XMLHttpRequest();
        xhr.onload = function() {
            console.log(xhr.response);
        }
        xhr.open("post", "http://127.0.0.1:3000/post");

        // formData传参,在谷歌浏览器的控制台中payload中显示form Data
        // 但是不一样的是 当点view source
        // formData是一个容器
        // let formData = new FormData();
        // formData.append("name", "z3")
        // formData.append("age", "18")
        // xhr.send(formData)

        let formData = new FormData(formEle);
        xhr.send(formData)
    }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

后端代码

const Koa = require("koa");
const cors = require("koa2-cors");
const logger = require("koa-logger");
const Router = require("@koa/router");
// 之前: body-parser
// 现在: koa-body
const koaBody = require("koa-body");
const app = new Koa();
const router = new Router();

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

router.post("/post", async (ctx, next) => {
    ctx.status = 200;
    ctx.body = ctx.request.body;
});

app.use(router.routes())
router.allowedMethods();

app.listen(3000, () => {
    console.log("running in http://127.0.0.1:3000");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 9. 传递多种形式的参数

前端代码

<script>
    let xhr = new XMLHttpRequest();
    xhr.onload = function() {
        console.log(xhr.response);
    }
    xhr.responseType = "json"

    xhr.open("post", "http://127.0.0.1:3000/post/wc/18?score=100&id=001");
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
    xhr.send("name=xq&age=28&address=zz");
</script>
1
2
3
4
5
6
7
8
9
10
11

后端代码

const Koa = require("koa");
const cors = require("koa2-cors");
const logger = require("koa-logger");
const Router = require("@koa/router");
// 之前: body-parser
// 现在: koa-body
const koaBody = require("koa-body");
const app = new Koa();
const router = new Router();

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

router.post("/post/:name/:age", async (ctx, next) => {
    ctx.status = 200;
    let postData = ctx.request.body;
    let paramsData = ctx.params;
    let queryData = ctx.query;
    console.log("postData:", postData);
    console.log("paramsData:", paramsData);
    console.log("queryData:", queryData);
    ctx.body = ctx.request.body;
});

app.use(router.routes())
router.allowedMethods();

app.listen(3000, () => {
    console.log("running in http://127.0.0.1:3000");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# 10. 总结


    get传参:
        query传参
            /get?name=wc&amp;age18
            后端: ctx.query
            在谷歌浏览器控制台中有一个payload面板
            payload面板中显示 Query Stirng  查询字符串
        params传参
            /get/wc/18/bj
            后端: /get/:name/:age/:address
                 ctx.params
            在谷歌浏览器控制台中没有payload面板

    post传参:
        send中直接传递请求体:
            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
            send(name=wc&amp;age=18&amp;address=bj)
            后端: 配置body-parser 或  koa-body 
            后端: ctx.request.body
            在谷歌浏览器控制台中有一个payload面板
            payload面板中显示 Form Data  点开view source 
                name=wc&amp;age=18&amp;address=bj

            如果没有配置
                xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
                谷歌浏览器控制台中有一个payload面板
                payload面板中显示 Request Data  

        把数据放到FormData容器:
            let formData = new FormData();
            向容器中放数据:
                1)formData.append("username","wc")
                2)在new FormData()直接指定表单  这样表单中的数据就是收集到容器

            谷歌浏览器控制台中有一个payload面板,payload面板中显示 Form Data,点开view source 和 send中传递请求体是不一样的

    如果是post传参,能不能传递query参数和params参数?
    答:可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# 11. 检测用户名是否存在

前端代码

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

<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<body>
    <h2>用户注册</h2>
    <form method="post">
        <ul>
            <li>用户名:<input type="text" name="username" id="user"><span id="msg"></span></li>
            <li>密码:<input type="text" name="pwd"></li>
            <li>确认密码:<input type="text" name="repwd"></li>
            <li><input type="submit" value="注册"></li>
        </ul>
    </form>
    <script>
        let user = document.querySelector("#user")
        let msg = document.querySelector("#msg")

        user.onblur = function () {
            // this 表示事件源  this.value 表示输入框中的内容
            let username = this.value;

            let xhr = new XMLHttpRequest();
            xhr.onload = function () {
                let res = xhr.response;
                if (res.code == 0) {
                    msg.innerHTML = res.msg;
                    msg.style.color = "red"
                } else {
                    msg.innerHTML = res.msg;
                    msg.style.color = "green"
                }
            }
            xhr.responseType = "json"
            xhr.open("post", "http://127.0.0.1:3000/check");

            xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
            xhr.send(`username=${username}`)
        }
    </script>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

后端代码

const Koa = require("koa");
const cors = require("koa2-cors");
const logger = require("koa-logger");
const Router = require("@koa/router");
const koaBody = require("koa-body");
const app = new Koa();
const router = new Router();

app.use(cors());
app.use(logger());
app.use(koaBody());

// 模拟从数据库中取到的用户信息
let users = ["wc", "xq", "admin"];

router.post("/check", (ctx) => {
    let username = ctx.request.body.username.trim();
    if (users.find(user => user === username)) {
        ctx.body = {
            code: 0,
            msg: "对不起,该用户名已经被注册,请换个用户名"
        }
    } else {
        ctx.body = {
            code: 1,
            msg: "恭喜你,该用户可以使用"
        }
    }

})

app.use(router.routes())
router.allowedMethods();

app.listen(3000, () => {
    console.log("running in http://127.0.0.1:3000");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# 12. 省市区三级联动

前端代码

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

<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<body>
    <h2>省市区三级联动</h2>
    <label for="">请选择省份:</label>
    <select id="province">
        <option value="">--省份--</option>
    </select>
    <select id="city">
        <option value="">--市区--</option>
    </select>
    <select id="country">
        <option value="">--区县--</option>
    </select>
    <script>
        let province = document.getElementById("province")
        let city = document.getElementById("city")

        // 请求所有的省份
        let xhr = new XMLHttpRequest(); // 第一步:创建xhr对象
        xhr.open("get", "http://127.0.0.1:3000/province"); // 第二步:建立连接
        xhr.send(null); // 第三步:发出请求  null可写可不写

        xhr.responseType = "json";

        // 一上来,就是获取所有的省
        xhr.onload = function() {
            let provinceData = xhr.response;

            let str = `<option value="">--省份--</option>`;
            provinceData.forEach(item => {
                str += `<option value="${item}">${item}</option>`
            })
            province.innerHTML = str;
        }

        province.onchange = function() {
            xhr.open("get", "http://127.0.0.1:3000/city?province=" + this.value)
            xhr.send(null);
            xhr.onload = function() {
                let cityData = xhr.response;
                let str = ` <option value="">--市区--</option>`;
                cityData.forEach(item => {
                    str += `<option value="${item}">${item}</option>`
                })
                city.innerHTML = str;
            }
        }
    </script>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

后端代码

const Koa = require("koa");
const cors = require("koa2-cors");
const logger = require("koa-logger");
const Router = require("@koa/router");
const koaBody = require("koa-body");
const app = new Koa();
const router = new Router();

app.use(cors());
app.use(logger());
app.use(koaBody());

// data表示服务器端的所有的数据
let data = require("./cityData.min.json")

// 响应所有的省份
router.get("/province", (ctx) => {
    let province = [];
    data.forEach(item => {
        // item代表每一个省的所有数据
        province.push(item.n)
    })
    // json有两种形式:1)对象的形式 2)数组的形式
    ctx.body = province; // 响应给xhr一个json字符串  ["北京市","河南省","河北省"...]
})

// 根据省份,响应对应的市
router.get("/city", (ctx) => {
    let province = ctx.query.province;
    let cities = [];
    data.forEach(item => {
        if (item.n === province) {
            item.s.forEach(item1 => {
                cities.push(item1.n)
            })
        }
    })
    ctx.body = cities
})

app.use(router.routes())
router.allowedMethods();

app.listen(3000, () => {
    console.log("running in http://127.0.0.1:3000");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

注意: 用到的json数据, 直接从今天课堂的代码中copy

# 14. 传统ajax分页

前端代码

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

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        li {
            list-style: none;
        }

        body {
            background: #eee;
        }

        .wrapper {
            background: #fff;
            width: 970px;
            margin: 20px auto;
            padding: 15px;
        }

        h1 {
            text-align: center;
            border-bottom: 1px solid #ddd;
            padding-bottom: 20px;
        }

        li {
            margin: 20px 0;
            border-bottom: 1px dotted #eee;
            padding-bottom: 20px;
        }

        p {
            line-height: 25px;
        }
    </style>

    <!-- CDN -->
    <script src="https://libs.baidu.com/jquery/1.11.3/jquery.min.js"></script>
</head>

<body>
    <div class="wrapper">
        <h1>新闻列表(AJAX普通分页)
            <script>
                document.write(new Date().toLocaleString())
            </script>
        </h1>
        <ul>

        </ul>
        <div class="footer">
            <p>总共有<span id="total"></span>条新闻,每页显示<span id="pagesize"></span>条,
                当前是<span id="page"></span>/<span id="size"></span><a href="#" id="prev">上一页</a>
                <a href="#" id="next">下一页</a>
            </p>
        </div>
    </div>
    <script>
        let page = 1;
        let pageSize = 3;
        // axios  promise
        function getNewsList(page, pageSize) {

            $.get("http://127.0.0.1:3000/news", {
                page,
                pageSize
            }, res => {
                let str = "";
                res.news.forEach(item => {
                    str += `
                        <li>
                            <h2>${item.title}</h2>
                            <p class="time">${item.time}</p>
                            <p class="summary">${item.summary}</p>
                        </li>
                    `
                })
                $("ul").html(str)
                $("#total").html(res.total)
                $("#pagesize").html(res.pageSize)
                $("#page").html(res.page)
                $("#size").html(res.size)
            })

        }
        getNewsList(page, pageSize)

        $("#prev").click(function(e) {
            e.preventDefault();
            if (page > 1) {
                getNewsList(--page, pageSize)
            }
        })
        $("#next").click(function(e) {
            e.preventDefault();
            if (page < $("#size").html()) {
                getNewsList(++page, pageSize)
            }
        })
    </script>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

后端代码

const Koa = require("koa");
const cors = require("koa2-cors");
const logger = require("koa-logger");
const Router = require("@koa/router");
const koaBody = require("koa-body");
const MongoClient = require('mongodb').MongoClient
const app = new Koa();
const router = new Router();

app.use(cors());
app.use(logger());
// app.use(koaBody());

const client = new MongoClient('mongodb://127.0.0.1:27017')
// 链接服务端
client.connect()
console.log('链接成功')

// 获取数据库 
const db = client.db('newsDB')
// 获取集合
const grade1 = db.collection('news')

router.get("/news", async ctx => {

    let page = ctx.query.page || 1;
    (page <= 0) && (page = 1)

    let pageSize = ctx.query.pageSize;
    let r = await grade1
        .find()
        .skip((page - 1) * pageSize)
        .limit(+pageSize)
        .toArray()

    let total = await grade1.find().count();
    let size = Math.ceil(total / pageSize) // size表示一共有多少页

    ctx.body = {
        news: r,
        total: total,
        pageSize,
        page,
        size
    }
    // 关闭客户端的链接
    // client.close()
})

app.use(router.routes())
router.allowedMethods();

app.listen(3000, () => {
    console.log("running in http://127.0.0.1:3000");
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
[
  {
    "title": "科学研判 习近平对经济发展提出这些重大论断",
    "time": "2020-08-12",
    "summary": "当今世界正经历百年未有之大变局,我国发展的内部条件和外部环境正在发生深刻复杂变化,一些传统行业受到冲击,而智能制造、在线消费等新兴产业展现出强大成长潜力,成为我们改造提升传统产业,培育壮大新兴产业的契机。"
  },
  {
    "title": "拒绝“舌尖上的浪费”  琅琅读书声",
    "time": "2020-08-12",
    "summary": "粮食问题一直是困扰世界的一大难题。自2020年全球新冠肺炎疫情蔓延以来,国际粮食市场出现较大波动,加之蝗灾、极端天气等因素影响,使得全球粮食安全及短缺问题更加严峻。"
  },
  {
    "title": "香港各界支持全国人大常委会依法作出决定",
    "time": "2020-08-12",
    "summary": "香港各界人士表示,全国人大常委会就香港特区第六届立法会继续运作作出的决定,不仅是宪法和基本法赋予的权力,更是照顾了特区的实际,确保香港社会经济有序发展。"
  },
  {
    "title": "央视快评丨维护香港根本利益的必要之举",
    "time": "2020-08-12",
    "summary": "十三届全国人大常委会第二十一次会议11日表决通过了《全国人民代表大会常务委员会关于香港特别行政区第六届立法会继续履行职责的决定》。根据《决定》,2020年9月30日后,香港特别行政区第六届立法会继续履行职责,不少于一年,直至香港特别行政区第七届立法会任期开始为止。"
  },
  {
    "title": "31省区市新增确诊病例25例,其中境外输入病例16例,本土病例9例",
    "time": "2020-08-12",
    "summary": "8月11日0—24时,31个省(自治区、直辖市)和新疆生产建设兵团报告新增确诊病例25例,其中境外输入病例16例(广东6例,上海4例,内蒙古1例,浙江1例,福建1例,山东1例,四川1例,陕西1例),本土病例9例(均在新疆);无新增死亡病例;新增疑似病例1例,为境外输入病例(在上海)。"
  },
  {
    "title": "“中国的帮助增强了我们抗疫信心”(患难见真情 共同抗疫情)",
    "time": "2020-08-12",
    "summary": "在阿布贾封城的情况下,工作人员带着特别通行证,挨家挨户敲门向商家购买材料。公司其他项目部也迅速送来急需的物资:阿布贾航站楼项目部送来脚手架、地面漆、电缆;卡诺项目部送来医用屏风;运营事业部从仓库里翻出水暖材料。“为了搭建钢结构的消毒间,我们把原来的保安房都拆了,终于凑齐了建筑材料……”负责新建消毒间的张贵回忆道。"
  },
  {
    "title": "港媒:以50万港元保释,5000万港元资产被冻结",
    "time": "2020-08-12",
    "summary": "香港警方10日以涉嫌违反香港国安法及串谋欺诈等罪名拘捕10人,其中包括乱港分子、香港“壹传媒”创办人黎智英。综合香港《东方日报》等港媒报道,黎智英获准保释,今天(12日)凌晨完成保释手续,走出旺角警署。其保释金为30万元(港元,下同)现金及20万元人事担保。"
  },
  {
    "title": "快讯!拜登宣布选择哈里斯作为竞选搭档",
    "time": "2020-08-12",
    "summary": "【环球网报道】美国民主党籍总统候选人、前副总统拜登发布推特宣布他将选择卡马拉·哈里斯(Kamala Harris)为自己的竞选搭档。"
  },
  {
    "title": "暴雨预警!全国13省市区有大到暴雨 京津冀局地大暴雨",
    "time": "2020-08-12",
    "summary": "预计,8月12日08时至13日08时,内蒙古东南部、山西中南部、河北、北京、天津、山东西北部、辽宁西部、河南北部、甘肃南部和东部、陕西南部、四川盆地中西部、云南西部和南部、广东南部沿海等地的部分地区有大到暴雨,其中,河北中部和东北部、北京、天津西部等地局地有大暴雨(100~200毫米),四川盆地中西部的部分地区有大暴雨到特大暴雨(100~280毫米)。"
  },
  {
    "title": "河南再迎强降雨!局部有暴雨、大暴雨!",
    "time": "2020-08-12",
    "summary": "8月我省沿黄及其以北降水明显偏多,12-13日上述地区仍有暴雨、大暴雨,强降水落区叠加,需加强防范豫北山洪和地质灾害、城市内涝及农田积涝,同时做好大秋作物田间管理。"
  },
  {
    "title": "北京最强暴雨预警刷屏!网友:这暴雨到底有多大?",
    "time": "2020-08-12",
    "summary": "8月11日,北京市气象部门预报显示,京津冀地区于12日将有一次区域性强降雨天气过程,大部分地区将出现大到暴雨,局地有大暴雨,为今年入汛以来最强降雨过程。"
  },
  {
    "title": "无纺复合工艺采用医用级防护胶 环保安全有保障",
    "time": "2020-08-12",
    "summary": "当前,新冠肺炎疫情时刻牵动着全国人民的心,在抗击疫情的战场上,医务人员的护身“铠甲”——防护服发挥了重要作用。据了解,一件防护服的生产至少需10道工序,每一道环节都必须层层把关,严防纰漏。"
  }
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

# 15. 点击加载更多

前端代码

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

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        li {
            list-style: none;
        }

        body {
            background: #eee;
        }

        .wrapper {
            background: #fff;
            width: 970px;
            margin: 20px auto;
            padding: 15px;
        }

        h1 {
            text-align: center;
            border-bottom: 1px solid #ddd;
            padding-bottom: 20px;
        }

        li {
            margin: 20px 0;
            border-bottom: 1px dotted #eee;
            padding-bottom: 20px;
        }

        p {
            line-height: 25px;
        }
    </style>
    <script src="https://libs.baidu.com/jquery/1.11.3/jquery.min.js"></script>
</head>

<body>
    <div class="wrapper">
        <h1>新闻列表(ajax点击加载更多分页)
            <script>
                document.write(new Date().toLocaleString())
            </script>
        </h1>
        <ul>

        </ul>
        <div class="footer" style="text-align: center;">
            <button id="btn" style="width: 120px; height: 60px; font-size: 20px;">加载更多</button>
        </div>
    </div>
    <script>
        let page = 1;
        let pageSize = 3;

        function getNewsList(page, pageSize) {
            $.get("http://127.0.0.1:3000/news", {
                page,
                pageSize
            }, res => {
                if (res.news.length) {
                    let str = "";
                    res.news.forEach(item => {
                        str += `
                             <li>
                                <h2>${item.title}</h2>
                                <p class="time">${item.time}</p>
                                <p class="summary">${item.summary}</p>
                            </li>
                        `
                    })
                    $("ul").append(str)
                }
            })
        }

        getNewsList(page, pageSize)

        $("#btn").click(function(e) {
            getNewsList(++page, pageSize)
        })
    </script>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

后端代码同上

# 16. 滚动加载更多

前端代码

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

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        li {
            list-style: none;
        }

        body {
            background: #eee;
        }

        .wrapper {
            background: #fff;
            width: 970px;
            margin: 20px auto;
            padding: 15px;
        }

        h1 {
            text-align: center;
            border-bottom: 1px solid #ddd;
            padding-bottom: 20px;
        }

        li {
            margin: 20px 0;
            border-bottom: 1px dotted #eee;
            padding-bottom: 20px;
        }

        p {
            line-height: 25px;
        }
    </style>
    <script src="https://libs.baidu.com/jquery/1.11.3/jquery.min.js"></script>
</head>

<body>
    <div class="wrapper">
        <h1>新闻列表(ajax滚动加载更多分页)
            <script>
                document.write(new Date().toLocaleString())
            </script>
        </h1>
        <ul>

        </ul>
        <div class="footer" style="text-align: center;">
            <img src="" alt="" width="40px">
        </div>
    </div>
    <script>
        let page = 1;
        let pageSize = 5;
        let load = true;

        function getNewsList(page, pageSize) {
            $(".footer img").attr("src", "./imgs/timg.gif")

            $.get("http://127.0.0.1:3000/news", {
                page,
                pageSize
            }, res => {
                if (res.news.length) {
                    let str = "";
                    res.news.forEach(item => {
                        str += `
                             <li>
                                <h2>${item.title}</h2>
                                <p class="time">${item.time}</p>
                                <p class="summary">${item.summary}</p>
                            </li>
                        `
                    })
                    $("ul").append(str)
                    load = true
                } else {
                    $(".footer").html("-----------我是有底线的-----------")
                    load = false;
                }
            })
        }
        getNewsList(page, pageSize);

        $(document).scroll(function() {
            let st = $(window).scrollTop(); // 卷上去的高度
            let ch = $(window).height(); // 一屏的高度
            let dh = $(document).height(); // 整体内容的高度
            // console.log("整体内容的高度:", dh);
            // console.log("卷上去的高度:", st);
            // console.log("一屏的高度:", ch);

            if ((st + ch) >= (dh - 3) && load) {
                console.log("到底了...");
                getNewsList(++page, pageSize)
            }

        })
    </script>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111

后端代码同上

# 13. 延迟时间timeout和取消请求

在网络请求的过程中,为了避免过长的时间服务器无法返回数据,通常我们会为请求设置一个超时时间:timeout

  • 当达到超时时间后依然没有获取到数据,那么这个请求会自动被取消掉
  • 默认值为0,表示没有设置超时时间
<script>
    let xhr = new XMLHttpRequest();
    xhr.open("get", "http://httpbin.org/delay/5")
    xhr.send();

    // 设置超时时间
    xhr.timeout = 3000; // 如果请求超过3秒就断开了(也就是自动取消请求)

    xhr.onload = function() {
        console.log(xhr.response);
    }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
<button>取消请求</button>
<script>
    let xhr = new XMLHttpRequest();
    xhr.open("get", "http://httpbin.org/delay/5");
    xhr.send();

    // xhr.timeout = 3000; // 如果超过3秒自动取消请求

    xhr.onload = function() {
        console.log(xhr.response);
    }

    let btn = document.getElementsByTagName("button")[0];
    btn.onclick = function() {
        // 手动取消请求
        xhr.abort();
    }
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Last Updated: 12/25/2022, 10:02:14 PM