为何条件语句赋值后变量仍为undefined?(jQuery滚动场景)
问题
我想要实现元素进入浏览器视口后,随scrollTop的移动同步位移,需要捕获初始scrollTop值用于后续计算。但问题是,尽管已在函数的条件语句中为变量赋值,该变量仍始终为undefined。我推测是作用域问题,以下是我的代码:
jQuery(document).ready(function($){ //function that indicates object is in view $.fn.isInViewport = function() { var elementTop = $(this).offset().top; var elementBottom = elementTop + $(this).outerHeight(); var viewportTop = $(window).scrollTop(); var viewportBottom = viewportTop + $(window).height(); return elementBottom > viewportTop && elementTop < viewportBottom; }; //add class when object in is view jQuery(window).bind('scroll',function(e){ if ($('.home-col-01-image').isInViewport()) { $('.home-col-01-image').addClass("in-view") } else { $('.home-col-01-image').removeClass("in-view") } }); //use scrollTop to move object in parallel jQuery(window).bind('scroll',function(e){ if ($(".home-col-01-image").hasClass("in-view")) { console.log("First initialSt: " + initialSt ) if(initialSt == undefined) { var initialSt = $(this).scrollTop(); console.log("Set initialSt: " + initialSt ) } else { console.log("not set initialSt: " + initialSt) } //console.log("in: ") var st = $(this).scrollTop(); var nst = st - initialSt; //var nst = Math.abs(initialSt - st) console.log("Use initialSt: " + initialSt) console.log("scrollTop: " + st) console.log("New scrollTop: " + nst) if ((nst<=170) && (nst>=0)) { $(".home-col-01-image").css("bottom", + nst); } } else { //console.log("out: ") } }); });
控制台输出示例:
First initialSt: undefined Set initialSt: 1047 Use initialSt: 1047 scrollTop: 1047 New scrollTop: 0 First initialSt: undefined Set initialSt: 1048 Use initialSt: 1048 scrollTop: 1048 New scrollTop: 0
首次输出时initialSt为undefined是正常的,但后续它应该保持已赋值的状态,可实际每次都是undefined。我的核心问题是变量无法被正确赋值,暂不关注代码优化。
解决方案
问题出在变量作用域上:你在滚动事件的回调函数内部用var声明了initialSt,这意味着每次触发滚动事件时,这个变量都是当前函数作用域内的新变量,函数执行完毕后就会被销毁,下次滚动触发时又重新创建,所以永远是undefined。
要解决这个问题,需要把initialSt的声明提升到滚动回调函数的外部,让它处于jQuery(document).ready的作用域内,这样就能在多次滚动回调中保留值。
修改后的代码如下:
jQuery(document).ready(function($){ // 把initialSt声明在全局ready作用域下,让所有滚动回调都能访问 var initialSt; //function that indicates object is in view $.fn.isInViewport = function() { var elementTop = $(this).offset().top; var elementBottom = elementTop + $(this).outerHeight(); var viewportTop = $(window).scrollTop(); var viewportBottom = viewportTop + $(window).height(); return elementBottom > viewportTop && elementTop < viewportBottom; }; //add class when object in is view jQuery(window).bind('scroll',function(e){ if ($('.home-col-01-image').isInViewport()) { $('.home-col-01-image').addClass("in-view") } else { $('.home-col-01-image').removeClass("in-view") // 可选:元素离开视口时重置initialSt,下次进入时重新捕获 initialSt = undefined; } }); //use scrollTop to move object in parallel jQuery(window).bind('scroll',function(e){ if ($(".home-col-01-image").hasClass("in-view")) { console.log("First initialSt: " + initialSt ) if(initialSt == undefined) { initialSt = $(this).scrollTop(); // 这里不再用var声明,直接赋值 console.log("Set initialSt: " + initialSt ) } else { console.log("not set initialSt: " + initialSt) } var st = $(this).scrollTop(); var nst = st - initialSt; console.log("Use initialSt: " + initialSt) console.log("scrollTop: " + st) console.log("New scrollTop: " + nst) if ((nst<=170) && (nst>=0)) { $(".home-col-01-image").css("bottom", + nst); } } }); });
关键修改点:
- 在
ready函数最顶部声明var initialSt;,让它处于所有滚动回调的父作用域中 - 在滚动回调里赋值时去掉
var,避免重新声明局部变量 - 可选:在元素离开视口时重置
initialSt,确保下次进入视口时能重新捕获初始scrollTop值
内容的提问来源于stack exchange,提问作者ells.eastwood
相关产品推荐
相关产品推荐

