最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

html - Use Javascript to write src attribute as data-src, as page is loading - Stack Overflow

programmeradmin8浏览0评论

Background: Back in December I wanted my (custom) PHP page-building engine to build a page one-way if the User Agent (UA) could handle Javascript and a different way if the UA could not. To achieve this, I needed to learn:

How to detect UA Javascript capability via PHP, prior to PHP building the page on-the-fly: Detecting javascript in PHP, before PHP builds page

Thanks to some very helpful guidance from @skobaljic, @Abhi Beckert and @GolezTrol, I learned that we can use Javascript to place a session cookie which PHP will be able to query on all subsequent page loads. Consequently, for every page after the first one, PHP will know whether the UA is Javascript-capable or not

So far, so good. Now I have reached the stage where I am no longer building pages with PHP on-the-fly but pre-generating them and uploading them to the server as static HTML documents.

If you're still with me, you'll have guessed correctly this means I am currently needing to pre-generate two static documents for each page - one for the non-JS-capable UAs and one for the JS-capable UAs. This isn't really ideal, hence my question below.

On the face of it, this looks like it ought to be a straightforward problem.

For Javascript-non-capable UAs, I want to build a document which contains lines like this:

<img src="/myfolder/myimage.png" alt="My Image" />

For Javascript capable UAs, I want to build the same document which contains lines like this:

<img data-src="/myfolder/myimage.png" alt="My Image" />

(for those who are curious, a javascript after onload converts all the data-src properties into src properties, following which many tens of server round-trips ensue but - crucially - only after the page has already substantially loaded).

I have already achieved this via PHP and a session cookie (see Background above), but now, if it's possible, I want to execute the whole thing on the front-end.

How can I write an attribute into the <img /> elements in the DOM as src by default but, additionally, (if javascript is available) prefix that attribute with data- so that it reads as data-src...

... such that...

[IMPORTANT BIT]

If the UA is javascript-capable it will automatically and instantaneously write all instances of src as data-src as the page is being downloaded by the UA, so that after onload a javascript can then re-write all those instances of data-src as src again.

Background: Back in December I wanted my (custom) PHP page-building engine to build a page one-way if the User Agent (UA) could handle Javascript and a different way if the UA could not. To achieve this, I needed to learn:

How to detect UA Javascript capability via PHP, prior to PHP building the page on-the-fly: Detecting javascript in PHP, before PHP builds page

Thanks to some very helpful guidance from @skobaljic, @Abhi Beckert and @GolezTrol, I learned that we can use Javascript to place a session cookie which PHP will be able to query on all subsequent page loads. Consequently, for every page after the first one, PHP will know whether the UA is Javascript-capable or not

So far, so good. Now I have reached the stage where I am no longer building pages with PHP on-the-fly but pre-generating them and uploading them to the server as static HTML documents.

If you're still with me, you'll have guessed correctly this means I am currently needing to pre-generate two static documents for each page - one for the non-JS-capable UAs and one for the JS-capable UAs. This isn't really ideal, hence my question below.

On the face of it, this looks like it ought to be a straightforward problem.

For Javascript-non-capable UAs, I want to build a document which contains lines like this:

<img src="/myfolder/myimage.png" alt="My Image" />

For Javascript capable UAs, I want to build the same document which contains lines like this:

<img data-src="/myfolder/myimage.png" alt="My Image" />

(for those who are curious, a javascript after onload converts all the data-src properties into src properties, following which many tens of server round-trips ensue but - crucially - only after the page has already substantially loaded).

I have already achieved this via PHP and a session cookie (see Background above), but now, if it's possible, I want to execute the whole thing on the front-end.

How can I write an attribute into the <img /> elements in the DOM as src by default but, additionally, (if javascript is available) prefix that attribute with data- so that it reads as data-src...

... such that...

[IMPORTANT BIT]

If the UA is javascript-capable it will automatically and instantaneously write all instances of src as data-src as the page is being downloaded by the UA, so that after onload a javascript can then re-write all those instances of data-src as src again.

Share Improve this question edited May 23, 2017 at 12:01 CommunityBot 11 silver badge asked Apr 11, 2015 at 13:04 RouninRounin 29.6k13 gold badges98 silver badges123 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 2

Like this - not tested but should work:

var imgs = document.getElementsByTagName('img');

for(var i = 0; i < imgs.length; i++) {
  var currentSrc = imgs[i].getAttribute('src');
  imgs[i].setAttribute('src',''); // remove old src data 
  imgs[i].setAttribute('data-src','currentSrc');
}

All this does is add a new data-src attribute, and clears the current src (if needed)

Add just before the </body> tag

This is a hacky way of doing it but all browsers (ie6+) support it:

