是否为每个滚动事件在变量内存中重新创建?

Is it recreate in variable memory for each scroll event?

我有一个名为 ".offer" class 的元素,就在页面内页脚的正上方。当我在滚动运动中接近这个元素时,我希望粘性 header 关闭。

我为此在滚动事件中写了一个函数,但我对某些事情感到好奇。

当我创建如下例所示的函数时,函数 re-created 中的变量是否在每次滚动移动时都在内存中?或者在简单的页面滚动事件中性能的真相是什么?

const stickyNearOfferClose = () => {

let scrollPos; 
let header = document.querySelector("header");
const documentOffset = document.querySelector(".offer").offsetTop;

  header.classList.toggle("sticky", window.scrollY);
  scrollPos = window.scrollY;

    if (scrollPos >= documentOffset) {
      header.classList.add("hide");
    } else {
      header.classList.remove("hide");
    }
};


window.addEventListener("scroll", function () {
  stickyNearOfferClose();
});

除了上面的问题

当我想对一个或多个滚动操作使用上述功能时,

为了性能和可用性,我们应该在函数内还是在 object 内定义变量?

我在下面分享了两个不同的例子。你觉得应该是哪一个?

const Obj = {
  scrollPos : null,
  elHeader: document.querySelector("header"),
  documentOffset: document.querySelector(".offer").offsetTop,
  // otherfunction (){},
  stickyNearOfferClose() {
    Obj.elHeader.classList.toggle("sticky", window.scrollY);

    if (Obj.scrollPos >= Obj.documentOffset) {
      Obj.elHeader.classList.add("hide");
    } else {
      Obj.elHeader.classList.remove("hide");
    }
  },
  // init(){}
};

window.addEventListener("scroll", function () {
  Obj.scrollPos = window.scrollY;
  requestAnimationFrame(Obj.stickyNearOfferClose);
});


// OR


const Obj = {
  // variables
  stickyNearOfferClose() {
    let scrollPos;
    const elHeader = document.querySelector("header");
    const elOffer = document.querySelector(".offer");
    const documentOffset = elOffer.offsetTop;

      let stickyClose = () => {
        elHeader.classList.toggle("sticky", window.scrollY);
          if (scrollPos >= documentOffset) {
            elHeader.classList.add("hide");
          } else {
            elHeader.classList.remove("hide");
          }
      };

    window.addEventListener("scroll", () => {
      scrollPos = window.scrollY;
      requestAnimationFrame(stickyClose);
    });
  },
  spyScrolling() {
    let scrollPos;
    const sections = document.querySelectorAll(".hero");

    let scrollActiveUrl = () => {
      for (let s in sections) {
        if (
          sections.hasOwnProperty(s) &&
          sections[s].offsetTop <= scrollPos + 150
        ) {
          const id = sections[s].id;
          document.querySelector(".active").classList.remove("active");
          document.querySelector(`a[href*=${id}]`).classList.add("active");
        }
      }
    };

    window.addEventListener("scroll", () => {
      scrollPos = document.documentElement.scrollTop || document.body.scrollTop;
      requestAnimationFrame(scrollActiveUrl);
    });
  }
  init(){
    this.stickyNearOfferClose();
    this.spyScrolling()
  }
};

是的,函数中的变量将在每次滚动事件时重新创建。但在你的情况下,你可以将一些变量放在函数之外以节省一点。

根据 MDN,您不应直接在函数中调用昂贵的 DOM 操作。相反,建议使用 requestAnimationFrame()setTimeout()CustomEvent 来限制事件。您可以在 here.

了解更多信息

以下是您的代码的改进示例:

let scrollPos;
const elHeader = document.querySelector("header");
const elOffer = document.querySelector(".offer");
// Note: I'm assuming that `documentOffset` don't need to be updated on every scroll events.
//       Update it as `scrollPos` if it need to be updated on every scroll events.
const documentOffset = elOffter.offsetTop;;

const stickyNearOfferClose = () => {
  
  // Note: Please move the following line in the scroll event 
  //       if it's also needed to be called on every scroll events.
  elHeader.classList.toggle("sticky", window.scrollY);

  if (scrollPos >= documentOffset) {
    elHeader.classList.add("hide");
  } else {
    elHeader.classList.remove("hide");
  }
};


window.addEventListener("scroll", function () {
  scrollPos = window.scrollY;
  requestAnimationFrame(stickyNearOfferClose);
});