黑马头条数据管理平台项目总结
今天完成了项目的四个功能和修复一个bug,也做了比较详细的注释笔记,下面就分享给大家。
首先就是获取文章列表数据,这里需要注意的是查询参数对象要写到函数外面,因为后面还有其他的请求需要用到这个对象,实现这些功能的时候要先考虑到还有没有地方需要用到的,有的话就需要封装成函数,封装完记得调用。
// 准备查询参数对象
const queryObj = {status: '', // 文章状态(1是待审核,2是审核通过)空字符串是全部channe1_id: '', // 文章频道id,空字符是全部page: 1, // 当前页码per_page: 2 // 当前页面的条数
}
// 因为考虑到还有其他地方需要用到这个文章列表数据所以选择了封装函数的做法
// 有了参数对象之后就可以获取文章列表数据了
async function setArtileList() {const res = await axios({url: '/v1_0/mp/articles',params: queryObj // 传入参数对象})console.log(res) // 打印获取成功的结果对象// 拿到结果对象之后展示到指定的标签结构中// 通过标签可以看到是tbody结构,需要把每一个对象信息映射成一个tr结构,再把数据放到每一个td单元格中// 因为对象里面有些用数字代表有无的,所以在模板字符串中嵌套条件表达式来判断// 剩下的就是找到对应的字段插入数据即可const htmlStr = res.data.results.map(item =>`<tr><td><img src="${item.cover.type === 0 ? `https://img2.baidu.com/it/u=2640406343,1419332367&fm=253&fmt=auto&app=138&f=JPEG?w=708&h=500` : item.cover.images[0]}" alt=""></td><td>${item.title}</td><td>${item.status === 1 ?`<span class="badge text-bg-primary">待审核</span>` : `<span class="badge text-bg-success">审核通过</span>`}</td><td><span>${item.pubdate}</span></td><td><span>${item.read_count}</span></td><td><span>${item.comment_count}</span></td><td><span>${item.like_count}</span></td><td><i class="bi bi-pencil-square edit"></i><i class="bi bi-trash3 del"></i></td>
</tr>`).join('')console.log(htmlStr)document.querySelector('.art-list').innerHTML = htmlStr // 映射完之后就可以插入到对应的标签字符串
}
setArtileList() // 因为封装了函数 不要忘记调用
第二个是文章筛选功能,这里用到伪数组的forEach方法,这样就循环给按钮绑定事件无需一个个绑,获取回来的数据调用之前封装好的渲染函数即可。
// 获取频道列表数据
// 使用async函数方便后面无需链式调用
async function setChannleList() {const res = await axios({url: '/v1_0/channels'})console.log(res) // 成功获取后的对象console.log(res.data.channels) // 取出数组形式的列表数据// 通过数组的map方法遍历 主要添加join('')不然遍历出来默认用逗号分隔const strHtml = res.data.channels.map(item => {return `<option value="${item.id}">${item.name}</option>`}).join('')// 遍历完之后获取标签并渲染,记得添加一个默认的头选项即可document.querySelector('.form-select').innerHTML = `<option value="" selected="">请选择文章频道</option>` + strHtml
}
setChannleList() // 网页运行后默认调用一次// 获取三个单选框的标签
// 注意是多个需要用ALL,会在原地留下一个伪数组,所以用伪数组的forEach方法遍历每个单选框
document.querySelectorAll('.form-check-input').forEach(radio => {// 给每个单选框循环绑定change事件radio.addEventListener('change', e => {// 触发之后先打印e.target得知target.value才是请求参数需要的,所以将该值赋值给请求体queryObj.status = e.target.value })
})
// 下面这段代码同理
document.querySelector('.form-select').addEventListener('change', e => {queryObj.channe1_id = e.target.value
})
// 最后给筛选按钮绑定点击事件
// 因为前面已经做过传参获取文章列表的数据并赋予到表格中的一个函数,所以下面直接调用即可
document.querySelector('.sel-btn').addEventListener('click', () => {setArtileList()
})
第三个就是分页功能,这里用到了一点点小算法,重要还是要理清临界值。
// 分页功能
// 先在开头声明一个保存文章总数的变量totalCount
// 给一下页按钮注册点击事件,紧接着进行临界值判断
document.querySelector('.next').addEventListener('click', () => {// 用文章总数除以每一页的条数然后用ceil方法取整就就得出最后一页是多少了if (queryObj.page < Math.ceil(totalCount / queryObj.per_page)) {queryObj.page++ // 每翻下一页就加加// 相对应的页数显示也要更改document.querySelector('.page-now').innerHTML = `第${queryObj.page}页`setArtileList() // 最后调用前面封装好的请求函数即可得到对应页数数据}
})
// 上一页按钮同理 只是临界值判断不同
document.querySelector('.last').addEventListener('click', () => {// 只有不小于1都是可以继承往前翻的if (queryObj.page > 1) {queryObj.page--document.querySelector('.page-now').innerHTML = `第${queryObj.page}页`setArtileList()}
})
最后一个就是删除功能,需要注意的是因为每条数据都是tr生成的,所以采用事件委托会来绑定事件更好,还有删除完记得记得从新向服务器获取数据渲染,前端最多删除标签,删除不了数据。这里会出现一个小bug就是在删除最后一页最后一项的时候不会往前面翻页,修复这个bug也是先做判断然后设置需要的时候向前翻页。
// 删除功能和出现的bug处理
// 因为每一条tr数据都是前面循环生成的,而tbody元素是一直在的,所以使用事件委托
document.querySelector('.art-list').addEventListener('click', async e => {// 需要判断用户点击的是删除元素图标if (e.target.classList.contains('del')) {// 点击之后就可以取到对应数据的id(删除数据需要传入id)const delId = e.target.parentNode.dataset.id// 调用删除接口,传入文章id到服务器上const res = await axios({url: `/v1_0/mp/articles/${delId}`, // 要求路径传参method: 'delete'})console.log(res) // 打印删除成功后的结果// 出现bug!!!删除最后一页的最后一条时没有向前翻页,这时就需解决// 先获取到它当前数据有几条,然后判断该页是否只有一条且不是第一页的情况const children = document.querySelector('.art-list').childrenif(children.length === 1 && queryObj.page !== 1) {queryObj.page-- // 符合条件则向前翻页document.querySelector('.page-now').innerHTML = `第${queryObj.page}页` // 记得要刷新页数显示}// 删除只是服务器端删除,前端没有刷新,所以再次调用前面做好的获取文章列表进行覆盖渲染setArtileList() }
})