Css псевдо-элемент (треугольник за пределами tr) позиция смещена, когда появляется полоса прокрутки

У меня есть панель, высота которой фиксирована, и overflow-y:auto; в этой панели я показываю таблицу, и когда пользователь нажимает на одну из строк, появляется треугольник в правой части строки, который работает нормально, пока полоса прокрутки не появится список таблиц. если на панели появляется панель прокрутки, то справа появляется панель. как решить эту проблему?

Вот Working Fiddle, а также я добавил полный фрагмент кода ниже, а изображение с проблемой соответствующее изображение

(function() {

  'use strict';

  angular
    .module('app', [])
    .controller('TableController', function($log, $scope) {
      $scope.tables = [{
          "name": "one_table",
          "purpose": "test"
        },
        {
          "name": "one_",
          "purpose": "test"
        }, {
          "name": "two_",
          "purpose": "test"

        }, {
          "name": "three_",
          "purpose": "test"
        }, {
          "name": "four_",
          "purpose": "test"
        }, {
          "name": "five_",
          "purpose": "test"
        }, {
          "name": "six_",
          "purpose": "test"
        }, {
          "name": "seven_",
          "purpose": "test"
        }, {
          "name": "eight_",
          "purpose": "test"
        }, {
          "name": "nine_",
          "purpose": "test"
        }, {
          "name": "ten_",
          "purpose": "test"
        }
      ];
      $scope.tindex = -1;
      $scope.rowClicked = function(idx) {
        $scope.tindex = idx;
      }
    });
})();
.panel-body {
  display: block;
  height: 230px;
  overflow-x: hidden;
  overflow-y: auto;
}

table {
  width: 100%;
  max-width: 100%;
}

.arrow-left:after {
  border-bottom: 20px solid transparent;
  border-left: 20px solid #eee;
  border-right: 20px solid transparent;
  border-top: 20px solid transparent;
  clear: both;
  content: '';
  float: right;
  height: 0px;
  margin: 1px auto;
  position: absolute;
  right: 8px;
  width: 0px;
}
<!DOCTYPE html>
<html ng-app="app">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<script src="https://code.jquery.com/jquery.min.js"></script>
<link href="#" onclick="location.href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css'; return false;" rel="stylesheet" type="text/css" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>

<body ng-controller="TableController">
  <div class="row col-md-12">
    <div class="col-md-4" data-define="tables">
      <div class="panel panel-default">
        <div class="panel-heading">
          <span>Tables</span>
        </div>
        <div class="panel-body no-padding">
          <table class="table table-striped">
            <tbody>
              <tr ng-repeat="table in tables track by $index" ng-click="rowClicked($index)" ng-class="tindex === $index ? 'arrow-left' : ''">
                <td>{{table.name}}</td>
                <td>{{table.purpose}}</td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>
    </div>
  </div>

</body>

</html>

Ответ 1

Наконец, я решил это по специальной директиве и немного CSS и с помощью моего коллеги.

добавьте настраиваемую директиву в панели и вычислите положение щелкнутой строки и высоты панели и переместите класс стрелки (без псевдоэлемента). Ниже приведен полный код

(function() {

    'use strict';

    angular
        .module('app',[])
        .controller('TableController', function($log, $scope) {
        $scope.tables = [
        {
          "name": "one_table",
          "columns": [
            {"name": "id"},{"name": "f_name"}           
          ]
        },
        {
          "name": "one_",
          "columns": []
        }, {
          "name": "two_",
          "columns": []
        }, {
          "name": "three_",
          "columns": []
        }, {
          "name": "four_",
          "columns": []
        }, {
          "name": "five_",
          "columns": []
        }, {
          "name": "six_",
          "columns": []
        }, {
          "name": "seven_",
          "columns": []
        }, {
          "name": "eight_",
          "columns": []
        }, {
          "name": "nine_",
          "columns": []
        }, {
          "name": "ten_",
          "columns": []
        }
      ];
      $scope.tindex = -1;
      $scope.rowClicked = function (idx) {
        $scope.tblRowClicked = idx;
        $scope.tindex = idx;
      }
    }).directive('showArrow', function($window, $timeout) {
            return {
                restrict: 'A',
                link: function(scope, element) {
                    // change the arrow position
                    var minHeight, maxHeight, maxWidth, tableHeight, style;
                    var row, rowPos, arrow;
                    var changeArrowPosition = function() {
                        $timeout(function() {
                            row = element.find('.hover');
                            rowPos = row.position(); // get position of clicked row
                            //console.log("rowPos:minHeight:maxHeight:tableHeight", rowPos, minHeight, maxHeight,tableHeight);
                            arrow = element.children('.dir-right');
                            arrow.hide();
                            if (rowPos) {
                                if (rowPos.top >= minHeight && rowPos.top <= maxHeight) {
                                    style = {"top": rowPos.top + "px"};
                                    arrow.css(style);
                                    // if table height is lesser than panel height
                                    if (tableHeight <= maxHeight && maxWidth > 435) {
                                        style = {"margin": "auto 5px"};
                                        arrow.css(style);
                                    }
                                    arrow.addClass('arrow-right').show();
                                }
                            }
                        });
                    };

                    element.on("click scroll", function() {
                        var elem = angular.element(this);
                        maxHeight = elem.height(); // panel height
                        maxWidth = elem.width(); //panel width
                        tableHeight = elem.children('table').height(); // table height
                        minHeight = elem.children('table').find('tr').eq(0).height(); // firt row height
                        changeArrowPosition();
                    });
                }
            };
        });
    
})();
.panel-body {
    display: block;
    height: 230px;
    padding: 0px !important;
    overflow-x: hidden;
    overflow-y: auto;
}
table {
  width:100%;
  max-width: 100%;
}
tr {
  cursor: pointer;
}
tr.hover {
  background-color: #e5ee4f!important;
}
.arrow-right {
    border-bottom: 20px solid transparent;
    border-left: 20px solid #e5ee4f;
    border-right: 20px solid transparent;
    border-top: 20px solid transparent;
    clear: both;
    content: '';
    float: right;
    height: 0px;
    left: 96%;
    margin: 0px auto;
    position: absolute;
    width: 0px;
}

