引言
最近碰到一个需求,需要在一个表格里实现可以编辑,可以新增,可以删除并且可以拖拽表格列实现排序的这样的功能。要求使用jQuery,bootstrap实现。
实现效果如下
引入JS,css外部文件
我们需要引入bootstrap-table来搭建表格,引入bootstrap-table-reorder-rows.js,jquery.tablednd.min.js等实现拖拽,
html结构如下
<div>
<div id="myTabContent" class="tab-content" style="padding: 30px;">
<div
style="background-color: #e8edf0;line-height: 50px;height: 50px;text-indent: 15px;margin-bottom: 30px;">
编辑模板</div>
<div class="tab-pane fade in active" id="bulletin">
<div class="form-group" style="display: flex;align-items: center;font-size: 18px;margin-bottom: 30px;">
<span>申建模板名称 :</span>
<div class="col-xs-12 col-sm-3">
<input type="text" class="form-control" onblur="getMbName()" name="mbName" value="" id="inp"
placeholder="新建模板表">
</div>
</div>
<p style="text-align: center;font-size: 28px;">新建申报表</p>
<div class="table-box" style="margin: 20px;">
<table id="table" data-unique-id="idx"
style="word-break:break-all; word-wrap:break-all;table-layout:fixed"></table>
<div id="toolbar">
<button id="btn_add" type="button" class="btn btn-info btn-sm rightSize">+ 新增填报项</button>
</div>
</div>
<div style="display: flex;margin-top: 40px;justify-content: center;"> </div>
</div>
<div style="background-color: #e8edf0;margin: 30px 0;line-height: 50px;height: 50px;text-indent: 15px;">申报流程
</div>
<div class="tab-pane fade in active" id="bulletin">
<p style="text-align: center;font-size: 28px;">审批流程</p>
<div class="table-box" style="margin: 20px;">
<table id="_table" data-unique-id="_idx"
style="word-break:break-all; word-wrap:break-all;table-layout:fixed"></table>
<div id="_toolbar">
<button id="_btn_add" type="button" class="btn btn-info btn-sm rightSize">+ 添加角色</button>
</div>
</div>
<div style="display: flex;margin-top: 40px;justify-content: center;">
<button type="button" class="btn btn-default">预览</button>
<button type="button" class="btn btn-info" style="margin-left: 10px;" id="btn_check">保存</button>
</div>
</div>
</div>
</div>
配置表格
根据bootstrapTable文档,通过table.bootstrapTable方法,初始化表格,在columns属性,配置每个单元格的内容,算了,我直接上代码吧,不想打字了。。。
代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="./js/jquery.js"></script>
<link rel="stylesheet" href="./css/bootstrap.min.css">
<link rel="stylesheet" href="./css/bootstrap-table.min.css">
<link rel="stylesheet" href="./css/bootstrap-table-reorder-rows.css">
<title>document</title>
<style>
.table>thead>tr>th,
.table>tbody>tr>th,
.table>tfoot>tr>th,
.table>thead>tr>td,
.table>tbody>tr>td,
.table>tfoot>tr>td {
vertical-align: middle;
border: 1px solid #ddd;
}
.bootstrap-table .fixed-table-container .table thead th .th-inner {
border-top: 1px solid #ddd;
}
</style>
</head>
<body>
<div>
<div id="myTabContent" class="tab-content" style="padding: 30px;">
<div
style="background-color: #e8edf0;line-height: 50px;height: 50px;text-indent: 15px;margin-bottom: 30px;">
编辑模板</div>
<div class="tab-pane fade in active" id="bulletin">
<div class="form-group" style="display: flex;align-items: center;font-size: 18px;margin-bottom: 30px;">
<span>申建模板名称 :</span>
<div class="col-xs-12 col-sm-3">
<input type="text" class="form-control" onblur="getMbName()" name="mbName" value="" id="inp"
placeholder="新建模板表">
</div>
</div>
<p style="text-align: center;font-size: 28px;">新建申报表</p>
<div class="table-box" style="margin: 20px;">
<table id="table" data-unique-id="idx"
style="word-break:break-all; word-wrap:break-all;table-layout:fixed"></table>
<div id="toolbar">
<button id="btn_add" type="button" class="btn btn-info btn-sm rightSize">+ 新增填报项</button>
</div>
</div>
<div style="display: flex;margin-top: 40px;justify-content: center;"> </div>
</div>
<div style="background-color: #e8edf0;margin: 30px 0;line-height: 50px;height: 50px;text-indent: 15px;">申报流程
</div>
<div class="tab-pane fade in active" id="bulletin">
<p style="text-align: center;font-size: 28px;">审批流程</p>
<div class="table-box" style="margin: 20px;">
<table id="_table" data-unique-id="_idx"
style="word-break:break-all; word-wrap:break-all;table-layout:fixed"></table>
<div id="_toolbar">
<button id="_btn_add" type="button" class="btn btn-info btn-sm rightSize">+ 添加角色</button>
</div>
</div>
<div style="display: flex;margin-top: 40px;justify-content: center;">
<button type="button" class="btn btn-default">预览</button>
<button type="button" class="btn btn-info" style="margin-left: 10px;" id="btn_check">保存</button>
</div>
</div>
</div>
</div>
</body>
<script src="./js/bootstrap.min.js"></script>
<script src="./js/bootstrap-table.min.js"></script>
<script src="./js/bootstrap-table-zh-CN.js"></script>
<script src="./js/jquery.tablednd.min.js"></script>
<script src="./js/bootstrap-table-reorder-rows.js"></script>
<script>
let MbName = ''
function getMbName() {
MbName = $('#inp').val()
}
$(function () {
let rowCount = 100
let $table = $('#table');
let $button = $('#button');
let $getTableData = $('#getTableData');
$table.bootstrapTable({
clickEdit: true,
useRowAttrFunc: true,
striped: true,
toolbar: '#toolbar',
toolbarAlign: 'bottom',
reorderableRows: true,
onReorderRow: function (newData) {
//拖拽某条数据后,保持序号递增
let xh = $("#table tr td:nth-of-type(7)");
for (let i = 0; i < xh.length; i++) {
$(xh[i]).text(i + 1);
}
$('#table').bootstrapTable(
"append",
{ 'name': '', 'type': '', 'idx': rowCount, 'ph': '', 'option': '', 'require': '', 'display': '', }
)
$('#table').bootstrapTable('removeByUniqueId', rowCount);
},
columns: [
{
field: 'name',
title: '数据名称',
width: '200',
align: 'center',
formatter: function formInput(value, row, index) {
return '<input id="ipt" class="form-control" type="text" placeholder="请输入名称" autocomplete="off" name="name" οnblur="changeData(' + index + ',this);" value="'
+ (function () {
return !row.name ? '' : row.name
})() + '">'
},
},
{
field: 'type',
title: '数据类型',
width: '120',
align: 'center',
formatter:
function setSelect(value, row, index) {
console.log('value', value);
var strHtml = "";
if (value == "单行文本") {
strHtml = `<select class='ss form-control'><option value=''>请选择类型</option>`
+ `<option value='单行文本' selected='selected'>单行文本</option>`
+ `<option value='长文本'>长文本</option>`
+ `<option value='附件'>附件</option>`
+ `<option value='图片'>图片</option>`
+ `<option value='单选'>单选</option>`
+ `<option value='多选'>多选</option>`
+ `<option value='日期'>日期</option>`
+ `<option value='下拉框'>下拉框</option>`
+ `<option value='密码'>密码</option>`
+ `<option value='数字'>数字</option></select>`;
}
else if (value == "长文本") {
strHtml = `<select class='ss form-control' ><option value=''>请选择类型</option>`
+ `<option value='单行文本' >单行文本</option>`
+ `<option value='长文本' selected='selected'>长文本</option>`
+ `<option value='附件' >附件</option>`
+ `<option value='图片' >图片</option>`
+ `<option value='单选' >单选</option>`
+ `<option value='多选' >多选</option>`
+ `<option value='日期' >日期</option>`
+ `<option value='下拉框'>下拉框</option>`
+ `<option value='密码'>密码</option>`
+ `<option value='数字' >数字</option></select>`;
}
else if (value == "附件") {
strHtml = `<select class='ss form-control'><option value=''>请选择类型</option>`
+ `<option value='单行文本' >单行文本</option>`
+ `<option value='长文本' >长文本</option>`
+ `<option value='附件' selected='selected'>附件</option>`
+ `<option value='图片'>图片</option>`
+ `<option value='单选'>单选</option>`
+ `<option value='多选'>多选</option>`
+ `<option value='日期'>日期</option>`
+ `<option value='下拉框'>下拉框</option>`
+ `<option value='密码'>密码</option>`
+ `<option value='数字'>数字</option></select>`;
}
else if (value == "图片") {
strHtml = `<select class='ss form-control'><option value=''>请选择类型</option>`
+ `<option value='单行文本' >单行文本</option>`
+ `<option value='长文本' >长文本</option>`
+ `<option value='附件' >附件</option>`
+ `<option value='图片' selected='selected'>图片</option>`
+ `<option value='单选'>单选</option>`
+ `<option value='多选'>多选</option>`
+ `<option value='日期'>日期</option>`
+ `<option value='下拉框'>下拉框</option>`
+ `<option value='密码'>密码</option>`
+ `<option value='数字'>数字</option></select>`;
}
else if (value == "单选") {
strHtml = `<select class='ss form-control'><option value=''>请选择类型</option>`
+ `<option value='单行文本' >单行文本</option>`
+ `<option value='长文本' >长文本</option>`
+ `<option value='附件' selected='selected'>附件</option>`
+ `<option value='图片'>图片</option>`
+ `<option value='单选' selected='selected'>单选</option>`
+ `<option value='多选'>多选</option>`
+ `<option value='日期'>日期</option>`
+ `<option value='下拉框'>下拉框</option>`
+ `<option value='密码'>密码</option>`
+ `<option value='数字'>数字</option></select>`;
}
else if (value == "多选") {
strHtml = `<select class='ss form-control'><option value=''>请选择类型</option>`
+ `<option value='单行文本' >单行文本</option>`
+ `<option value='长文本' >长文本</option>`
+ `<option value='附件' >附件</option>`
+ `<option value='图片'>图片</option>`
+ `<option value='单选'>单选</option>`
+ `<option value='多选' selected='selected'>多选</option>`
+ `<option value='日期'>日期</option>`
+ `<option value='下拉框'>下拉框</option>`
+ `<option value='密码'>密码</option>`
+ `<option value='数字'>数字</option></select>`;
}
else if (value == "日期") {
strHtml = `<select class='ss form-control'><option value=''>请选择类型</option>`
+ `<option value='单行文本' >单行文本</option>`
+ `<option value='长文本' >长文本</option>`
+ `<option value='附件' >附件</option>`
+ `<option value='图片'>图片</option>`
+ `<option value='单选'>单选</option>`
+ `<option value='多选'>多选</option>`
+ `<option value='日期' selected='selected'>日期</option>`
+ `<option value='下拉框'>下拉框</option>`
+ `<option value='密码'>密码</option>`
+ `<option value='数字'>数字</option></select>`;
}
else if (value == "下拉框") {
strHtml = `<select class='ss form-control'><option value=''>请选择类型</option>`
+ `<option value='单行文本' >单行文本</option>`
+ `<option value='长文本' >长文本</option>`
+ `<option value='附件' >附件</option>`
+ `<option value='图片'>图片</option>`
+ `<option value='单选'>单选</option>`
+ `<option value='多选'>多选</option>`
+ `<option value='日期' >日期</option>`
+ `<option value='下拉框' selected='selected'>下拉框</option>`
+ `<option value='密码'>密码</option>`
+ `<option value='数字'>数字</option></select>`;
}
else if (value == "密码") {
strHtml = `<select class='ss form-control'><option value=''>请选择类型</option>`
+ `<option value='单行文本' >单行文本</option>`
+ `<option value='长文本' >长文本</option>`
+ `<option value='附件' >附件</option>`
+ `<option value='图片'>图片</option>`
+ `<option value='单选'>单选</option>`
+ `<option value='多选'>多选</option>`
+ `<option value='日期' >日期</option>`
+ `<option value='下拉框' >下拉框</option>`
+ `<option value='密码' selected='selected'>密码</option>`
+ `<option value='数字'>数字</option></select>`;
}
else if (value == "数字") {
strHtml = `<select class='ss form-control'><option value=''>请选择类型</option>`
+ `<option value='单行文本' >单行文本</option>`
+ `<option value='长文本' >长文本</option>`
+ `<option value='附件' >附件</option>`
+ `<option value='图片'>图片</option>`
+ `<option value='单选'>单选</option>`
+ `<option value='多选'>多选</option>`
+ `<option value='日期'>日期</option>`
+ `<option value='下拉框'>下拉框</option>`
+ `<option value='密码'>密码</option>`
+ `<option value='数字' selected='selected'>数字</option></select>`;
}
else {
strHtml = `<select class='ss form-control' selected='selected'><option value=''>请选择类型</option>`
+ `<option value='单行文本' >单行文本</option>`
+ `<option value='长文本' >长文本</option>`
+ `<option value='附件' >附件</option>`
+ `<option value='图片' >图片</option>`
+ `<option value='单选' >单选</option>`
+ `<option value='多选' >多选</option>`
+ `<option value='日期' >日期</option>`
+ `<option value='下拉框'>下拉框</option>`
+ `<option value='密码'>密码</option>`
+ `<option value='数字' >数字</option></select>`;
}
return strHtml
},
events: {
'change .ss': function (e, value, row, index) {
let valueSelected = ''
for (let i = 0; i < 11; i++) {
if (e.currentTarget[i].selected == true) {
valueSelected = e.currentTarget[i].innerText
}
}
$table.bootstrapTable('updateCell', {
index: index, //行索引
field: 'type', //列名
value: valueSelected //cell值
})
}
}
},
{
field: 'ph',
title: '输入提示',
width: '110',
align: 'center',
formatter: function formInput(value, row, index) {
return '<input class="form-control" placeholder="请输入提示" type="text" autocomplete="off" name="ph" οnblur="changeData(' + index + ',this);" value="'
+ (function () {
console.log(row)
return !row.ph ? '' : row.ph
})() + '">'
},
},
{
field: 'option',
title: '<span>选项值(每行一个)</span>',
width: '120',
align: 'center',
formatter: function formInput(value, row, index) {
let str = ''
str = '<input class="form-control" placeholder="请输入选项值" type="text" autocomplete="off" name="option" οnblur="changeData(' + index + ',this);" value="'
+ (function () {
console.log(row)
return !row.option ? '' : row.option
})() + '">'
return str
},
},
{
field: 'require',
title: '是否必填',
width: '80',
align: 'center',
formatter:
function setSelect(value, row, index) {
console.log('value', value);
var strHtml = "";
if (value == true) {
strHtml = `<input type="checkbox" name="" id="" value='true' checked=checked class='order' />`;
}
else {
strHtml = `<input type="checkbox" name="" id="" value='false' class='order' />`;
}
return strHtml;
},
events: {
'click .order': function (e, value, row, index) {
console.log(e.currentTarget.checked)
if (e.currentTarget.checked == true) {
$table.bootstrapTable('updateCell', {
index: index, //行索引
field: 'require', //列名
value: true //cell值
})
} else {
$table.bootstrapTable('updateCell', {
index: index, //行索引
field: 'require', //列名
value: false //cell值
})
}
}
}
},
{
field: 'display',
title: '<span title="主表是否显示(最多勾选5个)">主表是否显示(最多勾选5个)</span>',
width: '100',
align: 'center',
formatter:
function setSelect(value, row, index) {
console.log('value', value);
var strHtml = "";
if (value == true) {
strHtml = `<input type="checkbox" name="" id="" value='true' checked=checked class='d-order' />`;
}
else {
strHtml = `<input type="checkbox" name="" id="" value='false' class='d-order' />`;
}
return strHtml;
},
events: {
'click .d-order': function (e, value, row, index) {
if (e.currentTarget.checked == true) {
$table.bootstrapTable('updateCell', {
index: index, //行索引
field: 'display', //列名
value: true //cell值
})
} else {
$table.bootstrapTable('updateCell', {
index: index, //行索引
field: 'display', //列名
value: false //cell值
})
}
}
}
},
{
field: 'order',
title: '排序',
width: '100',
align: 'center',
formatter: function (value, row, index) {
return index + 1;
}
},
{
field: 'shanchu',
title: '操作',
width: '70',
align: 'center',
formatter: function operateFormatter(value, row, index) {
return [
'<button type="button" class="btn btn-info" id="rowDel">删除</button>'
].join('');
},
events: {
'click #rowDel': function (e, value, row, index) {
var uid = $(this).parent().parent().attr("data-uniqueid");
$('#table').bootstrapTable('removeByUniqueId', uid);
}
}
},
],
data: [{ "name": "", "type": "", "idx": 1, "ph": "", "require": '', "display": '', "order": "", 'option': '' }],
});
$("#btn_add").click(function () {
console.log(`$('#table').bootstrapTable('getData')`, $('#table').bootstrapTable('getData'))
rowCount += 1
$('#table').bootstrapTable('append', { 'name': '', 'type': '', 'idx': rowCount, 'ph': '', 'option': '', 'require': '', 'display': ''});
})
});
function changeData(index, obj) {
var value = $(obj).val();
var name = $(obj).attr('name');
//通过 index 获取指定的行
var row = $("#table").bootstrapTable('getOptions').data[index];
//将 input 的值存进 row 中
row[name] = value;
//更新指定的行,调用 'updateRow' 则会将 row 数据更新到 data 中,然后再重新加载
$("#table").bootstrapTable('updateRow', { index: index, row: row });
}
// 审批流程
$(function () {
let _rowCount = 100
$("#_btn_add").click(function () {
let num =
_rowCount += 1
$('#_table').bootstrapTable('append', { 'checkOrder': num, 'role': '', '_idx': _rowCount, });
})
$("#_table").bootstrapTable({
clickEdit: true,
useRowAttrFunc: true,
striped: true,
toolbar: '#_toolbar',
reorderableRows: true,
onReorderRow: function (newData) {
//拖拽某条数据后,保持序号递增
let xh = $("#_table tr td:nth-of-type(1)");
for (let i = 0; i < xh.length; i++) {
$(xh[i]).text(i + 1);
}
$('#_table').bootstrapTable(
"append",
{ 'checkOrder': $('#_table').bootstrapTable('getData').length + 1, 'role': '', '_idx': _rowCount, }
)
$('#_table').bootstrapTable('removeByUniqueId', _rowCount);
},
columns: [
{
field: 'checkOrder',
title: '审核顺序',
width: '200',
align: 'center',
formatter: function (value, row, index) {
return index + 1;
}
},
{
field: 'role',
title: '审核角色名称',
width: '140',
align: 'center',
formatter:
function setSelect(value, row, index) {
var strHtml = "";
if (value == "省级") {
strHtml = `<select class='_ss form-control' ><option value=''>请选择角色</option>`
+ `<option value='省级' selected='selected'>省级</option>`
+ `<option value='市级' >市级</option>`
+ `<option value='县级' >县级</option></select>`;
}
else if (value == "市级") {
strHtml = `<select class='_ss form-control' ><option value=''>请选择角色</option>`
+ `<option value='省级' >省级</option>`
+ `<option value='市级' selected='selected'>市级</option>`
+ `<option value='县级' >县级</option></select>`;
}
else if (value == "县级") {
strHtml = `<select class='_ss form-control' ><option value=''>请选择角色</option>`
+ `<option value='省级' >省级</option>`
+ `<option value='市级' >市级</option>`
+ `<option value='县级' selected='selected'>县级</option></select>`;
}
else {
strHtml = `<select class='_ss form-control' selected='selected'><option value=''>请选择角色</option>`
+ `<option value='省级' >省级</option>`
+ `<option value='市级' >市级</option>`
+ `<option value='县级' >县级</option></select>`;
}
return strHtml;
},
events: {
'change ._ss': function (e, value, row, index) {
console.log('index', index)
console.log('row', row)
let valueSelected = ''
for (let i = 0; i < 4; i++) {
if (e.currentTarget[i].selected == true) {
valueSelected = e.currentTarget[i].innerText
}
}
$('#_table').bootstrapTable('updateCell', {
index: index, //行索引
field: 'role', //列名
value: valueSelected //cell值
})
console.log('getData', $('#_table').bootstrapTable('getData'))
}
}
},
{
field: 'shanchu',
title: '操作',
width: '80',
align: 'center',
formatter: function operateFormatter(value, row, index) {
return [
'<button type="button" class="btn btn-info" id="_rowDel">删除</button>'
].join('');
},
events: {
'click #_rowDel': function (e, value, row, index) {
console.log('$(this)', $(this).parent().parent().attr("data-uniqueid"))
let uid = $(this).parent().parent().attr("data-uniqueid");
console.log('uid',uid)
$('#_table').bootstrapTable('removeByUniqueId', uid);
}
}
},
],
data: [{ "checkOrder": 1, "role": "", "_idx": 1 }],
});
// 点击保存按钮
$('#btn_check').click(function () {
console.log($('#table').bootstrapTable('getData'))
let data = $('#table').bootstrapTable('getData')
let tips = ''
let disNum = 0
data.forEach((v, k) => {
if (v.name == '') {
tips = true
}
if (v.display == true) {
disNum += 1
}
})
console.log('disNum', disNum)
if (tips) {
alert('请填写数据名称');
return false
}
if (disNum > 5) {
alert('主表最多显示5个');
return false
}
});
});
</script>
</html>
后话
大概功能都能实现的时候,我简单的测试了一下,发现一个问题,在拖拽了某一行过后,点击这行的某个单元格,修改数据,比如选择下拉框,选择其他的下拉选项,发现当前单元格数据并没有改变,反而其他行的一个单元格的下拉框数据改变,然后我并没有找到问题,百度了一下也没有解决,最后发现通过在拖拽某行过后,给表格在增加一行,并且立即把这行删除,再来修改单元格的数据,就没有问题了。