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

相关推荐
G_G#4 分钟前
纯前端js插件实现同一浏览器控制只允许打开一个标签,处理session变更问题
前端·javascript·浏览器标签页通信·只允许一个标签页
@大迁世界20 分钟前
TypeScript 的本质并非类型,而是信任
开发语言·前端·javascript·typescript·ecmascript
ljt272496066124 分钟前
Compose笔记(六十九)--Pager
笔记
GIS之路28 分钟前
GDAL 实现矢量裁剪
前端·python·信息可视化
是一个Bug32 分钟前
后端开发者视角的前端开发面试题清单(50道)
前端
Amumu1213834 分钟前
React面向组件编程
开发语言·前端·javascript
koo3641 小时前
pytorch深度学习笔记13
pytorch·笔记·深度学习
持续升级打怪中1 小时前
Vue3 中虚拟滚动与分页加载的实现原理与实践
前端·性能优化
GIS之路1 小时前
GDAL 实现矢量合并
前端
hxjhnct1 小时前
React useContext的缺陷
前端·react.js·前端框架