[英]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>✔</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);
}
}
如果我理解正确的话,你想
您不必跟踪 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.