Ajax笔记(下)

一、图片上传

1.什么是图片上传?

就是把本地的图片上传到网页显示

2.图片上传怎么做?

先依靠文件选择元素获取用户选择的本地文件,接着提交到服务器保存,服务器会返回图片的url网址,然后把网址加载到img标签的src属性即可显示

3.为什么不直接显示到浏览器上,要放到服务器上呢?

因为浏览器保存时临时的,如果你想随时随地访问图片,需要上传到服务器上

4.图片上传怎么做呢?

(1)先获取图片文件对象

(2)使用FormData表单数据对象装入(因为图片是文件而不是以前的数字和字符了,所以传递文件一般需要放入FormData一键只对文件流的数据传递)

(3)提交表单数据对象,使用服务器返回图片url网址

5.核心代码

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>图片上传</title>
</head>

<body>
  <!-- 文件选择元素 -->
  <input type="file" class="upload">
  <img src="" alt="" class="my-img">

  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
    /**
     * 目标:图片上传,显示到网页上
     *  1. 获取图片文件
     *  2. 使用 FormData 携带图片文件
     *  3. 提交到服务器,获取图片url网址使用
    */
    // 文件选择元素->change改变事件
    document.querySelector('.upload').addEventListener('change', e => {
      // 1. 获取图片文件
      console.log(e.target.files[0])
      // 2. 使用 FormData 携带图片文件
      const fd = new FormData()
      fd.append('img', e.target.files[0])
      // 3. 提交到服务器,获取图片url网址使用
      axios({
        url: 'http://hmajax.itheima.net/api/uploadimg',
        method: 'POST',
        data: fd
      }).then(result => {
        console.log(result)
        // 取出图片url网址,用img标签加载显示
        const imgUrl = result.data.data.url
        document.querySelector('.my-img').src = imgUrl
      })
    })
  </script>
</body>

</html>

总结(图片上传的思路):

先用文件选择元素,获取到文件对象,然后装入 FormData 表单对象中,再发给服务器,得到图片在服务器的 URL 网址,再通过 img 标签加载图片显示

二、案例-网站-更换背景图

1.步骤:

(1)先获取到用户选择的背景图片,上传并把服务器返回的图片url网址设置给body背景

(2)上传成功时,保存图片url网址到localStorage中

(3)网页运行后,获取localStorage中的图片的url网址使用(并判断本地有图片url网址字符串才设置)

2.核心代码

javascript 复制代码
/**
 * 目标:网站-更换背景
 *  1. 选择图片上传,设置body背景
 *  2. 上传成功时,"保存"图片url网址
 *  3. 网页运行后,"获取"url网址使用
 * */
document.querySelector('.bg-ipt').addEventListener('change', e => {
  // 1. 选择图片上传,设置body背景
  console.log(e.target.files[0])
  const fd = new FormData()
  fd.append('img', e.target.files[0])
  axios({
    url: 'http://hmajax.itheima.net/api/uploadimg',
    method: 'POST',
    data: fd
  }).then(result => {
    const imgUrl = result.data.data.url
    document.body.style.backgroundImage = `url(${imgUrl})`

    // 2. 上传成功时,"保存"图片url网址
    localStorage.setItem('bgImg', imgUrl)
  })
})

// 3. 网页运行后,"获取"url网址使用
const bgUrl = localStorage.getItem('bgImg')
console.log(bgUrl)
bgUrl && (document.body.style.backgroundImage = `url(${bgUrl})`)

总结(localStorage取值和复制的语法分别是什么):

localStorage.getItem('key')是取值,localStorage.setItem('key',value)赋值

三、案例-个人信息设置

1.分析:

(1)先完成信息回显

(2)再做头像修改-立刻就更新给此用户

(3)收集个人信息表单-提交保存

(4)提交后反馈结果给用户(提示框)

2.信息渲染

(1)获取数据

(2)渲染到页面上

3.头像修改

步骤:

(1)获取到用户选择的头像文件

(2)调用头像修改接口,并除了头像文件外,还要在FormData表单数据中携带外号

(3)提交到服务器保存此用户对应头像文件,并把返回的头像图片的url网址设置到页面上

(3)注意:重新刷新重新获取,已经是修改后的头像

(4)核心代码:

javascript 复制代码
/**
 * 目标2:修改头像
 *  2.1 获取头像文件
 *  2.2 提交服务器并更新头像
 * */
