Angularjs表格指令
罗扬
【摘要】
本文介绍在angularjs1.x框架中,自己编写的表格指令。
【正文】
由于angularjs脏值检查的特性,我们在angularjs框架中使用jquery插件会造成一个天然的bug,即如果使用插件选择标签$(‘xx’)时,刚好在angularjs执行默认指令处理改标签时,会造成无法选中标签的情况,所以我们一般会把jquery插件的逻辑封装进指令中,然后把指令写在目标标签上,那么当标签生成之后才会触发指令,这时选择标签时就不会存在无法选中标签的情况。
当然本文介绍的表格指令不是在指令中封装已有插件,而是在指令中写一套表格逻辑。
那么在完成代码前,我们需要定义好这个表格指令需要实现的功能是什么:
1,
2,
3,
4,
5,
6,
app.directive('rgtablehtml',
["$compile", function ($compile) {
return {
require: '?ngModel',
restrict: 'EA',
link: function ($scope, el, attr) {
if (attr.rgtablehtml) {//此指令是为了自定义html功能,由于不能在angularjs渲染后插入含有angularjs指令的html代码,需要先经过$compile处理。
var uploadInfo =
$scope.$eval(attr.rgtablehtml)
var ele =
$compile(uploadInfo)($scope);
angular.element(el).append(ele);
}
}
}
}]);
app.directive('rgtable', function () {
return {
// {
// bottom:100, 距离底部的距离
// overflowop:'false', 数据过多隐藏
// data: [ 数据
// {a: '1', b: 2,c:2,d:2},
// ], title: [
// i.rgtable_index
// {'title':
'ceshi','titlergclass':'dsl', 'enname': 'a','rgclass':'test',rghtml,rgwidth},
// {'title': 'ceshi1',
'enname': 'b'},
// {'title': 'ceshi1',
'enname': 'c'},
//
{'title': 'ceshi1', 'enname': 'd'},
// ]
// }
require: '?ngModel',
template: '<div class="mytablebody">\
<div class="table_box">\
<div class="rgtable_no_data" ng-if="!mytable_data[0]"><span>暂无数据</span></div>\
<table>\
<thead>\
<th
class="mytable_checkall"
ng-if="mytable_all.checkoption"><input
type="checkbox" ng-model="checkall.op"
ng-change="mytable_chooseall()"></th>\
<th ng-repeat="o in
mytable_title" title="{{ o.title }}"
class="{{o.titlergclass}}" style="width:{{o.rgwidth}}">\
<span
ng-if="!o.thtml"
title="{{o.title}}">{{o.title}}</span><div
ng-if="o.thtml" rgtablehtml="o.thtml"></div>\
</th>\
</thead>\
<tbody ng-repeat="c in
mytable_data">\
<tr ng-repeat="i in c
">\
<td
ng-if="mytable_all.checkoption">\
<input
type="checkbox" ng-model="choose_data[i.id]">\
</td>\
<td title="{{
i.remarks }}" style="cursor: default;width:{{x.rgwidth}}"
ng-click="mytablecha($event)" ng-repeat="x in
mytable_title" class="{{x.ngclass}}">\
<div
class="rghtml" ng-if="x.rghtml"
rgtablehtml="x.rghtml"></div><span
title="{{i[x.enname]}}" ng-if="!x.rghtml">{{i[x.enname]}}</span>\
</td>\
</tr>\
</tbody>\
</table>\
</div>\
<div class="table_control">\
<div style="float:
left">条目总数:{{ mytable_option.mytable_count
}} 每页{{mytable_option.mytable_num}}</div>\
<div style="float:
right">当前第<input type="number"
ng-keyup="entersearchbtn($event)" style="width:
35px;line-height: 1em;border: 1px solid #d7d7d7;margin: 0 5px"
ng-model="mytable_option.mytable_show">页 <a
ng-click="reload()">跳转</a> 共{{mytable_option.mytable_pagenum}}页</div>\
<div style="float:
right;margin-left: 5px">\
<a
ng-click="mytable_fir()">首页</a>\
<a
ng-click="mytable_backnext()">上一页</a>\
<a
ng-click="mytable_next()">下一页</a>\
<a
ng-click="mytable_last()">尾页</a>\
</div>\
</div>\
</div>',
link: function ($scope, el, attr) {
$scope.checkall = {op: false};
$scope.mytable_option = {
mytable_show: 1,//当前的页数
mytable_num: 5, //一页显示的数据
mytable_pagenum: 0,//共多少页
mytable_count: 0 //数据总数
}
$scope.mytable_data = [];
$scope.mytable_title = [];
$scope.mytable_all = [];
$scope.mytable_data_back = [];
$scope.mytable_next = function () {//下一页
$scope.mytable_option.mytable_show - 1 <
$scope.mytable_option.mytable_pagenum - 1 ? $scope.mytable_option.mytable_show
= angular.copy($scope.mytable_option.mytable_show) + 1 :
$scope.mytable_option.mytable_show =
angular.copy($scope.mytable_option.mytable_show);
$scope.mytable_data =
[$scope.mytable_data_back[$scope.mytable_option.mytable_show - 1]]
}
$scope.mytable_last = function () {//最后一页
$scope.mytable_option.mytable_show =
angular.copy($scope.mytable_option.mytable_pagenum)
$scope.mytable_data =
[$scope.mytable_data_back[$scope.mytable_option.mytable_show - 1]]
}
$scope.mytable_backnext = function () {//上一页
$scope.mytable_option.mytable_show > 1 ?
$scope.mytable_option.mytable_show =
angular.copy($scope.mytable_option.mytable_show) - 1 : $scope.mytable_option.show
= angular.copy($scope.mytable_option.mytable_show);
$scope.mytable_data =
[$scope.mytable_data_back[$scope.mytable_option.mytable_show - 1]]
}
$scope.mytable_fir = function () {//第一页
$scope.mytable_option.mytable_show = 1;
$scope.mytable_data =
[$scope.mytable_data_back[$scope.mytable_option.mytable_show - 1]]
};
$scope.mytable_change = function () {//计算table高度
var height = 500;
if ($scope.mytable_all.total_h)
{
height =
parseInt($scope.mytable_all.total_h)
} else {
var bottom_len = 0;
if
($scope.mytable_all.bottom) {//自定也距离底部的距离
bottom_len =
parseInt($scope.mytable_all.bottom)
}
height = $('body').height()
- $(el).offset().top - bottom_len - 30
}
//30为控制区域的高度
$('.table_box').css('height',
height)
};
$scope.on = function (res) {//自适应的计算,先计算table高度,然后计算一页显示多少条数据
$scope.mytable_change();
var box = $('.mytablebody
.table_box').height();
var thfontsize = 14;
var tdfontsize = 12;
var bodyfontsize =
parseInt($('body').css('font-size').split('px')[0]);
if (bodyfontsize > 12) {
tdfontsize = bodyfontsize
}
if (bodyfontsize > 14) {
thfontsize = bodyfontsize;
tdfontsize = bodyfontsize
}
var th = thfontsize * 1.5 + 6 +
1;
var td = tdfontsize * 1.5 + 6 +
1 + 0.5;
var num = Math.floor((box - th)
/ td);
if (num <= 0) {
num = 1
}
$scope.mytable_option.mytable_num = num;
$scope.mytable_data_change(res)
};
$scope.mytablecha = function (e) { //数据过多会隐藏显示省略号,点击后显示
if ($scope.mytable_overop ==
'true') {
var obj_tag = e.target;
if ($(e.target)[0].tagName
== 'SPAN') {
obj_tag =
$(e.target).parents('td')[0]
}
if($(obj_tag).find('.rghtml').length){
obj_tag =
$($(obj_tag).find('.rghtml'))
}
if
($(obj_tag).css('white-space') == 'nowrap') {
$(obj_tag).css('white-space', 'normal')
} else {
$(obj_tag).css('white-space', 'nowrap')
}
}
}
$scope.mytable_chooseall = function () {//批量选择表格行数时,全选按钮的逻辑
var middata =
$scope.mytable_data[0];
if ($scope.checkall.op) {
for (i in middata) {
if (middata[i].id) {
$scope.choose_data[middata[i].id]
= true
}
}
} else {
for (i in middata) {
if (middata[i].id) {
$scope.choose_data[middata[i].id] = false
}
}
}
};
$scope.choose_data = {};
$scope.mytable_data_change = function (res) { //计算分页数据
get_data =
$scope.$eval(res.data) || [];
$scope.choose_data =
$scope.$eval(res.checkdata) || {};
// get_data = res.data || []
if
($scope.$eval(attr.rgtable).rgindex) {
for (i in get_data) {
get_data[i].rgtable_index = parseInt(i)
}
}
var mid_data = [];
$scope.mytable_option.mytable_count = get_data.length;
$scope.mytable_option.mytable_pagenum
= Math.ceil(get_data.length / $scope.mytable_option.mytable_num)
if
($scope.mytable_option.mytable_show - 1 >
$scope.mytable_option.mytable_pagenum) {
$scope.mytable_option.mytable_show = 1
}
for (var i = 0; i <
Math.ceil(get_data.length / $scope.mytable_option.mytable_num); i++) {
mid_data.push(get_data.slice(i * $scope.mytable_option.mytable_num, (i +
1) * $scope.mytable_option.mytable_num))
}
$scope.mytable_data_back =
mid_data;
$scope.mytable_data =
[mid_data[$scope.mytable_option.mytable_show - 1]]
};
var option_data = $scope.$eval(attr.rgtable).data;
$scope.$watch(option_data, function (a) {//监控指令变量
if ($scope.$eval(attr.rgtable))
{
$scope.mytable_title =
$scope.$eval(attr.rgtable).title;
$scope.mytable_all =
$scope.$eval(attr.rgtable);
$scope.mytable_overop =
$scope.$eval(attr.rgtable).overflowop || 'true';
$scope.on($scope.$eval(attr.rgtable))
}
}, true);
window.onresize = function () {//监控屏幕变化
$scope.reload();
$scope.$apply()
};
$scope.reload = function () { //改变页数时,进行重新计算
if
(CWApp.isNum($scope.mytable_option.mytable_show)) {
if
(($scope.mytable_option.mytable_show - 1) < 0) {
$scope.mytable_option.mytable_show = 1
}
if
($scope.mytable_option.mytable_pagenum != 0) {
if
($scope.mytable_option.mytable_show > $scope.mytable_option.mytable_pagenum)
{
$scope.mytable_option.mytable_show =
angular.copy($scope.mytable_option.mytable_pagenum)
}
}
} else {
return
}
$scope.on($scope.mytable_all)
};
$scope.entersearchbtn = function (e) {//回车搜索
var keycode = window.event ?
e.keyCode : e.which;
if (keycode == 13) {
$scope.reload()
}
}
}
}
});
CSS源码:
body {
font-size: 8px;
}
.mytablebody {
/*display: inline-block;*/
/*max-width: 100%;*/
/*overflow: auto;*/
/*border: 1px solid #d5d5d5;*/
/*max-height: 300px;*/
}
.mytablebody table {
min-width: 100%;
width: auto;
/*width: 100%;*/
table-layout: fixed;
}
.mytablebody button {
padding-top: 1px !important;
padding-bottom: 1px !important;
}
.mytablebody table th {
border-left: 1px solid #d7d7d7;
/*min-width: 100px;*/
font-size: 14px;
text-align: center;
/*background-color: #F3F5F7;*/
line-height: 1.5;
font-weight: 700;
/*border: none;*/
padding: 3px 5px;
/*border-right: none;*/
}
.mytablebody .table_bg {
background-color: #F3F5F7;
width: 12em;
}
.mytablebody table thead tr {
border-bottom: 1px solid #d7d7d7;
}
.mytablebody table th:first-child {
border-left: none;
}
.mytablebody table .mytable_checkall {
width: 40px!important;
}
.mytablebody table tr {
/*border-bottom: 1px solid #d7d7d7;*/
}
.mytablebody table td {
border: 1px solid #d7d7d7;
line-height: 1.5;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size:
12px;
/*min-width: 120px;*/
max-width: 160px;
word-wrap: break-word;
padding: 3px 5px;
text-align: center;
/*border: 1px solid #d5d5d5;*/
border-right: none;
/*border: none;*/
}
.mytablebody table td button{
padding:
0 10px!important;
}
.mytablebody table td:first-child {
border-left: none;
}
.mytablebody .rghtml {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.mytablebody .table_box {
overflow-x: auto;
height: 410px;
border: 1px solid #d5d5d5;
margin-bottom: 10px;
position: relative;
}
.mytablebody .table_control {
line-height: 30px;
height: 30px;
}
.mytablebody .table_control > div {
display: inline-block;
margin-right: 30px;
}
.mytablebody .table_control > div a {
cursor: pointer;
margin-left: 10px;
}
.mytablebody table td .btn-sm {
margin-left:5px;
margin-right:5px;
}
.mytablebody .rgtable_no_data {
position: absolute;
display: inline-block;
left: 50%;
top: 50%;
transform: translate(-50%);
font-size: 24px;
color: #d7d7d7;
}
入口函数:$scope.$watch()
监听指令传入的参数即整个表格的配置数据,当数据源变化时,则重新触发入口函数进行表格的重新计算
屏幕变化函数:window.onresize,当屏幕变化时,触发$scope.on()函数进行表格自适应的计算
表格自适应计算函数:
$scope.mytable_change():计算表格高度
$scope.on():计算表格一页展示的行数
数据计算函数:$scope.mytable_data_change(),计算数据源根据每页展示数量做计算,计算页数,计算当前页面展示的数据。
Html:
控制器Js:
数据源格式:
配置参数: