外观

02_Bootstrap 弹框 + 图片上传
01_Bootstrap 弹框
01_属性控制显示隐藏
01_属性控制显示隐藏
功能: 不离开当前页面, 显示单独内容, 供用户操作
步骤:
- 引入 bootstrap.css 和 bootstrap.js
- 准备
弹框标签
, 确认结构- 通过
自定义属性
, 控制弹框的显示
和隐藏

html
<!-- /code/test.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 1.引入 bootstrap.css -->
<link href="./Bootstrap/Bootstrap5.2.2.css" rel="stylesheet">
</head>
<body>
<!-- 4.通过自定义属性, 控制弹框的显示和隐藏, 显示弹框: data-bs-toggle="modal" data-bs-target="css 选择器" -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target=".my-box">
显示弹框
</button>
<!-- 3.弹框标签: bootstrap 的 modal 弹框, 添加 modal 类名 (默认隐藏) -->
<div class="modal my-box" tabindex="-1">
<div class="modal-dialog">
<!-- 弹框-内容 -->
<div class="modal-content">
<!-- 弹框-头部 -->
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<!-- 5.关闭弹框: data-bs-dismiss="modal" -->
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<!-- 弹框-身体 -->
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
<!-- 弹框-底部 -->
<div class="modal-footer">
<!-- 6.关闭弹框: data-bs-dismiss="modal" -->
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
<!-- 2.引入 bootstrap.js -->
<script src="./Bootstrap/Bootstrap 5.2.2.js"></script>
</body>
</html>
02_JS 控制显示隐藏
01_JS 控制显示隐藏
- 通过属性控制, 弹框显示或隐藏
单纯显示/隐藏
- 通过
JS
控制, 弹框显示或隐藏额外逻辑代码

html
<!-- /code/test.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 引入 bootstrap.css -->
<link href="./Bootstrap/Bootstrap5.2.2.css" rel="stylesheet">
</head>
<body>
<button type="button" class="btn btn-primary edit-btn">
编辑姓名
</button>
<!-- 弹框标签 -->
<div class="modal name-box" tabindex="-1">
<div class="modal-dialog">
<!-- 弹框-内容 -->
<div class="modal-content">
<!-- 弹框-头部 -->
<div class="modal-header">
<h5 class="modal-title">请输入姓名</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<!-- 弹框-身体 -->
<div class="modal-body">
<form action="">
<span>姓名: </span>
<input type="text" class="username">
</form>
</div>
<!-- 弹框-底部 -->
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-primary save-btn">保存</button>
</div>
</div>
</div>
</div>
<!-- 引入 bootstrap.js -->
<script src="./Bootstrap/Bootstrap 5.2.2.js"></script>
<script>
// 1.创建弹框对象
const modalDom = document.querySelector('.name-box')
const modal = new bootstrap.Modal(modalDom)
// 2.编辑姓名 ==> 点击 ==> 赋予默认姓名 ==> 弹框显示
document.querySelector('.edit-btn').addEventListener('click', () => {
document.querySelector('.username').value = '默认姓名'
// 3.显示弹框
modal.show()
})
// 4.保存 ==> 点击 ==> 获取姓名打印 ==> 弹框隐藏
document.querySelector('.save-btn').addEventListener('click', () => {
const username = document.querySelector('.username').value
console.log('模拟把姓名保存到服务器上', username)
// 5.隐藏弹框
modal.hide()
})
</script>
</body>
</html>
02_图书管理
01_渲染列表
01_渲染列表
自己的图书数据: 给自己起个 外号
, 并告诉服务器, 默认会有三本书, 基于这三本书做数据的 增删改查

javascript
// /code/js/index.js
const creator = '老张'
// 1.封装 获取并渲染图书列表函数
function getBooksList() {
// 3.获取数据
axios({
url: 'http://hmajax.itheima.net/api/books',
params: {
creator // 外号: 获取对应数据
}
}).then(result => {
const bookList = result.data.data
// 4.渲染数据
const htmlStr = bookList.map((item, index) => {
return `<tr>
<td>${index + 1}</td>
<td>${item.bookname}</td>
<td>${item.author}</td>
<td>${item.publisher}</td>
<td data-id=${item.id}>
<span class="del">删除</span>
<span class="edit">编辑</span>
</td>
</tr>`
}).join('')
document.querySelector('.list').innerHTML = htmlStr
})
}
// 2.网页加载运行, 获取并渲染列表一次
getBooksList()
02_新增图书
01_新增图书

