【问题标题】:if a ngSrc path resolves to a 404, is there a way to fallback to a default?如果 ngSrc 路径解析为 404,有没有办法回退到默认值?
【发布时间】:2013-04-24 23:42:08
【问题描述】:

我正在构建的应用程序需要我的用户设置 4 条信息,然后才能加载此图像。该图像是应用程序的核心部分,因此损坏的图像链接使它看起来像是整个事情都被破坏了。我想让另一个图像在 404 上取代它。

有什么想法吗?我想避免为此编写自定义指令。

我很惊讶我找不到类似的问题,尤其是当文档中的第一个问题是同一个问题时!

http://docs.angularjs.org/api/ng.directive:ngSrc

【问题讨论】:

标签: angularjs angularjs-directive


【解决方案1】:

要扩展 Jason 解决方案以捕获加载错误或空源字符串这两种情况,我们可以添加一个监视。

HTML:

<img ng-src="smiley.png" err-src="http://google.com/favicon.ico" />

Javascript:

var app = angular.module("MyApp", []);

app.directive('errSrc', function() {
  return {
    link: function(scope, element, attrs) {

      var watcher = scope.$watch(function() {
          return attrs['ngSrc'];
        }, function (value) {
          if (!value) {
            element.attr('src', attrs.errSrc);  
          }
      });

      element.bind('error', function() {
        element.attr('src', attrs.errSrc);
      });

      //unsubscribe on success
      element.bind('load', watcher);

    }
  }
});

【讨论】:

  • 不错的代码,但在模板中添加一个可以通过ng-if 轻松检查的内容(空 src 字符串)似乎有点矫枉过正
  • 似乎您可以将 ngSrc 替换为您自己的指令,并让它设置错误时绑定以使用 errSrc 而不是单独的 errSrc 指令(如果您想要的话)。你可以使用attrs.$observe('ngSrc', function(value) {...});,这就是ngSrc在内部使用而不是$watch
  • 空白的全部问题是因为如果值为空白,ngSrc 不会更新 src 属性,因此如果您有自己的指令替换 ngSrc,则不需要空白检查。
  • @Pokono - 您可以在错误函数内部检查当前的 'src' 属性是否与 'errSrc' 相同。
  • @BiswasKhayargoli - 添加了取消订阅的调用,因此在初始加载后不会有任何处理成本
【解决方案2】:

这将只允许循环两次,以检查 ng-src 是否不存在,否则使用 err-src,这样可以防止继续循环。

(function () {
    'use strict';
    angular.module('pilierApp').directive('errSrc', errSrc);

    function errSrc() {
        return {
            link: function(scope, element, attrs) {
             element.error(function () {
                // to prevent looping error check if src == ngSrc
                if (element.prop('src')==attrs.ngSrc){
                     //stop loop here
                     element.prop('src', attrs.errSrc);
                }              
            });
            }
        }
    }
})();