// 文件选择元素->change事件
document.querySelector('.upload').addEventListener('change', e => {
  // 2.1 获取头像文件
  console.log(e.target.files[0])
  const fd = new FormData()
  fd.append('avatar', e.target.files[0])
  fd.append('creator', creator)
  // 2.2 提交服务器并更新头像
  axios({
    url: 'http://hmajax.itheima.net/api/avatar',
    method: 'PUT',
    data: fd
  }).then(result => {
    const imgUrl = result.data.data.avatar
    // 把新的头像回显到页面上
    document.querySelector('.prew').src = imgUrl
  })
})

总结:为什么这次上传头像,需要携带外号呢?

因为这次头像上传到后端,是要保存在某个用户名下的,所以需要把外号名字一起携带过去、

4.信息修改:

需求:点击提交按钮,收集个人信息,提交到服务器保存(无需重新获取刷新,因为页面已经是最新的数据了)

(1)收集表单数据

(2)提交到服务器保存-调用用户信息更新接口(注意请求方式是PUT)代表数据更新的意思

核心代码:

javascript 复制代码
/**
 * 目标3:提交表单
 *  3.1 收集表单信息
 *  3.2 提交到服务器保存
 */
// 保存修改->点击
document.querySelector('.submit').addEventListener('click', () => {
  // 3.1 收集表单信息
  const userForm = document.querySelector('.user-form')
  const userObj = serialize(userForm, { hash: true, empty: true })
  userObj.creator = creator
  // 性别数字字符串,转成数字类型
  userObj.gender = +userObj.gender
  console.log(userObj)
  // 3.2 提交到服务器保存
  axios({
    url: 'http://hmajax.itheima.net/api/settings',
    method: 'PUT',
    data: userObj
  }).then(result => {
  })
})

总结:信息修改数据和以前的增删改查哪个实现的思路比较接近呢?

编辑:首先是回显已经做完了,然后收集用户最新改动后的数据,提交到服务器上保存,因为页面最终就是用户刚写的数据,所以不用重新获取并刷新页面了。

5.提示框

(1)需求:使用bootStrap提示框和modal弹框使用很像,语法如下:

首先准备对应的标签结构,然后设置延迟自动显示的时间

<div class="toast" data-bs-delay="1500">

提示框内容

</div>

最后:使用js的方式,在axios请求响应成功时,展示结果

// 创建提示框对象

const toastDom = document.querySelector('css选择器')

const toast = new bootstrap.Toast(toastDom)

// 显示提示框

toast.show()

核心代码:

javascript 复制代码
/**
 * 目标3:提交表单
 *  3.1 收集表单信息
 *  3.2 提交到服务器保存
 */
/**
 * 目标4:结果提示
 *  4.1 创建toast对象
 *  4.2 调用show方法->显示提示框
 */
// 保存修改->点击
document.querySelector('.submit').addEventListener('click', () => {
  // 3.1 收集表单信息
  const userForm = document.querySelector('.user-form')
  const userObj = serialize(userForm, { hash: true, empty: true })
  userObj.creator = creator
  // 性别数字字符串,转成数字类型
  userObj.gender = +userObj.gender
  console.log(userObj)
  // 3.2 提交到服务器保存
  axios({
    url: 'http://hmajax.itheima.net/api/settings',
    method: 'PUT',
    data: userObj
  }).then(result => {
    // 4.1 创建toast对象
    const toastDom = document.querySelector('.my-toast')
    const toast = new bootstrap.Toast(toastDom)

    // 4.2 调用show方法->显示提示框
    toast.show()
  })
})

总结:bootstrap弹框什么使用js显示呢?

需要执行一些其他的js逻辑后,再去显示/隐藏弹框时。

四、知识点自测

1.什么方法可以将js数据类型改成json数据类型?

JSON.stringfy()

2.以下哪个方法,会延迟一段时间,再执行函数体,并执行一次就停止?

A、setTImeout(函数体,毫秒值)

B、setInterval(函数体,毫秒值)

选择A,

3.下列代码结果是多少?

A、true

B、大于

C、240

D、false

let obj = {

status: 240

}

const result = obj.status >= 200 && obj.status < 300

结果是Atrue

4.代码运行结果是多少?

let result = 'http://www.baidu.com'

result += '?a=10'

result += '&b=20'

A、http://www.baidu.com

B、?a=10

C、&b=20
D、http://www.baidu.com?a=10\&b=20

5.以下哪个能实时监测到输入框值的变化?

A、input事件

B、change事件

选择A

五、XMLHttpRequest

1.基础使用

(1)AJAX是浏览器与服务器通信的技术,采用XMLHttpRequest对象的相关代码

