相关文章推荐
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

Uncaught TypeError: Failed to execute 'observe' on 'IntersectionObserver': parameter 1 is not of type 'Element'

Ask Question

I'm watching a video on Intersection Observer and I've copied his script word for word and I'm somehow getting this error. Someone had the same error but solved their problem by changing querySelectorAll to querySelector. Even when I copied their code and changed it to querySelector it still didn't work on my end. The code below is mine. I'm using vs code live server.

<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel='stylesheet' href='style.css'>
    <script src='script.js'></script>
</head>
    <section class = 'section1'></section>
    <section></section>
    <section></section>
    <section></section>
    <section></section>
    <section></section>
</body>
</html>
const sectionOne = document.querySelector('.section1');
const options = {};
const observer = new IntersectionObserver(function
(entries, observer){
    entries.forEach(entry => {
        console.log(entry);
}, options);
observer.observe(sectionOne);
body{
    padding: 0;
    margin: 0;
section{
    height: 100vh;
    width:100%;
section:nth-child(odd){
    background: lightcoral
                querySelector returns Element | null, so you'll need to assert the element exists somehow. For example try observer.observe(sectionOne!) or observer.observe(assertExists(sectionOne)).
– cs95
                Aug 15, 2020 at 17:39
                Didnt notice the element comes up null. Im using defer in my script tag to load the page before the script so the element can exist
– Joheb
                Aug 15, 2020 at 20:28

The element returns as null because the script runs before the HTML is parsed. I used defer in my script tag to avoid this problem.

<script src='script.js' defer></script>
                isn't there a natural way to do this...like run  the script when the entire window is ready? or is that not related?
– klewis
                Sep 8, 2021 at 17:15

You need to make sure the IntersectionObserver script will run after the DOM is completely loaded.

document.addEventListener("DOMContentLoaded", function(){
      // your instersectionobserver code here

your selection is for the first element as querySelector take the first one if you want to select all then use querySelectorAll, and loop through them so the observer can observe them one by one, it should be as follow:

const sections = document.querySelectorAll('section');
const options = {};
const observer = new IntersectionObserver(function
(entries, observer){
entries.forEach(entry => {
    console.log(entry);
}, options);
// loop 
sections.forEach( section => {
observer.observe(section);

Actually it looks like the example you posted works fine, you can check it in this JSFiddle I made: https://jsfiddle.net/sandro_paganotti/pomtng6f/3/

const sectionOne = document.querySelector('.section1');
const options = {};
const observer = new IntersectionObserver(function
 (entries, observer){
    entries.forEach(entry => {
       console.log(entry);
}, options);
observer.observe(sectionOne);

Of course being the observer only attached to the first section it'll only fire when the first section enters or leaves the viewport.

I believe intersectionObserver.observe can only observe one element. I've noticed that when there are multiple div elements with same class names, observe returns uncaught typeError.

Others who got it working by changing from querySelectorAll to querySelector might be because they had a several div with same class names.

function playPauseVideo() {
let videos = document.querySelectorAll("video");
videos.forEach((video) => {
    // We can only control playback without insteraction if video is mute
    video.muted = true;
    // Play is a promise so we need to check we have it
    let playPromise = video.play();
    if (playPromise !== undefined) {
        playPromise.then((_) => {
            let observer = new IntersectionObserver(
                (entries) => {
                    entries.forEach((entry) => {
                            entry.intersectionRatio !== 1 &&
                            !video.paused
                            video.pause();
                        } else if (video.paused) {
                            video.play();
                    threshold: 0.2
            observer.observe(video);

// And you would kick this off where appropriate with: playPauseVideo();

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.

 
推荐文章