<body>

    <noscript>
         <style>.img-hide { display: none; }</style>
    </noscript>

    <noscript><img src="/path/to/image1.jpg"></noscript>
    <img class="img-hide" data-src="/path/to/image1.jpg">

    <noscript><img src="/path/to/image2.jpg"></noscript>
    <img class="img-hide" data-src="/path/to/image2.jpg">

    <!-- etc etc etc -->

</body>

After nearly 3 days of head-scratching, I've finally cracked this.

HEAD

<head>

<script>
function initialiseImages() {
        var scripts = document.getElementsByTagName('script');
        var section = scripts[scripts.length-1].parentNode;
        var images = section.getElementsByTagName('img');
        for (var i = 0; i < images.length; i++) {
                        var src = images[i].getAttribute('src');
                        var datasrc = document.createAttribute('data-src');
                        datasrc.value = src;
                        images[i].setAttributeNode(datasrc);
                        images[i].removeAttribute('src');}}
</script>

</head>

BODY

<body>

<section>
<h2><img src="/myfolder/myimage.png" alt="My Image" />Second Level Heading</h2>
<ul><li><img src="/myfolder/myimage.png" alt="My Image" /></li></ul>
<script>initialiseImages();</script>
</section>

<section>
<h3>Third Level Heading</h3>
<ul>
<li><img src="/myfolder/myimage.png" alt="My Image" /></li>
<li><img src="/myfolder/myimage.png" alt="My Image" /></li>
<li><img src="/myfolder/myimage.png" alt="My Image" /></li>
</ul>
<script>initialiseImages();</script>
</section>

</body>

Update 1

Thanks to Dave Walsh's article Referencing a Script's own Tag (http://davidwalsh.name/script-tag), I have re-written the first 3 lines of function initialiseImages():

    var scripts = document.getElementsByTagName('script');
    var section = scripts[scripts.length-1].parentNode;
    var images = section.getElementsByTagName('img');

as a single line:

var images = document.currentScript.parentNode.getElementsByTagName('img');

As far as I can tell, this defines var images fractionally faster and consequently catches more instances of <img src= before the UA sends a file-request to the server.


Developer Notes follow...

Attempt #1 : Try to get Javascript to behave like PHP

I'm much more familiar with writing pages on-the-fly in PHP than with deploying Javascript, so my original intention was to find a way to use Javascript in a quasi-server-side manner to re-write the DOM instantaneously at the very moment it arrived:

For Javascript-non-capable UAs, I want to build a document which contains lines like this:

<img src="/myfolder/myimage.png" alt="My Image" />

For Javascript capable UAs, I want to build the same document which contains lines like this:

<img data-src="/myfolder/myimage.png" alt="My Image" />

If such an approach is possible, I couldn't find a way to do it - and, to be fair, Javascript certainly isn't designed for instantaneously re-writing element properties the moment they arrive.

Attempt #2 : Block image download via Javascript-added CSS

My second approach was to see if I could prevent image download via a line of CSS.

If I added that line with Javascript, only Javascript-capable UAs would be able to read the image-blocking style rule.

This didn't work either. It turns out, you can straightforwardly prevent CSS background-images from downloading, by applying display:none; to the parent container of the element which has the background-image. But the images I want to block (until after onload) are specifically <img>s, not background-images - and it turns out that as soon as the UA hits <img src, it runs off to the server to download the image.

Attempt #3 : Inline Javascript in every <img>

Inline Javascript is pretty old-school, but @Darren Sweeney has already suggested an imaginative <noscript> solution, so I didn't want to automatically dismiss old-school. I thought about tackling the issue something like this:

<img src="/myfolder/myimage.png" alt="My Image" onEvent="initialiseImage();" />

The main issue I ran into here was I couldn't find any appropriate onEvent. I placed the initialiseImage() function in the <head> and then I wanted to have that function automatically fire every time the UA reached an <img> - but after extensive reading, I'm not sure that automatic execution inline is possible. (Perhaps someone can let me know in the ments below, if it is...)

Certainly, I could find no onParse.

The only element-specific onEvent that made sense was onLoad, which, in the case of an <img> (if I understand it correctly) downloads the <img> before it fires. So that was no good at all.

Attempt #4 : Success at last!

Thus far:

1) From the start, the issue was that waiting until window.onload before using Javascript to rewrite every <img src= attribute was far too late;

2) I couldn't see a way to use Javascript to rewrite every <img src= instantly as it was downloading;

3) I couldn't see a way to use Javascript to rewrite every <img src= attribute just at the point the UA had parsed the <img>;

I reasoned that perhaps I could still use Javascript to rewrite every <img src= attribute at the moment the UA pleted parsing each <section> containing each set of <img>s.

I am delighted to say I have tested the code above fairly thoroughly and it appears (so far) to work perfectly - long before the UA starts to request the <img> files from the server, the <img src= attribute has been replaced with a <img data-src= property and that request is no longer executed.

发布评论

评论列表(0)

  1. 暂无评论