2009-07-16 84 views
0

我已经快速地编写了一种产品显示的东西,它从页面获取一半的输入,另一半从AJAX查询中获取。JavaScript中的变量范围问题

这里是代码...

function productDisplay() { 


    products = []; 

    this.index = 0; 

    setupProductDisplay(); 

    processListItems(); 

    showProduct(); 

    function setupProductDisplay() { 

     var productInfoBoxHtml = '<div id="product-info"><h3 class="hide-me"></h3><span id="dimensions" class="hide-me"></span><div id="product-gallery"><img alt="" src="" /></div><ul id="product-options" class="hide-me"><li id="spex-sheet"><a href="" rel="external">Download full spex sheet</a></li><li id="enlarge-image"><a href="" rel="lightbox-gallery">Enlarge image</a></li></ul><div id="product-description" class="hide-me"></div><span id="top"></span><span id="bottom"></span><span id="side"></span><span class="loading"></span></div>'; 
     $('#products').after(productInfoBoxHtml); 
    } 

    function processListItems() { 

     $('#products > li') 
      .append('<span class="product-view">View</span>') 
      .filter(':even') 
      .addClass('even') 
     .end() 
      .each(function() { 

       products.push({ 
        id: $(this).find('h3').html(),  
        title: $(this).find('h3').html(), 
        dimensions: $(this).find('.dimensions').html(), 
        description: $(this).find('.product-description').html() 
       }); 

     }) 
     .find('.product-view') 
      .click(function() { 

       var $thisListItem = $(this).parents('ul li'); 

       var index = $('#products > li').index($thisListItem); 

       this.index = index; 

       showProduct(); 


      }); 

    }; 


    function showProduct() { 

      var index = this.index; 

      console.log('INDEX = ' + index); 

     // hide current data 
      $('#product-info') 
      .show() 
      .find('.hide-me, #product-gallery') 
       .hide() 
      .parent() 
       .find('.loading') 
       .show(); 



      // get data contained in the page 

      $('#product-info') 
      .find('h3') 
       .html(products[index].title) 
      .parent() 
      .find('#dimensions') 
       .html(products[index].dimensions) 
      .parent() 
      .find('#product-description') 
       .html(products[index].description) 


      // get id & then product extra info 

      var id = $('#products > li').eq(index).attr('id').replace(/id-/, ''); 




      var downloadPath = PATH_BASE + 'downloads/'; 

      var imagePath = PATH_BASE + 'images/products/' 

      $.getJSON(PATH_BASE + 'products/get/' + id + '/', 
       function(data){   
        var file = '';  
        var images = []; 

        file = data.file; 

        images = data.images; 

        // show file list item if there is a file 
        if (file) { 
        $('#spex-sheet').show().find('a').attr({ href: downloadPath + file }); 
        } else {     
        $('#spex-sheet').hide(); 
        } 

        // image gallery 



        if (images.length != 0) { 
        $('#product-gallery').show(); 
        // preload image thumbnails 
        $.each(images, function(i, image){ 
         var img = new Image(); 
         img.src = imagePath + 'thumb-' + image; 
         img = null; 
        }); 

        // set first image thumbail and enlarge link 
        if (images[0]) { 
         $('#enlarge-image').show().find('a').attr({ href: imagePath + images[0] }); 
         $('#product-gallery img').attr ({ src: imagePath + 'thumb-' + images[0]}) 

        } 

        console.log(images); 

        // setup gallery 

        var currentImage = 0; 

        clearInterval(cycle); 

        console.log(cycle); 



        var cycle = setInterval(function() { 
         console.log(currentImage + ' = ' + index); 
         if (currentImage == images.length - 1) {    
          currentImage = 0;    
         } else {     
          currentImage ++;     
         }; 

         var obj = $('#product-gallery'); 

         var imageSource = imagePath + 'thumb-' + images[currentImage];   
         obj.css('backgroundImage','url(' + imageSource +')');  
         obj.find('img').show().fadeOut(500, function() { $(this).attr({src: imageSource}) }); 
         $('#enlarge-image a').attr({ href: imagePath + images[currentImage] });   
        }, 5000); 


        // setup lightbox 
        $("#enlarge-image a").slimbox({/* Put custom options here */}, null, function(el) { 
         return (this == el) || ((this.rel.length > 8) && (this.rel == el.rel)); 
        }); 



        } else { 
        // no images 

        $('#enlarge-image').hide(); 
        $('#product-gallery').hide(); 

        }; 


        // show the product info 
        $('#product-info') 
        .find('.hide-me') 
         .remove('#product-gallery, #spex-sheet') 
          .show() 
       .parent() 
        .find('.loading') 
         .hide(); 

      }); 


    }; 




}; 

