传图片文件不能像传文字一样用JSON格式,可以用form-data类型携带文件
1.获取图片文件对象
2.使用FormData(浏览器内置的构造函数)携带图片文件
3.提交表单数据到服务器,返回图片网址
这里可能用到的事件监听器:
change 事件通常用于在 HTML 表单元素的值改变时触发某些操作。最常见的应用场景是 ,
表单可以存储文件数据。为了实现这一目标,需要在HTML的form标签中添加enctype="multipart/form-data"属性。这种编码类型允许表单发送二进制数据,包括文件内容。当用户选择文件并提交表单时,文件数据会被包含在表单的POST请求中,并发送到服务器。服务器端的代码可以解析这个请求,提取出文件数据,并将其存储在服务器上。
- <body>
- <input class="upload" type="file">//选择的文件保存到了文件选择元素里
- <img src="" alt="">
-
- <script src="../form-serialize.js">script>
- <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js">script>
- <script src="../bootstrap-5.3.0-alpha1-dist/js/bootstrap.min.js">script>
- <script>
- const upload = document.querySelector('.upload')
- upload.addEventListener('change', e => {
- const f_d = new FormData()
- f_d.append('img', e.target.files[0])
- axios({
- url: 'http://hmajax.itheima.net/api/uploadimg',
- method: 'post',
- data: f_d
- }).then(result => {
- document.querySelector('img').src=result.data.data.url
-
- })
- })
- script>
- body>

信息设置:
提示框
好像bootstrap的提示框都是构造函数初始化 用show()显示


