AngularJS:非标准属性上的ng-src行为?

15

我正在使用“Video For Everybody”生成器在我的应用程序中集成媒体播放器。由于该播放器在浏览器不支持HTML5 videoaudio时会回退到flash,因此我必须使用object元素和param属性构建视频和占位符(图像)源。

正如预期的那样,我遇到了表达式未能及时解析的经典问题,我的浏览器发送请求到my.media.com/{{video.src}}而不是my.media.com/somevideo.mp4

不幸的是,还有几个属性(poster、flashvars、placeholder等)也面临同样的问题。我该如何创建与ng-srcng-href指令相同的行为?我尝试查找相关源代码,但我没有找到它。以下是一个展示有问题的HTML片段:

<video controls="controls" poster="{{mediaModel.mediaFile2}}" width="300" height="150">
<source ng-src="{{mediaModel.mediaFile}}" type="{{mediaModel.contentType}}" />
<object type="application/x-shockwave-flash" data="http://player.longtailvideo.com/player.swf" width="300" height="150">
    <param name="movie" value="http://player.longtailvideo.com/player.swf" />
    <param name="allowFullScreen" value="true" />
    <param name="wmode" value="transparent" />
    <param name="flashVars" value="{{'controllerbar=over&amp;image=' + media.mediaFile2 + '&amp;file=' + mediaModel.mediaFile}}" />
    <img ng-src="{{mediaModel.mediaFile2}}" width="300" height="150" title="{{mediaModel.uploadedTime}}" />
</object>


(这是一个空的段落标签,没有需要翻译的内容。)

你能分享一些你尝试过但没有奏效的方法吗? - Davin Tryon
目前我还在摸索中,试图弄清楚是否有可能应用自定义属性,因此我认为我现在拥有的任何代码都不会对问题有所帮助。当我有了一些进展时,我会尽快更新。 - Index
4个回答

48

现在您可以使用ng-attr-poster,或更普遍的是:ng-attr-whatever


8
在官方API文档中,可以轻松找到内置指令的源代码。在这种情况下,转到ngSrc的文档,页面顶部将看到两个按钮,“改进此文档”和“查看源码”,单击“查看源码”,它将自动带您到定义指令的正确源文件。这适用于所有内置指令,非常方便!
下面是ngSrc的代码,有趣的是它看起来并不复杂,关键行似乎是priority: 99,根据旁边的注释意味着具有优先级为99的指令将在属性被插值后运行。
// ng-src, ng-srcset, ng-href are interpolated
forEach(['src', 'srcset', 'href'], function(attrName) {
  var normalized = directiveNormalize('ng-' + attrName);
  ngAttributeAliasDirectives[normalized] = function() {
    return {
      priority: 99, // it needs to run after the attributes are interpolated
      link: function(scope, element, attr) {
        attr.$observe(normalized, function(value) {
          if (!value)
             return;

          attr.$set(attrName, value);

          // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
          // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
          // to set the property as well to achieve the desired effect.
          // we use attr[attrName] value since $set can sanitize the url.
          if (msie) element.prop(attrName, attr[attrName]);
        });
      }
    };
  };
});

考虑到上述内容,实现自己的指令应该很简单。

非常好,非常感谢。不敢相信我在 Angular 文档上花了这么多时间,却忽略了这个简单但非常实用的功能。顺便提一下:我将暂时不接受/奖励赏金,以防出现更多的答案。 - Index
@KGChristensen NP 很高兴我能帮到你。 - Beyers

1
我在video标签的poster属性上遇到了类似的问题。如果你将ng-cloak应用于具有类似src的属性的元素,则它们在被移除遮罩时才会变为可见状态并尝试加载内容。

1
所以最通用,易于维护,可配置和可重用的解决方案是创建一个自定义指令来处理它。

看一下这个-->PLNKR<--,基本上所有你需要的都在那里。你只需要稍微调整一下。

它的工作原理:向指令传递配置对象(如果需要更多对象,请创建其他属性)。元素可以有两种状态:准备好或未准备好。而$scope.isReady只是说明是否已经收集了所有的信息。如果是这样的话,ngSwitch将加载videoPlayer模板,并且由于所有的信息都在那里,不会发送任何不必要的请求。


感谢你的努力,但固定的超时时间并不是很用户友好或可行的选项。我成功创建了自己的ngSrc指令实现,使用$observe监听表达式解析。 - Index
@KGChristensen 你可能没有理解这段代码。使用$timeout只是为了演示这种方法确实可以工作,并且它是在控制器中而不是指令本身中使用的。指令会等待作用域被填充,检查是否所有数据都正确设置,然后才加载模板。如何填充作用域是完全无关紧要的:我使用 $timeout 是因为它最容易。如果控制器初始化时已经有了所有相关信息,那么指令也将正常工作。 - artur grzesiak
啊,抱歉 - 现在再仔细看一眼,上次有些匆忙。虽然我可以看到这种方法是可行的,但感觉有点繁琐:在数据准备好之前不包括模板并不像利用指令方法的优势(特别是与ngSrc方法相比)。 - Index
@KGChristensen,我可以问一下这种方法到底有什么问题吗?你只需要传递一个配置对象,而不需要手动设置每个单独的属性--你认为这比手动设置每个ngSrc更糟糕吗?(怎么可能呢?) - artur grzesiak
@KGChristensen 没有混淆问题。我仍然很好奇在html/template中放置了什么逻辑 - 你是否指的是实际上完全可以轻松避免的ng-switch的标准用法?您之前写道:“在数据准备好之前不包括模板不像发挥指令方法的优势” - 这听起来一点也不像:“我不喜欢在HTML /模板中放置逻辑”。此外:为什么使用指令是不可能的 - 我真的很好奇,因为几乎无法想象这样的情况... - artur grzesiak
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接