【问题标题】:Why does ng-src not trigger certain property changes in AngularJS?为什么 ng-src 不会触发 AngularJS 中的某些属性更改?
【发布时间】:2013-10-05 06:24:39
【问题描述】:

我有一个示例指令,用于监视元素的变化,例如 offsetWidth。

如果我将指令应用于通过 src 属性加载 url 的 img 元素,一切正常。

如果我将该指令应用于通过 ng-src 属性加载 url 的 img 元素,则 offsetWidth 不会得到更新。

HTML:

<!DOCTYPE html>
<html ng-app="test">

  <head>
    <script data-require="angular.js@1.2.0-rc2" data-semver="1.2.0-rc2" src="http://code.angularjs.org/1.2.0-rc.2/angular.js"></script>
    <script src="script.js"></script>
  </head>

  <body>
    <h1>OffsetWidth: {{offsetwidth}} OffsetLeft: {{offsetleft}}</h1>
    <img testing ng-src="{{'http://scienceblogs.com/scientificactivist/wp-content/blogs.dir/392/files/2012/04/i-dcb85296b3695e8ce6d1ae4d660cea30-Smiley-face.gif'}}"></img>
  </body>

</html>

Javascript:

angular.module('test', []).
  directive('testing', function() {
    return function(scope, element, attr) {
      scope.$watch(
        'element.offsetWidth',
        function(newVal, oldVal) {
          scope.offsetwidth = element[0].offsetWidth
        }
      )
      scope.$watch(
        'element.offsetLeft',
        function(newVal, oldVal) {
          scope.offsetleft = element[0].offsetLeft
        }
      )
    }
  });

Plunkr

更新:

我在下面应用了 Buu Nguyen 的解决方案,以确保观察到正确的更改,但似乎存在时间问题。多次重新加载页面时,我注意到有时值会正确更新,有时则不会。

更新的javascript:

angular.module('test', []).
  directive('testing', function() {
    return function(scope, element, attr) {
      scope.$watch(
        function() {
          return element[0].offsetWidth
        },
        function(newVal, oldVal) {
          scope.offsetwidth = element[0].offsetWidth
        }
      )
      scope.$watch(
        function() {
          return element[0].offsetLeft
        },
        function(newVal, oldVal) {
          scope.offsetleft = element[0].offsetLeft
        }
      )
    }
  });

Updated Plunkr

【问题讨论】:

    标签: javascript angularjs angularjs-directive


    【解决方案1】:

    您无法查看 element 的属性,因为它不在范围内。解决此问题而不用不必要的字段污染范围的一种方法是将监视函数传递给$watchDemo link.

    angular.module('test', []).
      directive('testing', function() {
        return function(scope, element, attr) {
          element.on('load', function() { 
            scope.offsetwidth = element[0].offsetWidth
            scope.offsetleft = element[0].offsetLeft
            scope.$apply();
          });
        }
      });
    

    注意:imgload 事件可能无法在所有浏览器中可靠地工作。如需更稳健的方法,请尝试library

    【讨论】:

    • 有趣。那么它之前是如何运作的呢?调用 'element.offsetLeft' 来观看会返回正确的值,因此它似乎在范围内正确评估。
    • 如果某些内容不在范围内,则范围无法通过字符串表达式查看它。但是,监视侦听器始终使用初始值初始化一次(如果您想知道原因,请阅读文档或代码),因此一些幸运的时机可能会让您的原始代码在某个时间点适用于某些属性,但这并不这意味着它是正确的代码。
    • 很容易验证,不要在监听器中使用element[0].offsetLeft,而是使用newVal。我确定它会是undefined
    • 我刚刚注意到这个解决方案不能保证有效。有时间问题。我重新加载了页面 10 次,其中一次,偏移宽度返回 0。
    • 好收获。如果 img 在初始摘要循环之后加载,则当其大小更改时,不会处理手表。我更新了代码以处理“加载”事件并运行循环。
    【解决方案2】:

    按照 Buu Nguyen 的回答,这是正确的,我应该说不建议使用观察者来监视 DOM,因为“Scope $watch 性能注意事项”部分下的 the Angular docs 状态:

    检查属性更改的范围是常见的操作 Angular,因此脏检查功能必须是 高效的。应该注意脏检查功能 不做任何 DOM 访问,因为 DOM 访问速度要慢几个数量级 然后对 JavaScript 对象进行属性访问。

    我不确定这是否会成为您的问题,但请记住这一点。

    【讨论】:

    • 那我可以用其他方式监控 DOM 吗?如果我的意图是让指令根据元素在页面上呈现时的当前大小和位置来做某事,你会建议什么?
    • 我之前在 Angular 中没有做过类似的事情,所以我没有一个直接的答案。什么呈现元素?您的指令是否可以这样做,以便它知道元素的大小和位置而无需监视这些属性?
    【解决方案3】:

    我只是在猜测,但可能是您的指令在 ng-src 之后运行,因此它没有获取更改,因为它及时错过了它(考虑到图像在浏览器缓存中)。指令的默认优先级是 0,但 ng-src 有 99,因此尝试为您的测试指令分配高于 99 的优先级不会有什么坏处。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-13
      • 2013-10-08
      • 2017-09-14
      • 1970-01-01
      • 1970-01-01
      • 2013-11-27
      相关资源
      最近更新 更多