-
-
- <style>
-
-
- body {
- background-color: #f0f2f5;
- padding: 20px;
- -moz-user-select: none;
- /*火狐*/
- -webkit-user-select: none;
- /*webkit浏览器*/
- -ms-user-select: none;
- /*IE10*/
- -khtml-user-select: none;
- /*早期浏览器*/
- user-select: none;
- font-size: 14px;
- }
-
- .container {
- background-color: #ffffff;
- padding: 20px;
- display: flex;
- padding-left: 0;
- margin: 0 auto;
- min-width: 700px;
- max-width: 1000px;
- border-radius: 2px;
- }
-
- .my-nav {
- width: 200px;
- border-right: 1px solid #f0f0f0;
- list-style: none;
- }
-
- .my-nav li {
- cursor: pointer;
- height: 40px;
- line-height: 40px;
- padding-left: 20px;
- font-size: 14px;
- }
-
- .my-nav li.active {
- background-color: #e9f7fe;
- color: #448ef7;
- border-right: 4px solid #448ef7;
- font-weight: 600;
- }
-
- .content {
- padding-top: 10px;
- /* padding-left: 40px; */
- flex: 1;
- display: flex;
- justify-content: space-evenly;
- }
-
- .content .title {
- font-size: 20px;
- margin-bottom: 30px;
- }
-
- /*.content .info-wrap {
- margin-right: 20px;
- }*/
-
- .content .avatar-box {
- display: flex;
- flex-direction: column;
- align-items: center;
- padding-top: 20px;
- /* flex: 1; */
- padding-top: 55px;
- width: 200px;
- }
-
- .content .avatar-box .avatar-title {
- font-size: 16px;
- text-align: left;
- align-self: flex-start;
- margin: 0;
- }
-
- .content .avatar-box .prew {
- width: 120px;
- height: 120px;
- border-radius: 50%;
- margin-bottom: 15px;
- }
-
- .content .avatar-box label {
- width: 100px;
- height: 30px;
- transition: all .3s;
- box-shadow: 0 2px 0 rgb(0 0 0 / 2%);
- cursor: pointer;
- font-size: 14px;
- border-radius: 2px;
- color: rgba(0, 0, 0, .85);
- border: 1px solid #d9d9d9;
- text-align: center;
- line-height: 30px;
- }
-
- .content .avatar-box label:hover {
- color: #40a9ff;
- border-color: #40a9ff;
- background: #fff;
- }
-
- .content .avatar-box #upload {
- display: none;
- }
-
-
-
- .content .user_form label:not(.male-label) {
- display: block;
- margin-bottom: 15px;
- margin-top: 15px;
- }
-
- .content .user_form .form-item {
- margin-bottom: 20px;
- }
-
- .content .user_form .form-item .male-label {
- margin-right: 20px;
- display: inline-flex;
- align-items: center;
- }
-
- .content .user_form input[type=radio] {
- margin-right: 10px;
- outline: none;
- background-size: contain;
- border: 1px solid rgba(0, 0, 0, .25);
- border-radius: 50%;
- box-sizing: border-box;
- width: 16px;
- height: 16px;
- appearance: none;
-
- }
-
-
-
- .content .user_form input[type=radio]:checked {
- border-radius: 50%;
- border-color: #0d6efd;
- background-color: #0d6efd;
- background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e");
- }
-
-
-
- .content .user_form input:not([type=radio]) {
- height: 30px;
- appearance: none;
- }
-
-
- .form-item input:not([type=radio]),
- textarea {
- display: block;
- width: 330px;
- outline: none;
- font-size: 14px;
- border: 1px solid #d9d9d9;
- border-radius: 2px;
- transition: all .3s;
- padding-left: 5px;
- }
-
- .content .user_form textarea {
- padding-top: 10px;
- width: 350px;
- resize: none;
- }
-
-
-
- .content .user_form input:focus,
- textarea:focus {
- border-color: #40a9ff;
- border-right-width: 1px;
- z-index: 1;
- border-color: #40a9ff;
- box-shadow: 0 0 0 2px rgb(24 144 255 / 20%);
- border-right-width: 1px;
- outline: 0;
- }
-
- .content .user_form button.submit {
- background: #4D8FF7;
- width: 78px;
- height: 32px;
- color: white;
- text-align: center;
- line-height: 32px;
- font-size: 14px;
- color: #FFFFFF;
- letter-spacing: 0;
- font-weight: 500;
- border: none;
- cursor: pointer;
- }
-
- .toast {
- position: fixed;
- top: 20px;
- left: 50%;
- transform: translateX(-50%);
- }
-
- .toast .toast-body {
- padding: 0 !important;
- }
-
- .toast .alert-success {
- margin-bottom: 0 !important;
- }
- style>
-
- head>
-
- <body>
-
- <div class="toast my_toast" data-bs-delay="1500">
- <div class="toast-body">
- <div class="alert alert-success info-box">
- 操作成功
- div>
- div>
- div>
-
- <div class="container">
- <ul class="my-nav">
- <li class="active">基本设置li>
- <li>安全设置li>
- <li>账号绑定li>
- <li>新消息通知li>
- ul>
- <div class="content">
- <div class="info-wrap">
- <h3 class="title">基本设置h3>
- <form class="user_form" action="javascript:;">
- <div class="form-item">
- <label for="email">邮箱label>
- <input id="email" name="email" class="email" type="text" placeholder="请输入邮箱" autocomplete="off">
- div>
- <div class="form-item">
- <label for="nickname">昵称label>
- <input id="nickname" name="nickname" class="nickname" type="text" placeholder="请输入昵称" autocomplete="off">
- div>
- <div class="form-item">
- <label>性别label>
- <label class="male-label"><input type="radio" name="gender" class="gender" value="0">男label>
- <label class="male-label"><input type="radio" name="gender" class="gender" value="1">女label>
- div>
- <div class="form-item">
- <label for="desc">个人简介label>
- <textarea id="desc" name="desc" class="desc" placeholder="请输入个人简介" cols="20" rows="10"
- autocomplete="off">textarea>
- div>
- <button class="submit">提交button>
- form>
- div>
- <div class="avatar-box">
- <h4 class="avatar-title">头像h3>
- <img class="prew" src="../img/头像.png" alt="">
- <label for="upload">更换头像label>
- <input id="upload" type="file" class="upload">
- div>
-
- div>
- div>
- <script src="../form-serialize.js">script>
- <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js">script>
- <script src="../bootstrap-5.3.0-alpha1-dist/js/bootstrap.min.js">script>
- <script>
- const user_form = document.querySelector('.user_form')
- axios({ //渲染页面
- url: 'http://hmajax.itheima.net/api/settings',
- params: {
- creator: 'wwx'
- }
- }).then(result => {
- const obj = result.data.data
- for (let key in obj) {
- if (key === 'avatar') {
- document.querySelector('.prew').src = obj[key]
- }
- else if (key === 'gender') {
- const gender = document.querySelectorAll('.gender')
- gender[obj[key]].checked = 'true'
- } else {
- document.querySelector(`.${key}`).value = obj[key]
- }
- }
- })
-
- const upload = document.querySelector('.upload')
- upload.addEventListener('change', e => {
- const fd = new FormData()
- fd.append('avatar', e.target.files[0])
- fd.append('creator', 'wwx')
- axios({
- url: 'http://hmajax.itheima.net/api/avatar',
- method: 'put',
- data: fd
- }).then(result => {
- document.querySelector('.prew').src = result.data.data.avatar
- })
- })
-
- document.querySelector('.submit').addEventListener('click', () => {//修改
- const obj = serialize(user_form, { hash: true, empty: true })
- obj.gender = +obj.gender
- obj.creator = 'wwx'
- axios({
- url: 'http://hmajax.itheima.net/api/settings',
- method: 'put',
- data: obj
- }).then(result => {
- const my_toast= document.querySelector('.my_toast')
- const toast=new bootstrap.Toast(my_toast)
- toast.show()
- })
- })
-
-
-
- script>
- body>

