为啥这个宽度监视 AngularJS 指令在切换 Bootstrap 选项卡时不起作用?
Posted
技术标签:
【中文标题】为啥这个宽度监视 AngularJS 指令在切换 Bootstrap 选项卡时不起作用?【英文标题】:Why does this width watching AngularJS directive not work upon switching Bootstrap tabs?为什么这个宽度监视 AngularJS 指令在切换 Bootstrap 选项卡时不起作用? 【发布时间】:2016-01-29 14:26:58 【问题描述】:我在一个页面上有两个 Bootstrap 选项卡,每个选项卡都显示一个列表。我希望每个列表项都是一个正方形,并编写了这个 AngularJS 指令来将每个列表项的高度设置为等于其 Bootstrap 控制的动态宽度:
app.directive('squareDiv', function ()
return
restrict: "A",
link: function (scope, element,attr)
scope.getWidth = function ()
return element.width();
;
scope.$watch(scope.getWidth, function (width)
element.css(
height: width + 'px'
);
, true);
;
);
当我加载这个页面时,第一个选项卡的列表项显示为正方形,这意味着指令正在工作。但是当我单击另一个选项卡时,那里的列表项的默认高度为 100 像素。当我切换回第一个选项卡时,即使是那里的列表项现在也有默认高度。
这里出了什么问题?
更新 1:
这里是一个说明这个问题的 plunker 的链接:http://plnkr.co/edit/Pc7keuRXR9R3U6AhZmFE?p=preview
更新 2:
将 Bootstrap 替换为 UI-Bootstrap 的 Plunker 仍然存在同样的问题:http://plnkr.co/edit/rLE1wUAHKzJP6FVnGF6b?p=preview
更新 3:
Plunker with watch for tab switch 而不是宽度变化(解决原来的宽度 watch 不能正常工作的问题;将需要使用单独的指令来适应由于窗口大小调整导致的宽度变化):http://plnkr.co/edit/Y4Goe0cexq979JsIcBxl?p=preview
我仍然想了解为什么宽度表在标签切换后停止正常工作。
【问题讨论】:
可能是因为标签页被隐藏了,所以它的内容还没有尺寸。无论如何,如果你做了一个 plunker 之类的,它会有所帮助。 没错,一个笨蛋可以帮上大忙! @Price - 我对角度一无所知,但你不能只使用引导程序shown.bs.tab
事件来设置列表项内.holder
元素的height
吗?这是一个例子Plunker。就像我说的那样,我不知道这是否是使用 angular 执行此操作的正确方法,但它确实有效。
@Price - 当然,没问题。最好等待,看看是否有更好的角度背景的人可以告诉你这里发生了什么。一般来说,每当我想操作引导程序组件中的内容时,我总是依赖引导程序事件,但由于我没有角度技能,可能有一个完全不同的解决方案来解决你的问题,我不知道。 ;-)
另见github.com/angular/angular.js/issues/…。
【参考方案1】:
您的指令的观察者是正在发生的事情的一个摘要周期。如果您仔细观察,您会发现第一个选项卡单击并没有多大作用(没有记录到控制台)。您看到的是活动选项卡的元素被调整为隐藏选项卡元素的高度。所以隐藏标签的高度是正确的。我强烈建议使用引导程序的角度版本而不是通用版本。这样一来,一切(事件)都将在 angular 的控制之下。
https://angular-ui.github.io/bootstrap/
编辑:这可能有助于理解 Angular 之外的摘要循环触发和回调:http://school.codecraftpro.com/courses/angularjs-1x-fundamentals/lectures/392422
edit2:也有用https://scotch.io/tutorials/how-to-correctly-use-bootstrapjs-and-angularjs-together
【讨论】:
谢谢!我认为 Angular 与标准的 Bootstrap 兼容。您如何确定观察者落后了一个摘要周期? 在页面加载时,您将看到 4-4 个控制台日志。单击选项卡 2 后,什么都没有。然后它又回来了。所以这基本上是因为 bootstrap js click 没有在 angular 中注册。将它包装在指令中可以解决这个问题,但由于 Angular 用户已经这样做了,你可以抽出一些时间:) 更正:未在该摘要周期内注册,但在一个周期后 感谢所有帮助!我创建了一个基于 ui-bootstrap 的新 plunker,但该指令似乎仍然落后于一个摘要周期。你能检查一下吗:plnkr.co/edit/rLE1wUAHKzJP6FVnGF6b?p=preview? ui.bootstrap.tabs 具有在选项卡选择上触发自定义表达式的设置。请检查此plnkr.co/edit/s5JepBEPMkvGW4Qbm4PH?p=preview 尽管这是一种不同的方法,但我的回答对于原始问题仍然有效。【参考方案2】:我们知道引导选项卡切换的摘要超过了 div 的宽度。因此,与其关注 div 的宽度发生变化,不如关注标签何时发生变化。当标签更改时,让我们等待1 ms以确保我们在下一个摘要周期。然后获取宽度并更新您的盒子高度。
我不知道为什么会这样,但这是可行的解决方案。
这是plunker example
Javascript
var app = angular.module("app",['ngAnimate', 'ui.bootstrap']);
app.controller('mainController',['$scope',function($scope)
$scope.tabs = [
'title': 'Tab 1',
'title': 'Tab 2'
];
]);
app.directive('squareDiv', function ($timeout)
return
restrict: "A",
link: function (scope, element, attr)
scope.active = function()
return scope.tabs.filter(function(tab)
return tab.active;
)[0];
;
scope.$watch(scope.active, function (tabActive)
$timeout(function()
element.css(
height: element.width()
);
, 1);
);
);
【讨论】:
谢谢!根据另一个答案的 cmets,我们需要删除对 ngAnimate 的引用,以防止多次切换选项卡而弄乱此解决方案中的高度。 实际上,如果您还在 $timeout 中包含 requestAnimationFrame,这将防止布局抖动,并且您可以保持 nganimate。见:wilsonpage.co.uk/preventing-layout-thrashing 非常有趣!我刚刚更新了 plunker - plnkr.co/edit/UyxNI9gsOyBg6sNdcvYs?p=preview - 以使用 requestAnimationFrame ,它似乎正在工作。另一个大问题似乎是@ExpertSystem 提出的 jQuery 正在将 100% 的宽度转换为 100px,这也不好。以上是关于为啥这个宽度监视 AngularJS 指令在切换 Bootstrap 选项卡时不起作用?的主要内容,如果未能解决你的问题,请参考以下文章
如何在我的angularjs指令中切换属性的值,如contenteditable?
指令容器的高度为 0px,宽度为 0px - angularjs