阳光总在风雨后,请相信有彩虹。
需求,点击添加按钮,没有离开当前页面,在当前页面弹出弹框(弹窗)
先学着实现一个简单的弹框,如下图右下角
bootstrap有两种方式控制弹框的显示和隐藏
1.引入bootstrap.css和bootstrap.js
并准备好显示弹框的按钮
2.准备弹框标签,确认结构
来到bootstrap文档,搜索modal(情态的、模式的)
Modal模态框
Bootstrap 模态框(Modal)插件的基本应用-Web前端开发资源网
点击复制,获取结构
复制过来后,到网页看,发现并没有出现弹框,查看样式发现有
display: none;
该display属性属于modal类
且默认隐藏
弹框整体结构
如何实现显示弹框?——bootstrap内部已经提供一些控制显示和隐藏的(自定义)属性
两个属性,分别是 data-bs-toggle 和 data-bs-target
data-bs-toggle="modal" :点击会出来一个modal弹框(注意:不是.modal类选择器)
data-bs-target="css选择器":一个网页里面可能会有多个弹框,需要传入 某个需要点击弹出的弹框的css选择器。
实操如下
控制隐藏
可在弹框头部的×号button元素看到,结构已经携带该属性
data-bs-dismiss="modal"
默认×号可关闭弹窗
删除该属性则×号关闭失效
Bootstrap 弹框
用属性控制不好吗,不够吗?
使用属性控制,在显示和隐藏时无法执行其他额外的JS逻辑
以下代码可以控制弹框的显示和隐藏
实操代码:
Bootstrap 弹框
案例-图书管理
图书管理
序号
书名
作者
出版社
操作
1
JavaScript程序设计
马特·弗里斯比
人民邮电出版社
删除
编辑
引入相关css文件
相关js文件
根据接口文档,书写axios获取数据
再渲染数据
新增图书核心代码:
/**
* 目标2:新增图书
* 2.1 新增弹框->显示和隐藏
* 2.2 收集表单数据,并提交到服务器保存
* 2.3 刷新图书列表
*/
// 2.1 创建弹框对象
const addModalDom = document.querySelector('.add-modal')
const addModal = new bootstrap.Modal(addModalDom)
// 保存按钮->点击->隐藏弹框
document.querySelector('.add-btn').addEventListener('click', () => {
// 2.2 收集表单数据,并提交到服务器保存
const addForm = document.querySelector('.add-form')
const bookObj = serialize(addForm, { hash: true, empty: true })
// console.log(bookObj)
// 提交到服务器
axios({
url: 'http://hmajax.itheima.net/api/books',
method: 'POST',
data: {
...bookObj,
creator
}
}).then(result => {
// console.log(result)
// 2.3 添加成功后,重新请求并渲染图书列表
getBooksList()
// 重置表单
addForm.reset()
// 隐藏弹框
addModal.hide()
})
})
/**
* 目标3:删除图书
* 3.1 删除元素绑定点击事件->获取图书id
* 3.2 调用删除接口
* 3.3 刷新图书列表
*/
// 3.1 删除元素->点击(事件委托)
document.querySelector('.list').addEventListener('click', e => {
// 获取触发事件目标元素
// console.log(e.target)
// 判断点击的是删除元素
if (e.target.classList.contains('del')) {
// console.log('点击删除元素')
// 获取图书id(自定义属性id)
const theId = e.target.parentNode.dataset.id
// console.log(theId)
// 3.2 调用删除接口
axios({
url: `http://hmajax.itheima.net/api/books/${theId}`,
method: 'DELETE'
}).then(() => {
// 3.3 刷新图书列表
getBooksList()
})
}
})
本次调用删除接口,需要在path路径上传参,method为delete
发送axios完成图书删除后,别忘了刷新列表(在then中刷新)
回显图书信息
需要用到的接口,查询图书详情接口,显示到编辑弹框里。
查询到的数据对象的属性名和 标签的类名 一致
我们可以遍历数据对象,使用属性去获取对应的标签,快速赋值
提交修改时,获取修改信息
观察表单,为什么会出现id?
存在隐藏的表单域id
可以不写吗?为什么隐藏?
——需要提交修改,需要携带图书id
——不能让用户看见,不然用户可以修改
因为存在id表单域,可被serialize收集到
使用修改图书详情接口,
先把serialize获取到的表单数据(对象)解构出来,再放入请求体,
前面已经定义好了外号creator
编辑图书核心代码:
/**
* 目标4:编辑图书
* 4.1 编辑弹框->显示和隐藏
* 4.2 获取当前编辑图书数据->回显到编辑表单中
* 4.3 提交保存修改,并刷新列表
*/
// 4.1 编辑弹框->显示和隐藏
const editDom = document.querySelector('.edit-modal')
const editModal = new bootstrap.Modal(editDom)
// 编辑元素->点击->弹框显示
document.querySelector('.list').addEventListener('click', e => {
// 判断点击的是否为编辑元素
if (e.target.classList.contains('edit')) {
// 4.2 获取当前编辑图书数据->回显到编辑表单中
const theId = e.target.parentNode.dataset.id
axios({
url: `http://hmajax.itheima.net/api/books/${theId}`
}).then(result => {
const bookObj = result.data.data
// document.querySelector('.edit-form .bookname').value = bookObj.bookname
// document.querySelector('.edit-form .author').value = bookObj.author
// 数据对象“属性”和标签“类名”一致
// 遍历数据对象,使用属性去获取对应的标签,快速赋值
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', () => {
// 4.3 提交保存修改,并刷新列表
const editForm = document.querySelector('.edit-form')
const { id, bookname, author, publisher } = serialize(editForm, { hash: true, empty: true})
// 保存正在编辑的图书id,隐藏起来:无需让用户修改
//
axios({
url: `http://hmajax.itheima.net/api/books/${id}`,
method: 'PUT',
data: {
bookname,
author,
publisher,
creator
}
}).then(() => {
// 修改成功以后,重新获取并刷新列表
getBooksList()
// 隐藏弹框
editModal.hide()
})
})
上传图片接口请求体所需数据类型不再是application-json而是form-data
为文件类型,图片文件file不能直接转成json格式。
使用input元素(type="file")供用户选择上传文件,
使用change监听事件,
通过e.target获取表单元素,
通过files属性获得一个文件伪数组,
打印文件对象:
使用FormData携带图片文件,
根据接口文档在axios中传入数据:
选择图片并发送axios请求,
到控制台查看本次请求,
点击请求,打开载荷,
图片文件浏览器进行了格式化(二进制)
再看到服务器的响应,已返回图片地址
使用图片地址,展示图片
使用label标签(样式容易修改)的for属性关联input标签的id
设置成功后进行本地存储,注意,每次打开页面时需要判断,
本地存有背景图地址才进行设置(使用逻辑与的短路特性):
但逻辑与的运算符优先级高于赋值运算符,需要添加小括号
gbUrl && (document.body.style.backgroundImage = `url(${bgUrl})`)
实操代码:
/**
* 目标:网站-更换背景
* 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})`)
/**
* 目标1:信息渲染
* 1.1 获取用户的数据
* 1.2 回显数据到标签上
* */
const creator = '播仔'
// 1.1 获取用户的数据
axios({
url: 'http://hmajax.itheima.net/api/settings',
params: {
creator
}
}).then(result => {
const userObj = result.data.data
// 1.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]
}
})
})
/**
* 目标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
})
})
和模态框使用方法相似
提示框结构
核心JS代码
/**
* 目标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()
})
})
HTML文件
个人信息设置
操作成功
- 基本设置
- 安全设置
- 账号绑定
- 新消息通知
基本设置
头像