我正在尝试在单击按钮后打开表内的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>
答案 0 :(得分: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>
...
答案 1 :(得分:0)
向position: relative
添加.corpo .grid .linhas-grid td
即可。
目前,您的下拉菜单中有position: absolute
属性,但父容器没有设置position: relative
,因此它会占用下一个父级,直到找到相对位置,并将0px放在此容器的左侧(因为下拉菜单中有left: 0
)。
将相对位置添加到td
父级会使其根据td
的位置进行定位。
但正如@makshh所回答的那样,在td中添加一个.dropdown
类也会起到作用,并且会更清洁&#34;因为它是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);
}
});
&#13;
.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;
}
&#13;
<!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>
&#13;