写代码啦
【前后分离】AJAX 的原理
回复数(0) 浏览数(48)
{{topic.upvote_count || 0}} 编辑 回复

Async JavaScript And XML

目录 §


1. AJAX原理 §

AJAX是浏览器上的功能

  • 用JS发请求和收响应
  • 浏览器可以发请求收响应
  • 浏览器在window上加一个 XMLHttpRequest 函数
typeof window.XMLHttpRequest
// function
  • 用这个构造函数(类)可以构造出一个对象
  • JS通过它实现发请求收响应

准备服务器

  • 使用 server.js 作为服务器
  • 下载或复制代码即可用 node sever.js 8888启动
  • 使用node-dev工具 ,安装
yarn global add node-dev

# 或者用
npm install -g node-dev
  • node-dev代替node,实现自动重启服务器
  • 但不能监听页面自动刷新
node-dev server.js 8888
  • 添加index.html / main.js两个路由
  • 路由就是if..else
  • index.html中加载路由读取的main.js
  • 加载的文件中引用到的路径,必须和路由的if..else中的路径path一致,server.js才会加载
  • response.write(fs.readFileSync('src/xxx'))中的是相对路径,和path的不同

复习

  • server.js中添加路由(条件),访问文件
  • 添加response.statusCode = 200
  • 设置Content-Type为对应的类型response.setHeader('Content-Type', 'text/javascript;charset=utf-8')
  • 把文件读成字符串,再传入response.write
  • 结束,关闭 response.end()
const string = fs.readFileSync('src/index.html')
response.write(string)

文件实际上对于node服务器来说就是字符串,只不过把字符串写到文件里而已

【HTTP非全解】请求和响应 & Node.Js Server


2. AJAX加载CSS §

以前使用<link rel="stylesheet" href="/style.css">引入

<!DOCTYPE html>
<html lang="zh-Hans">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no,viewport-fit=cover">
    <link rel="stylesheet" href="/style.css">
    <title>AJAX demo</title>
</head>
<body>
  <h1>AJAX demo</h1>
</body>
</html>
  • 这里--<link rel="stylesheet" href="/style.css">中的/style.css"是路由path的请求路径

server.js

// ...
if (path === '/index.html') {
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    const string = fs.readFileSync('src/index.html')
    response.write(string)
    response.end()
  }
// ...

style.css

body {
  color: red;
  background-color: #eaeaea;
}

使用 AJAX 加载 CSS 的四个步骤

server.js里写路由

// ...
if (path === '/index.html') {
response.statusCode = 200
response.setHeader('Content-Type', 'text/html;charset=utf-8')
const string = fs.readFileSync('src/index.html')
response.write(string)
response.end()
} else if (path === '/main.js') {
response.statusCode = 200
response.setHeader('Content-Type', 'text/javascript;charset=utf-8')
response.write(fs.readFileSync('src/main.js'))
response.end()
} else if (path === '/style.css') {
response.statusCode = 200
response.setHeader('Content-Type', 'text/css;charset=utf-8')
response.write(fs.readFileSync('src/style.css'))
response.end()
}
// ...
  • 区别路由path的请求路径和fs.readFileSync('src/xxx')的查找文件目录路径

index.html

<!DOCTYPE html>
<html lang="zh-Hans">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta name="viewport"
    content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no,viewport-fit=cover">
  <!-- <link rel="stylesheet" href="/style.css"> -->
  <title>AJAX demo 2</title>
</head>

<body>
  <h1>AJAX demo CSS</h1>
  <p>
    <button id="getCSS">请求CSS</button>
  </p>
  <script src="/main.js"> </script>
</body>
</html>
  • index.html里写的所有路径(/style.css/main.js),必须和路由的path路径一致,才能生效
  • 创建一个 button 测试

main.js里写

