使用 ng-src 与 src

这个 教程演示了使用指令 ngSrc而不是 src:

<ul class="phones">
<li ng-repeat="phone in phones" class="thumbnail">
<img ng-src="{{phone.imageUrl}}">
</li>
</ul>

他们要求:

用一个普通的旧 src 属性替换 ng-src 指令。
使用 Firebug 或 Chrome 的 Web 检查器等工具,或检查 网络服务器访问日志,确认应用程序确实是一个 对 /app/% 7B% 7Bphone. imageUrl% 7D% 7D的无关请求(或 /app/{{ phone.imageUrl }} ).

我这样做了,它给了我正确的结果:

<li class="thumbnail ng-scope" ng-repeat="phone in phones">
<img src="img/phones/motorola-xoom.0.jpg">
</li>

有什么原因吗?

102383 次浏览
<img ng-src="\{\{phone.imageUrl}}">

This gives you expected result, because phone.imageUrl is evaluated and replaced by its value after angular is loaded.

<img src="\{\{phone.imageUrl}}">

But with this, the browser tries to load an image named \{\{phone.imageUrl}}, which results in a failed request. You can check this in the console of your browser.

From Angular docs

The buggy way to write it:

<img src="http://www.gravatar.com/avatar/\{\{hash}}"/>

The correct way to write it:

<img ng-src="http://www.gravatar.com/avatar/\{\{hash}}"/>

Why? this is because on load of page, before angular bootstrapping and creation of controllers, browser will try to load image from http://www.gravatar.com/avatar/\{\{hash}} and it will fail. Then once angular is started, it understands that that \{\{hash}} has to be replaced with say logo.png, now src attribute changes to http://www.gravatar.com/avatar/logo.png and image correctly loads. Problem is that there are 2 requests going and first one failing.

TO solve this we should use ng-src which is an angular directive and angular will replace ng-src value into src attribute only after angular bootstrapping and controllers are fully loaded, and at that time \{\{hash}} would have already been replaced with correct scope value.

The src="\{\{phone.imageUrl}}" is unnecessary and creates an extra request by the browser. The browser will make at least 2 GET requests attempting to load that image:

  1. before the expression is evaluated \{\{phone.imageUrl}}
  2. after the expression is evaluated img/phones/motorola-xoom.0.jpg

You should always use ng-src directive when dealing with Angular expressions. <img ng-src="\{\{phone.imageUrl}}"> gives you the expected result of a single request.


On a side note, the same applies to ng-href so you don't get broken links till the first digest cycle kicks in.

Well actually it makes 100% sense because HTML gets processed sequentially and when this HTML page is being processed line by line, by the time it gets to this image, the line and processing the image, our phone.imageUrl is not yet defined yet.

And in fact, Angular JS has not yet processed this chunk of HTML, and hasn't yet looked for these placeholders and substitute these expressions with the values. So what ends up happening is that the browser gets this line and tries to fetch this image at this URL.

And of course this is a bogus URL, if it still has those mustache and curly braces in it, and therefore it gives you a 404, but once of course Angular takes care of this, it substitutes this URL for the proper one, and then we still see the image, but yet the 404 error message remains in our console.

So, how can we take care of this? Well, we can not take care of this using regular HTML tricks. But, we can take care of it using Angular. We need somehow to tell the browser not to try to fetch this URL but at the same time fetch it only when Angular is ready for interpretation of these placeholders.

Well, one way of doing it is to put an Angular attribute on here instead of the standard HTML one. And the Angular attribute is just ng-src. So if we say that now, go back, you'll see that there's no errors anymore because the image only got fetched once Angular got a hold of this HTML and translated all the expressions into their values.