.dir-right {
    display: none;
}
<!DOCTYPE html>
<html ng-app="app">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<script src="https://code.jquery.com/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<body ng-controller="TableController">
<div class="row">
  <div class="col-md-12">
    <div class="col-md-4" data-define="tables">
      <div class="panel panel-default">
          <div class="panel-heading">
              <span>Tables</span>
          </div>
          <div class="panel-body" show-arrow>
              <table class="table table-striped">
                  <tbody >
                      <tr ng-repeat="table in tables track by $index" ng-click="rowClicked($index)" ng-class="tindex === $index ? 'hover' : ''">
                          <td>{{table.name}}</td>
                      </tr>
                  </tbody>
              </table>
              <i ng-if="vm.tblRowClicked === vm.tindex" class="dir-right"></i>
          </div>
      </div>
     </div>
   </div>
  </div>
</body>
</html>

Ответ 2

Похоже, что псевдоэлемент неправильно расположен, даже если tr задан position: relative

Эта проблема может быть исправлена ​​добавлением псевдоэлемента в td.

<tr ng-repeat="table in tables track by $index" >
   <td ng-click="rowClicked($index)" ng-class="tindex === $index ? 'arrow-left' : ''">{{table.name}}</td>
</tr>

и слегка измените CSS:

table tbody tr td {
  position: relative;
}

.arrow-left:after {
    border-bottom: 20px solid transparent;
    border-left: 20px solid #eee;
    border-right: 20px solid transparent;
    border-top: 20px solid transparent;
    clear: both;
    content: '';
    float: right;
    height: 0px;
    margin: 1px auto;
    position: absolute;
    top: -3px;
    right: -18px;
    width: 0px;
}

Я не уверен, что перемещение события click в td является для вас решением.

jsbin

Обновление

Чтобы работать с несколькими td, обновите CSS, как показано ниже:

table tbody tr td {
  position: relative;
}

.arrow-left td:last-of-type:after {
    border-bottom: 20px solid transparent;
    border-left: 20px solid #eee;
    border-right: 20px solid transparent;
    border-top: 20px solid transparent;
    clear: both;
    content: '';
    float: right;
    height: 0px;
    position: absolute;
    top: -2px;
    right: 0;
    width: 0px;
}

jsbin

Ответ 3

Если вы примените position: relative к элементу таблицы, стрелка не выйдет из контейнера. По какой-то причине спецификация говорит position: relative on table-row, а другие элементы таблицы - undefined.

Здесь спецификация для получения дополнительной информации: https://www.w3.org/TR/CSS21/visuren.html#propdef-position

Ответ 4

Вы ожидали такого.

(function() {

  'use strict';

  angular
    .module('app', [])
    .controller('TableController', function($log, $scope) {
      $scope.tables = [{
          "name": "one_table",
          "purpose": "test"
        },
        {
          "name": "one_",
          "purpose": "test"
        }, {
          "name": "two_",
          "purpose": "test"

        }, {
          "name": "three_",
          "purpose": "test"
        }, {
          "name": "four_",
          "purpose": "test"
        }, {
          "name": "five_",
          "purpose": "test"
        }, {
          "name": "six_",
          "purpose": "test"
        }, {
          "name": "seven_",
          "purpose": "test"
        }, {
          "name": "eight_",
          "purpose": "test"
        }, {
          "name": "nine_",
          "purpose": "test"
        }, {
          "name": "ten_",
          "purpose": "test"
        }
      ];
      $scope.tindex = -1;
      $scope.rowClicked = function(idx) {
        $scope.tindex = idx;
      }
    });
})();
.panel-body {
 display: block;
    height: 230px;
    overflow-x: hidden;
    overflow-y: auto;
}