的重要功能是显示产品()。现在通常我不写这样的JS,但我决定放弃它。我的问题是,当用户点击一个'更多'按钮,它显示产品,它不会重置简单的幻灯片(图像var被重置,我认为它可能与setInterval()也许,或者它似乎每次都会创建一个showProduct()的新实例)。

有谁知道我在做什么错?

+0

该代码有点难以遵循。 “更多”按钮在哪里?您是否在谈论调用showProduct的'.product-view'点击事件?另外,你能描述一下哪些工作不正常吗? showProduct是否第一次工作,但不是当有人点击产品时工作? – SolutionYogi 2009-07-16 03:02:53

+0

@SolutionYogi - 对不起,关于代码 - 我尽可能快地做到了。动态插入更多按钮。是的,我正在谈论调用showProduct()的点击事件。它第一次工作,但点击其他人的幻灯片放映。它显示了与之前的图片相关的新图片,该图片中点击了之前的产品。 – alex 2009-07-16 03:06:05

回答

2

我不得不重新格式化您的代码以真正理解发生了什么。无论如何,我发现代码的问题。

正如你猜对的那样,问题在于范围,但不是变量'图像',而是变量'循环'。为什么?

此行

var cycle = setInterval(function() { 

总是创建一个新的本地循环变量(注意“变种”)时显示产品被调用,第二次是不可访问。这意味着该行

clearInterval(cycle); 

是基本上是无用的,因为它总是传递空来调用clearInterval功能,并且不清晰的东西。这意味着当你继续点击'more'时,你正在创建越来越多的setInterval函数调用,永远不会清除旧的。

无论如何,我重构了你的代码一点点,我认为这应该按预期工作。我做的更改如下:

  1. 删除了this.index变量。在showProduct方法调用并使showProduct使用该变量之前,最好将'index'传递给showProduct,而不是设置this.index。另外,你为什么在变量前添加'this'?

  2. 声明的cycler变量超出showProduct的范围,本地为productDisplay方法。这确保您可以在不同的showProduct调用期间访问cycler。

  3. 创建了名为showFile,showGallery,showProductInfo的更小函数,以便更容易理解/维护代码。

让我知道如果您有任何问题或如果代码仍然无法正常工作。

function productDisplay() { 

    //Instead of keeping this.index variable, it's better to make showProduct function 
    //take index variable. 

    products = []; 
    setupProductDisplay(); 
    processListItems(); 

    //We have to define cycler outside the showProduct function so that it's maintained 
    //in between showProduct calls. 
    var cycler = null; 

    showProduct(0); 

    function setupProductDisplay() 
    { 
     var productInfoBoxHtml = '<div id="product-info"><h3 class="hide-me"></h3><span id="dimensions" class="hide-me"></span><div id="product-gallery"><img alt="" src="" /></div><ul id="product-options" class="hide-me"><li id="spex-sheet"><a href="" rel="external">Download full spex sheet</a></li><li id="enlarge-image"><a href="" rel="lightbox-gallery">Enlarge image</a></li></ul><div id="product-description" class="hide-me"></div><span id="top"></span><span id="bottom"></span><span id="side"></span><span class="loading"></span></div>'; 
     $('#products').after(productInfoBoxHtml); 
    } 

    function processListItems() 
    { 
     $('#products > li') 
      .append('<span class="product-view">View</span>') 
      .filter(':even') 
      .addClass('even') 
      .end() 
      .each(
       function() 
       { 
        products.push({ 
            id: $(this).find('h3').html(),   
            title: $(this).find('h3').html(), 
            dimensions: $(this).find('.dimensions').html(), 
            description: $(this).find('.product-description').html() 
          }); 

       }) 
      .find('.product-view') 
      .click(function() 
        { 
         var $thisListItem = $(this).parents('ul li'); 
         showProduct($('#products > li').index($thisListItem)); 

        } 
       ); 

    }; 

    function showFile(file) 
    { 
     if (file) 
     { 
      $('#spex-sheet').show().find('a').attr({ href: downloadPath + file });  
     } 
     else 
     {          
      $('#spex-sheet').hide(); 
     } 
    } 

    function showGallery(images) 
    { 
     if(! images || !images.length || images.length == 0) 
     { 
      $('#enlarge-image').hide(); 
      $('#product-gallery').hide(); 
      return; 
     } 

     $('#product-gallery').show(); 

     $.each(images, 
       function(i, image) 
       { 
        var img = new Image(); 
        img.src = imagePath + 'thumb-' + image; 
        img = null; 
       }); 

     // set first image thumbail and enlarge link 
     if (images[0]) 
     { 
      $('#enlarge-image').show().find('a').attr({ href: imagePath + images[0] }); 
      $('#product-gallery img').attr ({ src: imagePath + 'thumb-' + images[0]}) 
     } 

     var currentImage = 0; 
     clearInterval(cycler); 

     cycler = setInterval(
       function() 
       { 
        currentImage = currentImage == images.length - 1 ? 0 : currentImage++; 
        var obj = $('#product-gallery'); 

        var imageSource = imagePath + 'thumb-' + images[currentImage];     
        obj.css('backgroundImage','url(' + imageSource +')');   
        obj.find('img').show().fadeOut(500, function() { $(this).attr({src: imageSource}) }); 
        $('#enlarge-image a').attr({ href: imagePath + images[currentImage] });     
       }, 5000); 



     $("#enlarge-image a").slimbox({/* Put custom options here */}, null, function(el) { 
             return (this == el) || ((this.rel.length > 8) && (this.rel == el.rel)); 
           }); 

    }; 

    function showProductInfo() 
    { 
     $('#product-info') 
      .find('.hide-me') 
       .remove('#product-gallery, #spex-sheet') 
       .show() 
      .parent() 
       .find('.loading') 
       .hide(); 
    } 

    function showProduct(index) 
    { 
     $('#product-info') 
      .show() 
      .find('.hide-me, #product-gallery') 
       .hide() 
      .parent() 
       .find('.loading') 
       .show(); 

     // get data contained in the page 
     $('#product-info') 
      .find('h3') 
       .html(products[index].title) 
      .parent() 
       .find('#dimensions') 
        .html(products[index].dimensions) 
       .parent() 
       .find('#product-description') 
        .html(products[index].description) 

     // get id & then product extra info 
     var id = $('#products > li').eq(index).attr('id').replace(/id-/, ''); 

     var downloadPath = PATH_BASE + 'downloads/'; 
     var imagePath = PATH_BASE + 'images/products/' 

     $.getJSON(PATH_BASE + 'products/get/' + id + '/', 
      function(data) 
      {   
       showFile(data.file); 
       showGallery(data.image); 
       showProductInfo(); 

      }); 

    }; 




}; 
1

如果您没有用var(例如var images = ...;)定义变量,那么它们将被视为全局变量(window对象的成员)。

如果定义他们var那么他们到整个功能(变量声明甚至更早),他们在声明。

我不能马上看到的问题是什么,但我可见会建议最小化变量的范围 - 如果它们不需要是全局的,那么确保它们不是全局的。