繁体   English   中英

为什么回调没有检测到 class 实例变量的最新值

[英]Why callback not detecting latest value of class instance variable

我有一个 web 组件,它基本上是一个 class:

class NavList extends HTMLElement {
      _wrapper;
      _observer;
      _observerActive = true;

      get observerState() {
        return this._observerActive;
      }

 render() {
        this._wrapper.innerHTML = "";
        const activeList = window.location.hash.slice(1);
        const container = htmlToElement(`<nav class="navlist"></nav>`);
        for (let list in veritabani) {
          container.appendChild(
            htmlToElement(
              `<a href=#${list} class="nav-entry ${
                activeList === list ? "active" : ""
              }">${list}</div>`
            )
          );
        }

        // prevent observer from changing hash during smooth scrolling
        container.addEventListener("click", this.disableObserver);

        this._wrapper.appendChild(container);

      }

      observe() {
        let options = {
          root: document.querySelector(".check-list"),
          rootMargin: "0px",
          threshold: 0.4,
        };

        let observer = new IntersectionObserver(
          this.observerCallback.bind(this),
          options
        );
        this._observer = observer;
        const targets = document.querySelectorAll("check-list");
        console.log("observer target:", targets);

        for (let target of targets) {
          observer.observe(target);
        }
      }

      observerCallback(entries, observer) {
        console.log("observer active?", this.observerState);
        entries.forEach((entry) => {
          if (entry.isIntersecting && this.observerState) {
            const targetListName = entry.target.getAttribute("list");
            console.log(entry, targetListName);
            window.location.hash = targetListName;
            this.render();
          }
        });
      }

      disableObserver() {
        this._observerActive = false;
        console.log("observer disabled", this._observerActive);
        function enableObserver() {
          this._observerActive = true;
          console.log("observer enabled", this._observerActive);
        }
        const timer = setTimeout(enableObserver, 2000);
      }

      connectedCallback() {
        console.log("hash", window.location.hash);
        // wrapper for entire checklist element
        const wrapper = this.appendChild(
          htmlToElement(
            `<span class="navlist-wrapper ${window.location.hash}"></span>`
          )
        );

        this._wrapper = wrapper;

        this.render();

        setTimeout(() => {
          this.observe();
        }, 1);
      }

 // more code below

如您所见,我有一个路口观察器,我试图在单击锚点时禁用它的回调。

观察者检测页面上的元素并更改 URL hash 以便可见元素名称在navlist上突出显示,这工作正常但会干扰 navlist 的navlist因为单击navlist条目也应该将页面滚动到该元素!

我的解决方案是在使用navlist单击setTimout列表条目后禁用路口观察器的回调:

      disableObserver() {
        this._observerActive = false;
        console.log("observer disabled", this._observerActive);
        function enableObserver() {
          this._observerActive = true;
          console.log("observer enabled", this._observerActive);
        }
        const timer = setTimeout(enableObserver, 2000);
      }

上面的代码在点击 navlist 后将一个实例变量设置为false ,该变量将navlist更改为false ,但观察者的回调没有看到更改并使用默认为true的旧 state。

我的问题:为什么会这样? 我该如何解决?

我尝试延迟回调 function 认为它在 state 更改之前被激活,但它没有用。

更新:这是我正在做的 现场演示的链接

我找到了解决方案,但我仍然不太明白发生了什么。

解决方案是将标志_observerActive Navlist

   let OBSERVER_STATE = true;
    class NavList extends HTMLElement {
      _wrapper;
      _observer;

      render() {
        this._wrapper.innerHTML = "";
        const activeList = window.location.hash.slice(1);
        const container = htmlToElement(`<nav class="navlist"></nav>`);
        for (let list in veritabani) {
          console.log(`active? ${list}===${activeList}`);

          container.appendChild(
            htmlToElement(
              `<a href=#${list} class="nav-entry ${
                activeList === list ? "active" : ""
              }">${list}</div>`
            )
          );
        }

        // prevent observer from changing hash during smooth scrolling
        container.addEventListener("click", this.disableObserver);

        const addButton = htmlToElement(
          `<button class="nav-add">
            <span class="nav-add-content">
              <span class="material-symbols-outlined">add_circle</span>
              <p>Yeni list</p>
            </span>
            </button>`
        );

        addButton.addEventListener("click", this.addList.bind(this));

        this._wrapper.appendChild(container);
        this._wrapper.appendChild(addButton);
      }

      disableObserver() {
        OBSERVER_STATE = false;
        console.log("observer disabled", this.OBSERVER_STATE);
        function enableObserver() {
          OBSERVER_STATE = true;
          console.log("observer enabled", OBSERVER_STATE);
        }
        const timer = setTimeout(enableObserver, 2000);
      }

