英雄管理案例
0.前期工作
添加axios的全局配置
主要是配置根路径:axios.defaults.baseURL = 'http://127.0.0.1:3001'
设置全局配置
首先,创建一个utils文件夹,在里面创建一个request.js文件,在文件里面设置全局配置
axios.defaults.baseURL = 'http://127.0.0.1:3001'
创建index.js文件
在网页文件引入外部资源
<!-- bootstrap资源文件,它要基于jquery -->
<script src="./libs/bootstrap/js/bootstrap.min.js"></script>
<!-- 引入axios文件 -->
<script src="./libs/axios.js"></script>
<!-- 引入全局配置 -->
<script src="./utils/request.js"></script>
<!-- 引入index -->
<script src="./js/index.js"></script>
<!-- 注意:引入资源的顺序一定要留心,先有axios插件,再引入全局配置,最后才是引入自己的index文件,否则全局配置不起效,到时会报错 -->
1.实现数据动态渲染
动态数据的渲染,封装函数,遍历拼接,渲染一定要准备好静态结构和数据
- 获取元素
- 发起ajax请求,请求路径:/getHeroList
- 封装为一个函数
- 对数据进行遍历拼接
// 获取元素
let tbody = document.querySelector('tbody')
// 1.数据渲染
function init(){
axios({
// method默认为'get',所以此处可省略
url: '/getHeroList',
}).then(res => {
console.log(res)
let htmlStr = ''
res.data.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 imgUpload" data-id='${value.id}'>
上传头像
</button>
<button type="button" class="btn btn-warning btndel" data-id="${value.id}">
删除
</button>
</td>
</tr>`
})
tbody.innerHTML = htmlStr
})
}
init()
2.实现数据搜索--查询
查询,搜索和渲染本质上都是查询 ,意味着共享同一个方法
- 获取元素,绑定事件,在事件处理函数中获取用户输入的内容,实现搜索
- 获取用户输入内容
- 调用init方法,添加一个参数,参数就是搜索关键字
- 在axios请求的配置选项中添加params选项,用于参数的设置
- 细节:是否有查询参数,没有传递参数就查询所有值,如果有参数就根据参数进行查询
// 获取元素
let btn_search = document.querySelector('#btn_search')
let hname = document.querySelector('#hname')
function init(heroName){
axios({
url: '/getHeroList',
params: { heroName }
}).then(res => {
console.log(res)
let htmlStr = ''
res.data.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 imgUpload" data-id='${value.id}'>
上传头像
</button>
<button type="button" class="btn btn-warning btndel" data-id="${value.id}">
删除
</button>
</td>
</tr>`
})
tbody.innerHTML = htmlStr
})
}
init()
// 2.搜索实现
btn_search.addEventListener('click', function(){
// 获取输入框的值,作为参数传递给封装的函数
let key = hname.value
init(key)
})
3.添加英雄数据
3.1 弹出新增模态框
- 获取元素
- 单击“新增”按钮,需要弹出模态框
- 使用jq的方法:$('#addHeroModal').modal('show')
let btn_search = document.querySelector('#btn_search')
let hname = document.querySelector('#hname')
// 获取模态框元素
let openDialog = document.querySelector('.openDialog')
let heroname = document.querySelector('#heroname')
let herogender = document.querySelector('#gender')
let btnAdd = document.querySelector('.btnAdd')
// 3.1弹出新增模态框
openDialog.addEventListener('click',function(){
$('#addHeroModal').modal('show')
})
3.2 实现新增功能
需求:弹出模态框后,在输入框中输入英雄信息后,单击确认按钮,实现英雄数据的新增
- 收集用户数据,收集方式有三种方法:(1)一个一个收集:获取元素,获取元素的value值 (2)serialize()方法(3)formadata方法
- 发起ajax请求,请求方式:post,请求地址:/addHero,请求参数name,gender,img,因为参数比较少,我们选择第一种收集方式,参数只能是key=value&key1=value1
- 请求成功后,给出提示,隐藏模态框,重新渲染,清空之前的内容
// 3.2实现新增功能
btnAdd.addEventListener('click',function(){
let name = heroname.value
let gender = herogender.value
// js中的文件的路径参照 不是参照当前js的文件,而是参照引入这个js文件的页面
let img = './images/default.jpg'
axios({
method: 'post',
url: '/addHero',
// 参数格式只能写key=value&key1=value1
data: `name=${name}&gender=${gender}&img=${img}`
// data: { name, gender, img } 错误演示
}).then(res => {
console.log(res);
if(res.data.code == 200){
alert(res.data.msg)
$('#addHeroModal').modal('hide')
init()
heroname.value = ''
herogender.value = '男'
}
})
})
重点细节
新增接口的参数只支持key=value&key=value
新增面板中没有图片,所以我们可以为其设置一个默认值
4.实现删除功能
动态元素的事件绑定使用事件委托
- 要判断是否操作指定的元素
- 可以添加一个判断语句是否确定删除,如果不删可以取消,这样可以防止误删
- 发起ajax请求,请求方式:get,请求地址:/delHeroById,请求参数:id
- 由于参数是id,删除需要传入 英雄id 做为条件,现存再取,为删除按钮添加自定义属性id,通过元素.dataset获取id
- 删除成功后,给出提示,重新渲染
// 4.实现删除功能
tbody.addEventListener('click', function(e){
// 判断是否单击了删除按钮
if(e.target.classList.contains('btndel')){
// 弹出是否确定删除确认框
if(confirm("你确定要删除吗?")){
let id = e.target.dataset.id
axios({
url: '/delHeroById',
params: { id }
}).then(res => {
console.log(res);
if(res.data.code == 200){
alert(res.data.msg)
init()
}
})
}
}
})
5.实现文件上传
5.1 弹出文件上传模态框
使用事件委托的方式绑定事件
判断单击的是否是上传文件按钮
// 获取文件上传元素
let btnHeroEdit = document.querySelector('.btnHeroEdit')
let heroImg = document.querySelector('#heroImg')
// 5.实现文件上传
let editId;
// 5.1 弹出文件上传模态框
tbody.addEventListener('click', function(e){
// 判断单击的是上传文件按钮
if(e.target.classList.contains('imgUpload')){
$('#uploadImgModal').modal('show')
editId = e.target.dataset.id
}
})
5.2 实现用户头像的更新
- 获取文件对象
- 创建formdata对象,通过formdata收集文件数据,new FormData(form表单元素)
- 将文件对象追加到formdata中,formdata.append(键,文件对象),发起ajax请求,formdata可以直接做为参数传递
- 发起ajax请求实现文件上传
- 当文件上传成功之后,还需要更新用户的头像信息,接口要求传递数据id,先存再取,在弹出模态框时,获取id的值
- 更新头像还需要传递头像路径,这个路径就是来自于文件上传成功之后的返回数据
// 5.2 实现文件上传的功能
btnHeroEdit.addEventListener('click', function(){
// 获取文件对象
let myfile = heroImg.files[0]
// 创建formdata对象
let formdata = new FormData()
// 将文件对象追加到formdata中
formdata.append('file_data', myfile)
// 判断是否选择了文件
if(heroImg.value = ''){
alert('请选择文件')
return
}
// 发起ajax请求实现文件上传
axios({
method: 'post',
url: '/uploadFile',
data: formdata
}).then(res => {
console.log(res);
if(res.data.code == 200){
alert(res.data.msg)
// 再发起ajax请求实现用户头像更新
axios({
method: 'post',
url: '/updateHero',
data: `id=${editId}&img=${res.data.src}`
}).then(result => {
console.log(result);
if(result.data.code == 200){
alert(result.data.msg)
$('#uploadImgModal').modal('hide')
init()
heroImg.value = ''
}
})
}
})
})
完成代码结构
HTML代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>英雄管理</title>
<link rel="stylesheet" href="./libs/bootstrap/css/bootstrap.min.css" />
<style>
.panel {
width: 900px;
margin: 10px auto;
}
.table img {
width: 40px;
height: 40px;
}
</style>
</head>
<body>
<div class="container">
<div class="panel panel-primary">
<div class="panel-heading">英雄列表管理</div>
<div class="panel-body">
<div class="row">
<div class="col-lg-6">
<div class="input-group">
<input
type="text"
id="hname"
class="form-control"
placeholder="输入英雄信息..."
autocomplete="true"
/>
<span class="input-group-btn">
<button class="btn btn-default" id="btn_search" type="button">
搜索
</button>
</span>
</div>
</div>
<div class="col-lg-3 col-lg-offset-3">
<button type="button" class="btn btn-success openDialog">
添加英雄
</button>
</div>
</div>
</div>
<table class="table">
<thead>
<tr>
<th>编号</th>
<th>英雄名称</th>
<th>英雄性别</th>
<th>头像</th>
<th>操作区</th>
</tr>
</thead>
<!-- 表格主体 -->
<tbody id="tbody">
<!-- <tr>
<td>1</td>
<td>74期小伙伴</td>
<td>男/女</td>
<td>
<img src="./images/default.jpg" alt="" />
</td>
<td>
<button type="button" class="btn btn-info">
上传头像
</button>
<button type="button" class="btn btn-warning">
删除
</button>
</td>
</tr> -->
</tbody>
</table>
</div>
</div>
<!-- 新增英雄模态框 -->
<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="请输入英雄名称"
name="name"
/>
</div>
</div>
<div class="form-group">
<label for="gender" class="col-sm-2 control-label"
>英雄性别</label
>
<div class="col-sm-10">
<!-- 对于下拉列表,如果option没有设置 value属性,就获取option之间的内容,如果有value属性就获取value属性 -->
<select class="form-control" id="gender" name="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 btnAdd">确定</button>
</div>
</div>
</div>
</div>
<!-- 上传文件的模态框 -->
<div
class="modal fade"
id="uploadImgModal"
tabindex="-1"
role="dialog"
aria-labelledby="myModalLabel"
>
<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" id="myModalLabel">上传头像</h4>
</div>
<div class="modal-body">
<input type="file" id="heroImg" />
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
取消
</button>
<button type="button" class="btn btn-primary btnHeroEdit">
确定
</button>
</div>
</div>
</div>
</div>
<script src="./libs/jquery/jquery.min.js"></script>
<!-- bootstrap资源文件,它要基于jquery -->
<script src="./libs/bootstrap/js/bootstrap.min.js"></script>
<!-- 引入axios文件 -->
<script src="./libs/axios.js"></script>
<!-- 引入全局的配置文件 -->
<script src="./utils/request.js"></script>
<!-- 引入页面的js文件 -->
<script src="./js/index copy 2.js"></script>
</body>
</html>
// 获取表格结构元素
let tbody = document.querySelector('tbody')
let btn_search = document.querySelector('#btn_search')
let hname = document.querySelector('#hname')
// 获取模态框元素
let openDialog = document.querySelector('.openDialog')
let heroname = document.querySelector('#heroname')
let herogender = document.querySelector('#gender')
let btnAdd = document.querySelector('.btnAdd')
// 获取文件上传元素
let btnHeroEdit = document.querySelector('.btnHeroEdit')
let heroImg = document.querySelector('#heroImg')
// 1.数据渲染
function init(heroName){
axios({
url: '/getHeroList',
params: { heroName }
}).then(res => {
console.log(res)
let htmlStr = ''
res.data.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 imgUpload" data-id='${value.id}'>
上传头像
</button>
<button type="button" class="btn btn-warning btndel" data-id="${value.id}">
删除
</button>
</td>
</tr>`
})
tbody.innerHTML = htmlStr
})
}
init()
// 2.搜索实现
btn_search.addEventListener('click', function(){
// 获取输入框的值,作为参数传递给封装的函数
let key = hname.value
init(key)
})
// 3.新增英雄数据
// 3.1弹出新增模态框
openDialog.addEventListener('click',function(){
$('#addHeroModal').modal('show')
})
// 3.2实现新增功能
btnAdd.addEventListener('click',function(){
let name = heroname.value
let gender = herogender.value
// js中的文件的路径参照 不是参照当前js的文件,而是参照引入这个js文件的页面
let img = './images/default.jpg'
axios({
method: 'post',
url: '/addHero',
// 参数格式只能写key=value&key1=value1
data: `name=${name}&gender=${gender}&img=${img}`
// data: { name, gender, img } 错误演示
}).then(res => {
console.log(res);
if(res.data.code == 200){
alert(res.data.msg)
$('#addHeroModal').modal('hide')
init()
heroname.value = ''
herogender.value = '男'
}
})
})
// 4.实现删除功能
tbody.addEventListener('click', function(e){
// 判断是否单击了删除按钮
if(e.target.classList.contains('btndel')){
// 弹出是否确定删除确认框
if(confirm("你确定要删除吗?")){
let id = e.target.dataset.id
axios({
url: '/delHeroById',
params: { id }
}).then(res => {
console.log(res);
if(res.data.code == 200){
alert(res.data.msg)
init()
}
})
}
}
})
// 5.实现文件上传
let editId;
// 5.1 弹出文件上传模态框
tbody.addEventListener('click', function(e){
// 判断单击的是上传文件按钮
if(e.target.classList.contains('imgUpload')){
$('#uploadImgModal').modal('show')
editId = e.target.dataset.id
}
})
// 5.2 实现文件上传的功能
btnHeroEdit.addEventListener('click', function(){
// 获取文件对象
let myfile = heroImg.files[0]
// 创建formdata对象
let formdata = new FormData()
// 将文件对象追加到formdata中
formdata.append('file_data', myfile)
// 判断是否选择了文件
if(heroImg.value = ''){
alert('请选择文件')
return
}
// 发起ajax请求实现文件上传
axios({
method: 'post',
url: '/uploadFile',
data: formdata
}).then(res => {
console.log(res);
if(res.data.code == 200){
alert(res.data.msg)
// 再发起ajax请求实现用户头像更新
axios({
method: 'post',
url: '/updateHero',
data: `id=${editId}&img=${res.data.src}`
}).then(result => {
console.log(result);
if(result.data.code == 200){
alert(result.data.msg)
$('#uploadImgModal').modal('hide')
init()
heroImg.value = ''
}
})
}
})
})