我有一个与 Javascript 中的 Intersection Observer API 相关的问题。
我写了一段代码,其中 svg 在进入视口时“绘制自身”,并在退出视口时“擦除自身”。
这个问题仅在 .svg 第一次出现时出现,带有某种小故障。 svg 完全显示并在绘制自身之前快速消失。 这个“故障”只在第一次出现时发生。 这是html代码(当然,Lorem5000代表5000字):
<div>Lorem5000</div>
<svg id="svg1" width="210mm" height="297mm" version="1.1" viewBox="0 0 210 297" xmlns="http://www.w3.org/2000/svg">
<path d="m66.694 68.511a64.589 39.591 0 0159.486 18.831 64.589 39.591 0 01.29525 41.038 64.589 39.591 0 01-59.213 19.152" fill="none" stroke="#000048" stroke-miterlimit="4.1" stroke-width="22.861"/>
</svg>
这是CSS:
svg {
width: 60%;
/* position: fixed; */
top: 5%;
left: 20%;
}
svg path {
stroke-dasharray: 0;
stroke-dashoffset: 0;
stroke-width: 30;
stroke:blue;
fill: none;
}
最后,这是 JS 代码:
let paths = document.querySelectorAll('path');
const svg = document.querySelector('svg');
let observer = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
if (entry.intersectionRatio >= 0.3) {
console.log("visible");
for (var i = 0; i < paths.length; i++) {
let path = paths[i];
let pathLength = path.getTotalLength();
path.style.strokeDasharray = pathLength;
path.style.strokeDashoffset = pathLength;
setTimeout(function() {
path.style.transition = 'stroke-dashoffset 1s';
path.style.strokeDashoffset = 0;
}, i * 100);
}
}
} else {
console.log("pas visible");
for (var i = 0; i < paths.length; i++) {
let path = paths[i];
let pathLength = path.getTotalLength();
path.style.transition = 'stroke-dashoffset 2s';
path.style.strokeDashoffset = pathLength;
}
}
});
}, { threshold: 0.3 });
observer.observe(document.querySelector("#svg1"));
有人可以帮我解决这个奇怪的故障吗? 预先感谢。
迪迪尔
IntersectionObserver 在连接后确实会触发。所以你会接到第一个电话,其中
entry.isIntersecting
将为 false:
const observer = new IntersectionObserver(([{ isIntersecting }]) => {
console.log({ isIntersecting });
});
observer.observe(document.querySelector("p"));
p { margin-top: 300vh; }
<p>target</p>
这样做,您将把路径的
strokeDashoffset
设置为 pathLength
,但它的 strokeDasharray
仍然是 CSS 中的 0
。因此,无论如何它都会被完全抚摸,当它进入屏幕时你会看到它:
const path = document.querySelector("path");
const pathLength = path.getTotalLength();
path.style.transition = "stroke-dashoffset 2s";
path.style.strokeDashoffset = pathLength;
document.querySelector("button").onclick = (evt) => {
path.style.strokeDasharray = pathLength;
path.style.strokeDashoffset = pathLength;
setTimeout(() => {
path.style.transition = 'stroke-dashoffset 1s';
path.style.strokeDashoffset = 0;
});
};
svg path {
stroke-dasharray: 0;
stroke-dashoffset: 0;
stroke-width: 30;
stroke:blue;
fill: none;
}
<button>simulate intersection</button>
<svg id="svg1" viewBox="0 40 210 297" xmlns="http://www.w3.org/2000/svg">
<path d="m66.694 68.511a64.589 39.591 0 0159.486 18.831 64.589 39.591 0 01.29525 41.038 64.589 39.591 0 01-59.213 19.152" fill="none" stroke="#000048" stroke-miterlimit="4.1" stroke-width="22.861"/>
</svg>
为了避免这种情况,您可以将
strokeDasharray
设置在观察者回调之外:
let paths = document.querySelectorAll('path');
const svg = document.querySelector('svg');
// Set the dash-array of every path
for (const path of paths) {
const pathLength = path.getTotalLength();
path.style.strokeDasharray = pathLength;
}
let observer = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
if (entry.intersectionRatio >= 0.3) {
console.log("visible");
for (var i = 0; i < paths.length; i++) {
let path = paths[i];
let pathLength = path.getTotalLength();
path.style.strokeDasharray = pathLength;
path.style.strokeDashoffset = pathLength;
setTimeout(function() {
path.style.transition = 'stroke-dashoffset 1s';
path.style.strokeDashoffset = 0;
}, i * 100);
}
}
} else {
console.log("pas visible");
for (var i = 0; i < paths.length; i++) {
let path = paths[i];
let pathLength = path.getTotalLength();
path.style.transition = 'stroke-dashoffset 2s';
path.style.strokeDashoffset = pathLength;
}
}
});
}, {
threshold: 0.3
});
observer.observe(document.querySelector("#svg1"));
.lorem {
height: 120vh;
}
svg {
width: 60%;
/* position: fixed; */
top: 5%;
left: 20%;
}
svg path {
stroke-dasharray: 0;
stroke-dashoffset: 0;
stroke-width: 30;
stroke: blue;
fill: none;
}
<div class="lorem">Lorem5000</div>
<svg id="svg1" width="210mm" height="297mm" version="1.1" viewBox="0 0 210 297" xmlns="http://www.w3.org/2000/svg">
<path d="m66.694 68.511a64.589 39.591 0 0159.486 18.831 64.589 39.591 0 01.29525 41.038 64.589 39.591 0 01-59.213 19.152" fill="none" stroke="#000048" stroke-miterlimit="4.1" stroke-width="22.861"/>
</svg>
但我忍不住注意到你在可见的调用中使用了一个奇怪的
setTimeout
。我想这是为了避免这样的事实:否则过渡将不适用。如果是这种情况,我邀请您查看 Web Animations API。它更加干净和高效:
let paths = document.querySelectorAll('path');
const svg = document.querySelector('svg');
// Set the dash-array of every path
for (const path of paths) {
const pathLength = path.getTotalLength();
path.style.strokeDasharray = pathLength;
}
let observer = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
for (let i = 0; i < paths.length; i++) {
const path = paths[i];
const pathLength = path.getTotalLength();
if (!entry.isIntersecting) {
console.log("pas visible");
path.animate([
{ strokeDashoffset: pathLength },
], { duration: 2000, fill: "forwards" });
}
else if (entry.intersectionRatio >= 0.3) {
console.log("visible");
path.animate([
{ strokeDashoffset: pathLength },
{ strokeDashoffset: 0 },
], { duration: 1000, fill: "forwards", delay: i * 100 });
}
}
});
}, { threshold: 0.3 });
observer.observe(document.querySelector("#svg1"));
.lorem {
height: 120vh;
}
svg {
width: 60%;
/* position: fixed; */
top: 5%;
left: 20%;
}
svg path {
stroke-dasharray: 0;
stroke-dashoffset: 0;
stroke-width: 30;
stroke:blue;
fill: none;
}
<div class="lorem">Lorem5000</div>
<svg id="svg1" width="210mm" height="297mm" version="1.1" viewBox="0 0 210 297" xmlns="http://www.w3.org/2000/svg">
<path d="m66.694 68.511a64.589 39.591 0 0159.486 18.831 64.589 39.591 0 01.29525 41.038 64.589 39.591 0 01-59.213 19.152" fill="none" stroke="#000048" stroke-miterlimit="4.1" stroke-width="22.861"/>
</svg>