首页> 前端开发> Angularjs表格指令

[文章]Angularjs表格指令

收藏
0 282 0

Angularjs表格指令

罗扬

【摘要】

本文介绍在angularjs1.x框架中,自己编写的表格指令。

【正文】

   需求:

1.1       为什么要用指令:

由于angularjs脏值检查的特性,我们在angularjs框架中使用jquery插件会造成一个天然的bug,即如果使用插件选择标签$(‘xx’)时,刚好在angularjs执行默认指令处理改标签时,会造成无法选中标签的情况,所以我们一般会把jquery插件的逻辑封装进指令中,然后把指令写在目标标签上,那么当标签生成之后才会触发指令,这时选择标签时就不会存在无法选中标签的情况。

 

1.2       表格功能:

当然本文介绍的表格指令不是在指令中封装已有插件,而是在指令中写一套表格逻辑。

那么在完成代码前,我们需要定义好这个表格指令需要实现的功能是什么:

1,  可定义表头和数据源中key的对应关系

2,  可自定义某列td单元格的html内容

3,  表格高度可自适应屏幕

4,  表格分页

5,  表格每页展示的行数自适应

6,  单元格内容过多,超出部分用……显示,点击此单元格,显示所有内容,再次点击则恢复……隐藏。

 

 

   源代码解析:

2.1       源代码:

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 }}&nbsp;&nbsp;&nbsp;&nbsp;每页{{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">&nbsp;<a ng-click="reload()">跳转</a>&nbsp;&nbsp;&nbsp;{{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;

}

 

 

2.2       解读:

入口函数:$scope.$watch()

                   监听指令传入的参数即整个表格的配置数据,当数据源变化时,则重新触发入口函数进行表格的重新计算

 

屏幕变化函数:window.onresize,当屏幕变化时,触发$scope.on()函数进行表格自适应的计算

 

 

表格自适应计算函数:

         $scope.mytable_change():计算表格高度

$scope.on():计算表格一页展示的行数

 

         数据计算函数:$scope.mytable_data_change(),计算数据源根据每页展示数量做计算,计算页数,计算当前页面展示的数据。

 

 

 

 

   使用说明

3.1       使用说明:

Html


控制器Js

 

数据源格式:


配置参数:

 

 

 

3.2       截图


 

前端开发
最近热帖
{{item.Title}} {{item.ViewCount}}
近期热议
{{item.Title}} {{item.PostCount}}