简体   繁体   中英

Reload captcha image

I have a php script which generates a png image with a captcha code as image text.

session_start();   
$captchanumber = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz'; 
$captchanumber = substr(str_shuffle($captchanumber), 0, 8); 
$_SESSION["code"] = $captchanumber; 
$image = imagecreatefromjpeg("cap.jpg");     
$black  = imagecolorallocate($image, 160, 160, 160);   
$font = '../assets/fonts/OpenSans-Regular.ttf';  
imagettftext($image, 20, 0, 35, 27, $black, $font, $captchanumber);   
header('Content-type: image/png');    
imagepng($image);
imagedestroy($image);

I want to reload the image via jQuery or JavaScript,so i'm using something like this:

$(document).ready(function(e) {
    $('.captcha').click(function(){
        alert('yolo');
        var id = Math.random();
        $(".captcha").replaceWith('<img class="captcha" src="img/captcha.php?id='+id+'" />');
        id ='';

    });
});

the field:

<img class="captcha" src="img/captcha.php">

As the first attempt,it works , but after that if i click on the field again it won't work anymore and i have no idea why .

You are replacing the dom element with new element, it will destroy all attached event handlers.

Method 1: You can resolve this by using event delegation to listen dynamically added elements event.

$(document).ready(function(e) {
    $('body').on('click', '.captcha', function(){
        alert('yolo');
        var id = Math.random();
        $(this).replaceWith('<img class="captcha" src="img/captcha.php?id='+id+'" />');
    });
});

 $(document).ready(function(e) { $('body').on('click', '.captcha', function() { alert('yolo'); var id = Math.random(); $(this).replaceWith('<img class="captcha" src="img/captcha.php?id=' + id + '" />'); }); }); 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <img class="captcha" src="img/captcha.php"> 


Method 2: Instead of replacing entire element just update the img src attribute with new url.

$(document).ready(function(e) {
    $('.captcha').click(function(){
        alert('yolo');
        var id = Math.random();
        $(this).attr('src', 'img/captcha.php?id='+id);
    });
});

 $(document).ready(function(e) { $('.captcha').click(function() { alert('yolo'); var id = Math.random(); $(this).attr('src', 'img/captcha.php?id=' + id); }); }); 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <img class="captcha" src="img/captcha.php"> 


Method 3: Also you can get it done with pure JavaScript with same logic as previous.

 document.querySelector('.captcha').addEventListener('click', function() { alert('yolo'); var id = Math.random(); this.setAttribute('src', 'img/captcha.php?id=' + id); }); 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <img class="captcha" src="img/captcha.php"> 


Method 4: Setting onClick attribute to the element and handling the click event with pure JavaScript, where you need to pass this as argument to refer the element.

 function captcha(ele) { alert('yolo'); var id = Math.random(); ele.setAttribute('src', 'img/captcha.php?id=' + id); } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <img class="captcha" onclick="captcha(this)" src="img/captcha.php"> 

The reason your code only works once is because the original element with captcha class is replaced and the click is no longer detected .

Solution

A clean solution would be to replace the src of the image instead of the complete element.

Working example

Jquery

  $(document).ready(function () {
        $("#changeThis").click(
            function () {
                changeImage();
            }            
        );
    });

function changeImage() {
   //we want whole numbers not numbers with dots here for cleaner urls
   var id = Math.floor((Math.random() * 1000) + 1);
   $('#changeThis').attr("src",'img/captcha.php?id='+id);
   //Not sure why you want to empty id though.
   id ='';
}

Or in oneline:

$("#changeThis").click($('#changeThis').attr("src",'img/captcha.php?id='+Math.floor((Math.random() * 1000) + 1)));

HTML For unique elements use the id="" syntax instead of class="", class is used when multiple elements can have the same class, id is an identifier for a unique element.

<img class="captcha" id="changeThis" src="img/captcha.php">

Might just be a problem with binding events to elements that your code replaces. Consider delegate binding to the document instead:

// Replace
$(document).ready(function(e) {
    $('.captcha').click(function(){
// With
$(document).ready(function(e) {
    $('.captcha').on('click', document, function(){

Okay. The problem is that you declare the id variable, and you try to redeclare it in the second function call, when there already is an id variable, so it will silently be ignored and the empty string used instead.

Try moving var id =''; out of the function, and use id = Math.random() in the function.

This is a delegation issue, as you have inserted a new element, so the event listener is removed, there are many solutions:

Solution 1:

Use inline event binding

function rebindCaptcha()
{
var id = Math.random();
        $(".captcha").replaceWith('<img onclick="rebindCaptcha()" class="captcha" src="img/captcha.php?id='+id+'" />');
}

Solution 2:

Keep your element in dom, and just change the src attribute:

$(document).ready(function(e) {
      $('.captcha').click(function(){
          var id = Math.random();
          this.src = 'img/captcha.php?id='+id+';
          id ='';

      });
  });  

Just for your reference, jQuery delegation can be done with like:

$(".parent .child").on("event",function(){/*your handler here*/}) 

or

$(".parent").on("event",".child",function(){/*your handler here*/})

Usually pick a parent that you are sure it will always exist in your dom, and always attach listener after document ready event.

For me its working as i say you have to use id in javascript for changing things

// reload is your button reload and captcha must be a div who surrounding the captcha img

document.querySelector('#reload').addEventListener('click', function(e){
  var reload = document.getElementById('captcha')
  reload.innerHTML = "your new logic"
})

//reload.innerHTML gonna be the new captcha html code

In order to load the image with new code, you can use version paramter for captcha.php. See the following code.

<img class="captcha" id="secure_code" src="img/captcha.php"> <a href="#" id="reload_captcha">Reload</a> 

$(document).ready(function(e) {
    $('#relaod_captcha').click(function(e) {
        e.preventDefault() ;
        $('#secure_code').attr('src', "img/captcha.php?ver="+Math.random()) ;
    }) ;
}) ;

I wish it will help.

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