JavaScript中的可变范围问题

时间:2009-07-16 02:55:38

标签: javascript jquery variables

我已经快速编写了一种产品展示的东西,它从页面获得了一半的输入,另一半来自AJAX查询。

这是代码......

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();

            });


    };




};

重要的功能是showProduct()。现在我一般不会写这样的JS,但我决定试一试。我的问题是,当用户点击“更多”按钮并显示产品时,它不会重置简单的幻灯片显示(图像var重置,我认为它与setInterval()有关,或者它似乎每次都在制作一个新的showProduct()实例。

有谁知道我做错了什么?

2 个答案:

答案 0 :(得分:2)

我必须重新格式化您的代码才能真正了解正在发生的事情。无论如何,我发现了代码的问题。

正如您猜对的那样,问题在于范围,但不是变量'images',而是变量'cycle'。为什么呢?

这一行

var cycle = setInterval(function() {

始终创建一个新的本地循环变量(注意'var'),当第二次调用showProduct时,该变量是不可访问的。这意味着这一行

clearInterval(cycle);

基本上没用,因为它总是将null传递给clearInterval函数并且不会清除任何内容。这意味着当您继续单击“更多”时,您正在创建越来越多的setInterval函数调用,从不清除旧函数。

无论如何,我已经重构了你的代码,我认为这应该按预期工作。我做的改变是:

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

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

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

  4. 如果您有任何问题或者代码是否仍无效,请告诉我。

    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 :(得分:1)

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

如果使用var定义它们,那么整个函数可以看到它们(甚至在声明变量之前)它们被声明为。

我无法立即看到问题所在,但我建议尽量减少变量的范围 - 如果它们不需要是全局的,那么请确保它们不是全局的。