table {

    color:#000!important;
  width: 100%;
  max-width: 100%;
}

.arrow-left:after {
    border-bottom: 15px solid transparent;
    border-left: 15px solid #eee;
   border-right: 15px solid transparent; 
    border-top: 15px solid transparent;
    clear: both;
    content: '';
    float: right;
    height: 0px;
    margin: 1px auto;
    position: relative;
    right: 8px;
    width: 0px;
}
.arrow-left1:after {
        border-bottom: 15px solid transparent;
    border-left: 15px solid #eee;
    border-right: 15px solid transparent;
    border-top: 15px solid transparent;
    clear: both;
    content: '';
    float: left;
    height: 0px;
    margin: 1px auto;
    position: relative;
    right: 0px;
    width: 0px;
}
<!DOCTYPE html>
<html ng-app="app">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<script src="https://code.jquery.com/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>

<body ng-controller="TableController">
  <div class="row col-md-12">
    <div class="col-md-4" data-define="tables">
      <div class="panel panel-default">
        <div class="panel-heading">
          <span>Tables</span>
        </div>
        <div class="panel-body no-padding">
          <table class="table table-striped">
            <tbody>
              <tr ng-repeat="table in tables track by $index" ng-click="rowClicked($index)">
                <td>{{table.name}}</td>
                <td>{{table.purpose}}</td>
                <td ng-class="tindex === $index ? 'arrow-left' : ''"></td>
              </tr>
            </tbody>
          </table>
        </div>
        <br><br>
         <div class="panel-body no-padding">
          <table class="table table-striped">
            <tbody>
              <tr ng-repeat="table in tables track by $index" ng-click="rowClicked($index)" ng-class="tindex === $index ? 'arrow-left1' : ''">
                <td>{{table.name}}</td>
                <td>{{table.purpose}}</td>  
                <td>{{table.purpose}}</td>
              </tr>
            </tbody>
          </table>
        </div>
        
      </div>
    </div>
  </div>

</body>

</html>

Ответ 5

пожалуйста, проверьте эти результаты, я думаю, что он работает правильно, ожидая

(function() {

    'use strict';

    angular
        .module('app',[])
        .controller('TableController', function($log, $scope) {
        $scope.tables = [
        {
          "name": "one_table",
          "columns": [
            {"name": "id"},{"name": "f_name"}           
          ]
        },
        {
          "name": "one_",
          "columns": []
        }, {
          "name": "two_",
          "columns": []
        }, {
          "name": "three_",
          "columns": []
        }, {
          "name": "four_",
          "columns": []
        }, {
          "name": "five_",
          "columns": []
        }, {
          "name": "six_",
          "columns": []
        }, {
          "name": "seven_",
          "columns": []
        }, {
          "name": "eight_",
          "columns": []
        }, {
          "name": "nine_",
          "columns": []
        }, {
          "name": "ten_",
          "columns": []
        }
      ];
      $scope.tindex = -1;
      $scope.rowClicked = function (idx) {
        $scope.tindex = idx;
      }
    });
})();
.panel-body {
    display: block;
    height: 230px;
    overflow-x: hidden;
    overflow-y: auto;
}
table {
    width:100%;
    max-width: 100%;
}
.table tbody tr td {
    border-top: 0px !important;
}
.arrow-left:after {
    border-bottom: 20px solid transparent;
    border-left: 20px solid #ccc;
    /* border-right: 20px solid transparent; */
    border-top: 20px solid transparent;
    clear: both;
    content: '';
    float: right;
    height: 0px;
    /* margin: 1px auto; */
    position: relative;
    right:8px;
    width: 0px;
}
table tr {
    width:100%;
    position:relative;
    border-top: 1px solid #ccc;
  
}
table tr td {
    width:100%;
}
<!DOCTYPE html>
<html ng-app="app">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<script src="https://code.jquery.com/jquery.min.js"></script>
<link href="#" onclick="location.href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css'; return false;" rel="stylesheet" type="text/css" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<body ng-controller="TableController">
<div class="row col-md-12">
  <div class="col-md-4" data-define="tables">
      <div class="panel panel-default">
          <div class="panel-heading">
              <span>Tables</span>
          </div>
          <div class="panel-body no-padding">
              <table class="table table-striped">
                  <tbody >
                      <tr ng-repeat="table in tables track by $index" ng-click="rowClicked($index)" ng-class="tindex === $index ? 'arrow-left' : ''">
                          <td>{{table.name}}</td>
                      </tr>
                  </tbody>
              </table>
          </div>
      </div>
      <div class="col-md-4" data-define="tables">HERE </div>
  </div>
  </div>

</body>
</html>