前端表格插件说明
我们再前端处理表格时,经常会使用bootstrap插件;bootstarp可以完成一些基本的作用,若是我们需要一些高级的功能,如:分页,排序,搜索等功能时bootstrap就显得力不从心了,下面介绍两个专门用于前端表格处理的插件。
1、bootstrap-table: 这个应该时官方的文档,但是文档有很多广告,并且我没找到实例的源码,不过bootstrap-table还有一个说明文档,有很多实例和属性说明,并且还都是中文的:bootstrap-table演示
2、datatables文档:这个插件也可以完成分页,排序,搜索的功能,也可以看一下。
3、bootstrap-edit: 这个主要用于行内编辑表格,也有中文的说明文档: bootstrap-edit中文文档
下面通过一个实例来说明bootstrap-table的简单用法和行内编辑:
bootstrap-table简单使用
因为这些插件下载需要翻墙,这里我们这片文章中用到的插件信息都打包成一个压缩包了,可以直接下载即可:主要有以下四个文件,
[root@localhost bootstrap]# tree
.
├── bootstrap-3.3.7-dist.zip
├── bootstrap3-editable-1.5.1.zip
├── bootstrap-table_v1.13.zip
└── jquery.js
bootstrap-table初始化表格
1、引入需要的js文件和css文件,初始化表格,设置基本属性
<!--引入css文件 -->
<link rel="stylesheet" href="/static/bootstrap/bootstrap-3.3.7-dist/css/bootstrap.css">
<link rel="stylesheet" href="/static/bootstrap/bootstrap-table/css/bootstrap-table.min.css">
<!-- 引入js文件 -->
<script src="/static/js/jquery.js"></script>
<script src="/static/bootstrap/bootstrap-3.3.7-dist/js/bootstrap.js"></script>
<script src="/static/bootstrap/bootstrap-table/js/bootstrap-table.min.js"></script>
html中的body代码可以使用一个单纯的table标签即可,如下:
<div class="row" style="margin-left: 20%; margin-right: 20%">
<table id="table"></table>
</div>
初始化的可以直接使用如下bootstrap-table即可:
<script type="text/javascript">
var columns = [{
field: 'id',
title: "编号",
visible: false,
},{
field: "env",
title: "环境"
},{
field: "port",
title: "端口",
},{
field: "ip",
title: "ip地址",
},{
field: "db_name",
title: "database名",
sortable: true,
}
];
$("#table").bootstrapTable({
<!-- 定义表格表头-->
columns:columns,
<!-- 从url中获取数据-->
url: '/query/' ,
<!-- 获取数据发送请求方式 -->
method: 'GET',
<!-- 数据和总数对应的字段 -->
totalField: 'count',
dataField: 'data',
<!-- 分页设置 -->
pagination: true, #开启分页
sidePagination: 'client', #客户端分页
pageList: [20,30,50], #这里显示可选择每页显示的数据量
pageSize: 10, #每页默认显示10条数据,
<!-- 搜索设置-->
search:true,
searchOnEnterKey: true,
<!-- 是否启用排序-->
sortable:true, #这个字段应该是设置到对应的字段上的,这里只是为了说明
})
</script>
url查询说明
上面的使用url: '/query/'
说明这里的数据是通过这个url查询得到的,后端返回的数据类型应该是json类型,具体格式如下:
注意这里的的count对应上面配置的totalField
的值,data字段对应的就是dataField
的值。
data中的字段类型需要和上面定义的columns中的字段一一对应 。
{
"count": 3,
"data": [
{
"id": 1,
"env": "dev",
"port": "3309",
"ip": "10.9.68.41",
"db_name": "embackend"
},
{
"id": 2,
"env": "dev",
"port": "3309",
"ip": "10.9.68.42",
"db_name": "live_contents_jzy"
},
{
"id": 3,
"env": "dev",
"port": "3309",
"ip": "10.9.68.42",
"db_name": "usertipdb"
}
]
}
在这里使用了后端返回的方式,如果数据量不是很多的话,可以直接的上面的html中定义data变量,把需要展示的数据写入到html中。在上面的bootstarp-table演示的文档中有这种形式的实例。
服务端分页
上面的分页是在client端分页完成的,在数据量不是很多时,客户端分页可以节省很多工作量,特别时那个search的模糊搜索功能,我觉得很有用,但是若是如果数据量变得很大的话加载就会变得很慢,这个时候我们就需要用到服务端分页。
前端分页数据一次性加载完毕,如果我们对页面行内进行编辑的话;那么编辑的渲染只会渲染第一页,跳转到第二页之后,因为不会自动执行编辑渲染操作,第二页就无法编辑。因此下面行内编辑页面中使用的是服务端分页
下面给出一个服务端分页设置的实例,如下:
pagination: true,
sidePagination: 'server', #设置服务的分页
pageNumber:1, #设置默认为第一页
pageList: [20,30,50], #和上面一样,可以改变当前页面展示多少条数据
pageSize: 10, #默认每个页显示10条数据
queryParamsType: 'limit', #发送符合restful格式的参数,默认为limit
queryParams:function(params){
return {
pageSize: params.limit, #传递的是每页显示数据多少条
pageOffset: params.offset, #偏移量
}
},
参数queryParms
表示向后端传递的参数,其值是一个函数;当表格初始化时和点击下一页以及搜索时,会产传递这里数据到后端服务中。
通过google的F12可以发现传递的参数如下:
http://192.168.1.121:8000/query/?pageSize=10&pageOffset=10
因为选择的时get请求,所以通过url就可以看到传递的参数。
在js的queryParams中可以通过console.log(params)命令打印出params参数的具体有哪些值。
然后根据传到后端的参数返回需要的数据。
这里使用django作为后端数据传输,需要知道怎么根据offset偏移量和limit计算出哪一个页的数据。后端代码如下:
def query(request):
if request.method == "GET":
search_info = {"count":10, "data": []}
# 计算偏移数据
offset = int(request.GET.get("pageOffset", 10))
limit = int(request.GET.get("pageSize", 10))
start_index = int(offset/limit)
start_row = start_index * limit
end_row = start_row + limit
print(start_row, end_row)
dbinfo_obj = dbinfo.objects.all()
query_obj = dbinfo_obj[start_row:end_row]
search_info["count"] = dbinfo_obj.count()
for item in query_obj:
tmp_dict = dict()
tmp_dict["id"] = item.id
tmp_dict["env"] = item.env
tmp_dict["port"] = item.port
tmp_dict["ip"] = item.ip
tmp_dict["db_name"] = item.db_name
search_info["data"].append(tmp_dict)
return JsonResponse(search_info)
前端的页面如下形式:[说明一点后端传递的总数据count要大于每页显示的数据,不然不会显示下面的分页按钮]
服务端分页加搜索功能
在使用服务端分页之后,bootstrap-table自带的搜索功能也将无法使用,这个时候就需要自己定义一个搜索。
bootstarp-table自带的搜索功能(前端分页时使用的),默认是模糊搜索,并且可以搜索所有的字段。在页面的最上方加一个搜索框,代码如下:
<div class="panel">
<div class="panel-body" style="padding-bottom: 1px;">
<div class="form-group" >
<div class="col-sm-3" style="margin-left: 20%">
<!-- 自定义搜索框 -->
<input type="text" name="searchString" id="searchString_id" class="form-control" placeholder="请输入搜索内容" onkeydown="" />
</div>
<div class="col-sm-1">
<button type="button" class="btn btn-primary btn-w-m" onclick="searchClick()">
<span class="glyphicon glyphicon-search" id="queryBtn"></span> 搜索
</button>
</div>
</div>
</div>
</div>
</div>
上面有提到queryParams函数里面定义的就是向后端传递的参数,这里需要做的就是把搜索框中的值作为搜索条件传给后端,因此在前端的实现可以这样写:
<-- 初始化这里的 -->
queryParams:function(params){
console.log(params)
return {
pageSize: params.limit,
pageOffset: params.offset,
searchString: $("#searchString_id").val()
}
}
<-- 再给前端的click定义要给函数 -->
function searchClick() {
keyword = $("#searchString_id").val();
$("table").bootstrapTable('refresh')
}
这里完成之后,点击界面的搜索按钮,就会向后端传入searchString参数,这时候传递的url如下:
http://192.168.1.121:8000/query/?pageSize=10&pageOffset=20&searchString=123
问题 如果这样写的这里会有个问题;例如:选择第三页,然后点击搜索,这时候前端会把当前的页面偏移量也传给后端,如果后端根据偏移量计算当前值是会出错的。
http://10.9.8.23/dbApply/mysql/query?queryType=db&pageSize=20&pageIndex=3&searchString=live_contents
解决办法 刷新的时候使用refreshOptions
参数而不是refresh
参数,这两个参数的区别在于refresh 在现有配置的情况下刷新。有关两个属性的区别可以查看详情。
重写searchClick方法如下:
$("table").bootstrapTable('refreshOptions', { pageNumber:1,pageSize:30 });
这样每次搜索时会把pageNumber
设置为1,后端处理时就不会过滤掉数据了。
后端处理就是根据传递的参数,返回数据;返回数据的格式和上面的一样。
行内编辑实现
表格的td标签并不能实现行内编辑,若要实现行内编辑,则需要一个a或者span标签。
需求:对上面表格中ip列和库名列进行编辑
1、在ip列和库名列的td标签中加入span标签,这个可以借助bootstrap-table的formatter
属性,需要注意的时需要给每一行一个唯一id并且传到后端,这样在后端我们才可以知道前端修改的是哪一行记录。
formatter
属性的值是一个函数,并且传入了三个参数,可以使用console.log
打印出参数,查看三个参数的值,在变量cocolumns
中设置ip的属性如下:
{
field: "ip",
title: "ip地址",
formatter: function (value, row, index) {
console.log(value, row, index)
}
使用google浏览器的调试界面,可以看到打印出的三个参数的值如下:
value
的值就是当前的字段值,上面图片中的ip地址
row
的值是一个对象,表示的是这一行记录的对象
id
值是表示的第几行,这个id值和row对象中的哪个id不一样,row中的哪个id是自己定义的,这里的id是bootstrap-table中的
这个属性可以在渲染td标签,把渲染之后的标签return
返回即可:
{
field: "ip",
title: "ip地址",
formatter: function (value, row, index) {
return "<span id='ip' data-pk=" + row.id + " style='border: none' class='glyphicon glyphicon-edit'>" + value + "</span>"
}
},{
field: "db_name",
title: "database名",
sortable: true,
formatter: function (value, row, index) {
return "<span id='db_name' data-pk=" + row.id + " style='border: none' class='glyphicon glyphicon-edit'>" + value + "</span>"
}
}
展示界面如下:这样就给td标签添加了一个span标签
2、引入bootstarp-edit的css文件和js文件,实现行内编辑
引入之后,所有此次需要引入的css和js文件如下:
<!--引入css文件 -->
<link rel="stylesheet" href="/static/bootstrap/bootstrap-3.3.7-dist/css/bootstrap.css">
<link rel="stylesheet" href="/static/bootstrap/bootstrap-table/css/bootstrap-table.min.css">
<link rel="stylesheet" href="/static/bootstrap/bootstrap3-editable/css/bootstrap-editable.css">
<!-- 引入js文件 -->
<script src="/static/js/jquery.js"></script>
<script src="/static/bootstrap/bootstrap-3.3.7-dist/js/bootstrap.js"></script>
<script src="/static/bootstrap/bootstrap-table/js/bootstrap-table.min.js"></script>
<script src="/static/bootstrap/bootstrap3-editable/js/bootstrap-editable.min.js"></script>
上面的所需的文件引入之后,行内编辑实现就很简单,bootstrap-table有个onLoadSuccess
事件,当表格加载完成之后,会触发这个事件。
onLoadSuccess:function () {
$("#table span").editable({
validate: function (value) { /**不为空严重 **/
if (!$.trim(value)) {
return '不能为空';
}
}
});
}
这个时候点击前端中相应的字段就可以编辑了:
这样的直接编辑,在刷新数据之后就会丢失,因此我们需要把数据传入到后端;上面的添加span标签时,给它添加了一些属性信息,这些属性信息,在这里会用到。
<span id='db_name' data-pk=" + row.id + " style='border: none' class='glyphicon glyphicon-edit'>" + value + "</span>
data-pk
表示的时主键信息,这个属性值不要改变
id
表示的是这个字段的说明信息,后端会根据这个id判断你更改的是那个值
value
就是更改的值了
要传递到后端需要借助url
属性,具体代码如下,
onLoadSuccess:function () {
$("#table span").editable({
validate: function (value) { //字段验证
if (!$.trim(value)) {
return '不能为空';
}
},
url: function (params) {
params.csrfmiddlewaretoken = "{{ csrf_token }}";
console.log(params);
$.ajax({
url: "/learn/",
type: "POST",
data: params,
dataType: "Json",
success:function (data) {
console.log(data)
}
})
}
});
}
本质就是一个ajax请求,然后后端根据传入的数据,做update更新处理;后端逻辑不再处理,可以看下点击√之后的ajax请求:
看到ajax传递的值中pk的值取自span的data-pk
,name的值取自span的id
的值,value的值就是span的value
值。
最后的csrfmiddlewaretoken
的值,是因为django的后端验证,发送POST
请求必须要传递,若是使用的非django后端,可以不用传递。
由唯一键,变更的字段名,变更的字段值,就可以在后端确定一条记录并更改。
嵌套表格
bootstrap-table的嵌套表格主要用到detailview
属性,只要在初始化表格时加入一个detailView: true,
即可,如下:
这个属性会在表格的最前一列插入一列,点击+号就可以打开隐藏的列,隐藏的列默认时没有任何显示的,可以使用detailFormatter
属性来定义隐藏的列该显示什么样的内容,注意这个属性的值是一个函数。
<!-- 嵌套表设置 -->
detailView: true,
detailFormatter: function (index, row) {
var html = []
$.each(row, function (key, value) {
html.push('<p><b>' + key + ':</b> ' + value + '</p>')
});
return html.join('');
}
然后在前端展开表格,可以看到如下内容:
在这个例子中,只是对当前行的数据进行了加工然后换一种方式显示,并没有和后端交互。可以在函数中向后端发送一个ajax请求,然后展示相应的数据。
需求: 点击前面的
+
号,显示出当前主机的从库信息,这个时候就需要向后端请求数据;显示的从库信息也需要用表格展示。
<!-- 嵌套表设置 -->
detailView: true,
detailFormatter: "detailFormatter",
这里把detailFormatter
属性值设置为一个函数,函数就是一个发送ajax请求,然后初始化表格的过程,如下:
/** 子表初始化 **/
function detailFormatter(index, row, $detail) {
var sub_table = $detail.html('<table></table>').find('table');
$(sub_table).bootstrapTable({
url :"/query?queryType=subinfo",
method: 'get',
queryParams: { host: row.ip, port: row.port },
dataField:"data",
totalField:"count",
formatNoMatches:function (index, row, $detail) { /**没有数据返回时候的显示信息**/
return "当前实例没有从库信息"
},
columns: [{
field: "msg",
title:"实例说明",
},{
field: "ip",
title: "ip地址"
},{
field: "port",
title: "端口",
},{
field: "idc",
title: "idc",
}]
});
}
ajax请求根据传递的参数不同,返回不同的信息,这里返回数据结构和上面的bootstarp-table初始化所需的数据结构是一样的。
有关bootstrap-table的介绍就结束了,其实最上面的那个连接文档中有很详细的说明。