getCSS.onclick = () => {
  const request = new XMLHttpRequest()
  request.open('GET', '/style.css');
  request.onload = () => {
    // console.log('成功了')
    console.log('request.response')
    console.log(request.response)
    // 之后将响应的内容,用对应的标签包裹,插入html页面相应位置
  }
  request.onerror = () => {
    console.log('失败了')
  }
  request.send()
}
  1. 创建 HttpRequest 对象 (全称是 XMLHttpRequest
  2. 调用对象的 open 方法
  3. 监听对象的 onloadonerror 事件
  4. 调用对象的 send 方法(发送请求)
  5. 获取资源用request.open('GET', '/xxx');,只用两个参数,mdn 中后面的参数不用XMLHttpRequest.open() MDN

request.response就是响应得到的文件内容

  • 要使这段内容生效,就在外包裹一层对应的标签
// 将响应的内容,用对应的标签包裹,插入html页面相应位置
const style = document.createElement('style') // 创建 style 标签
style.innerHTML = request.response // 填写 style 内容
document.head.appendChild(style) // 插入head标签里

触发onerror事件

request.onerror = () => {
console.log('失败了')
}
  • server.js路径写错:你输入的路径不存在对应的内容
//...
else {
    response.statusCode = 404
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    response.write(`你输入的路径不存在对应的内容`)
    response.end()
}
//...
  • 只会渲染路径错误时的路由,并不触发onerror 事件
  • onerror对AJAX的支持不好

在第3步中,AJAX一般改用 onreadystatechange 事件,不用onloadonerror

  • 用对象的status属性,即状态码来判断,响应是否成功
  • 注意onreadystatechange全小写
getCSS.onclick = () => {
  const request = new XMLHttpRequest()
  request.open('GET', '/style.css');
  request.onreadystatechange = () => {
    // 监听对象的 readyState属性
    // console.log(request.readyState) // 2 3 4
    if (request.readyState === 4) {
      // console.log('下载完成')
      // 下载完成,但不知道下载成功还是失败

      if (request.status >= 200 && request.status < 300) {
        // 将响应的内容,用对应的标签包裹,插入html页面相应位置
        const style = document.createElement('style') // 创建 style 标签
        style.innerHTML = request.response // 填写 style 内容
        document.head.appendChild(style) // 插入head标签里
      } else {
        console.log('加载CSS失败')
      }
    }
  }
  request.send()
}

3. AJAX加载JS §

以前使用<script src="main.js"></script>引入

使用 AJAX 加载 JS 的四个步骤

server.js

// ...
else if (path === '/getJS.js') {
response.statusCode = 200
response.setHeader('Content-Type', 'text/javascript;charset=utf-8')
response.write(fs.readFileSync('src/getJS.js')) // 在目录中创建一个测试的getJS.js
response.end()
}
//...

index.html

<p>
<button id="getCSS">请求CSS</button>
<button id="getJS">请求JS</button>
</p>
  1. 创建 HttpRequest 对象 (全称是 XMLHttpRequest
  2. 调用 open 方法
  3. 监听对象的 onreadystatechange 事件
  4. 调用对象的 send 方法(发送请求)

main.js

//...
// AJAX 加载 JS
getJS.onclick = () => {
    const request = new XMLHttpRequest
    request.open('GET', '/getJS.js')
    request.onreadystatechange = () => {
        if (request.readyState === 4 && request.status >= 200 && request.status < 300) {
            // 创建script标签
            const script = document.createElement('script')
            // 填写 script内容
            script.innerHTML = request.response
            // 插到body里
            document.body.appendChild(script)
            }
        }
  request.send()
}
//...
  • 在事件处理函数里操作 JS 文件内容
  • 将响应的内容,用对应的标签包裹,插入html页面相应位置
  • AJAX下载并执行响应的内容

4. AJAX加载HTML §

以前没有加载过 HTML

  • 在目录src/下创建测试用indexOld.html,不写全,只写个标签
<h2>AJAX demo 2</h2>
<div style="background-color: bisque;border: 1px solid orange;width:300px;height:300px;">动态内容</div>

配置路由server.js

//...
else if (path === '/indexOld.html') {
response.statusCode = 200
response.setHeader('Content-Type', 'text/html;charset=utf-8')
response.write(fs.readFileSync('src/indexOld.html'))
response.end()
}
//...

index.html 加测试按钮

<p>
    <button id="getCSS">请求CSS</button>
    <button id="getJS">请求JS</button>
    <button id="getHTML">请求HTML</button>
</p>

使用 AJAX 加载 HTML 的四个步骤

  1. 创建 HttpRequest 对象
  2. 调用对象的 open 方法
  3. 监听对象的 onreadystatechange 事件
  4. 调用对象的 send 方法
//...
// AJAX 加载 HTML
getHTML.onclick = () => {
    const request = new XMLHttpRequest
    request.open('GET', '/indexOld.html')
    request.onreadyStatechange = () => {
        if (request.readyState === 4 && request.status >= 200 && request < 300) {
            // 创建 div 标签
            const div = document.createElement('div')
            // 填写 div 内容
            div.innerHTML = request.response
            // 插到body里
            document.body.appendChild(div)
        }
     }
  request.send()
}
//...
  • 在事件处理函数里操作 HTML 文件内容
  • 动态展示index.html
  • 控制台 Network 查看请求 点Preview 预览请求的页面
  • Response 看源代码
  • 把页面拆成不同的部分,在用户点击时,请求这个部分
  • 可以请求一小块 HTML,而 iframe 是请求整个网页,更加臃肿
  • AJAX 可以做到轻量级的请求,任意 HTTP 支持的文件类型

5. AJAX加载XML §

使用 AJAX 加载 XML 的四个步骤

server.js

//...
else if (path === '/getXML.xml') {
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/xml;charset=utf-8')
    response.write(fs.readFileSync('src/getXML.xml'))
    response.end()
  }
//...

index.html

<p>
    <button id="getCSS">请求CSS</button>
    <button id="getJS">请求JS</button>
    <button id="getHTML">请求HTML</button>
    <button id="getXML">请求XML</button>
</p>

getXML.xml

<?xml version="1.0" encoding="UTF-8"?>
<message>
    <warning>
         Hello World
    </warning>
</message>
  1. 创建 HttpRequest 对象(全称是 XMLHttpRequest
  2. 调用对象的 open 方法
  3. 监听对象的 onreadystatechange 事件
  4. 调用对象的 send 方法(发送请求)

main.js

// AJAX 加载 XML
getXML.onclick = () => {
  const request = new XMLHttpRequest()
  request.open('GET', '/getXML.xml')
  request.onreadystatechange = () => {
    if (request.readyState === 4 && request.status >= 200 && request.status < 300) {
      // console.log(request.responseXML)
      const dom = request.responseXML
      const text = dom.getElementsByTagName('warning')[0].textContent.trim();
      console.log(text)
      console.log(request.responseXML)
    }
  }
  request.send()
}
  • 在事件处理函数里操作 responseXML
  • request.responseXML是 DOM 对象

6. AJAX小结 §

HTTP 可以请求的类型

  • 可以请求 HTML CSS JS ...
  • 设置正确的 Content-Type
  • 响应的内容,用对应的标签包裹,插入html页面相应位置
  • 知道怎么解析,就可以使用

解析方法

  • 得到 CSS 后生成 style
  • 得到 JS 后生成 script
  • 得到 HTML 使用 innerHTMLDOM API
  • 得到 XML 后使用 responseXMLDOM API
  • 不同类型的数据有不同的解析办法

7. JSON §

Java*Script **Object **N*otation

  • JSON 是 轻量级的数据交换格式语言
  • 和HTML CSS JS一样是门独立的语言
  • 和HTML XML Markdown 是 标记语言,用来展示数据
  • 中文官网
  • 一页纸
  • 铁轨图

支持的类型

  • string 只支持双引号,不支持单引号、反引号和无引号
  • number 支持科学技术法
  • bool truefalse
  • null 没有 undefined
  • object
  • array

区别于 JS 的类型

  • 不支持函数与变量(即不支持引用)

和JS语法的区别:

  • JSON 的字符串必须用双引号。
  • JSON 无法表示 undefined,只能表示 "undefined"
  • JSON 无法表示函数
  • JSON 的对象语法不能有引用

8. AJAX加载JSON §

server.js

else if (path === '/getJSON.json') {
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/json;charset=utf-8') // 'application/json;charset=utf-8'也可
    response.write(fs.readFileSync('src/getJSON.json'))
    response.end()
}

getJSON.json

{
  "name": "frank",
  "gender": "male",
  "age": 18,
  "xxx": null
}

index.html

<p>
    <button id="getCSS">请求CSS</button>
    <button id="getJS">请求JS</button>
    <button id="getHTML">请求HTML</button>
    <button id="getXML">请求XML</button>
    <button id="getJSON">请求JSON</button>
</p>
<h2>Hello <span id="myName"></span></h2>

使用 AJAX 加载 JSON 的四个步骤

  1. 创建 HttpRequest 对象(全称是 XMLHttpRequest
  2. 调用对象的 open 方法
  3. 监听对象的 onreadystatechange 事件
  4. 调用对象的 send 方法(发送请求)

main.js

// AJAX 加载 JSON
getJSON.onclick = () => {
  const request = new XMLHttpRequest()
  request.open('GET', '/getJSON.json')
  request.onreadystatechange = () => {
    if (request.readyState === 4 && request.status === 200) {
      console.log(request.response)
      const object = JSON.parse(request.response)
      console.log(object)
      myName.textContent = object.name
    }
  }
  request.send()
}
  • 在事件函数里使用 JSON.parse
  • JSON.parse 把符合 JSON 语法的字符串变成对应的对象或者是其他东西

9. window.JSON §

JSON.parse

  • 解析字符串
  • 将符合 JSON 语法的字符串转换成 JS 对应类型的数据
  • JSON字符串 -> JS 数据
  • 转换成的不一定是对象,可以是 JSON 值类型的其他类型( typeof )
  • 由于 JSON 只有六种类型,所以转成的数据也只有6种
  • 如果不符合 JSON 语法,则直接抛出一个 Error对象
  • 一般用 try...catch捕获错误
let object
try{
    object = JSON.parse(`{'name':'frank'}`)
}catch(error){
    console.log('Error!')
    console.log(error)
    object = {"name":"no name"}
}
console.log(object)

JSON.stringify 序列化

  • JSON.parse的逆运算
  • JS 数据 ->JSON字符串
  • 由于 JS 的数据类型比 JSON 多,所以不一定成功
  • 如果失败,则直接抛出一个 Error对象
const obj = {"hi": "Ho", fn=(){}}
JSON.stringify(obj) // 不报错 直接忽略不合法的类型

10. AJAX综合应用:加载分页 §

加载列表

  • 用户打开页面,开到第一页数据
  • 用户点击下一页,看到第二页数据
  • 用户点击下一页,看到第三页数据
  • 用户点击下一页,提示没有更多了

/db/page1.json page2.json page3.json

  • 前后端不分离的渲染

index.html

<body>
<!-- ... -->
  <h2>Hello <span id="myName"></span></h2>
  <div>
    {{page1}}
  </div>
<!-- ... -->
</body>

server.js

if (path === '/index.html') {
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    let string = fs.readFileSync('src/index.html').toString() // 调用toString()前 是buffer

    // AJAX分页
    const page1 = fs.readFileSync('db/page1.json')
    // li
    const array = JSON.parse(page1) // [{ "id": 1 }, { "id": 2 }, { "id": 3 }, { "id": 4 }, { "id": 5 }, { "id": 6 }, { "id": 7 }, { "id": 8 }, { "id": 9 }, { "id": 10 }]
    const result = array.map(item => {
      return `<li>${item.id}</li>`
    }).join('')
    string = string.replace('{{page1}}', `<ul>${result}</ul>`)
    response.write(string)
    response.end()
}
  • 从数据库中拿出,拼接字符串

main.js

let pageCount = 1
// AJAX 加载 分页
getPage.onclick = () => {
  const request = new XMLHttpRequest()
  request.open('GET', `/page${pageCount + 1}`)
  request.onreadystatechange = () => {
    if (request.readyState === 4 && request.status === 200) {
      const array = JSON.parse(request.response)
      array.forEach(item => {
        const li = document.createElement('li')
        li.textContent = item.id
        xxx.appendChild(li)
      });

      // console.log(request.response)
      const object = JSON.parse(request.response)
      // console.log(object)
      myName.textContent = object.name

      pageCount += 1
    }
  }
  request.send()
}

优化点

  • 在点击第三页的时候就禁用下一页按钮

main.js

//...
let page = [1, 2, 3]
let currentPage = page[0]
// AJAX 加载 分页
getPage.onclick = () => {
  if (currentPage < 3) {
    const request = new XMLHttpRequest()
    request.open('GET', `/page${currentPage + 1}`)
    request.onreadystatechange = () => {
      if (request.readyState === 4 && request.status === 200) {
        const array = JSON.parse(request.response)
        array.forEach(item => {
          const li = document.createElement('li')
          li.textContent = item.id
          xxx.appendChild(li)
        });
        // console.log(request.response)
        const object = JSON.parse(request.response)
        // console.log(object)
        myName.textContent = object.name
        currentPage += 1
      }
    }
    request.send()
  } else {
    // console.log("Ban")
    getPage.disabled = true
  }
}
//...

11. 手写AJAX §

使用原生 JS 写出一个 AJAX 请求

mybutton.onclick = () => {
    let request = new XMLHttpRequest()
    request.open('GET','/xxx')
    request.onreadystatechange = () => {
        if(request.readystate === 4 && request.status = 200) {
            let string = request.responseText
            let string = window.JSON.parse(string)
        }
    }
    request.send()
}

后台的server.js,处理请求

if(path === '/xxx') {
    response.statusCode = 200
    response.setHeader('Content-Type','text/json;charset=utf-8')
    response.write(`{"status":"ok"}`)
    response.end()
}

·未完待续·


参考链接


  • 作者: Joel
  • 文章链接:
  • 版权声明
  • 非自由转载-非商用-非衍生-保持署名

{{topic.upvote_count || 0}}

Async JavaScript And XML

目录 §


1. AJAX原理 §

AJAX是浏览器上的功能

  • 用JS发请求和收响应
  • 浏览器可以发请求收响应
  • 浏览器在window上加一个 XMLHttpRequest 函数
typeof window.XMLHttpRequest
// function
  • 用这个构造函数(类)可以构造出一个对象
  • JS通过它实现发请求收响应

准备服务器

  • 使用 server.js 作为服务器
  • 下载或复制代码即可用 node sever.js 8888启动
  • 使用node-dev工具 ,安装
yarn global add node-dev

# 或者用
npm install -g node-dev
  • node-dev代替node,实现自动重启服务器
  • 但不能监听页面自动刷新
node-dev server.js 8888
  • 添加index.html / main.js两个路由
  • 路由就是if..else
  • index.html中加载路由读取的main.js
  • 加载的文件中引用到的路径,必须和路由的if..else中的路径path一致,server.js才会加载
  • response.write(fs.readFileSync('src/xxx'))中的是相对路径,和path的不同

复习

  • server.js中添加路由(条件),访问文件
  • 添加response.statusCode = 200
  • 设置Content-Type为对应的类型response.setHeader('Content-Type', 'text/javascript;charset=utf-8')
  • 把文件读成字符串,再传入response.write
  • 结束,关闭 response.end()
const string = fs.readFileSync('src/index.html')
response.write(string)

文件实际上对于node服务器来说就是字符串,只不过把字符串写到文件里而已

【HTTP非全解】请求和响应 & Node.Js Server


2. AJAX加载CSS §

以前使用<link rel="stylesheet" href="/style.css">引入

<!DOCTYPE html>
<html lang="zh-Hans">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no,viewport-fit=cover">
    <link rel="stylesheet" href="/style.css">
    <title>AJAX demo</title>
</head>
<body>
  <h1>AJAX demo</h1>
</body>
</html>
  • 这里--<link rel="stylesheet" href="/style.css">中的/style.css"是路由path的请求路径

server.js

// ...
if (path === '/index.html') {
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    const string = fs.readFileSync('src/index.html')
    response.write(string)
    response.end()
  }
// ...

style.css

body {
  color: red;
  background-color: #eaeaea;
}

使用 AJAX 加载 CSS 的四个步骤

server.js里写路由

// ...
if (path === '/index.html') {
response.statusCode = 200
response.setHeader('Content-Type', 'text/html;charset=utf-8')
const string = fs.readFileSync('src/index.html')
response.write(string)
response.end()
} else if (path === '/main.js') {
response.statusCode = 200
response.setHeader('Content-Type', 'text/javascript;charset=utf-8')
response.write(fs.readFileSync('src/main.js'))
response.end()
} else if (path === '/style.css') {
response.statusCode = 200
response.setHeader('Content-Type', 'text/css;charset=utf-8')
response.write(fs.readFileSync('src/style.css'))
response.end()
}
// ...
  • 区别路由path的请求路径和fs.readFileSync('src/xxx')的查找文件目录路径

index.html

<!DOCTYPE html>
<html lang="zh-Hans">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta name="viewport"
    content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no,viewport-fit=cover">
  <!-- <link rel="stylesheet" href="/style.css"> -->
  <title>AJAX demo 2</title>
</head>

<body>
  <h1>AJAX demo CSS</h1>
  <p>
    <button id="getCSS">请求CSS</button>
  </p>
  <script src="/main.js"> </script>
</body>
</html>
  • index.html里写的所有路径(/style.css/main.js),必须和路由的path路径一致,才能生效
  • 创建一个 button 测试

main.js里写

getCSS.onclick = () => {
  const request = new XMLHttpRequest()
  request.open('GET', '/style.css');
  request.onload = () => {
    // console.log('成功了')
    console.log('request.response')
    console.log(request.response)
    // 之后将响应的内容,用对应的标签包裹,插入html页面相应位置
  }
  request.onerror = () => {
    console.log('失败了')
  }
  request.send()
}
  1. 创建 HttpRequest 对象 (全称是 XMLHttpRequest
  2. 调用对象的 open 方法
  3. 监听对象的 onloadonerror 事件
  4. 调用对象的 send 方法(发送请求)
  5. 获取资源用request.open('GET', '/xxx');,只用两个参数,mdn 中后面的参数不用XMLHttpRequest.open() MDN

request.response就是响应得到的文件内容

  • 要使这段内容生效,就在外包裹一层对应的标签
// 将响应的内容,用对应的标签包裹,插入html页面相应位置
const style = document.createElement('style') // 创建 style 标签
style.innerHTML = request.response // 填写 style 内容
document.head.appendChild(style) // 插入head标签里

触发onerror事件

request.onerror = () => {
console.log('失败了')
}
  • server.js路径写错:你输入的路径不存在对应的内容
//...
else {
    response.statusCode = 404
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    response.write(`你输入的路径不存在对应的内容`)
    response.end()
}
//...
  • 只会渲染路径错误时的路由,并不触发onerror 事件
  • onerror对AJAX的支持不好

在第3步中,AJAX一般改用 onreadystatechange 事件,不用onloadonerror

  • 用对象的status属性,即状态码来判断,响应是否成功
  • 注意onreadystatechange全小写
getCSS.onclick = () => {
  const request = new XMLHttpRequest()
  request.open('GET', '/style.css');
  request.onreadystatechange = () => {
    // 监听对象的 readyState属性
    // console.log(request.readyState) // 2 3 4
    if (request.readyState === 4) {
      // console.log('下载完成')
      // 下载完成,但不知道下载成功还是失败

      if (request.status >= 200 && request.status < 300) {
        // 将响应的内容,用对应的标签包裹,插入html页面相应位置
        const style = document.createElement('style') // 创建 style 标签
        style.innerHTML = request.response // 填写 style 内容
        document.head.appendChild(style) // 插入head标签里
      } else {
        console.log('加载CSS失败')
      }
    }
  }
  request.send()
}

3. AJAX加载JS §

以前使用<script src="main.js"></script>引入

使用 AJAX 加载 JS 的四个步骤

server.js

// ...
else if (path === '/getJS.js') {
response.statusCode = 200
response.setHeader('Content-Type', 'text/javascript;charset=utf-8')
response.write(fs.readFileSync('src/getJS.js')) // 在目录中创建一个测试的getJS.js
response.end()
}
//...

index.html

<p>
<button id="getCSS">请求CSS</button>
<button id="getJS">请求JS</button>
</p>
  1. 创建 HttpRequest 对象 (全称是 XMLHttpRequest
  2. 调用 open 方法
  3. 监听对象的 onreadystatechange 事件
  4. 调用对象的 send 方法(发送请求)

main.js

//...
// AJAX 加载 JS
getJS.onclick = () => {
    const request = new XMLHttpRequest
    request.open('GET', '/getJS.js')
    request.onreadystatechange = () => {
        if (request.readyState === 4 && request.status >= 200 && request.status < 300) {
            // 创建script标签
            const script = document.createElement('script')
            // 填写 script内容
            script.innerHTML = request.response
            // 插到body里
            document.body.appendChild(script)
            }
        }
  request.send()
}
//...
  • 在事件处理函数里操作 JS 文件内容
  • 将响应的内容,用对应的标签包裹,插入html页面相应位置
  • AJAX下载并执行响应的内容

4. AJAX加载HTML §

以前没有加载过 HTML

  • 在目录src/下创建测试用indexOld.html,不写全,只写个标签
<h2>AJAX demo 2</h2>
<div style="background-color: bisque;border: 1px solid orange;width:300px;height:300px;">动态内容</div>

配置路由server.js

//...
else if (path === '/indexOld.html') {
response.statusCode = 200
response.setHeader('Content-Type', 'text/html;charset=utf-8')
response.write(fs.readFileSync('src/indexOld.html'))
response.end()
}
//...

index.html 加测试按钮

<p>
    <button id="getCSS">请求CSS</button>
    <button id="getJS">请求JS</button>
    <button id="getHTML">请求HTML</button>
</p>

使用 AJAX 加载 HTML 的四个步骤

  1. 创建 HttpRequest 对象
  2. 调用对象的 open 方法
  3. 监听对象的 onreadystatechange 事件
  4. 调用对象的 send 方法
//...
// AJAX 加载 HTML
getHTML.onclick = () => {
    const request = new XMLHttpRequest
    request.open('GET', '/indexOld.html')
    request.onreadyStatechange = () => {
        if (request.readyState === 4 && request.status >= 200 && request < 300) {
            // 创建 div 标签
            const div = document.createElement('div')
            // 填写 div 内容
            div.innerHTML = request.response
            // 插到body里
            document.body.appendChild(div)
        }
     }
  request.send()
}
//...
  • 在事件处理函数里操作 HTML 文件内容
  • 动态展示index.html
  • 控制台 Network 查看请求 点Preview 预览请求的页面
  • Response 看源代码
  • 把页面拆成不同的部分,在用户点击时,请求这个部分
  • 可以请求一小块 HTML,而 iframe 是请求整个网页,更加臃肿
  • AJAX 可以做到轻量级的请求,任意 HTTP 支持的文件类型

5. AJAX加载XML §

使用 AJAX 加载 XML 的四个步骤

server.js

//...
else if (path === '/getXML.xml') {
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/xml;charset=utf-8')
    response.write(fs.readFileSync('src/getXML.xml'))
    response.end()
  }
//...

index.html

<p>
    <button id="getCSS">请求CSS</button>
    <button id="getJS">请求JS</button>
    <button id="getHTML">请求HTML</button>
    <button id="getXML">请求XML</button>
</p>

getXML.xml

<?xml version="1.0" encoding="UTF-8"?>
<message>
    <warning>
         Hello World
    </warning>
</message>
  1. 创建 HttpRequest 对象(全称是 XMLHttpRequest
  2. 调用对象的 open 方法
  3. 监听对象的 onreadystatechange 事件
  4. 调用对象的 send 方法(发送请求)

main.js

// AJAX 加载 XML
getXML.onclick = () => {
  const request = new XMLHttpRequest()
  request.open('GET', '/getXML.xml')
  request.onreadystatechange = () => {
    if (request.readyState === 4 && request.status >= 200 && request.status < 300) {
      // console.log(request.responseXML)
      const dom = request.responseXML
      const text = dom.getElementsByTagName('warning')[0].textContent.trim();
      console.log(text)
      console.log(request.responseXML)
    }
  }
  request.send()
}
  • 在事件处理函数里操作 responseXML
  • request.responseXML是 DOM 对象

6. AJAX小结 §

HTTP 可以请求的类型

  • 可以请求 HTML CSS JS ...
  • 设置正确的 Content-Type
  • 响应的内容,用对应的标签包裹,插入html页面相应位置
  • 知道怎么解析,就可以使用

解析方法

  • 得到 CSS 后生成 style
  • 得到 JS 后生成 script
  • 得到 HTML 使用 innerHTMLDOM API
  • 得到 XML 后使用 responseXMLDOM API
  • 不同类型的数据有不同的解析办法

7. JSON §

Java*Script **Object **N*otation

  • JSON 是 轻量级的数据交换格式语言
  • 和HTML CSS JS一样是门独立的语言
  • 和HTML XML Markdown 是 标记语言,用来展示数据
  • 中文官网
  • 一页纸
  • 铁轨图

支持的类型

  • string 只支持双引号,不支持单引号、反引号和无引号
  • number 支持科学技术法
  • bool truefalse
  • null 没有 undefined
  • object
  • array

区别于 JS 的类型

  • 不支持函数与变量(即不支持引用)

和JS语法的区别:

  • JSON 的字符串必须用双引号。
  • JSON 无法表示 undefined,只能表示 "undefined"
  • JSON 无法表示函数
  • JSON 的对象语法不能有引用

8. AJAX加载JSON §

server.js

else if (path === '/getJSON.json') {
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/json;charset=utf-8') // 'application/json;charset=utf-8'也可
    response.write(fs.readFileSync('src/getJSON.json'))
    response.end()
}

getJSON.json

{
  "name": "frank",
  "gender": "male",
  "age": 18,
  "xxx": null
}

index.html

<p>
    <button id="getCSS">请求CSS</button>
    <button id="getJS">请求JS</button>
    <button id="getHTML">请求HTML</button>
    <button id="getXML">请求XML</button>
    <button id="getJSON">请求JSON</button>
</p>
<h2>Hello <span id="myName"></span></h2>

使用 AJAX 加载 JSON 的四个步骤

  1. 创建 HttpRequest 对象(全称是 XMLHttpRequest
  2. 调用对象的 open 方法
  3. 监听对象的 onreadystatechange 事件
  4. 调用对象的 send 方法(发送请求)

main.js

// AJAX 加载 JSON
getJSON.onclick = () => {
  const request = new XMLHttpRequest()
  request.open('GET', '/getJSON.json')
  request.onreadystatechange = () => {
    if (request.readyState === 4 && request.status === 200) {
      console.log(request.response)
      const object = JSON.parse(request.response)
      console.log(object)
      myName.textContent = object.name
    }
  }
  request.send()
}
  • 在事件函数里使用 JSON.parse
  • JSON.parse 把符合 JSON 语法的字符串变成对应的对象或者是其他东西

9. window.JSON §

JSON.parse

  • 解析字符串
  • 将符合 JSON 语法的字符串转换成 JS 对应类型的数据
  • JSON字符串 -> JS 数据
  • 转换成的不一定是对象,可以是 JSON 值类型的其他类型( typeof )
  • 由于 JSON 只有六种类型,所以转成的数据也只有6种
  • 如果不符合 JSON 语法,则直接抛出一个 Error对象
  • 一般用 try...catch捕获错误
let object
try{
    object = JSON.parse(`{'name':'frank'}`)
}catch(error){
    console.log('Error!')
    console.log(error)
    object = {"name":"no name"}
}
console.log(object)

JSON.stringify 序列化

  • JSON.parse的逆运算
  • JS 数据 ->JSON字符串
  • 由于 JS 的数据类型比 JSON 多,所以不一定成功
  • 如果失败,则直接抛出一个 Error对象
const obj = {"hi": "Ho", fn=(){}}
JSON.stringify(obj) // 不报错 直接忽略不合法的类型

10. AJAX综合应用:加载分页 §

加载列表

  • 用户打开页面,开到第一页数据
  • 用户点击下一页,看到第二页数据
  • 用户点击下一页,看到第三页数据
  • 用户点击下一页,提示没有更多了

/db/page1.json page2.json page3.json

  • 前后端不分离的渲染

index.html

<body>
<!-- ... -->
  <h2>Hello <span id="myName"></span></h2>
  <div>
    {{page1}}
  </div>
<!-- ... -->
</body>

server.js

if (path === '/index.html') {
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/html;charset=utf-8')
    let string = fs.readFileSync('src/index.html').toString() // 调用toString()前 是buffer

    // AJAX分页
    const page1 = fs.readFileSync('db/page1.json')
    // li
    const array = JSON.parse(page1) // [{ "id": 1 }, { "id": 2 }, { "id": 3 }, { "id": 4 }, { "id": 5 }, { "id": 6 }, { "id": 7 }, { "id": 8 }, { "id": 9 }, { "id": 10 }]
    const result = array.map(item => {
      return `<li>${item.id}</li>`
    }).join('')
    string = string.replace('{{page1}}', `<ul>${result}</ul>`)
    response.write(string)
    response.end()
}
  • 从数据库中拿出,拼接字符串

main.js

let pageCount = 1
// AJAX 加载 分页
getPage.onclick = () => {
  const request = new XMLHttpRequest()
  request.open('GET', `/page${pageCount + 1}`)
  request.onreadystatechange = () => {
    if (request.readyState === 4 && request.status === 200) {
      const array = JSON.parse(request.response)
      array.forEach(item => {
        const li = document.createElement('li')
        li.textContent = item.id
        xxx.appendChild(li)
      });

      // console.log(request.response)
      const object = JSON.parse(request.response)
      // console.log(object)
      myName.textContent = object.name

      pageCount += 1
    }
  }
  request.send()
}

优化点

  • 在点击第三页的时候就禁用下一页按钮

main.js

//...
let page = [1, 2, 3]
let currentPage = page[0]
// AJAX 加载 分页
getPage.onclick = () => {
  if (currentPage < 3) {
    const request = new XMLHttpRequest()
    request.open('GET', `/page${currentPage + 1}`)
    request.onreadystatechange = () => {
      if (request.readyState === 4 && request.status === 200) {
        const array = JSON.parse(request.response)
        array.forEach(item => {
          const li = document.createElement('li')
          li.textContent = item.id
          xxx.appendChild(li)
        });
        // console.log(request.response)
        const object = JSON.parse(request.response)
        // console.log(object)
        myName.textContent = object.name
        currentPage += 1
      }
    }
    request.send()
  } else {
    // console.log("Ban")
    getPage.disabled = true
  }
}
//...

11. 手写AJAX §

使用原生 JS 写出一个 AJAX 请求

mybutton.onclick = () => {
    let request = new XMLHttpRequest()
    request.open('GET','/xxx')
    request.onreadystatechange = () => {
        if(request.readystate === 4 && request.status = 200) {
            let string = request.responseText
            let string = window.JSON.parse(string)
        }
    }
    request.send()
}

后台的server.js,处理请求

if(path === '/xxx') {
    response.statusCode = 200
    response.setHeader('Content-Type','text/json;charset=utf-8')
    response.write(`{"status":"ok"}`)
    response.end()
}

·未完待续·


参考链接


  • 作者: Joel
  • 文章链接:
  • 版权声明
  • 非自由转载-非商用-非衍生-保持署名

48
回复 编辑