浏览器自动播放音视频-前端实现方案

目录

前言

浏览器自动播放策略

策略详情:

实现方案

[方案1: 互动后播放](#方案1: 互动后播放)

[方案2: 互动后出声](#方案2: 互动后出声)

总结


前言

在开发中可能有遇到这样的需求,当用户打开页面后,需要自动播放视频或音频,按理说那就打开页面时play()一下不就搞定了吗,但实际情况很明显不是,不然也没得这篇文章喽,要实现这个需求,我们得先了解一下浏览器自动播放策略。再给出相应解决方案。

浏览器自动播放策略

Chrome浏览器的自动播放策略自Chrome66起生效,动机是改善用户体验

策略详情:

Chrome 的自动播放政策很简单:

  1. 始终允许静音自动播放。
  2. 在以下情况下,带声音的自动播放会被允许:
    1. 用户已经与当前域进行了交互(click、tap)
    2. 在桌面设备上,用户的==媒体参与度==指数阈值已超过,这意味着用户之前播放过有声视频。
    3. 用户已将网站添加到移动设备上的主屏幕或在桌面上安装了 PWA。
  3. 顶部帧可以将自动播放权限委派给其 iframe,以允许自动播放声音。

==媒体参与度(MEI, Media Engagement Index)==

媒体参与度 (MEI) 是衡量个人在网站上使用多媒体的倾向。

它是一个数字,可通过 chrome://media-engagement/ 查看。

数值越高,用户对该站点的媒体参与度越高,就越有机会自动播放。

但对于开发者而言:

媒体参与度的计算规则无法通过技术手段更改

媒体参与度的计算规则不同版本的浏览器可能会有变动

实现方案

首先呢,我们直接在用户进入页面的时候play(),可以发现视频并没有播放,并且报错Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="./index.css" />
  </head>
  <body>
    <div class="vdo-container">
      <video src="./test.mp4"></video>
    </div>
    <script>
      const vdo = document.querySelector('video');
      vdo.play();
    </script>
  </body>
</html>

这个错误的意思是浏览器已经尝试在没有用户交互的情况下播放媒体文件,但是因为这是不允许的,所以浏览器拒绝了该操作。如果没有这个保护机制,那么网站可以在用户不知情的情况下播放音频和视频,这是不安全和不负责任的行为。

方案1: 互动后播放

先尝试自动播放,若发生异常,则引导用户进行互动操作,然后再进行播放

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>互动后播放</title>
    <link rel="stylesheet" href="./index.css" />
  </head>
  <body>
    <div class="vdo-container">
      <video src="./test.mp4"></video>
      <div class="modal">
        <button class="btn">开始播放</button>
      </div>
    </div>

    <script>
      const vdo = document.querySelector('video');
      const modal = document.querySelector('.modal');
      const btn = document.querySelector('.btn');
      async function play() {
        try {
          await vdo.play();
          modal.style.display = 'none';
          btn.removeEventListener('click', play);
        } catch (err) {
          modal.style.display = 'flex';
          btn.addEventListener('click', play);
        }
      }
      play();
    </script>
  </body>
</html>

进入页面后发现不能自动播放,这时显示开始播放按钮,用户点击后开始播放。

方案2: 互动后出声

先静音播放,然后根据是否能自动播放决定是否取消静音,如果:

  1. 能自动播放,取消静音
  2. 不能自动播放,引导用户进行互动操作后取消静音
html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>互动后取消静音</title>
    <link rel="stylesheet" href="./index.css" />
  </head>
  <body>
    <div class="vdo-container">
      <video src="./test.mp4"></video>
      <div class="modal">
        <button class="btn">打开声音</button>
      </div>
    </div>

    <script>
      const vdo = document.querySelector('video');
      const modal = document.querySelector('.modal');
      const btn = document.querySelector('.btn');
      function play() {
        vdo.muted = true; // 静音
        vdo.play();
        const ctx = new AudioContext();
        const canAutoPlay = ctx.state === 'running';
        ctx.close();
        if (canAutoPlay) {
          vdo.muted = false;
          modal.style.display = 'none';
          btn.removeEventListener('click', play);
        } else {
          modal.style.display = 'flex';
          btn.addEventListener('click', play);
        }
      }
      play();
    </script>
  </body>
</html>

进入页面后静音播放视频,然后判断是否允许自动播放,如果允许,则取消静音,但我们这里不允许,所以显示打开声音按钮。

引用的index.css文件内容如下:

css 复制代码
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.vdo-container {
  width: 50%;
  margin: 1em auto;
  position: relative;
}
video {
  display: block;
  width: 100%;
}
.modal {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
  display: none;
}
.btn {
  border: none;
  outline: none;
  background: #409eff;
  color: #fff;
  display: inline-block;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  text-align: center;
  transition: 0.1s;
  font-weight: 500;
  user-select: none;
  padding: 12px 20px;
  font-size: 14px;
  border-radius: 4px;
}
.btn:hover {
  background: #66b1ff;
}
.btn:active {
  background: #3a8ee6;
}
.btn:disabled {
  background: #66b1ff80;
  cursor: not-allowed;
}

总结

如果文中出现有瑕疵的地方各位通过评论或者私信联系我,我们一起进步,有兴趣的伙伴可以关注订阅一下:点击查看更多实用技巧及技术

相关推荐
哆木19 分钟前
部署在线GBA游戏,并通过docker安装启动
游戏·html·gba
天下无贼!1 小时前
2024年最新版Vue3学习笔记
前端·vue.js·笔记·学习·vue
Jiaberrr1 小时前
JS实现树形结构数据中特定节点及其子节点显示属性设置的技巧(可用于树形节点过滤筛选)
前端·javascript·tree·树形·过滤筛选
赵啸林1 小时前
npm发布插件超级简单版
前端·npm·node.js
cuijiecheng20181 小时前
音视频入门基础:AAC专题(6)——FFmpeg源码中解码ADTS格式的AAC的Header的实现
ffmpeg·音视频·aac
我码玄黄2 小时前
THREE.js:网页上的3D世界构建者
开发语言·javascript·3d
罔闻_spider2 小时前
爬虫----webpack
前端·爬虫·webpack
吱吱鼠叔2 小时前
MATLAB数据文件读写:1.格式化读写文件
前端·数据库·matlab
爱喝水的小鼠2 小时前
Vue3(一) Vite创建Vue3工程,选项式API与组合式API;setup的使用;Vue中的响应式ref,reactive
前端·javascript·vue.js
小晗同学2 小时前
Vue 实现高级穿梭框 Transfer 封装
javascript·vue.js·elementui