【问题标题】:Bootstrap's Dropdown appears below the tableBootstrap 的下拉菜单出现在表格下方
【发布时间】:2017-03-28 08:30:04
【问题描述】:

单击按钮后,我正在尝试在表格中打开 Bootstrap 下拉菜单。但是下拉菜单出现在表格下方,无论按下哪个按钮,都始终位于相同的位置。

有人遇到过同样的问题吗?是不是我缺少一些 css 位置?

我的目标是:每个下拉菜单都必须出现在按下的按钮下方。

这是一个演示:

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.filteredList = [];
   $scope.servers = [
      {
        name: 'Server 1',
        port: 5014
      },
      {
        name: 'Server 2',
        port: 5015
      },
      {
        name: 'Server 3',
        port: 5016
      },
      {
        name: 'Server 4',
        port: 5017
      },
      {
        name: 'Server 5',
        port: 5018
      },
      {
        name: 'Server 6',
        port: 5019
      },
      {
        name: 'Server 7',
        port: 5020
      },
      {
        name: 'Server 8',
        port: 8081
      },
      {
        name: 'Server 9',
        port: 8082
      },
      {
        name: 'Server 10',
        port: 8083
      }
    ];
  
  
  $scope.orderByField = "name";
  $scope.orderByReverse = false;            
  $scope.currentPage = 1;
  $scope.itemsPerPage = 5;

  $scope.orderBy = function(field) {
      if (field == $scope.orderByField)
          $scope.orderByReverse = !$scope.orderByReverse
      else {
          $scope.orderByField = field;
          $scope.orderByReverse = false;
      }
  };

  
})

.factory('Utils', function($timeout, $window) {
    return {
        getNormalizedString: getNormalizedString,
        setFocus: setFocus
    }

    function getNormalizedString(str) {
        str = str.toLowerCase();
        str = str.replace(new RegExp("\\s", 'g'), "");
        str = str.replace(new RegExp("[àáâãäå]", 'g'), "a");
        str = str.replace(new RegExp("æ", 'g'), "ae");
        str = str.replace(new RegExp("ç", 'g'), "c");
        str = str.replace(new RegExp("[èéêë]", 'g'), "e");
        str = str.replace(new RegExp("[ìíîï]", 'g'), "i");
        str = str.replace(new RegExp("ñ", 'g'), "n");
        str = str.replace(new RegExp("[òóôõö]", 'g'), "o");
        str = str.replace(new RegExp("œ", 'g'), "oe");
        str = str.replace(new RegExp("[ùúûü]", 'g'), "u");
        str = str.replace(new RegExp("[ýÿ]", 'g'), "y");
        str = str.replace(new RegExp("\\W", 'g'), "");
        return str;
    }

    function setFocus(id) {
        $timeout(function() {
            var element = $window.document.getElementById(id);
            if (element)
                element.focus();
        });
    }
})

.filter('normalizedOrderBy', function(Utils, $filter) {
    return function(list, orderByField, orderByReverse) {
        function normalize(item) {
            var value = item[orderByField];
            if (typeof value === "string")
                value = Utils.getNormalizedString(value);

            // Forces the empty names to the end.
            if (value === null || value === "")
                return '~';

            return value;
        };

        return $filter('orderBy')(list, normalize, orderByReverse);
    }
})

.filter('normalizedFilter', function(Utils, $filter) {
    return function(list, search) {
        function comparator(actual, expected) {
            // Filtro vazio ou nulo.
            if (expected === "" || expected == null)
                return true;
            // Exatamente iguais.
            if (actual == expected)
                return true;

            if (typeof actual === "string" && typeof expected === "string") {
                actual = Utils.getNormalizedString(actual);
                expected = Utils.getNormalizedString(expected);
                return actual.indexOf(expected) > -1;
            }

            return false;
        };

        return $filter('filter')(list, search, comparator);
    }
});
.corpo {     
    margin-left: auto; 
    margin-right: auto;
    padding: 5px; 
    width: 95%;    
}

.corpo .filtros { margin-top: 50px; }    

