AngularJs - $watch仅在Chrome Developer Tools打开时有效

AngularJs - $watch only works when Chrome Developer Tools is open

本文关键字:Tools 有效 Developer Chrome watch 仅在 AngularJs      更新时间:2023-09-26

我正在尝试将$watch附加到一个指令上,该指令监视元素的高度和宽度何时更改,以便它可以使用高度和宽度在图像顶部居中。

这是我的应用程序.js代码:

app.directive('centerElement', function ($timeout) {
return function (scope, element, attrs) {
        scope.$watch(function () {
            return { 
                'h': element[0].offsetHeight, 
                'w': element[0].offsetWidth 
            };
        }, 
        function (newValue, oldValue) {
            var elementHeight = newValue.h;
            var elementWidth = newValue.w;
            /*To account for rounding errors and not loop*/
            if(elementHeight % 2 === 0)
            {
                element.css('margin-top', '-' + ((elementHeight) / 2) + 'px');
            }
            else 
            {
                element.css('margin-top', '-' + ((elementHeight + 1) / 2) + 'px');
            }
            if(elementWidth % 2 === 0)
            {
                element.css('margin-left', '-' + ((elementWidth) / 2) + 'px');
            }
            else
            {
                element.css('margin-left', '-' + ((elementWidth + 1) / 2) + 'px');
            }
        }, true);
        element.bind('centerElement', function () {
            scope.$apply();
        });
};
});

这是我的 html 代码:

<div class="row relativePosition">
    <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 noPadding">
        <img id="getStartedGiveGiftImage" ng-src="{{homeCtrl.getHomeImageBySectionName('getStartedGiveGift').url}}"/>
    </div>
    <div id="getStartedGiveGiftCol" class="absolutePosition" center-element>
        <div class="col-lg-8 col-md-8 col-sm-8 col-xs-12">
            <div class="getStartedGiveGiftText headingTitle">
                Swapping, Sharing,
                <div class="getStartedGiveGiftText text-right">
                    and Caring
                </div>
            </div>
        </div>
        <div id="getStartedGiveGiftButtons" class="col-lg-4 col-md-4 col-sm-4 col-xs-12 text-right">
            <div>
                <a id="getStartedGiveGiftButton1" class="btn btn-default text-right redBackgroundGradient" href="{{homeCtrl.getPage('Get Started').route}}">Get Started</a>
            </div>
            <div>
                <a id="getStartedGiveGiftButton2" class="btn btn-default getStartedGiveGiftButton greenBackgroundGradient text-right text-white" href="{{homeCtrl.getPage('Give a Gift').route}}">Give a Gift</a>
            </div>
        </div>
    </div>
</div>

我已经将 .getStartedGiveGiftCol 的 css 设置为

#getStartedGiveGiftCol {
top: 50%;
left: 50%; }

margin-top值和margin-left值添加到高度的一半和宽度的一半,将元素直接放置在图像的中心。

当我在未打开开发人员工具的情况下在谷歌浏览器中运行该应用程序时,当加载图像并在元素上调整高度和宽度时,不会调用 centerElement 指令手表,但是当我通过逐步运行应用程序时 Chrome 开发人员工具,元素在图像上居中就好了。 当我在没有它的情况下运行应用程序后打开开发人员工具时,没有错误。
另外,我尝试在Internet Explorer,Edge和Firefox中运行该应用程序。 Internet Explorer和Firefox的行为方式都与Chrome相同,但是,Edge是唯一以应有的方式将图像居中的浏览器。

我宁愿不使用$watch,因为它可能存在性能问题,但从我在文档和谷歌上所做的研究来看,我无法找到另一种方法来做到这一点,但我对想法非常开放。 我试图在等待图像加载然后居中元素时找到一些东西,但我没有运气。 我将在应用程序的其他部分重复此指令,因此不必使用$watch会很棒。

我对 angularJS 很陌生,所以非常感谢任何帮助。 我也是关于stackoverflow的新手,所以如果您需要更多信息,请告诉我。

谢谢!

编辑:我为 image 创建了另一个指令,它在加载时会调用 scope.$digest()。 这似乎有所帮助,但是当我多次刷新页面时,有时它仍然不起作用。 有什么想法吗?

这是我添加的指令:

app.directive('imageOnload', function() {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            element.bind('load', function() {
                scope.$digest();
            });
            element.bind('error', function(){
                alert('image could not be loaded');
            });
        }
    };
});

我自己想通了。 我需要在我的centerElement指令中添加$timeout();。 这将强制在完成当前$digest时进行$scope.$apply();,以便将$watch中所做的更改实际应用于页面。

我的指令如下:

app.directive('centerElement', function ($timeout) {
return function (scope, element, attrs) {
        scope.$watch(function () {
            $timeout();
            return { 
                'h': element[0].offsetHeight, 
                'w': element[0].offsetWidth 
            };
        }, 
        function (newValue, oldValue) {
            var elementHeight = newValue.h;
            var elementWidth = newValue.w;
            /*To account for rounding errors and not loop*/
            if(elementHeight % 2 === 0)
            {
                element.css('margin-top', '-' + ((elementHeight) / 2) + 'px');
            }
            else 
            {
                element.css('margin-top', '-' + ((elementHeight + 1) / 2) + 'px');
            }
            if(elementWidth % 2 === 0)
            {
                element.css('margin-left', '-' + ((elementWidth) / 2) + 'px');
            }
            else
            {
                element.css('margin-left', '-' + ((elementWidth + 1) / 2) + 'px');
            }
        }, true);
        element.bind('centerElement', function () {
            scope.$apply();
        });
};
});

如果有人对如何避免使用$watch有任何想法,请告诉我。 我不能只使用 CSS,因为rowposition: relative的,元素是position: absolute所以我必须使用top: 50%left: 50%margin-top负数和元素高度的一半,margin-left负数和宽度的一半(即 当元素高度为 200px 时margin-top: -100px,当元素宽度为 100px 时margin-left: -50px),以便将元素在图像上居中。 我需要找出元素的宽度和高度,而不是将其硬编码为 CSS,这在将来出于维护目的可能会很乏味,因为我必须找出所有屏幕尺寸的大小才能引导。 因此,为什么我使用$watch.我也在使用引导程序,所以 CSS3 flexbox是不可能的,因为它搞砸了引导网格响应能力。

因此,如果有人有任何想法如何摆脱$watch,请告诉我。