2

我知道这已经被问了一千次了,但我想我已经尝试了我读过的每一个解决方案,但我似乎无法让它发挥作用。

我有一个从中获取图像的 API,在将图像拉入视图后,我希望它们使用 photoswipe 在移动设备上显示。

我有一个指令:

'use strict';

App.directive('photoswipe', function () {
return {
    replace: false,
    restrict: 'A',
    link: function photoSwipeLink(scope, element, attr) {
      scope.$watch(attr.photoswipe, function(value){
        angular.element('#gallery a').photoSwipe({
          enableMouseWheel: false,
          enableKeyboard: false
        });
      });
    }
  };
});

我在控制台中收到此错误:

Code.PhotoSwipe.createInstance: No images to passed.

我猜这是因为指令在视图渲染之前运行。

如果我添加 $timeout 而不是 watch 那么代码确实有效。不幸的是,这个解决方案并不好,因为从 API 获取数据可能会有延迟。此外,代码在超时内不起作用。

我已经尝试过,上面的代码,我尝试过使用 $viewcontentloaded,尝试过在 ng-repeat 中的最后一个元素之后触发函数,但都不起作用。

任何帮助将非常感激。

编辑:

这是HTML。

<h1>{{ gallery.headline }}</h1>
<ul id="gallery" photoswipe>
  <li class="gallery" ng-repeat="image in gallery.images">
    <a href="{{ image.url }}" alt="image.caption">
      <img ng-src="{{ image.thumb_url }}" class="thumb" alt="{{ image.caption }}" style="display: block;">
      <h3 class="headline">{{ image.caption }}</h3>
    </a>
  </li>
</ul>
4

3 回答 3

3

我认为这是因为 Angular 在结果绑定到列表之前正在处理您的指令。这可能是一种竞争条件。解决此问题的一种方法是

$scope.$broadcast("picsDownloaded" ... 

获得结果后,控制器中的事件。在指令上,而不是

scope.$watch(attr.photoswipe ....

做这个

scope.$on("picsDownloaded" ....

并在该处理程序中应用 Jquery 插件。

于 2013-05-13T19:34:13.673 回答
0

是的,您可以使用事件在数据存在时发出信号。尽管您可能必须使用 $rootScope,但这取决于用例。

但我认为您的错误最可能的原因是,AngularJS 在使用未定义的值初始化它们时第一次调用所有 $watchers。

您应该在 $watch 函数中检查是否可以立即解决您的问题。

于 2013-05-13T19:45:17.640 回答
0

正如其他人指出的那样,您需要等到所有这些东西都被渲染出来,这只有在您的 api 调用返回结果后才会发生。您的指令的信号将是gallery.images数组的更改。所以,让你的指令像下面这样监视它。

请注意新引入的隔离范围 - 对我来说,它听起来应该是隔离的,但我不能肯定地说,因为我不知道你的应用程序代码的其余部分。

无论如何,它告诉 Angular 模板中属性中使用的任何值photoswipe(见下文)都应该绑定到images指令范围的属性。使用这样的结构可确保在每次更改时都会发生这种情况,gallery.images无论何时以及如何发生。您需要做的只是在 api 调用完成时更改集合,其余的就可以了。没有事件(对我来说,它们在 angular 1.x 中非常麻烦),不同组件之间没有联系,没有混合关注点。非常干净的解决方案。但是,您需要了解$watchCollection()是如何工作的,它与常规的有点不同$watch,它执行浅集合扫描并且不比较集合中的对象本身,而只比较它们的引用。

另一个重要时刻是清理工作。您必须确保从集合中删除某些内容时,相应的事件以及插件绑定到元素的任何其他内容都被正确销毁,否则您最终会遇到内存泄漏、意外事件和性能不佳的问题。

App.directive('photoswipe', function ($timeout) {
return {
    replace: false,
    restrict: 'A',
    scope: {
        "images": "=photoswipe"
    },
    link: function photoSwipeLink(scope, element, attr) {
        scope.$watchCollection('images', function(value){
            // here $timeout() is necessary because this event will be fired
            // immediately after collection change
            // thus not giving angular time to render it
            // so, jquery plugin will be fired on the next angular digest
            // and everything will be rendered by then.
            $timeout(function () {
                angular.element('#gallery a').photoSwipe({
                    enableMouseWheel: false,
                    enableKeyboard: false
                });
                // and now figure out how to clean it up!
            });
        });
    }
  };
});

现在到模板。请注意,我第一次使用photoswipe="gallery.images"属性。这就是告诉 Angular 绑定到属性指令gallery.images范围的原因。photoswipeimages

由于指令现在引入了自己的隔离范围,因此它内部的所有内容都应考虑到这一事实。这就是为什么ng-repeat="image in images"

<h1>{{ gallery.headline }}</h1>
<ul id="gallery" photoswipe="gallery.images">
  <li class="gallery" ng-repeat="image in images">
    <a href="{{ image.url }}" alt="image.caption">
      <img ng-src="{{ image.thumb_url }}" class="thumb" alt="{{ image.caption }}" style="display: block;">
      <h3 class="headline">{{ image.caption }}</h3>
    </a>
  </li>
</ul>

老实说,我没有测试这段代码,但除了可能的语法错误之外,它应该可以工作。另外,我想再强调一次,我不知道你的应用程序其余部分的结构,所以如果你的指令中的某些东西被绑定到更高的范围,那么引入隔离范围可能会破坏它 - 但对我来说这是个坏主意本身,因为它在组件之间引入了隐藏的互连。

于 2017-12-14T16:32:08.197 回答