(2)axios是对XHR相关的代码进行了封装,让我们只关心传递的接口参数

(3)学习XHR也是了解axios的内部与服务器交互过程的真正原理

语法如下:

javascript 复制代码
const xhr = new XMLHttpRequest()
xhr.open('请求方法', '请求url网址')
xhr.addEventListener('loadend', () => {
  // 响应结果
  console.log(xhr.response)
})
xhr.send()

六、同步代码与异步代码

1.同步代码:

逐行执行,需要原地等待结果后,才能继续向下执行

2.异步代码:

调用后耗时,不阻塞代码继续执行(不必原地等待),在将来完成过后触发一个回调函数

const result = 0 + 1

console.log(result)

setTimeout(() => {

console.log(2)

}, 2000)

document.querySelector('.btn').addEventListener('click', () => {

console.log(3)

})

document.body.style.backgroundColor = 'pink'

console.log(4)

###结果是1,4,2,,点击一次按钮打印一次3

总结:(1)JS中有哪些异步代码?

setTimeout、setInterval、事件、Ajax

(2)异步代码用什么接受结果?

用回调函数

七、回调函数地狱

1.概念:

在回调函数中嵌套回调函数,一直嵌套下去就形成了回调函数地狱

2.缺点:

可读性差,异常无法捕获,耦合性严重,牵一发动全身

八、Promise-链式调用

1.概念:

依靠 then() 方法会返回一个新生成的 Promise 对象特性,继续串联下一环任务,直到结束

2.细节:

then() 回调函数中的返回值,会影响新生成的 Promise 对象最终状态和结果

3.优点:

通过链式调用,解决回调函数嵌套问题

总结:

(1)什么是Promise的链式调用?

使用then方法返回新的Promise对象特性,一直串联下去

(2)then回调函数,return的值回传递给那哪里?

传递给then方法生成的新Promise对象

(3)Promise链式调用有什么作用?

解决回调函数嵌套问题

九、解决回调函数地狱

方法:每个 Promise 对象中管理一个异步任务,用 then 返回 Promise 对象,串联起来

核心代码:

javascript 复制代码
let pname = ''
// 1. 得到-获取省份Promise对象
axios({url: 'http://hmajax.itheima.net/api/province'}).then(result => {
  pname = result.data.list[0]
  document.querySelector('.province').innerHTML = pname
  // 2. 得到-获取城市Promise对象
  return axios({url: 'http://hmajax.itheima.net/api/city', params: { pname }})
}).then(result => {
  const cname = result.data.list[0]
  document.querySelector('.city').innerHTML = cname
  // 3. 得到-获取地区Promise对象
  return axios({url: 'http://hmajax.itheima.net/api/area', params: { pname, cname }})
}).then(result => {
  console.log(result)
  const areaName = result.data.list[0]
  document.querySelector('.area').innerHTML = areaName
})

十、async函数和await

1.概念:

在 async 函数内,使用 await 关键字取代 then 函数,等待获取 Promise 对象成功状态的结果值

2.方法:

使用 async 和 await 解决回调地狱问题

3.核心代码:

javascript 复制代码
async function getData() {
  // 2. await等待Promise对象成功的结果
  const pObj = await axios({url: 'http://hmajax.itheima.net/api/province'})
  const pname = pObj.data.list[0]
  const cObj = await axios({url: 'http://hmajax.itheima.net/api/city', params: { pname }})
  const cname = cObj.data.list[0]
  const aObj = await axios({url: 'http://hmajax.itheima.net/api/area', params: { pname, cname }})
  const areaName = aObj.data.list[0]


  document.querySelector('.province').innerHTML = pname
  document.querySelector('.city').innerHTML = cname
  document.querySelector('.area').innerHTML = areaName
}

getData()

十一、async函数和await捕获错误

1.try 和 catch 的作用:语句标记要尝试的语句块,并指定一个出现异常时抛出的响应