该对象用于与服务器交互。
axios对XHR封装,其内部就是采用XHR与服务器交互

查询参数
http://xxx.com/xxx/xxx?参数名1=值1&参数名2=值
可以自动生成字符串

用于表示一个异步操作的最终完成及其结果值
promise的三种状态:
待定(pending):初始状态,即没有被兑现,也没有被拒绝
已兑现(fulfilled):操作成功完成
以拒绝(rejected):操作失败
有了Promise对象,就可以把异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供了统一的接口,使得控制异步操作更加容易。Promise通过将异步操作的结果封装在一个对象中,使得我们可以更加清晰和简洁地处理异步操作。
异步任务有结果后,与处理函数相关联
- // 假设 fetchData 是一个返回 Promise 的函数
- function fetchData(url) {
- return new Promise((resolve, reject) => {
- // 模拟异步操作
- setTimeout(() => {
- const data = `Data from ${url}`;
- resolve(data);
- }, 1000);
- });
- }
-
- // 使用 Promise 链式调用
- fetchData('https://example.com/api/data1')
- .then(data1 => {
- console.log(data1);
- return fetchData('https://example.com/api/data2'); // 返回新的 Promise
- })
- .then(data2 => {
- console.log(data2);
- // 可以继续添加更多的异步操作...
- })
- .catch(error => {
- console.error('An error occurred:', error);
- });
不用过渡嵌套返回信息
- function myaxios(obj) {
- return new Promise((resolve, reject) => {
- const xhr = new XMLHttpRequest()
- xhr.open(obj.method || 'get', obj.url)
- if (obj.params) {
- const paramsobj = new URLSearchParams(obj.params)
- const parame_string = paramsobj.toString()
- obj.url += `?${parame_string}`
- }
- xhr.addEventListener('loadend', () => {
- if (xhr.status >= 200 && xhr.status <= 300)
- resolve(JSON.parse(xhr.response))
- else
- reject(new Error(xhr.response))
- })
- if (obj.data) {
- xhr.setRequestHeader('Content-Type', 'application/json')//设置请求头
- const data_srting = JSON.stringify(obj.data)
- xhr.send(data_srting)//发送请求体
- } else {
- xhr.send()
- }
-
- })
- }
同步代码与异步代码
同步代码
代码按顺序一行一行执行,上一行执行完才会执行下一行
异步代码
耗时,不必等待任务完成,异步代码完成后,会用回调函数回传
依靠then()方法返回一个新生成的promise对象特性,继续串联下一个任务,直到结束
创建的promise方法调用then方法,then具有回调函数,return的结果可以传递给then产生的新promise对象
我们可以使用then函数返回的新promise对象特征,一直串联,解决函数嵌套

基于promise,而无需调用
用async声明该函数为异步函数,在函数内,使用await获取promise对象成功状态结果值

执行代码和收集异步任务的模型,在调用栈空闲时,反复调用任务队列里回调函数的机制
js执行同步代码,遇到异步代码交给宿主浏览器环境运行
宏任务:由浏览器环境执行的异步代码
| 任务 | 执行所在代码 |
|---|---|
| js脚本执行事件 | 浏览器 |
| 定时器 | 浏览器 |
| Ajax请求的完成事件 | 浏览器 |
| 用户交互事件 | 浏览器 |
微任务:由js引擎环境执行的异步代码
promise.then()
promise本身是同步的,而then和catch回调函数是异步的
promise.all
合并多个promise对象,等待所有同时成功完成(或有一个失败),做后续逻辑
- const p=Promise.all([Promise对象,Promise对象,Promise对象...])
- p.then(result => {
- //result结果:[Promise成功结果,Promise成功结果,Promise成功结果...]
- }).catch(error => {
- //第一个失败的Promise对象,抛出的异常
- })