javascript
// /code/js/index.js
// 1.创建弹框对象
const addModalDom = document.querySelector('.add-modal')
const addModal = new bootstrap.Modal(addModalDom)
// 2.保存按钮 ==> 点击 ==> 隐藏弹框
document.querySelector('.add-btn').addEventListener('click', () => {
// 3.收集表单数据, 并提交到服务器保存
const addForm = document.querySelector('.add-form')
const bookObj = serialize(addForm, { hash: true, empty: true })
// 4.提交到服务器
axios({
url: 'http://hmajax.itheima.net/api/books',
method: 'POST',
data: {
...bookObj,
creator
}
}).then(result => {
// 5.添加成功后, 重新请求并渲染图书列表
getBooksList()
addForm.reset() // 重置表单
addModal.hide() // 隐藏弹框
})
})
03_删除图书
01_删除图书

javascript
// /code/js/index.js
// 1.删除元素 ==> 点击 (事件委托)
document.querySelector('.list').addEventListener('click', e => {
// 2.获取触发事件目标元素
// console.log(e.target)
// 3.判断点击的是删除元素
if (e.target.classList.contains('del')) {
// 4.获取图书 id (自定义属性 id)
const theId = e.target.parentNode.dataset.id
// 5.调用删除接口
axios({
url: `http://hmajax.itheima.net/api/books/${theId}`,
method: 'DELETE'
}).then(() => {
// 6.刷新图书列表
getBooksList()
})
}
})
04_编辑图书 弾框准备
01_编辑图书 弾框准备

javascript
// /code/js/index.js
// 1.编辑弹框 ==> 显示和隐藏
const editDom = document.querySelector('.edit-modal')
const editModal = new bootstrap.Modal(editDom)
// 2.编辑元素 ==> 点击 ==> 弹框显示
document.querySelector('.list').addEventListener('click', e => {
// 3.判断点击的是否为编辑元素
if (e.target.classList.contains('edit')) {
editModal.show() // 显示弹框
}
})
// 4.修改按钮 ==> 点击 ==> 隐藏弹框
document.querySelector('.edit-btn').addEventListener('click', () => {
editModal.hide() // 隐藏弹框
})
05_编辑图书 数据回显
01_编辑图书 数据回显

javascript
// /code/js/index.js
// 编辑弹框 ==> 显示和隐藏
const editDom = document.querySelector('.edit-modal')
const editModal = new bootstrap.Modal(editDom)
// 编辑元素 ==> 点击 ==> 弹框显示
document.querySelector('.list').addEventListener('click', e => {
// 判断点击的是否为编辑元素
if (e.target.classList.contains('edit')) {
// 1.获取当前编辑图书数据 ==> 回显到编辑表单中
const theId = e.target.parentNode.dataset.id
axios({
url: `http://hmajax.itheima.net/api/books/${theId}`
}).then(result => {
const bookObj = result.data.data
// 2.数据对象 "属性" 和标签 "类名" 一致; 遍历数据对象, 使用属性去获取对应的标签, 快速赋值
const keys = Object.keys(bookObj) // ['id', 'bookname', 'author', 'publisher']
keys.forEach(key => {
document.querySelector(`.edit-form .${key}`).value = bookObj[key]
})
})
editModal.show() // 显示弹框
}
})
// 修改按钮 ==> 点击 ==> 隐藏弹框
document.querySelector('.edit-btn').addEventListener('click', () => {
editModal.hide() // 隐藏弹框
})
06_编辑图书 保存修收
01_编辑图书 保存修收

javascript
// /code/js/index.js
// 编辑弹框 ==> 显示和隐藏
const editDom = document.querySelector('.edit-modal')
const editModal = new bootstrap.Modal(editDom)
// 编辑元素 ==> 点击 ==> 弹框显示
document.querySelector('.list').addEventListener('click', e => {
// 判断点击的是否为编辑元素
if (e.target.classList.contains('edit')) {
// 获取当前编辑图书数据 ==> 回显到编辑表单中
const theId = e.target.parentNode.dataset.id
axios({
url: `http://hmajax.itheima.net/api/books/${theId}`
}).then(result => {
const bookObj = result.data.data
// 数据对象 "属性" 和标签 "类名" 一致; 遍历数据对象, 使用属性去获取对应的标签, 快速赋值
const keys = Object.keys(bookObj) // ['id', 'bookname', 'author', 'publisher']
keys.forEach(key => {
document.querySelector(`.edit-form .${key}`).value = bookObj[key]
})
})
editModal.show() // 显示弹框
}
})
// 修改按钮 ==> 点击 ==> 隐藏弹框
document.querySelector('.edit-btn').addEventListener('click', () => {
// 1.提交保存修改, 并刷新列表
const editForm = document.querySelector('.edit-form')
const { id, bookname, author, publisher } = serialize(editForm, { hash: true, empty: true})
// 2.保存正在编辑的图书 id, 隐藏起来: 无需让用户修改
// <input type="hidden" class="id" name="id" value="84783">
axios({
url: `http://hmajax.itheima.net/api/books/${id}`,
method: 'PUT',
data: {
bookname,
author,
publisher,
creator
}
}).then(() => {
// 3.修改成功以后, 重新获取并刷新列表
getBooksList()
editModal.hide() // 隐藏弹框
})
})
07_总结
01_渲染数据

