Javascript 为什么这个宽度监视AngularJS指令在切换引导选项卡时不起作用?

Javascript 为什么这个宽度监视AngularJS指令在切换引导选项卡时不起作用?,javascript,jquery,css,angularjs,twitter-bootstrap,Javascript,Jquery,Css,Angularjs,Twitter Bootstrap,我在一个页面上有两个引导选项卡,每个选项卡都显示一个列表。我希望每个列表项都是正方形,并编写了以下AngularJS指令,将每个列表项的高度设置为等于其引导控制的动态宽度: app.directive('squareDiv', function () { return { restrict: "A", link: function (scope, element,attr) { scope.getWidth = function (

我在一个页面上有两个引导选项卡,每个选项卡都显示一个列表。我希望每个列表项都是正方形,并编写了以下AngularJS指令,将每个列表项的高度设置为等于其引导控制的动态宽度:

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 px。当我切换回第一个选项卡时,即使那里的列表项现在也具有默认高度

这里出了什么问题

更新1:

以下是说明此问题的plunker链接:

更新2:

将引导程序替换为UI引导程序的Plunker仍然存在相同的问题:

更新3:

Plunker带有watch for tab开关,而不是宽度变化(解决宽度变化不能正常工作的原始问题;需要使用单独的指令来适应由于窗口大小调整而引起的宽度变化):


我仍然想理解为什么宽度表在切换制表符后停止正常工作。

您的指令的观察程序比正在发生的事情晚了一个消化周期。如果仔细观察,您会发现第一次单击选项卡并没有什么作用(控制台中没有记录任何内容)。您看到的是活动选项卡的元素被调整为隐藏选项卡元素高度。因此隐藏选项卡的高度是正确的。我强烈建议使用有角度的引导版本,而不是一般的引导版本。这样,一切(事件)都将受控制

编辑:这可能有助于理解摘要周期触发和外部回调:


edit2:也很有用

我们知道,引导选项卡切换的摘要比div的宽度要快。因此,与其关注div的宽度变化,不如关注tab的变化。当选项卡更改时,让我们等待1毫秒以确保进入下一个摘要周期。然后获取宽度并更新框的高度

我不知道为什么会这样,但这里有一个可行的解决方案

这是一个

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);

            });

        }
    }
});

这可能是因为选项卡是隐藏的,所以其内容还没有维度。不管怎么说,如果你做了一个扑克牌什么的,它会有帮助的。没错,扑克牌可能会有很大的帮助@价格-我对angular完全不了解,但你能不能只使用bootstraps
Showed.bs.tab
事件来设置列表项中
.holder
元素的
高度?这里有一个例子。就像我说的,我不知道这是否是正确的方法,但它是有效的。@Price-当然,没问题。也许最好等着看,是否有人在angular方面有更好的背景可以告诉你这里发生了什么。一般来说,每当我想操纵引导组件内的内容时,我总是依赖引导事件,但由于我没有角度技能,可能会有一个完全不同的解决方案来解决您的问题,我不知道。;-)另见,谢谢!我认为Angular与标准引导兼容。您是如何确定观察者落后一个摘要周期的?在pageload上,您将看到4-4个控制台日志。单击选项卡2后,没有任何内容。然后它又回来了。这基本上是因为bootstrap js click没有在angular中注册。将其包装在一个指令中可以解决这个问题,但由于angular ui人员已经这样做了,您可以抽出一些时间:)更正:未在该摘要周期内注册,但在一个周期后注册谢谢所有帮助!我已经基于ui引导创建了一个新的plunker,但该指令似乎仍然落后一个消化周期。您能检查一下吗:?ui.bootstrap.tabs有一个在“选择”选项卡上触发自定义表达式的设置。请检查这一点,即使这是一个不同的方法,我的答案仍然适用于原始问题。谢谢!根据对另一个答案的评论,我们需要删除对ngAnimate的引用,以防止在该解决方案中多次切换选项卡,从而扰乱高度。实际上,如果在$timeout中还包含requestAnimationFrame,则可以防止布局抖动,并且可以保留ngAnimate。看:很有趣!我刚刚更新了plunker--使用requestAnimationFrame,它似乎正在工作。另一个大问题似乎是@ExpertSystem提出的jQuery正在将100%的宽度转换为100px,这也不好。