.corpo .area-grid { padding: 30px 0px; background-color: #ededee; }
    .corpo .area-grid .container{ margin-left: 5px; margin-right: 10px; width: 100%; }
    .corpo .area-grid .container table { border-collapse: separate; border-spacing: 0 0px; margin-top: -10px; }

        .corpo .grid .grid-header th { color: #999; cursor:pointer; font-family: "RobotoLight", Roboto-Light, sans-serif; padding: 2px 12px; text-align: left; text-decoration: none; }            

        .corpo .grid .linhas-grid.linha-par { background-color: #f8f8f8; }
        .corpo .grid .linhas-grid td { border: 1px solid #ededee; border-style: solid solid; color: #333; font-size: 0.88em; line-height:0.8; padding: 2px 12px; }
        .corpo .grid .linhas-grid td+td { border-left: 2px  #ddd; }
        .corpo .grid .linhas-grid td img { height: 35px; width: 35px; }
        .corpo .grid .linhas-grid td:first-child{ border-left-style: solid; border-top-left-radius: 10px; border-bottom-left-radius: 10px; }
        .corpo .grid .linhas-grid td:last-child { background-color: #ededee; }
        
        .corpo .grid .linhas-grid .icone-grid { background-color: #f5f5f5; box-shadow: 1px 1px 1px #c9c8c9;}
        .corpo .grid .linhas-grid .icone-grid i { color: #999;}
                     
        .corpo .grid .checkbox { height: 17px; width: 17px; margin: 1px; }        
        
        .container .largura100 { width: 98%;}

        .container .largura80 { width: 78%; }
        .container .largura60 { width: 58%; }
        .container .largura40 { width: 38%; }
        .container .largura35 { width: 33%; }
        .container .largura30 { width: 28%; }
        .container .largura20 { width: 18%; }
        .container .largura15 { width: 13%; }
        .container .largura10 { width: 8%; }
        .container .largura5  { width: 3%; }

        .container .largura75 { width: 73%; }
        .container .largura50 { width: 48%; }
        .container .largura25 { width: 23%; }

        .container .largura66 { width: 64%; }
        .container .largura33 { width: 31%; }

        .container .largura100, 
        .container .largura80,
        .container .largura60,
        .container .largura40,
        .container .largura35,
        .container .largura30,
        .container .largura20,
        .container .largura15,
        .container .largura10,
        .container .largura5, 
        .container .largura75,
        .container .largura50,
        .container .largura25,
        .container .largura66,
        .container .largura33        
         {
	        padding-right:1% !important;
	        padding-left:1% !important;
	        margin:8px 0px 8px 0px !important;
        }
<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script data-require="jquery@2.2.4" data-semver="2.2.4" src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
    <link data-require="bootstrap@3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
    <link data-require="bootstrap@3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootswatch/3.3.5/cosmo/bootstrap.min.css" />
    <link data-require="bootstrap@3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" />
    <link data-require="font-awesome@4.5.0" data-semver="4.5.0" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.css" />
    <script data-require="bootstrap@3.3.5" data-semver="3.3.5" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="angular.js@1.4.x" src="https://code.angularjs.org/1.4.12/angular.js" data-semver="1.4.9"></script>
    
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl" class="corpo">
    <div class="filtros" ng-init="selectedTab='access'">
      <div class="row">
        <div class="col-xs-12">
          <div class="campo-pesquisa">
            <div class="input-group margin-bottom-sm">
              <input ng-model="search.$" class="form-control" type="text" placeholder="Pesquisar" />
              <span class="input-group-addon">
                <i class="fa fa-search fa-fw"></i>
              </span>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="area-grid">
      <div class="container">
        <table class="grid">
          <tbody>
            <tr class="grid-header">
              <th ng-click="orderBy('name')" class="largura20 sort">Nome                                                 <span ng-show="orderByField == 'name'" class="fa fa-sort-{{ orderByReverse ? 'desc' : 'asc' }}" aria-hidden="true"></span>
              </th>
              <th ng-click="orderBy('port')" class="largura10 sort">Porta                                                 <span ng-show="orderByField == 'port'" class="fa fa-sort-{{ orderByReverse ? 'desc' : 'asc' }}" aria-hidden="true"></span>
              </th>
              <th class="col largura15"></th>
            </tr>
            <tr class="linhas-grid" ng-class-odd="'linha-par'" ng-class-even="'linha-impar'" ng-repeat="item in servers | normalizedFilter:search |  normalizedOrderBy:orderByField:orderByReverse as filteredList">
              <td>{{ :: item.name }}</td>
              <td>{{ :: item.port }}</td>
              <td>
                <button class="btn btn-default dropdown-togle icone-grid" data-toggle="dropdown">
                  <i class="fa fa-gears"></i>
                </button>
                <ul class="dropdown-menu" role="menu">
                  <li>
                    <a class="dropdown-item" href="#">Atualizar</a>
                  </li>
                  <li>
                    <a class="dropdown-item" href="#">Reiniciar</a>
                  </li>
                  <li role="separator" class="divider"></li>
                  <li>
                    <a class="dropdown-item" href="#">Modificar IP</a>
                  </li>
                  <li>
                    <a class="dropdown-item active" href="#">Avançado</a>
                  </li>
                  <li role="separator" class="divider"></li>
                  <li>
                    <a class="dropdown-item" href="#">Importar</a>
                  </li>
                  <li>
                    <a class="dropdown-item" href="#">Exportar</a>
                  </li>
                </ul>
              </td>
            </tr>
          </tbody>
          <tfoot>
            <tr>
              <td colspan="8" class="text-center">
                <span ng-show="servers == null">Carregando...</span>
                <span ng-show="filteredList.length === 0">Nenhum registro encontrado.</span>
                <uib-pagination ng-show="filteredList.length > 0" ng-model="currentPage" total-items="filteredList.length" items-per-page="itemsPerPage" max-size="10" num-pages="numPages" boundary-links="true" previous-text="‹" next-text="›" first-text="«" last-text="»" class="pagination-sm" style="margin: 0px; margin-bottom: -5px"></uib-pagination>
              </td>
            </tr>
          </tfoot>
        </table>
      </div>
      <!-- fim do container -->
    </div>
    <!-- fim da área do grid -->
  </body>

</html>

【问题讨论】:

    标签: css angularjs twitter-bootstrap html-table dropdown


    【解决方案1】:

    position: relative 添加到您的.corpo .grid .linhas-grid td 即可。

    目前,您的下拉菜单有一个position: absolute 属性,但父容器没有设置position: relative,因此它将取下一个父容器,直到找到相对位置,并将位置 0px 到这个容器的左边(因为下拉菜单有一个left: 0)。

    将相对位置添加到td 父级将使其根据td 的位置定位。

    但正如@makshh 回答的那样,向 td 添加 .dropdown 类也可以解决问题,并且会“更干净”,因为它是 Bootstrap 进行下拉的方式。

    但基本上两者都可以,因为dropdown 类会将position: relative 属性添加到元素。

    var app = angular.module('plunker', []);
    
    app.controller('MainCtrl', function($scope) {
      $scope.filteredList = [];
       $scope.servers = [
          {
            name: 'Server 1',
            port: 5014
          },
          {
            name: 'Server 2',
            port: 5015
          },
          {
            name: 'Server 3',
            port: 5016
          },
          {
            name: 'Server 4',
            port: 5017
          },
          {
            name: 'Server 5',
            port: 5018
          },
          {
            name: 'Server 6',
            port: 5019
          },
          {
            name: 'Server 7',
            port: 5020
          },
          {
            name: 'Server 8',
            port: 8081
          },
          {
            name: 'Server 9',
            port: 8082
          },
          {
            name: 'Server 10',
            port: 8083
          }
        ];
      
      
      $scope.orderByField = "name";
      $scope.orderByReverse = false;            
      $scope.currentPage = 1;
      $scope.itemsPerPage = 5;
    
      $scope.orderBy = function(field) {
          if (field == $scope.orderByField)
              $scope.orderByReverse = !$scope.orderByReverse
          else {
              $scope.orderByField = field;
              $scope.orderByReverse = false;
          }
      };
    
      
    })
    
    .factory('Utils', function($timeout, $window) {
        return {
            getNormalizedString: getNormalizedString,
            setFocus: setFocus
        }
    
        function getNormalizedString(str) {
            str = str.toLowerCase();
            str = str.replace(new RegExp("\\s", 'g'), "");
            str = str.replace(new RegExp("[àáâãäå]", 'g'), "a");
            str = str.replace(new RegExp("æ", 'g'), "ae");
            str = str.replace(new RegExp("ç", 'g'), "c");
            str = str.replace(new RegExp("[èéêë]", 'g'), "e");
            str = str.replace(new RegExp("[ìíîï]", 'g'), "i");
            str = str.replace(new RegExp("ñ", 'g'), "n");
            str = str.replace(new RegExp("[òóôõö]", 'g'), "o");
            str = str.replace(new RegExp("œ", 'g'), "oe");
            str = str.replace(new RegExp("[ùúûü]", 'g'), "u");
            str = str.replace(new RegExp("[ýÿ]", 'g'), "y");
            str = str.replace(new RegExp("\\W", 'g'), "");
            return str;
        }
    
        function setFocus(id) {
            $timeout(function() {
                var element = $window.document.getElementById(id);
                if (element)
                    element.focus();
            });
        }
    })
    
    .filter('normalizedOrderBy', function(Utils, $filter) {
        return function(list, orderByField, orderByReverse) {
            function normalize(item) {
                var value = item[orderByField];
                if (typeof value === "string")
                    value = Utils.getNormalizedString(value);
    
                // Forces the empty names to the end.
                if (value === null || value === "")
                    return '~';
    
                return value;
            };
    
            return $filter('orderBy')(list, normalize, orderByReverse);
        }
    })
    
    .filter('normalizedFilter', function(Utils, $filter) {
        return function(list, search) {
            function comparator(actual, expected) {
                // Filtro vazio ou nulo.
                if (expected === "" || expected == null)
                    return true;
                // Exatamente iguais.
                if (actual == expected)
                    return true;
    
                if (typeof actual === "string" && typeof expected === "string") {
                    actual = Utils.getNormalizedString(actual);
                    expected = Utils.getNormalizedString(expected);
                    return actual.indexOf(expected) > -1;
                }
    
                return false;
            };
    
            return $filter('filter')(list, search, comparator);
        }
    });
    .corpo {     
        margin-left: auto; 
        margin-right: auto;
        padding: 5px; 
        width: 95%;    
    }
    
    .corpo .filtros { margin-top: 50px; }    
    
    .corpo .area-grid { padding: 30px 0px; background-color: #ededee; }
        .corpo .area-grid .container{ margin-left: 5px; margin-right: 10px; width: 100%; }
        .corpo .area-grid .container table { border-collapse: separate; border-spacing: 0 0px; margin-top: -10px; }
    
            .corpo .grid .grid-header th { color: #999; cursor:pointer; font-family: "RobotoLight", Roboto-Light, sans-serif; padding: 2px 12px; text-align: left; text-decoration: none; }            
    
            .corpo .grid .linhas-grid.linha-par { background-color: #f8f8f8; }
            .corpo .grid .linhas-grid td { border: 1px solid #ededee; border-style: solid solid; color: #333; font-size: 0.88em; line-height:0.8; padding: 2px 12px;position: relative; }
            .corpo .grid .linhas-grid td+td { border-left: 2px  #ddd; }
            .corpo .grid .linhas-grid td img { height: 35px; width: 35px; }
            .corpo .grid .linhas-grid td:first-child{ border-left-style: solid; border-top-left-radius: 10px; border-bottom-left-radius: 10px; }
            .corpo .grid .linhas-grid td:last-child { background-color: #ededee; }
            
            .corpo .grid .linhas-grid .icone-grid { background-color: #f5f5f5; box-shadow: 1px 1px 1px #c9c8c9;}
            .corpo .grid .linhas-grid .icone-grid i { color: #999;}
                         
            .corpo .grid .checkbox { height: 17px; width: 17px; margin: 1px; }        
            
            .container .largura100 { width: 98%;}
    
            .container .largura80 { width: 78%; }
            .container .largura60 { width: 58%; }
            .container .largura40 { width: 38%; }
            .container .largura35 { width: 33%; }
            .container .largura30 { width: 28%; }
            .container .largura20 { width: 18%; }
            .container .largura15 { width: 13%; }
            .container .largura10 { width: 8%; }
            .container .largura5  { width: 3%; }
    
            .container .largura75 { width: 73%; }
            .container .largura50 { width: 48%; }
            .container .largura25 { width: 23%; }
    
            .container .largura66 { width: 64%; }
            .container .largura33 { width: 31%; }
    
            .container .largura100, 
            .container .largura80,
            .container .largura60,
            .container .largura40,
            .container .largura35,
            .container .largura30,
            .container .largura20,
            .container .largura15,
            .container .largura10,
            .container .largura5, 
            .container .largura75,
            .container .largura50,
            .container .largura25,
            .container .largura66,
            .container .largura33        
             {
    	        padding-right:1% !important;
    	        padding-left:1% !important;
    	        margin:8px 0px 8px 0px !important;
            }
    <!DOCTYPE html>
    <html ng-app="plunker">
    
      <head>
        <meta charset="utf-8" />
        <title>AngularJS Plunker</title>
        <script data-require="jquery@2.2.4" data-semver="2.2.4" src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
        <link data-require="bootstrap@3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
        <link data-require="bootstrap@3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootswatch/3.3.5/cosmo/bootstrap.min.css" />
        <link data-require="bootstrap@3.3.5" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" />
        <link data-require="font-awesome@4.5.0" data-semver="4.5.0" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.css" />
        <script data-require="bootstrap@3.3.5" data-semver="3.3.5" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
        <script>document.write('<base href="' + document.location + '" />');</script>
        <link rel="stylesheet" href="style.css" />
        <script data-require="angular.js@1.4.x" src="https://code.angularjs.org/1.4.12/angular.js" data-semver="1.4.9"></script>
        
        <script src="app.js"></script>
      </head>
    
      <body ng-controller="MainCtrl" class="corpo">
        <div class="filtros" ng-init="selectedTab='access'">
          <div class="row">
            <div class="col-xs-12">
              <div class="campo-pesquisa">
                <div class="input-group margin-bottom-sm">
                  <input ng-model="search.$" class="form-control" type="text" placeholder="Pesquisar" />
                  <span class="input-group-addon">
                    <i class="fa fa-search fa-fw"></i>
                  </span>
                </div>
              </div>
            </div>
          </div>
        </div>
        <div class="area-grid">
          <div class="container">
            <table class="grid">
              <tbody>
                <tr class="grid-header">
                  <th ng-click="orderBy('name')" class="largura20 sort">Nome                                                 <span ng-show="orderByField == 'name'" class="fa fa-sort-{{ orderByReverse ? 'desc' : 'asc' }}" aria-hidden="true"></span>
                  </th>
                  <th ng-click="orderBy('port')" class="largura10 sort">Porta                                                 <span ng-show="orderByField == 'port'" class="fa fa-sort-{{ orderByReverse ? 'desc' : 'asc' }}" aria-hidden="true"></span>
                  </th>
                  <th class="col largura15"></th>
                </tr>
                <tr class="linhas-grid" ng-class-odd="'linha-par'" ng-class-even="'linha-impar'" ng-repeat="item in servers | normalizedFilter:search |  normalizedOrderBy:orderByField:orderByReverse as filteredList">
                  <td>{{ :: item.name }}</td>
                  <td>{{ :: item.port }}</td>
                  <td>
                    <button class="btn btn-default dropdown-togle icone-grid" data-toggle="dropdown">
                      <i class="fa fa-gears"></i>
                    </button>
                    <ul class="dropdown-menu" role="menu">
                      <li>
                        <a class="dropdown-item" href="#">Atualizar</a>
                      </li>
                      <li>
                        <a class="dropdown-item" href="#">Reiniciar</a>
                      </li>
                      <li role="separator" class="divider"></li>
                      <li>
                        <a class="dropdown-item" href="#">Modificar IP</a>
                      </li>
                      <li>
                        <a class="dropdown-item active" href="#">Avançado</a>
                      </li>
                      <li role="separator" class="divider"></li>
                      <li>
                        <a class="dropdown-item" href="#">Importar</a>
                      </li>
                      <li>
                        <a class="dropdown-item" href="#">Exportar</a>
                      </li>
                    </ul>
                  </td>
                </tr>
              </tbody>
              <tfoot>
                <tr>
                  <td colspan="8" class="text-center">
                    <span ng-show="servers == null">Carregando...</span>
                    <span ng-show="filteredList.length === 0">Nenhum registro encontrado.</span>
                    <uib-pagination ng-show="filteredList.length > 0" ng-model="currentPage" total-items="filteredList.length" items-per-page="itemsPerPage" max-size="10" num-pages="numPages" boundary-links="true" previous-text="‹" next-text="›" first-text="«" last-text="»" class="pagination-sm" style="margin: 0px; margin-bottom: -5px"></uib-pagination>
                  </td>
                </tr>
              </tfoot>
            </table>
          </div>
          <!-- fim do container -->
        </div>
        <!-- fim da área do grid -->
      </body>
    
    </html>

    【讨论】:

    • 就是这样,正如 makshh 和你所说,问题是 与相对位置无关。从字面上应用相对或使用下拉类就可以了。
    【解决方案2】:

    您应该将dropdown 类添加到dropdown-menu 元素的父级(在您的情况下是td 元素)。

    <td class="dropdown">
      <button class="btn btn-default dropdown-togle icone-grid" data-toggle="dropdown">
        <i class="fa fa-gears"></i>
      </button>
      <ul class="dropdown-menu" role="menu">
        <li>
          <a class="dropdown-item" href="#">Atualizar</a>
        </li>
          ...
    

    【讨论】:

    • 非常感谢,我错过了这个细节。
    猜你喜欢
    • 2013-02-22
    • 2013-07-26
    • 2014-08-04
    • 2017-02-05
    • 2020-03-28
    • 1970-01-01
    • 2012-11-28
    • 2022-01-03
    • 2017-03-06
    相关资源
    最近更新 更多