繁体   English   中英

JavaScript中的可变范围问题

[英]Variable scope issue in JavaScript

我已经快速编写了一种产品展示的东西,它的一半输入来自页面,另一半来自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()的新实例)。

有人知道我在做什么错吗?

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

您猜对了,问题出在范围上,而不是变量“ 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范围之外声明的循环器变量,在productDisplay方法本地。 这样可确保您可以在不同的showProduct调用期间访问循环仪。

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

            });

    };




};

如果不使用var定义变量(例如var images = ...; ),则将它们视为全局变量( window对象的成员)。

如果使用var定义它们,则它们在整个函数中可见(甚至在声明变量之前),并且在其中声明它们。

我无法立即看到问题所在,但我建议您最小化变量的范围-如果不需要全局变量,请确保它们不是全局变量。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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