如何破解触发网页滚动的Javascript代码行

How to break on the Javascript line of code that triggers a webpage scroll?

本文关键字:滚动 网页 Javascript 代码 何破解 破解      更新时间:2023-09-26

我的网页在切换选项卡时会滚动,我正试图找出导致这种滚动的原因。我可以确认,我观察到的行为实际上是滚动,而不是页面高度变化的结果,因为window.pageYOffset在切换选项卡时会发生变化。

如何查找导致此滚动的代码?

我尝试在Chrome中添加滚动事件侦听器断点,但调用堆栈只列出了这个调用:指向滚动事件处理代码的elemData.handle (jquery.js:4334)eventHandle = elemData.handle = function( e ) {...}未捕获触发此滚动事件的调用。

然后我阅读了关于使用Javascript的Object.defineProperty()方法在属性更改时设置断点的教程:http://johnkpaul.com/blog/2013/07/20/break-on-property-change/并为CCD_ 5编写了一个自定义的setter方法,但在页面滚动时没有触发。这是我使用的代码:

Object.defineProperty(window,'pageYOffset',{
    set:function(val){
        window.pageYOffset=val;
        debugger;
    }
});

我们可以使用上述任一方法来识别滚动触发代码吗?人们是否已经使用了其他方法来执行此任务?

我评论道:

如果你点击激活表的是一个锚点,并且你使用href="#tabname"来识别标签,那么可能导致滚动的是浏览器本身:它正试图转到该锚点目标。所以你不能在上面设置断点。但如果我是对的,幸运的是,你不必:只需阻止click事件的默认操作(即跟随链接),就可以停止滚动。

您回复:

您对导致浏览器滚动到该元素的定位标记的ID是正确的。我通过反复尝试找到了它,但我仍然想知道是否有办法通过断点捕获有问题的代码。

恐怕你不能在浏览器的代码中设置断点。唯一能弄清楚这一点的方法是你和我所做的:反复试验,知道可能的原因,等等。

关于defineProperty()方法,我应该如何构造setter方法以避免递归?我遵循了我链接的博客的模板。

在这种情况下(可能还有很多其他情况),您可能肯定不能,因为此属性可能只是窗口对象中某些内部信息的访问器。该特定属性的行为实际上非常有趣(无论如何,在Chrome上):它由窗口设置,除非将其设置为不同的值。将其设置为不同的值a)不滚动窗口,B)使属性停止告诉您窗口已经滚动了多远(即使您再次移动它)。

在一般情况下,您只能在以下情况下使用本文中的技巧:

  • 属性可配置

  • 该属性当前没有getter或setter

在这种情况下,你会这样做(但请参阅下面的cmoplete版本):

(function() {
  var value = obj.theProperty;
  Object.defineProperty(obj, "theProperty", {
    enumerable: desc.enumerable,
    get: function() {
      return value;
    },
    set: function(newValue) {
      value = newValue;
      // It changed
    }
  });
})();

请注意我们是如何承担存储价值的责任的。我们可以将它存储在对象的另一个属性(比如___overidden___foo)上,但闭包中的变量更容易、更安全。

以下是更全面的版本:

// A function to capture property changes
function callbackOnChange(obj, propName, cb) {
  var value = obj[propName];
  var desc = Object.getOwnPropertyDescriptor(obj, propName);
  // Descriptor will be null if the property doesn't exist yet
  // on the object, either because it doesn't exist *at all*,
  // or because the object is inheriting it. Either way is
  // fine for what we want to do
  if (desc != null) {
    if (!desc.configurable) {
      throw new Error("Property " + propName + " cannot be reconfigured");
    }
    if (desc.set) {
      throw new Error("Property " + propName + " has a setter");
    }
    if (desc.get) {
      throw new Error("Property " + propName + " has a getter");
    }
    if (!desc.writable) {
      throw new Error("Property " + propName + " is not writable, so will never change");
    }
  }
  Object.defineProperty(obj, propName, {
    enumerable: desc.enumerable,
    get: function() {
      return value;
    },
    set: function(newValue) {
      value = newValue;
      cb(obj, propName, newValue);
    }
  });
}
// Create object and property
var obj = {
  foo: "bar"
};
// Set the value, no notification
obj.foo = "update1";
// Capture changes
try {
  callbackOnChange(obj, "foo", function(o, propName, newValue) {
    snippet.log(propName + " changed to " + newValue);
    // Could use debugger; here
  });
} catch (e) {
  snippet.log("Couldn't capture changes: " + e.message);
}
// Set the value, we get a notification
obj.foo = "update2"; // Got notification
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>