admin管理员组

文章数量:1289412

I encounter an error trying to autoplay video in Chrome, which says: DOMException: play() failed because the user didn't interact with the document first.

There is a solution for that for 'normal' pages:

var promise = document.querySelector('video').play();
if (promise !== undefined) {
  promise.then(_ => {
    // Autoplay started!
  }).catch(error => {
    // Autoplay was prevented.
    // Show a "Play" button so that user can start playback.
  });
}

But I play video using Phaser framework Video object, which doesn't return promise, so I need to determine it user has interacted with the page before trying to play video. Is there any solution for that?

I encounter an error trying to autoplay video in Chrome, which says: DOMException: play() failed because the user didn't interact with the document first.

There is a solution for that for 'normal' pages:

var promise = document.querySelector('video').play();
if (promise !== undefined) {
  promise.then(_ => {
    // Autoplay started!
  }).catch(error => {
    // Autoplay was prevented.
    // Show a "Play" button so that user can start playback.
  });
}

But I play video using Phaser framework Video object, which doesn't return promise, so I need to determine it user has interacted with the page before trying to play video. Is there any solution for that?

Share Improve this question edited Nov 13, 2018 at 12:07 Dmitry Samoylov asked Nov 13, 2018 at 12:02 Dmitry SamoylovDmitry Samoylov 1,3283 gold badges17 silver badges30 bronze badges 6
  • Have you tried setting play on page load? – andrea-f Commented Nov 13, 2018 at 12:04
  • @andrea-f Page could be loaded in some other tab, so that user don't interact with it even as it loads – Dmitry Samoylov Commented Nov 13, 2018 at 12:05
  • Maybe it's ok to handle tab changes, and dispatch event at this moment? – Ishikawa Yoshi Commented Nov 13, 2018 at 12:32
  • @DmitrySamoylov I think it will need at least focus. Unless you can simulate a user action on the page that would trigger autoplay, like for example sending a click event. – andrea-f Commented Nov 13, 2018 at 14:47
  • It's surely because your video has sound, due to new policy, Chrome blocks videos that autoplay with sound : developers.google./web/updates/2017/09/… – luiswill Commented Feb 28, 2019 at 10:26
 |  Show 1 more ment

4 Answers 4

Reset to default 3

I'm not satisfied with the responses to this kind of question so here's my take / solution. Keep in mind this uses React but can also be done natively.

(1) Add event listeners

  const [userInteracted, setUserInteracted] = useState(false)

  useEffect(() => {
    const handleInteraction = (event) => { setUserInteracted(true); console.log(`Event log for: ${event}`); }
  
    document.addEventListener('click', handleInteraction, true)
    document.addEventListener('scroll', handleInteraction, true)
  
    return () => {
      document.removeEventListener('click', handleInteraction('click'))
      document.removeEventListener('scroll', handleInteraction('scroll'))
    }
  }, [])

(2) Use native browser detection object

  if (navigator.userActivation.hasBeenActive) { doSomething() }

I personally use this on a div which plays audio when hovered over:

const App = () => {
  const [userInteracted, setUserInteracted] = useState(false)
  const audioRef = useRef(new Audio(BirdSinging))

  const playAudio = () => { if (audioRef.current && userInteracted && navigator.userActivation.hasBeenActive) audioRef.current.play() }

  const stopAudio = () => {
    if (audioRef.current && userInteracted) {
      audioRef.current.pause()
      audioRef.current.currentTime = 0
    }
  }

  // avoids play() failed because the user didn't interact with the document first
  useEffect(() => {
    const handleInteraction = (thing) => { setUserInteracted(true); console.log(thing); }
  
    document.addEventListener('click', handleInteraction, true)
    document.addEventListener('scroll', handleInteraction, true)
  
    return () => {
      document.removeEventListener('click', handleInteraction('clik'))
      document.removeEventListener('scroll', handleInteraction('scr'))
    }
  }, [])

  useEffect(() => {
    return () => {
      audioRef.current.pause()
    }
  }, [])

  return (
    <div className="logo" onMouseEnter={playAudio} onMouseLeave={stopAudio}>
      <img src={Logo} alt="Logo" />
    </div>
  )
}

Look for user interaction with the window

var interacted = false;
function fun(){
   interacted = true;
   $(window).unbind("scroll");
   $(window).unbind("click");
   play();
}
$(window).bind("scroll click", fun);
function play(){
     if(interacted){
        //play audio or video
     }
}

window.onFocus

You can use this method to call an event when the tab is focused using JavaScript.

window.onFocus = function(){
playVideo(); //A dummy function
}

mousemove

You can check mouse movement.

document.addEventListener('mousemove', playVideo);

keydown

You can check if user has pressed a key

document.addEventListener('keydown', playVideo);

I think, these events must be enough to check if user has interacted with your site and call a method.


        // Set a flag if the user has interacted because the video can't play before
        useEffect(() => {
          interactionListeners()
        }, [])

        function interactionListeners(){
          window.addEventListener("click", setInteractedFunction)
          window.addEventListener("scroll", setInteractedFunction)
        }
        function removeInteractionListeners(){
          window.removeEventListener("click", setInteractedFunction)
          window.removeEventListener("scroll", setInteractedFunction)
        }
        function setInteractedFunction(){
          console.log("setting interacted")
          if(!interacted)
            dispatcher(setInteracted(true))
          removeInteractionListeners()
        }

本文标签: javascriptHow to determine if user interacted with document to start videoStack Overflow