Javascript Intersection Observer API 问题

问题描述 投票:0回答:1

我有一个与 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"));

有人可以帮我解决这个奇怪的故障吗? 预先感谢。

迪迪尔

javascript svg css-animations intersection-observer
1个回答
0
投票

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>

© www.soinside.com 2019 - 2024. All rights reserved.