02_新增数据

03_删除数据

04_编辑数据


03_图片上传
01_图片上传
01_图片上传
获取 图片文件
对象
使用 FormData
携带图片文件

提交表单数据到服务器, 使用 图片 url 网址

html
<!-- /code/test.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 文件选择元素 -->
<input type="file" class="upload">
<img src="" alt="" class="my-img">
<script src="/js/axios1.2.0.js"></script>
<script>
// 1.文件选择元素 ==> change 改变事件
document.querySelector('.upload').addEventListener('change', e => {
// 2.获取图片文件
// console.log(e.target.files[0])
// 3.使用 FormData 携带图片文件
const fd = new FormData()
fd.append('img', e.target.files[0])
// 4.提交到服务器, 获取图片 url 网址使用
axios({
url: 'http://hmajax.itheima.net/api/uploadimg',
method: 'POST',
data: fd
}).then(result => {
console.log(result)
// 5.取出图片 url 网址, 用 img 标签加载显示
const imgUrl = result.data.data.url
document.querySelector('.my-img').src = imgUrl
})
})
</script>
</body>
</html>
02_网站更换背景案例
01_网站更换背景案例
- 选择
图片上传
, 设置 body 背景- 上传成功时,
保存
url 网址- 网页运行后,
获取
url 网址使用

javascript
// /code/js/index.js
document.querySelector('.bg-ipt').addEventListener('change', e => {
// 1.选择图片上传, 设置 body 背景
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')
bgUrl && (document.body.style.backgroundImage = `url(${bgUrl})`)
04_个人信息设置
01_介绍
01_步骤
- 信息渲染
- 头像修改
- 提交表单
- 结果提示

02_信息渲染
01_信息渲染
自己的用户信息: 给自己起个 外号
, 并告诉服务器, 获取对应的用户信息

javascript
// /code/js/index.js
// 1.信息渲染 获取用户的数据
const creator = '播仔'
axios({
url: 'http://hmajax.itheima.net/api/settings',
params: {
creator
}
}).then(result => {
const userObj = result.data.data
// 2.回显数据到标签上
Object.keys(userObj).forEach(key => {
if (key === 'avatar') {
// 赋予默认头像
document.querySelector('.prew').src = userObj[key]
} else if (key === 'gender') {
// 赋予默认性别 获取性别单选框: [男 radio 元素, 女 radio 元素]
const gRadioList = document.querySelectorAll('.gender')
// 获取性别数字: 0 男, 1 女
const gNum = userObj[key]
// 通过性别数字, 作为下标, 找到对应性别单选框, 设置选中状态
gRadioList[gNum].checked = true
} else {
// 赋予默认内容
document.querySelector(`.${key}`).value = userObj[key]
}
})
})
03_头像修改
01_头像修改

javascript
// /code/js/index.js
// 1.修改头像 文件选择元素 ==> change 事件
document.querySelector('.upload').addEventListener('change', e => {
// 2.获取头像文件
const fd = new FormData()
fd.append('avatar', e.target.files[0])
fd.append('creator', creator)
// 3.提交服务器并更新头像
axios({
url: 'http://hmajax.itheima.net/api/avatar',
method: 'PUT',
data: fd
}).then(result => {
const imgUrl = result.data.data.avatar
// 4.把新的头像回显到页面上
document.querySelector('.prew').src = imgUrl
})
})
04_信息修改
01_信息修改

javascript
// /code/js/index.js
// 1.提交表单 保存修改 ==> 点击
document.querySelector('.submit').addEventListener('click', () => {
// 2.收集表单信息
const userForm = document.querySelector('.user-form')
const userObj = serialize(userForm, { hash: true, empty: true })
userObj.creator = creator
userObj.gender = +userObj.gender // 性别数字 字符串, 转成数字类型
// 3.提交到服务器保存
axios({
url: 'http://hmajax.itheima.net/api/settings',
method: 'PUT',
data: userObj
})
})
05_Bootstrap 提示框
01_Bootstrap 提示框

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