简体   繁体   中英

Javascript replace( ) function running more than once on the same image

I'm running a Javascript replace function to replace standard images with class="replace-2x" on my jQuery Mobile site with Retina-quality images if the user is on a mobile device with Retina display. For example, on a Retina device, logo.png will be replaced with logo@2x.png . The JS function is here:

function highdpi_init() {
    $(".replace-2x").each(function () {
        var src = $(this).attr("src");
        $(this).attr("src", src.replace(".png", "@2x.png").replace(".jpg", "@2x.jpg"));

    });
}

$(".page").live('pageinit',function(event){
    highdpi_init();
});

I'm now running into an issue where the replace function is running more than once. So for example, it replaces logo.png with logo@2x.png as the page is loading, but then as the page continues to load, it KEEPS replacing .png with @2x.png in the img src over and over so that the image tag ends up looking like this:

<img src="mobile/images/logo@2x@2x@2x@2x@2x@2x@2x@2x@2x@2x@2x.png" class="replace-2x" alt="logo" width="200">

How can I prevent this from replacing on a single img element more than once? Keep in mind, I will have multiple images on the same page, so the function will need to apply to all images, but only one time each.

The problem is surely that your 'pageinit' event is being called more than once. You can either follow MДΓΓ БДLL's idea (which won't work if images are dynamically added) or you can make your handler smarter so that it doesn't replace the src if it already was replaced

function highdpi_init() {
    $(".replace-2x").each(function () {
        var $this = $(this);
        var src = $this.attr("src");
        $this.attr("src", src.replace(".png", "@2x.png").replace(".jpg", "@2x.jpg"));
        // Remove the class so it doesn't replace it again
        $this.removeClass('replace-2x')

    });
}

You don't need JS for this, you could do it in CSS only.

<link rel="stylesheet" media="only screen and (-webkit-min-device-pixel-ratio: 2)" href="/css/highdpi.css"/> 

You could make your images look like

<img src="transparent.gif" class="logo-a" alt="logo" width="200" />

And in highdpi.css you could do

img.logo-a {
   background-image: url('file@2x.png') 
}

And in lowdpi.css

img.logo-a {
   background-image: url('file.png') 
}

Using.one() should work since it is just a binding and if you are using Jquery Mobile the way that is suggested it will be just fine. That is unless you are passing back the html from the server. In which case it would be a good idea to add an extra condition to make sure that the src doesn't already have @2x.png before replacing.

There is disappointingly little documentation on pageinit on the offical jQuery Mobile docs. So I'm going to speculate here. It looks like pageinit is used to fire events for when a specific DOM element has finished loading, since it may not have been loaded on the initial page load (deferred until needed). That being said, it may be that adding/altering images to the DOM element in question fires the pageinit again. Could you tag each updated image with something that says, 'hey, I've already been updated to 2x'? Something such as

$.data(targetimg, 'retinafied', true); 

And then check for that value before replacing the src?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM