这个表格加持还是不错了,自带了全局搜索,分页,数据导出,卡片视图,等,本次整合添加了数据添加弹窗和编辑数据回显弹窗,附完整页面代码,只需要拿过来替换自己实际的接口即可。
效果图
接口案例
数据列表:
{"code": 200,"msg": "ok","data": [{"categoryId": 52,"categoryName": "哈哈哈"},{"categoryId": 53,"categoryName": "哈哈哈地方"},{"categoryId": 7,"categoryName": "悬疑灵异"},{"categoryId": 4,"categoryName": "武侠仙侠"},{"categoryId": 3,"categoryName": "玄幻奇幻"}]
}
增:/novel-category/add
删:/novel-category/delete/{id}
改:/novel-category/update
查:/novel-category/list
批量删:/novel-category/deleteBatch
对应后端实现
package com.xxx.readverse.controller;import cn.dev33.satoken.util.SaResult;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xxx.readverse.entity.Category;
import com.xxx.readverse.service.CategoryService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;import java.util.Arrays;
import java.util.List;@Controller
@RequestMapping("/novel-category")
@Api(tags = "小说分类")
@CrossOrigin
public class CategoryController {@Autowiredprivate CategoryService novelCategoryService;@GetMapping("/list")@ApiOperation("分类列表")@ResponseBodypublic SaResult getNovelCategories() {List<Category> categoryList = novelCategoryService.list(new QueryWrapper<Category>().last("limit 12"));return SaResult.data(categoryList);}@PostMapping("/add")@ApiOperation("新增分类")@ResponseBodypublic SaResult add(Category novelCategory) {try {novelCategoryService.save(novelCategory);} catch (DuplicateKeyException e) {return SaResult.error("操作未成功,可能是因为数据重复导致的");}return SaResult.data(novelCategory.getCategoryId());}@GetMapping("/deleteBatch")@ApiOperation("批量删除")@ResponseBodypublic SaResult deleteBatch(@RequestParam("ids") Integer[] ids) {novelCategoryService.removeByIds(Arrays.asList(ids));return SaResult.ok();}@GetMapping("/delete/{id}")@ApiOperation("删除分类")@ResponseBodypublic SaResult delete(@PathVariable Integer id) {novelCategoryService.removeById(id);return SaResult.ok();}@PostMapping("/update")@ApiOperation("修改分类")@ResponseBodypublic SaResult update(Category novelCategory) {novelCategoryService.updateById(novelCategory);return SaResult.ok();}@GetMapping("/{id}")@ApiOperation("获取某个分类信息")@ResponseBodypublic SaResult getById(@PathVariable Integer id) {Category category = novelCategoryService.getById(id);return SaResult.data(category);}}
页面完整代码
需要注意的问题
-
注意依赖引进
-
方法异步操作,特别是弹窗组件
-
数据项的ID,并不是每个都是id,根据实体数据来确认。
-
新增,编辑使用弹窗,控制弹窗的显示和关闭,$(‘xxx’).modal(‘show’), $(‘xxx’).modal(‘hide’)
-
基本通用,直接换接口名称就行。
<!doctype html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport"content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>表格演示</title><link href="https://cdn.jsdelivr.net/npm/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet"><link href="https://cdn.jsdelivr.net/npm/bootstrap-table@1.22.3/dist/bootstrap-table.min.css" rel="stylesheet"><script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script><script src="https://cdn.jsdelivr.net/npm/bootstrap/dist/js/bootstrap.bundle.min.js"></script><script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.22.3/dist/bootstrap-table.min.js"></script><script src="https://cdn.jsdelivr.net/npm/bootstrap-table@1.22.3/dist/locale/bootstrap-table-zh-CN.min.js"></script><link href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet"><script src="https://cdn.jsdelivr.net/npm/tableexport.jquery.plugin@1.28.0/tableExport.min.js"></script><script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script><style>.select,#locale {width: 100%;}.edit {margin-right: 10px;}</style>
</head><body><!-- 新增弹窗 --><!-- Modal Body --><!-- if you want to close by clicking outside the modal, delete the last endpoint:data-bs-backdrop and data-bs-keyboard --><div class="modal fade" id="addModal" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false" role="dialog"aria-labelledby="modalTitleId" aria-hidden="true"><div class="modal-dialog modal-dialog-scrollable modal-dialog-centered modal-md" role="document"><form id="addForm"><div class="modal-content"><div class="modal-header"><h5 class="modal-title" id="modalTitleId">新增</h5><button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button></div><div class="modal-body"><div class="form-floating mb-3"><input type="text" class="form-control" name="categoryName" id="categoryName" placeholder="" /><label for="categoryName">Name</label></div></div><div class="modal-footer"><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button><button type="reset" class="btn btn-outline-danger">清空</button><button type="submit" class="btn btn-primary">保存</button></div></div></form></div></div><!-- 编辑弹窗 --><!-- Modal Body --><!-- if you want to close by clicking outside the modal, delete the last endpoint:data-bs-backdrop and data-bs-keyboard --><div class="modal fade" id="editModal" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false" role="dialog"aria-labelledby="modalTitleId" aria-hidden="true"><div class="modal-dialog modal-dialog-scrollable modal-dialog-centered modal-md" role="document"><form id="editForm"><div class="modal-content"><div class="modal-header"><h5 class="modal-title" id="modalTitleId">编辑</h5><button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button></div><div class="modal-body"><input type="hidden" name="categoryId"><div class="form-floating mb-3"><input type="text" class="form-control" name="categoryName" id="categoryName" placeholder="" /><label for="categoryName">Name</label></div></div><div class="modal-footer"><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button><button type="reset" class="btn btn-outline-danger">清空</button><button type="submit" class="btn btn-primary">保存</button></div></div></form></div></div><div class="container"><!-- 自定义工具栏 --><div id="toolbar"><button id="add" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addModal"><i class="bi bi-plus-square"></i> 新增</button><button id="export" class="btn btn-success"><i class="bi bi-file-earmark-spreadsheet"></i> 导出</button><button id="remove" class="btn btn-danger" disabled><i class="bi bi-trash"></i> 批量删除</button></div><!-- 表格初始化 --><table id="table" data-toolbar="#toolbar" data-search="true" data-show-refresh="true" data-show-toggle="true"data-show-fullscreen="true" data-show-columns="true" data-show-columns-toggle-all="true" data-detail-view="true"data-show-export="true" data-click-to-select="true" data-detail-formatter="detailFormatter"data-minimum-count-columns="2" data-show-pagination-switch="true" data-pagination="true" data-id-field="id"data-page-list="[5,10, 25, 50, 100, all]" data-show-footer="true" data-side-pagination="client"data-url="/novel-category/list" data-response-handler="responseHandler"></table></div></body>
<script>// 获取组件var $table = $('#table')var $remove = $('#remove')var selections = []// 获取被选中行的IDfunction getIdSelections() {return $.map($table.bootstrapTable('getSelections'), function (row) {return row.categoryId})}// 处理远程响应的数据,可以指定要在表格显示的数据function responseHandler(res) {return res.data;}// 自定义显示样式function detailFormatter(index, row) {var html = []$.each(row, function (key, value) {html.push('<p><b>' + key + ':</b> ' + value + '</p>')})return html.join('')}function operateFormatter(value, row, index) {return ['<button type="button" class="btn btn-outline-primary edit btn-sm" title="编辑">','<i class="bi bi-pencil"></i> 编辑','</button> ','<button type="button" class="btn btn-outline-danger remove btn-sm" title="删除">','<i class="bi bi-trash"></i> 删除','</button>'].join('');}// 按钮点击事件window.operateEvents = {'click .edit': function (e, value, row, index) {// 弹窗编辑回显$.each(row, function (key, value) {$('#editForm input[name="' + key + '"]').val(value);// 如果表单字段是<input>标签之外的其他类型,也可以使用类似的方式进行赋值});$editModal.modal('show');// alert('You click edit action, row: ' + JSON.stringify(row))},// 移除'click .remove': async function (e, value, row, index) {if (await askDelete()) {// 从表格中移除选中的行remove(row.categoryId);}}}// 表格初始化function initTable() {$table.bootstrapTable('destroy').bootstrapTable({exportDataType: 'all',height: 550,locale: $('#locale').val(),columns: [[{field: 'state',checkbox: true,align: 'center',valign: 'middle'},{title: 'ID编号',field: 'categoryId',align: 'center',valign: 'middle',sortable: true,},{title: '分类名',field: 'categoryName',sortable: true,align: 'center'},{field: 'operate',title: '操作',align: 'center',clickToSelect: false,events: window.operateEvents,formatter: operateFormatter}]]})// 监听表格的选择事件,当表格中的行被选中或取消选中时触发$table.on('check.bs.table uncheck.bs.table ' +'check-all.bs.table uncheck-all.bs.table',function () {// 根据当前选中的行的数量来启用或禁用删除按钮$remove.prop('disabled', !$table.bootstrapTable('getSelections').length)// 保存你的数据,这里只保存当前页的数据selections = getIdSelections()console.log("当前选中:" + selections)// 如果你想要保存所有选中的数据,可以在这里使用 push 或 splice 方法})// 监听表格的所有事件,用于调试目的$table.on('all.bs.table', function (e, name, args) {// console.log(name, args)})// 点击删除按钮时执行的操作$remove.click(async function () {// 获取所有选中行的 IDvar ids = getIdSelections()if (await askDelete()) {// 从表格中移除选中的行console.log("要删除的ids:" + ids)removeBatch(ids);// 禁用删除按钮$remove.prop('disabled', true)}})}// 绑定导出按钮点击事件$('#export').click(function () {$table.tableExport({type: 'excel', // 导出文件类型,可选 'csv', 'txt', 'sql', 'json', 'xml', 'excel', 'doc', 'png', 'pdf'escape: 'false' // 是否使用转义,默认为 true});});$(function () {initTable();$('#locale').change(initTable)})// 删除确认弹窗async function askDelete() {const result = await Swal.fire({title: "确定要删除它吗?",text: "删除后无法恢复!",icon: "warning",showCancelButton: true,confirmButtonColor: "#3085d6",cancelButtonColor: "#d33",confirmButtonText: "确定!"});return result.isConfirmed;}// 操作提示function mess() {Swal.fire({position: "top-end",icon: "success",title: "操作OK",showConfirmButton: false,timer: 1500});}var $addModal = $('#addModal');var $editModal = $('#editModal');// 新增$('#addForm').submit(function (event) {event.preventDefault();var data = $('#addForm').serialize();console.log(data);save(data)$addModal.modal('hide');})// 保存编辑$('#editForm').submit(function (event) {event.preventDefault();var data = $('#editForm').serialize();console.log(data);update(data);$editModal.modal('hide');})function save(data) {$.post("/novel-category/add", data, function (data) {if (data.code === 200) {mess();refresh();}})}function update(data) {$.post("/novel-category/update", data, function (data) {if (data.code === 200) {mess();refresh();}})}function remove(id) {$.get("/novel-category/delete/" + id, function (data) {if (data.code === 200) {refresh();mess();}})}function removeBatch(data) {$.get("/novel-category/deleteBatch?ids=" + data.join(','), function (data) {if (data.code === 200) {mess();refresh();}})}function refresh() {$table.bootstrapTable('refresh');}</script></html>
注意数据的对接,特别是每行数据的id项,根据实际数据调整。