javascript 复制代码
try {
  // 要执行的代码
} catch (error) {
  // error 接收的是,错误消息
  /

2.尝试把代码中 url 地址写错,运行观察 try catch 的捕获错误信息能力

总结:try和catch有什么作用?(捕获异常)

捕获同步流程的代码报错信息

十二、事件循环

1.概念:

执行代码和收集异步任务的模型,在调用栈空闲,反复调用任务队列里回调函数的执行机制,就叫事件循环

总结:

(1)什么是事件循环?

执行代码和收集异步任务,在调用栈空闲时,反复调用任务队列里的回调执行机制

(2)为什么有事件循环?

JavaScript是单线程的,为了不阻塞JS引擎,设计执行代码的模型

(3)JavaScript内代码是如何执行的?

执行同步代码,遇到异步代码交给宿主浏览器环境执行

十三、事件循环练习

javascript 复制代码
console.log(1)
setTimeout(() => {
  console.log(2)
}, 0)
function myFn() {
  console.log(3)
}
function ajaxFn() {
  const xhr = new XMLHttpRequest()
  xhr.open('GET', 'http://hmajax.itheima.net/api/province')
  xhr.addEventListener('loadend', () => {
    console.log(4)
  })
  xhr.send()
}
for (let i = 0; i < 1; i++) {
  console.log(5)
}
ajaxFn()
document.addEventListener('click', () => {
  console.log(6)
})
myFn()

打印结果是?

1 5 3 2 4 点击一次document就会执行一次打印6

十四、宏任务与微任务

1.异步任务划分为了

  • 宏任务:由浏览器环境执行的异步代码

  • 微任务:由 JS 引擎环境执行的异步代码

2.输出结果

javascript 复制代码
/**
 * 目标:阅读并回答打印的执行顺序
*/
console.log(1)
setTimeout(() => {
  console.log(2)
}, 0)
const p = new Promise((resolve, reject) => {
  resolve(3)
})
p.then(res => {
  console.log(res)
})
console.log(4)

注意:宏任务每次在执行同步代码时,产生微任务队列,清空微任务队列任务后,微任务队列空间释放!

下一次宏任务执行时,遇到微任务代码,才会再次申请微任务队列空间放入回调函数消息排队

即:一个宏任务包含微任务队列,他们之间是包含关系,不是并列关系

总结:

(1)什么是宏任务?

浏览器执行的异步代码 例如:JS 执行脚本事件,setTimeout/setInterval,AJAX请求完成事件,用户交互事件等

(2)什么是微任务?

JS 引擎执行的异步代码 例如:Promise对象.then()的回调

(3)JavaScript内代码如何执行?

执行第一个 script 脚本事件宏任务,里面同步代码 遇到 宏任务/微任务 交给宿主环境,有结果回调函数进入对应队列 当执行栈空闲时,清空微任务队列,再执行下一个宏任务,从1再来

十五、事件循环经典面试题目

javascript 复制代码
// 目标:回答代码执行顺序
console.log(1)//1
setTimeout(() => {//宏任务
  console.log(2)//5
  const p = new Promise(resolve => resolve(3))//6(宏中微)
  p.then(result => console.log(result))
}, 0)
const p = new Promise(resolve => {
  setTimeout(() => {//宏任务
    console.log(4)//7
  }, 0)
  resolve(5)//3
})
p.then(result => console.log(result))//微任务
const p2 = new Promise(resolve => resolve(6))//4
p2.then(result => console.log(result))//微任务
console.log(7)//2

答案:1 7 5 6 2 3 4

十六、Promise.all静态方法

1.概念:

合并多个 Promise 对象,等待所有同时成功完成(或某一个失败),做后续逻辑

2.语法:

const p = Promise.all([Promise对象, Promise对象, ...])

p.then(result => {

// result 结果: [Promise对象成功结果, Promise对象成功结果, ...]

}).catch(error => {

// 第一个失败的 Promise 对象,抛出的异常对象

})

总结:

什么时候使用Promise.all ?

合并多个Promise对象并等待所有同时成功的结果,如果有一个报错就会最终为失败状态,当需要同时渲染多个接口数据同时到网页上使用。

相关推荐
三十_A4 小时前
【NestJS】HTTP 接口传参的 5 种方式(含前端调用与后端接收)
前端·网络协议·http
Ares-Wang4 小时前
JavaScript》》JS》》ES6》》 数组 自定义属性
开发语言·javascript·es6
几个高兴4 小时前
ES6和CommonJS模块区别
前端
要做朋鱼燕5 小时前
【C++】 Vector容器操作全解析
开发语言·c++·笔记·学习笔记
渊不语5 小时前
Webpack 深入学习指南
前端·webpack
hvinsion5 小时前
零依赖每月工作计划备忘录:高效管理你的每一天
javascript·css·python·开源·html
北京_宏哥5 小时前
《刚刚问世》系列初窥篇-Java+Playwright自动化测试-38-屏幕截图利器-上篇(详细教程)
java·前端·面试
子兮曰5 小时前
🚀别再被JSON.parse坑了!这个深度克隆方案解决了我3年的前端痛点
前端·javascript·全栈
R瑾安5 小时前
VUE基础
前端·javascript·vue.js