英雄案例
目标
回顾ajax方法的使用
数据动态渲染的流程
体会ajax可以实现页面的局部刷新
掌握数据的完整的增加删除修改和查询
了解模态框的使用
初步理解数据操作的细节
整个页面效果是基于bootstrap
实现数据的动态渲染
静态结构 》 查阅接口文档 》 ajax请求获取数据 》分析数据 》 拼接生成动态结构(模板引擎) 》填充到指定位置
页面一加载就需要发起请求获取数据,实现动态渲染
查阅接口文档
02-英雄信息管理 - 1获取所有英雄-Ajax课程 > http://127.0.0.1:3001/getHeroList
请求方式:get
请求参数:heroName,参数如果不传递则获取所有数据,如果传递则获取满足条件的数据
说明:数据渲染和查询本质都是查询,区别在于是否有条件
动态渲染
let tbody = this.document.querySelector('#tbody')
// 1.实现数据的渲染--封装为一个函数,后期复用
function init() {
// 发起请求
axios({
url: 'http://127.0.0.1:3001/getHeroList'
}).then(res => {
let data = res.data.data
// 遍历拼接
let htmlStr = ''
data.forEach(function(value, index) {
htmlStr += `<tr>
<td>${index + 1}</td>
<td>${value.name}</td>
<td>${value.gender}</td>
<td>
<img
src="${value.img}"
alt=""
/>
</td>
<td>
<button type="button" class="btn btn-info">
上传头像
</button>
<button type="button" class="btn btn-warning">
删除
</button>
</td>
</tr>`
})
tbody.innerHTML = htmlStr
})
}
init()
实现数据的查询
查询的本质也是数据获取
如果没有参数就是全部获取,如果有参数就是查询,本质上都是发起同一个请求,只是参数不一样,所以我们可以将获取数据的操作封装为一个函数,将用户关键字做为函数的参数
1.获取用户关键字
2.单击按钮,发起ajax请求,同时将用户关键字做为参数传递
代码实现
function init(key = '') {
// 发起请求
axios({
url: 'http://127.0.0.1:3001/getHeroList',
params: { heroName: key }
}).then(res => {
let data = res.data.data
// 遍历拼接
let htmlStr = ''
data.forEach(function(value, index) {
htmlStr += `<tr>
<td>${index + 1}</td>
<td>${value.name}</td>
<td>${value.gender}</td>
<td>
<img
src="${value.img}"
alt=""
/>
</td>
<td>
<button type="button" class="btn btn-info">
上传头像
</button>
<button type="button" class="btn btn-warning">
删除
</button>
</td>
</tr>`
})
tbody.innerHTML = htmlStr
})
}
init()
// 搜索也是查询操作(渲染,搜索,分页)
btn_search.addEventListener('click', function() {
let key = hname.value
init(key)
})
说明
1.为什么没有会参数时,也能正确的查询到所有值
答:因为任何字符串都包含空字符串
2.后台是如何实现查询业务的
答:后台是使用模糊查询,只要包含你输入的用户关键字,就能获取到对应的结果
英雄数据的新增
一:弹出模态框
- 了解bootstrap文档的使用方式
- 在页面中先添加一个模态框
- 能够弹出模态框
- 制作模态框
二:实现英雄数据的新增
- 查阅接口文档,确定你需要收集的数据
- 发起ajax请求
- 。。。
添加新增英雄模态框
模态框应该做为body的直接子元素
不要同时弹出多个模态框
直接拷贝模态框的基本代码
打开模态框
- data属性设置弹出模态框
- data-toggle="modal":说明它是一个手风琴效果的模态框
- data-target="#myModal":指定当前载体所关联的模态框
- 说明:myModal就模态框的id,可以自定义
- 在新增按钮中添加这两个属性
- js方式弹出模态框
- 有些场景,我们不仅仅只需要弹出模态框,而且还要进行其它的一些业务处理
- 错误细节:如果发现模态框一闪而过,一般是因为你同时使用属性和js方式弹出同一个模态框
制作模态框
- 模态框分为上中下三块结构,分别代码标题,内容,底部按钮
- 主体内容的表单元素来自于 全局css样式 》 表单
- 注册结构要闭合
模态框的添加
<!-- 新增英雄模态框 -->
<div class="modal fade" id="addHeroModal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">添加英雄</h4>
</div>
<div class="modal-body">
<form class="form-horizontal">
<div class="form-group">
<label for="heroname" class="col-sm-2 control-label"
>英雄名称</label
>
<div class="col-sm-10">
<input
type="text"
class="form-control"
id="heroname"
placeholder="请输入英雄名称"
/>
</div>
</div>
<div class="form-group">
<label for="gender" class="col-sm-2 control-label"
>英雄性别</label
>
<div class="col-sm-10">
<select class="form-control" id='gender'>
<option>男</option>
<option>女</option>
</select>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
取消
</button>
<button type="button" class="btn btn-success">确定</button>
</div>
</div>
</div>
</div>
实现英雄的新增
- 收集用户数据
- 发起ajax请求
下拉列表的基本特性
整体说明:获取表单元素的值本质就是获取它的value值,对于下拉列表,一种是给用户看的值,一种是给程序员使用的值
- option标签之间的内容是给用户看值
- option的value属性是下拉列表选项的实际值
1.如果下拉列表的option选项没有设置value属性,则获取option标签之间的内容
2.如果下拉列表的option选项设置了value属性,则优先获取value属性的值
实现新增
btnAdd.addEventListener('click', function() {
// 收集数据
let name = heroname.value
let gender = herogender.value
// axios请求
// axios({
// method: 'post',
// url: 'http://127.0.0.1:3001/addHero',
// data: `name=${name}&gender=${gender}`
// })
axios
.post('http://127.0.0.1:3001/addHero', `name=${name}&gender=${gender}`)
.then(res => {
console.log(res)
if (res.data.code == 200) {
alert(res.data.msg)
// 关闭模态框
$('#addHeroModal').modal('hide')
// 重新渲染
init()
}
})
})
英雄数据的删除
- 查阅接口文档,我们发现接口文档明确告诉我们,删除数据的时候需要传入一个参数id--删除操作一定要考虑是否有条件,如果没有条件就会删除所有数据
- 这个id就是能够唯一标识你想删除的数据
- 所以,我们发现,删除最重新的前提是:获取当前你想删除的数据的id
事件绑定
动态生成的元素的事件绑定应该使用事件委托,因为异步非阻塞,所以直接为删除按钮绑定事件的时候,html结构还没有生成 ,所以才需要使用事件委托
// 实现英雄数据的删除
// 动态生成的元素的事件绑定需要使用事件委托
tbody.addEventListener('click', function(e) {
if (e.target.classList.contains('btndel')) {
axios({
url: '/delHeroById',
method: 'get',
params: { id: e.target.dataset.id }
}).then(res => {
alert(res.data.msg)
init()
})
}
})
实现删除操作
删除操作最关键的问题在于获取当前你想删除的数据的id
意味着:你做一个操作需要使用到一个变量(数据),那么
1.能传递参数就传递参数
2.如果不能传递参数就先存储再获取:如何存储,存储在那里?如何获取
在渲染的时候,在删除按钮中添加自定义属性存储id
<button type="button" class="btn btn-warning btndel" data-id='${value.id}'> 删除 </button>
在单击“删除"按钮的时候,获取里面存储的id号
上传头像-编辑
添加编辑用户的模态框
为编辑按钮添加委托事件
这个操作的本质是编辑用户头像信息,所以它有两个操作
1.上传文件
2.更新用户信息--编辑操作
实现文件上传
-
收集文件数据
let myfile = document.querySelector('#heroImg').files[0] // 使用formdata收集文件数据 let formdata = new FormData() // 键:后台接口的参数名称 // 值:可以是任意类型的数据,当然也包含文件 // formdata.append(键,值) // formdata.append('file_data',文件对象) formdata.append('file_data', myfile)
-
发起ajax请求
// 实现文件上传 btnHeroEdit.addEventListener('click', function() { // 一:实现文件上传 // 1.文件数据的收集需要使用formdata // 2.收集所有表单元素的数据: new FormData(form),还可以只收集文件数据: formdata.append(key,File对象) let myfile = heroImg.files[0] if (!myfile) return let formdata = new FormData() formdata.append('file_data', myfile) // 发起axios请求 axios({ method: 'post', url: 'http://127.0.0.1:3001/uploadFile', data: formdata }).then(res => { // console.log(res) if (res.data.code == 200) { alert(res.data.msg) // res.data.src:文件上传成功之后,在服务器端的存储路径,我们就是将这个路径更新到用户信息 // console.log(res.data.src) // 二:接下来要实现用户头像的s编辑 } }) })
实现用户头像的编辑
看接口文档
编辑操作有一个特点:你传递什么参数,就进行什么编辑
重点说明:编辑操作一定要考虑是否有条件,因为如果没有传递条件,就会更新所有数据,所以我们的编辑操作必须传递id
意味着我们更新用户头像最少需要传递两个参数
- id:当前英雄数据的id,我们可以在按钮中添加自定义属性的存储,单击按钮之后,获取id,将其存储到一个变量中,供请求来使用
- img:来自于文件上传成功之后,服务器所返回的路径
id的处理
-
添加列表中的”上传文件“按钮的自定义属性存在
<button type="button" class="btn btn-info btnEdit" data-id='${value.id}'> 上传头像 </button>
-
单击列表中的”上传文件“按钮,获取自定义属性,并转存到一个公共变量中
// 打开上传文件模态框:只是打开上传文件的模态框,并没有做上传文件的操作,:动态生成的元素的事件绑定需要使用事件委托 tbody.addEventListener('click', function(e) { if (e.target.classList.contains('btnupload')) { $('#uploadImgModal').modal('show') editId = e.target.dataset.id } })
-
在编辑用户信息的时候,使用这个公共变量
axios .post( 'http://127.0.0.1:3001/updateHero', `id=${editId}&img=${res.data.src}` ) .then(result => { // console.log(result) if (result.data.code == 200) { alert(result.data.msg) $('#uploadImgModal').modal('hide') init() } })
完整代码
// 实现文件上传
btnHeroEdit.addEventListener('click', function() {
// 一:实现文件上传
// 1.文件数据的收集需要使用formdata
// 2.收集所有表单元素的数据: new FormData(form),还可以只收集文件数据: formdata.append(key,File对象)
let myfile = heroImg.files[0]
if (!myfile) return
let formdata = new FormData()
formdata.append('file_data', myfile)
// 发起axios请求
axios({
method: 'post',
url: 'http://127.0.0.1:3001/uploadFile',
data: formdata
}).then(res => {
// console.log(res)
if (res.data.code == 200) {
alert(res.data.msg)
// res.data.src:文件上传成功之后,在服务器端的存储路径,我们就是将这个路径更新到用户信息
// console.log(res.data.src)
// 二:接下来要实现用户头像的s编辑
axios
.post(
'http://127.0.0.1:3001/updateHero',
`id=${editId}&img=${res.data.src}`
)
.then(result => {
// console.log(result)
if (result.data.code == 200) {
alert(result.data.msg)
$('#uploadImgModal').modal('hide')
init()
}
})
}
})
})