      addList() {
        const inputGroup = htmlToElement(`
          <div class="input-group">

          </div>`);
        const input = inputGroup.appendChild(
          htmlToElement(`
        <input placeholder="Liste Adi Giriniz"></input>`)
        );
        const button = inputGroup.appendChild(
          htmlToElement(`
            <button>&#10004;</button>`)
        );

        button.addEventListener("click", () =>
          this.addNewCheckList(input.value)
        );
        input.addEventListener("keypress", (e) => {
          if (e.key === "Enter") {
            console.log(input.value);
            this.addNewCheckList(input.value);
          }
        });
        const addButton = document.querySelector(".nav-add");
        console.log(this._wrapper);
        this._wrapper.replaceChild(inputGroup, addButton);
      }

      addNewCheckList(baslik) {
        veritabani[baslik] = {};
        const checkListContainer = document.querySelector(".check-list");
        const newCheckList = htmlToElement(`
              <check-list
                baslik="${baslik} Listem"
                list="${baslik}"
                placeholder="�� A��klamas�..."
              ></check-list>`);
        checkListContainer.appendChild(newCheckList);
        this._observer.observe(newCheckList);
        this.render();
        newCheckList.scrollIntoView();
      }

      observe() {
        let options = {
          root: document.querySelector(".check-list"),
          rootMargin: "0px",
          threshold: 0.4,
        };

        let observer = new IntersectionObserver(
          this.observerCallback.bind(this),
          options
        );
        this._observer = observer;
        const targets = document.querySelectorAll("check-list");
        console.log("observer target:", targets);

        for (let target of targets) {
          observer.observe(target);
        }
      }

      observerCallback(entries, observer) {
        console.log("observer active?", OBSERVER_STATE);
        entries.forEach((entry) => {
          if (entry.isIntersecting && OBSERVER_STATE) {
            const targetListName = entry.target.getAttribute("list");
            window.location.hash = targetListName;
            this.render();
          }
        });
      }

      connectedCallback() {
        console.log("hash", window.location.hash);
        // wrapper for entire checklist element
        const wrapper = this.appendChild(
          htmlToElement(
            `<span class="navlist-wrapper ${window.location.hash}"></span>`
          )
        );

        this._wrapper = wrapper;

        this.render();

        setTimeout(() => {
          this.observe();
        }, 1);
      }
    }

如果我理解正确的话,你想

  • 创建一个导航列表,为页面上的每个锚点 (id) 呈现一个链接。
  • 当目标滚动到视图中时,突出显示关联的链接并更新位置 hash
  • 单击导航栏中的链接时,滚动到目标并更新位置 hash

您不必跟踪 IntersectObserver state,也不必禁用它。 只需使用 pushState() 而不是 location.hash 来更新hash。https://developer.mozilla.org/en-US/docs/Web/API/History/pushState

index.html

<head>
    <style>
        /* Makes sure that the first section scrolls up enough to trigger the effect */
        section { scroll-margin: 20px }
    </style>
</head>
<body>
    <div class="sidebar">
        <nav-bar></nav-bar>
    </div>
    <div class="content">
        
        <section id="One">
            <header><h1>One</h1></header>
            <p> A bunch of text</p>
        </section>

        <!-- A Bunch of Sections -->

    </div>
</body>

组件.js

export class NavList extends HTMLElement {
    #template = `
    <style>
        .visible {
            background-color: orange;
        }
    </style>
    <menu></menu>
    `;

    constructor() {
        super();
        this.shadow = this.attachShadow({mode: "open"});
    }

    connectedCallback() {
        const li = document.createElement('li');
        const a = document.createElement('a');
        this.tmpl = document.createRange().createContextualFragment(this.#template);
        this.menu = this.tmpl.querySelector('menu');
        this.anchors = document.querySelectorAll('[id]');
        this.observer = new IntersectionObserver( entries => {
            const entry = entries.shift();
            const id = entry.target.getAttribute('id');
            const link = this.menu.querySelector(`a[href="#${id}"]`);
            Array.from(this.menu.querySelectorAll('a')).map(a => a.classList.remove('visible'));
            link.classList.add('visible');
            history.pushState({}, '', `#${id}`);
        }, {threshold: 1});

        for (let anchor of this.anchors) {
            const item = li.cloneNode();
            const link = a.cloneNode();
            const id = anchor.getAttribute('id');
            link.setAttribute('href', `#${id}`);
            link.innerText = id;
            link.addEventListener('click', evt => this.clicked(evt));
            item.append(link);
            this.menu.append(item);
            this.observer.observe(anchor);
        }

        this.render();
    }

    disconnectedCallback() {
        this.observer.disconnect();
    }

    clicked(evt) {
        evt.preventDefault();
        const target = evt.target.getAttribute('href');
        const elem = document.querySelector(target);
        elem.scrollIntoView({behavior: "smooth"});
        history.pushState({}, '', `#${target}`);
    }

  render() {
    this.shadow.append(this.tmpl);
  }


}

customElements.define('nav-list', NavList);

暂无
暂无

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

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