【讨论】:

    【解决方案3】:

    你不需要 Angular,甚至 CSS 或 JS。如果你愿意,你可以将这个答案(链接)包装在一个简单的指令中,以使其更简单,比如或其他东西,但这是一个非常简单的过程......只需将它包装在一个对象标签中......

    How to hide image broken Icon using only CSS/HTML (without js)

    【讨论】:

      【解决方案4】:

      想出了我自己的解决方案。 如果 src 或 ngSrc 为空,并且如果 img 返回 404,它会替换 image。

      (@Darren 解决方案的分支)

      directive('img', function () {
      return {
          restrict: 'E',        
          link: function (scope, element, attrs) {   
              if((('ngSrc' in attrs) && typeof(attrs['ngSrc'])==='undefined') || (('src' in attrs) && typeof(attrs['src'])==='undefined')) {
                  (function () {
                      replaceImg();
                  })();
              };
              element.error(function () {
                  replaceImg();
              });
      
              function replaceImg() {
                  var w = element.width();
                  var h = element.height();
                  // using 20 here because it seems even a missing image will have ~18px width 
                  // after this error function has been called
                  if (w <= 20) { w = 100; }
                  if (h <= 20) { h = 100; }
                  var url = 'http://placehold.it/' + w + 'x' + h + '/cccccc/ffffff&text=No image';
                  element.prop('src', url);
              }
          }
      }
      });
      

      【讨论】:

        【解决方案5】:
        App.directive('checkImage', function ($q) {
            return {
                restrict: 'A',
                link: function (scope, element, attrs) {
                    attrs.$observe('ngSrc', function (ngSrc) {
                        var deferred = $q.defer();
                        var image = new Image();
                        image.onerror = function () {
                            deferred.resolve(false);
                            element.attr('src', BASE_URL + '/assets/images/default_photo.png'); // set default image
                        };
                        image.onload = function () {
                            deferred.resolve(true);
                        };
                        image.src = ngSrc;
                        return deferred.promise;
                    });
                }
            };
        });
        

        在 HTML 中:

        <img class="img-circle" check-image ng-src="{{item.profileImg}}" />
        

        【讨论】:

        • 我觉得这应该是公认的答案,因为它不使用 jQuery 并解决了问题
        【解决方案6】:

        这是我使用本机 javascript 提出的解决方案。我正在检查图像是否损坏,然后为图像添加一个类以防万一并更改源。

        我的部分答案来自 Quora 答案http://www.quora.com/How-do-I-use-JavaScript-to-find-if-an-image-is-broken

        app.directive('imageErrorDirective', function () {
            return {
                restrict: 'A',
                link: function (scope, element, attrs) {
                    element[0].onerror = function () {
                        element[0].className = element[0].className + " image-error";
                        element[0].src = 'http://img3.wikia.nocookie.net/__cb20140329055736/pokemon/images/c/c9/702Dedenne.png';
                    };
                }
            }
        });
        

        【讨论】:

          【解决方案7】:

          如果图像为 404 或图像为空,则无论不需要指令,您都可以像这样简单地使用 ng-src 过滤器 :)

          <img ng-src="{{ p.image || 'img/no-image.png' }}" />
          

          【讨论】:

          • 不,如果 p.image 在 AJAX 调用中返回 404,它会将其视为“真”并且不会继续处理第二个 img/no-image.png。
          • @JamesGentes - 情况似乎并非如此。 ng-src 的这种使用对我来说完全如图所示。而且它要简单得多。
          • @shaneveeg 谢谢,这很有趣 - 我想知道后端是否有什么不同。我正在用 Express 运行 Node,也许它的处理方式不同。
          • @JamesGentes - 更正我之前的评论。当模型返回一个有效的 URI 时,OP 正在寻找一个解决方案,但是当它被跟踪时是 404。在这种情况下,此解决方案不起作用,它会导致图像损坏。如果 angular 没有为图像值返回任何内容,则正确选择了后备。
          • 我正在使用 Laravel,如果是 404、null 或 empty,它对我来说是完美的。但也许 Express 返回某种错误而不是像 404 这样的代码响应,所以是的可能取决于服务器框架
          【解决方案8】:

          我使用类似的东西,但它假定 team.logo 是有效的。如果“team.logo”未设置或为空,则强制默认。

          <img ng-if="team.logo" ng-src="https://api.example.com/images/{{team.logo}}">
          <img ng-hide="team.logo" ng-src="img/default.png">
          

          【讨论】:

          • 这是正确的,因为它将“team.logo”评估为字符串(真/假),而 ng-src 将看到 {{team.logo}} 为真,即使它返回 404。
          【解决方案9】:

          虽然我想出了一个解决方案来解决我正在构建的系统中或多或少相同的问题。

          不过,我的想法是在全局范围内处理每个图像 img 标签。

          我不想在我的HTML 中添加不必要的指令,例如此处显示的err-src。很多时候,特别是对于动态图像,您不会知道它是否丢失,直到为时已晚。在图像丢失的情况下添加额外的指令对我来说似乎有点矫枉过正。

          相反,我扩展了现有的img 标签——这确实是 Angular 指令的全部内容。

          所以 - 这就是我想出的。

          注意:这需要完整的 JQuery 库,而不仅仅是 JQlite Angular,因为我们使用的是 .error()

          你可以在Plunker看到它的实际效果

          指令看起来很像这样:

          app.directive('img', function () {
              return {
                  restrict: 'E',        
                  link: function (scope, element, attrs) {     
                      // show an image-missing image
                      element.error(function () {
                          var w = element.width();
                          var h = element.height();
                          // using 20 here because it seems even a missing image will have ~18px width 
                          // after this error function has been called
                          if (w <= 20) { w = 100; }
                          if (h <= 20) { h = 100; }
                          var url = 'http://placehold.it/' + w + 'x' + h + '/cccccc/ffffff&text=Oh No!';
                          element.prop('src', url);
                          element.css('border', 'double 3px #cccccc');
                      });
                  }
              }
          });
          

          当发生错误时(这将是因为图像不存在或无法访问等),我们会捕获并做出反应。您也可以尝试获取图像尺寸 - 如果它们首先出现在图像/样式中。如果没有,请为自己设置一个默认值。

          此示例使用 placehold.it 来显示图像。

          现在每张图片,无论是使用src 还是ng-src,都已被覆盖,以防万一没有加载...

          【讨论】:

          • 非常好的解决方案!让我们投票给这个吧!
          • 我不得不说这很漂亮。实际上,如果无法解析,我根本不希望显示任何图像,因此我使用了: element.css("display", "none");完全隐藏它
          • nice :) 或者您可以使用 element.remove() 将其从 DOM 中完全删除; :)
          • 效果很好,谢谢!
          • 对您的解决方案进行了一些编辑,因此当路径为空时也可以使用。 stackoverflow.com/a/35884288/2014288
          【解决方案10】:

          这是一个非常简单的指令,用于监视加载图像的错误并替换 src。 (Plunker)

          HTML:

          <img ng-src="smiley.png" err-src="http://google.com/favicon.ico" />
          

          Javascript:

          var app = angular.module("MyApp", []);
          
          app.directive('errSrc', function() {
            return {
              link: function(scope, element, attrs) {
                element.bind('error', function() {
                  if (attrs.src != attrs.errSrc) {
                    attrs.$set('src', attrs.errSrc);
                  }
                });
              }
            }
          });
          

          如果您想在 ngSrc 为空时显示错误图像,您可以添加此(Plunker)

          attrs.$observe('ngSrc', function(value) {
            if (!value && attrs.errSrc) {
              attrs.$set('src', attrs.errSrc);
            }
          });
          

          问题是如果值为空,ngSrc 不会更新 src 属性。

          【讨论】:

          • 如果 url 被破坏 (404) 效果很好,但如果它是一个空字符串,ng-src 会默默地吞下错误。
          • 如果一个空字符串对您的模型无效,那么请确保您使用 ng-src 绑定到的表达式不会返回空字符串。
          • 更新了脚本以支持对err-src 图像使用src 属性:plnkr.co/edit/b05WtghBOHkxKdttZ8q5
          • @JustinLovero 我认为这是一个角度错误并报告了它。问题是如果值为空,ngSrc 将不会设置 src 属性。这实际上可能是一个问题,例如,如果您正在显示一部手机并使用缺少图像 url 的 ajax 加载另一部手机。旧手机的图像将继续显示,但我认为错误或占位符会更合适。是的,您可以在模型中处理它,但我认为留下旧图像的行为比显示错误更错误。
          • @JasonGoemaat,如何用文本替换损坏的图像?
          【解决方案11】:

          我建议您可能喜欢使用 Angular UI Utils 'if statement' 指令来解决您的问题,如 http://angular-ui.github.io/ 所示。我刚刚用它来做同样的事情。

          这是未经测试的,但您可以执行以下操作:

          控制器代码:

          $scope.showImage = function () {
              if (value1 && value2 && value3 && value4) { 
                  return true;
              } else {
                  return false;
              }
          };
          

          (或更简单)

          $scope.showImage = function () {
              return value1 && value2 && value3 && value4;
          };
          

          视图中的 HTML:&lt;img ui-if="showImage()" ng-src="images/{{data.value}}.jpg" /&gt;

          或者更简单,您可以只使用范围属性:

          控制器代码:

          $scope.showImage = value1 && value2 && value3 && value4;
          

          视图中的 HTML:&lt;img ui-if="showImage" ng-src="images/{{data.value}}.jpg" /&gt;

          对于占位符图像,只需添加另一个类似的 &lt;img&gt; 标记,但在 ui-if 参数前加上感叹号 (!) 标记,并让 ngSrc 具有占位符图像的路径,或者只使用 @ 987654330@ 标记为正常的 ol' HTML。

          例如。 &lt;img ui-if="!showImage" src="images/placeholder.jpg" /&gt;

          显然,当您的 4 条信息都不完整时,上述所有代码示例都假设 value1、value2、value3 和 value4 中的每一个都等于null / false(因此也等于一个布尔值true 的值(当它们完成时)。

          PS。 AngularUI 项目最近被拆分为子项目,目前似乎缺少ui-if 的文档(虽然它可能在某个包中)。但是,如您所见,它使用起来非常简单,而且我在 Angular UI 项目上记录了一个 Github 的“问题”,也向团队指出了这一点。

          更新:AngularUI 项目中缺少“ui-if”,因为它已集成到核心 AngularJS 代码中!仅从 v1.1.x 开始,目前被标记为“不稳定”。

          【讨论】:

          • ng-if 进入核心顺便说一句(如果我没记错的话,从 1.1.5 开始)。
          【解决方案12】:

          是否存在无法在代码中声明后备图像的特定原因?

          据我了解,您的图片来源有两种可能的情况:

          1. 正确设置信息片段
          2. 正确设置信息 == 4 = 生成的 URL。

          我认为这应该由您的应用处理 - 如果当前无法确定正确的 URL,请改为传递加载/后备/占位符图像 URL。

          原因是您永远不会有“丢失”图像,因为您已明确声明要在任何时间点显示的正确 URL。

          【讨论】:

          • 对不起,我应该澄清一下,即使设置了所有 4 个值,URL 仍然可以是 404(用户可以在此过程中添加文件夹。)同时我添加了一个函数设置所有值后检查 URL 的响应标头。在没有特殊处理的情况下处理这个仍然会很好,我敢打赌我会再次遇到这个:)
          • 很酷,您应该将其显示为答案并将其标记为已接受以供将来搜索的任何人使用。
          猜你喜欢
          • 2017-08-10
          • 2013-12-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-05
          • 1970-01-01
          相关资源
          最近更新 更多