npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

vue-easy-player

v1.1.1

Published

Vue 2 视频播放器组件,支持 H265/HEVC 编码的 HLS(m3u8)、HTTP-FLV、WS-FLV,集成 WASM 软解码,即装即用

Downloads

767

Readme

vue-easy-player

Vue 2 视频播放器组件,基于 EasyDarwin EasyPlayer.js 官方 SDK 封装,完整映射官方 API

即装即用,支持 H265/HEVC 硬解 + 软解码,支持 HTTP-FLV、WS-FLV、HLS(m3u8)、WebRTC、fMP4 等多种协议,支持直播、点播(Seek/倍速/多清晰度)。


目录


特性

  • 即装即用:零静态文件配置,所有脚本/WASM 全部内联到 bundle,消费者无需拷贝任何静态资源
  • 零额外依赖:安装后无需再安装 crypto-js 等依赖,SDK 及其运行时全部打包内联
  • 协议全覆盖:HLS(m3u8) / HTTP-FLV / WS-FLV / WebRTC / fMP4 / 裸流
  • H265 软解码:通过 WASM 实现浏览器端 H265/HEVC 解码
  • 多解码模式:MSE 硬解码 / WebCodec / WASM(含 SIMD) / WebGPU
  • 多实例隔离:每个播放器实例拥有独立的 Worker 和 WASM 运行时,互不影响,可同时播放多路视频
  • 自定义控制栏:通过 showControls=false + btns 精细控制,父组件自定义 UI
  • 完整事件:映射官方 SDK 所有 20+ 个事件
  • 完整方法:通过 $refs 暴露所有 15+ 个播放器实例方法

环境要求

| 项目 | 要求 | |------|------| | Vue | 2.6+ | | 浏览器 | Chrome 51+ / Firefox 54+ / Edge 79+ / Safari 10+ | | WASM | 播放 H265 时需要浏览器支持 WebAssembly(主流浏览器均支持) |


安装

npm install vue-easy-player

安装完成后无需任何额外操作——无需拷贝静态文件、无需配置 publicPath、无需安装额外依赖。


快速开始

方式一:插件注册(推荐)

// main.js
import Vue from "vue";
import VueEasyPlayer from "vue-easy-player";

Vue.use(VueEasyPlayer);
<!-- App.vue -->
<template>
  <EasyPlayer :playerId="1" videoUrl="https://example.com/live/stream.m3u8" />
</template>

方式二:按需引入

<script>
import { EasyPlayer } from "vue-easy-player";

export default {
  components: { EasyPlayer },
};
</script>

方式三:HTML UMD 标签引入

<script src="https://unpkg.com/vue@2/dist/vue.js"></script>
<script src="https://unpkg.com/vue-easy-player/dist/vue-easy-player.umd.js"></script>
<!-- 自动注册:<EasyPlayer> 即可使用 -->

Props 完整列表

基础配置

| Prop | 类型 | 默认值 | 说明 | |------|------|--------|------| | playerId ★ | Number\|String | 必填 | 播放器唯一 ID,多实例必须区分 | | videoUrl ★ | String | 必填 | 视频流地址 | | isLive | Boolean | true | true=直播,false=点播(支持 Seek/倍速) | | idIndex | Number | undefined | 已废弃,使用 playerId 替代,保留以兼容旧代码 |

★ 为必填项

控制栏

| Prop | 类型 | 默认值 | 说明 | |------|------|--------|------| | showControls | Boolean\|String | true | true=显示所有 / false=完全隐藏 / "partial"=按 btns 精细控制 | | btns | Object | 见下方 | 按钮精细控制对象 |

// btns 默认值(对应 SDK 官方 operateBtns 配置)
{
  fullscreen: true,   // 全屏按钮
  screenshot: true,   // 截图按钮
  play: true,         // 播放/暂停按钮
  audio: true,        // 音量/静音按钮
  record: true,       // 录制按钮
  stretch: true,      // 拉伸切换按钮
  zoom: false,        // 电子放大按钮
  ptz: false,         // 云台控制按钮
  quality: false,     // 清晰度切换按钮
  close: false,       // 关闭按钮
  scale: false,       // 缩放按钮
  logSave: false,     // 日志保存按钮
}

音频

| Prop | 类型 | 默认值 | SDK 映射 | |------|------|--------|----------| | hasAudio | Boolean | true | hasAudio | | isMute | Boolean | false | isMute |

显示

| Prop | 类型 | 默认值 | SDK 映射 | |------|------|--------|----------| | stretch | Boolean | true | stretch | | poster | String | "" | poster | | controlAutoHide | Boolean | false | controlAutoHide — 鼠标不动时自动隐藏控制栏,移入时显示 | | isLogo | Boolean | true | isLogo — 是否显示播放器 LOGO | | loadingIcon | Boolean | true | loadingIcon — 是否显示加载动画图标 | | loadingText | String | "" | loadingText — 加载中提示文字 |

缓冲 & 重连

| Prop | 类型 | 默认值 | SDK 映射 | |------|------|--------|----------| | bufferTime | Number | 1 | 最小缓冲时长(秒) | | loadTimeOut | Number | 10 | 加载超时(秒) | | loadTimeReplay | Number | 3 | 重连次数,-1 无限 |

解码模式

| Prop | 类型 | 默认值 | SDK 映射 | 说明 | |------|------|--------|----------|------| | MSE | Boolean | false | MSE | MSE 硬解码(H264 优先) | | WCS | Boolean | false | WCS | WCS 硬解码 | | WASM | Boolean | false | WASM | WASM 软解码 | | WASMSIMD | Boolean | false | WASMSIMD | WASM-SIMD 加速 | | gpuDecoder | Boolean | false | gpuDecoder | WebGPU 硬解码 | | isFlv | Boolean | false | isFlv | 强制 FLV 解码 | | webGPU | Boolean | false | webGPU | WebGPU 渲染 | | canvasRender | Boolean | false | canvasRender | Canvas 渲染 |

协议特殊配置

| Prop | 类型 | 默认值 | SDK 映射 | 说明 | |------|------|--------|----------|------| | isRtcSRS | Boolean | false | isRtcSRS | SRS 类型 WebRTC | | isRtcZLM | Boolean | false | isRtcZLM | ZLM 类型 WebRTC | | isFlow | Boolean | false | isFlow | 裸流模式 |

水印

| Prop | 类型 | 默认值 | SDK 映射 | |------|------|--------|----------| | watermark | Object | null | { text: {content,color,opacity,fontSize}, right, top } | | fullWatermark | Object | null | { text, angle, color, fontSize, opacity } |

<!-- 局部水印示例 -->
<EasyPlayer
  :playerId="1"
  videoUrl="..."
  :watermark="{ text: { content: '监控-01', color: 'rgba(255,255,255,0.7)', opacity: 0.6, fontSize: '14px' }, right: 10, top: 10 }"
/>

清晰度

| Prop | 类型 | 默认值 | SDK 映射 | |------|------|--------|----------| | quality | Array | null | ['普清','高清','超清','4K','8K'] | | defaultQuality | String | "" | 默认清晰度名 |

云台控制

| Prop | 类型 | 默认值 | SDK 映射 | |------|------|--------|----------| | ptzConfig | Object | null | { ptz: true, ptzMore: true } |

调试

| Prop | 类型 | 默认值 | SDK 映射 | |------|------|--------|----------| | debug | Boolean | false | debug — 开启控制台日志 | | showBandwidth | Boolean | true | showBandwidth — 显示网速状态 | | isBand | Boolean | undefined | @deprecated,使用 showBandwidth 替代 |

高级自定义

| Prop | 类型 | 默认值 | 说明 | |------|------|--------|------| | options | Object | {} | 直接传递给 SDK 构造函数的配置,优先级最高 |

<!-- 当 props 无法覆盖的配置,通过 options 直传 -->
<EasyPlayer
  :playerId="1"
  videoUrl="..."
  :options="{ MSE: true, gpuDecoder: true, debug: true }"
/>

Events 完整列表

所有事件的回调参数中均包含 playerId,方便多实例场景区分来源。

播放生命周期

| 事件 | 参数 | 说明 | |------|------|------| | player-created | { playerId, player, err } | 播放器实例创建完成(err 非 null 表示初始化失败) | | play | playerId | 播放开始 | | pause | playerId | 暂停 | | liveEnd | playerId | 直播结束 | | playbackSeek | { playerId, time } | 点播跳转完成 | | playbackRate | { playerId, rate } | 倍速变化 | | timestamps | { playerId, timestamp } | 播放时间戳回调 |

错误与超时

| 事件 | 参数 | 说明 | |------|------|------| | error | { playerId, error } | 播放异常 | | timeout | playerId | 加载超时 |

媒体信息

| 事件 | 参数 | 说明 | |------|------|------| | videoInfo | { playerId, info } | 视频参数 | | audioInfo | { playerId, info } | 音频参数 | | decodeHevc | { playerId, info } | 编码类型回调 |

交互状态

| 事件 | 参数 | 说明 | |------|------|------| | fullscreen | { playerId, isFullscreen } | 全屏状态变化 | | mute | { playerId, isMute } | 静音状态变化 | | stretch | { playerId, isStretch } | 拉伸切换 | | kBps | { playerId, speed } | 当前网速 kB/s(每秒触发) | | qualityChange | { playerId, qualityName } | 清晰度切换完成 | | ptz | { playerId, data } | 云台操作数据 | | screenshots | { playerId, data } | 截图完成回调 | | contextmenuClose | playerId | 右键菜单关闭 |

录制

| 事件 | 参数 | 说明 | |------|------|------| | recordStart | playerId | 录制开始 | | recordEnd | { playerId, fileInfo } | 录制结束 |

事件使用示例

<template>
  <EasyPlayer
    :playerId="1"
    videoUrl="..."
    :showControls="false"
    @player-created="onCreated"
    @play="onPlay"
    @error="onError"
    @kBps="onSpeed"
    @fullscreen="onFullscreen"
    @screenshots="onScreenshot"
  />
</template>

<script>
export default {
  methods: {
    onCreated({ playerId, player, err }) {
      if (!err) console.log(`播放器 ${playerId} 就绪`);
    },
    onPlay(playerId) {
      console.log(`通道 ${playerId} 开始播放`);
    },
    onError({ playerId, error }) {
      console.error(`通道 ${playerId} 异常:`, error);
    },
    onSpeed({ playerId, speed }) {
      console.log(`通道 ${playerId} 网速: ${speed} kB/s`);
    },
    onFullscreen({ playerId, isFullscreen }) {
      console.log(`通道 ${playerId} 全屏: ${isFullscreen}`);
    },
    onScreenshot({ playerId, data }) {
      console.log(`通道 ${playerId} 截图完成`, data);
    },
  },
};
</script>

实例方法(通过 $refs 调用)

完整映射 EasyPlayer.js 官方实例方法

播放控制

| 方法 | 参数 | 说明 | |------|------|------| | play(url?) | url 直播流地址(可选) | 播放直播流 | | playback(url?) | url 视频地址(可选) | 点播播放 | | pause() | - | 暂停 | | getIsPause() | - | 返回是否暂停 Boolean | | setRate(rate) | rate: Number | 设置回放倍速 | | seekTime(seconds) | seconds: Number | 跳转到指定时间(点播) |

音频

| 方法 | 参数 | 说明 | |------|------|------| | setMute(state) | state: Boolean | 静音/取消静音 | | getIsMute() | - | 返回是否静音 Boolean | | setMic(state) | state: Boolean | 对讲开关(需 PTZ 开启) |

全屏

| 方法 | 参数 | 说明 | |------|------|------| | setFullscreen() | - | 进入全屏 | | exitFullscreen() | - | 退出全屏 |

截图

| 方法 | 参数 | 说明 | |------|------|------| | screenshot(filename?, format?, quality?, type?) | filename: 文件名 / format: 'png'|'jpeg'|'webp' / quality: 0-1 / type: 'download'|'base64'|'blob' | 截图,返回 base64/Blob |

清晰度

| 方法 | 参数 | 说明 | |------|------|------| | setQuality(name) | name: String | 切换清晰度 |

信息获取

| 方法 | 参数 | 说明 | |------|------|------| | getVideoInfo() | - | 获取视频信息 | | getAudioInfo() | - | 获取音频信息 |

生命周期

| 方法 | 参数 | 说明 | |------|------|------| | destroy() | - | 销毁播放器(组件卸载时自动调用) | | reload() | - | 销毁旧实例 -> 重新初始化(切换源后重置) |


自定义控制栏(多实例)

这是最常用的高级场景:关闭 SDK 自带控制栏,父组件自己实现控制 UI,同时管理多个播放器实例。

多实例隔离保证:每个播放器实例拥有独立的 Web Worker 和 WASM 运行时,实例之间互不影响——切换、销毁任一实例不会导致其他实例画面中断。

<template>
  <div class="monitor-page">
    <!-- 4 路视频同时播放 -->
    <div class="grid">
      <div v-for="ch in channels" :key="ch.id" class="cell">
        <EasyPlayer
          :ref="'player_' + ch.id"
          :playerId="ch.id"
          :videoUrl="ch.url"
          :showControls="false"
          :isLive="true"
          :stretch="true"
          @player-created="onPlayerCreated"
          @error="onError"
          @kBps="onSpeed"
        />
        <!-- 自定义控制栏 -->
        <div class="custom-controls">
          <span class="channel-label">通道 {{ ch.id }}</span>
          <button @click="playChannel(ch.id)">&#9654;</button>
          <button @click="pauseChannel(ch.id)">&#9208;</button>
          <button @click="fullscreenChannel(ch.id)">&#9974;</button>
          <button @click="snapshotChannel(ch.id)">&#128247;</button>
          <button @click="muteChannel(ch.id)">
            {{ mutes[ch.id] ? '&#128263;' : '&#128266;' }}
          </button>
          <span class="speed">{{ speeds[ch.id] }} kB/s</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      channels: [
        { id: 1, url: "https://example.com/live/ch1.m3u8" },
        { id: 2, url: "https://example.com/live/ch2.m3u8" },
        { id: 3, url: "https://example.com/live/ch3.m3u8" },
        { id: 4, url: "https://example.com/live/ch4.m3u8" },
      ],
      players: {},
      mutes: {},
      speeds: {},
    };
  },
  methods: {
    getComponent(playerId) {
      return this.$refs["player_" + playerId];
    },

    onPlayerCreated({ playerId, player, err }) {
      if (err) {
        console.error(`通道 ${playerId} 初始化失败`, err);
        return;
      }
      this.players[playerId] = player;
      this.$set(this.mutes, playerId, false);
    },

    playChannel(playerId) {
      this.getComponent(playerId)?.play();
    },
    pauseChannel(playerId) {
      this.getComponent(playerId)?.pause();
    },
    fullscreenChannel(playerId) {
      this.getComponent(playerId)?.setFullscreen();
    },
    snapshotChannel(playerId) {
      const base64 = this.getComponent(playerId)?.screenshot("snapshot", "png", 0.8, "base64");
      if (base64) {
        console.log(`通道 ${playerId} 截图:`, base64.substring(0, 50) + "...");
      }
    },
    muteChannel(playerId) {
      const comp = this.getComponent(playerId);
      if (comp) {
        const current = comp.getIsMute();
        comp.setMute(!current);
        this.$set(this.mutes, playerId, !current);
      }
    },

    onError({ playerId, error }) {
      console.error(`通道 ${playerId} 错误:`, error);
    },
    onSpeed({ playerId, speed }) {
      this.$set(this.speeds, playerId, speed);
    },
  },
};
</script>

注意:由于 Vue 2 组件中 method 不能与 prop 同名,查询方法使用 get 前缀:getIsMute()getIsPause()


H265/HEVC 播放原理

为什么需要 WASM 软解码

主流浏览器 HLS 实现(无论是原生 <video> 标签还是 HLS.js)只支持 H264 解码,不支持 H265/HEVC。H265 在监控摄像头、安防行业广泛使用。

本插件解决方案

videoUrl = "https://.../stream.m3u8"
        │
        ▼
  EasyPlayer SDK 加载
        │
        ▼
  HLS.js 解析播放列表 & 检测 TS 分片的 codec
        │
    ┌───┴───┐
    ▼       ▼
  H264    H265 (HEVC)
    │       │
    ▼       ▼
  浏览器原生    WASM 软解码器
  解码播放    (EasyPlayer-pro.wasm)
                │
                ▼
        Canvas 渲染画面

整个过程对开发者透明,只需传入流地址即可。也可以手动指定解码模式:

<!-- 强制 WASM -->
<EasyPlayer :playerId="1" videoUrl="..." :WASM="true" />
<!-- WASM-SIMD 加速 -->
<EasyPlayer :playerId="1" videoUrl="..." :WASMSIMD="true" />

内部加载机制

本插件采用全内联策略,将 SDK 的所有运行时文件打包进 bundle,消费者无需关心静态文件路径:

EasyPlayer-pro.js      → asset/source 内联为字符串 → Blob URL 动态 <script> 注入
EasyPlayer-lib.js      → asset/source 内联为字符串 → 每次 new Worker() 时创建独立 Blob URL
EasyPlayer-decode.js   → asset/source 内联为字符串 → 每次 new Worker() 时创建独立 Blob URL
EasyPlayer-pro.wasm    → asset/inline 编码为 base64 → 拦截 fetch/XHR,每次返回 ArrayBuffer 副本
EasyPlayer-snap.wasm   → asset/inline 编码为 base64 → 拦截 fetch/XHR,每次返回 ArrayBuffer 副本

多实例隔离实现

| 隔离维度 | 实现方式 | |----------|----------| | Worker 隔离 | 拦截 window.Worker 构造函数,每次创建播放器时为 EasyPlayer-lib.js / EasyPlayer-decode.js 生成新的 Blob URL,确保每个实例拥有独立的解码 Worker | | WASM 隔离 | 拦截 fetch / XMLHttpRequest,每次 .wasm 请求返回原始 ArrayBuffer.slice(0) 副本,避免 WebAssembly.instantiate 消费后 buffer detached | | SDK 实例隔离 | 每个组件通过 new EasyPlayerPro(container, config) 创建独立实例,channelIdplayerId prop 决定,避免 SDK 内部状态冲突 |


命名说明

import VueEasyPlayer from "vue-easy-player"   // 插件对象(有 install 方法)
Vue.use(VueEasyPlayer)                        // 内部: Vue.component("EasyPlayer", 组件)
<EasyPlayer />                                // 标签名 = 组件的 name 属性

也可以绕过插件直接拿组件:

import { EasyPlayer } from "vue-easy-player";  // 不需要 Vue.use()

视频流格式自动识别

| URL 特征 | 识别为 | 内核 | |----------|--------|------| | http(s)://.../xxx.m3u8 | HLS | HLS.js | | http(s)://.../xxx.flv | HTTP-FLV | FLV.js | | ws(s)://.../xxx.flv | WS-FLV | FLV.js (WebSocket) | | http(s)://.../xxx.mp4 | MP4 点播 | 原生 MSE | | webrtc://... | WebRTC | SDK 内置 |

H265/HEVC 编码由 HLS.js 解析 TS 分片后自动检测,SDK 在编码不支持时自动切换到 WASM 解码器。


常见问题

Q1: url /xxx must be "http:" or "https:" or "ws:" protocol

原因:传入的 videoUrl 是相对路径,SDK 要求完整 URL。

解决:使用完整地址 https://your-domain.com/path/stream.m3u8

Q2: EasyPlayer-lib.js:1 Uncaught SyntaxError

原因:SDK Web Worker 脚本路径无法解析。

解决:本插件 >= 1.1.0 已内联 Worker 脚本,升级即可。

Q3: 如何实现多画面同时播放?

自定义控制栏(多实例) 完整示例。每个实例拥有独立的 Worker 和 WASM 运行时,互不影响。

Q4: 多实例时已播放的窗口画面中断/不再加载

原因:旧版本中所有实例共享同一个 Worker Blob URL 和同一个 ArrayBuffer(WASM 二进制),第一个实例消费后 buffer 被 transfer/detach,后续实例无法再编译 WASM。

解决:本插件 >= 1.1.0 已修复——每次创建 Worker 时生成新的 Blob URL,每次 WASM 请求返回 ArrayBuffer.slice(0) 副本。升级即可。

Q5: 如何切换视频源?

this.currentUrl = "https://new-source.com/stream.m3u8"; // 响应式更新
// 或调用方法
this.$refs.player_1.play("https://new-source.com/stream.m3u8");

Q6: 如何获取截图并上传?

const base64 = this.$refs.player_1.screenshot("capture", "jpeg", 0.8, "base64");
fetch("/api/upload", { method: "POST", body: JSON.stringify({ image: base64 }) });

Q7: WebRTC 如何配置?

<!-- SRS WebRTC -->
<EasyPlayer :playerId="1" videoUrl="webrtc://..." :isRtcSRS="true" />
<!-- ZLM WebRTC -->
<EasyPlayer :playerId="1" videoUrl="webrtc://..." :isRtcZLM="true" />

Q8: 安装后项目中有哪些文件?

node_modules/vue-easy-player/
├── package.json
├── README.md
└── dist/
    ├── vue-easy-player.umd.js        (~11 MB)
    ├── vue-easy-player.umd.min.js
    ├── vue-easy-player.common.js
    └── *.map

零额外文件 -- 所有 SDK/WASM 已内联。无需 postinstall 拷贝、无需配置 publicPath。

Q9: 打包发布到生产环境后播放器加载失败?

原因:旧版本中 SDK 脚本经过 babel 转译后内联了开发机器上的绝对路径 require("D:/..."),在生产环境中无法解析。

解决:本插件 >= 1.1.0 已修复——SDK 文件通过 asset/source 规则以原始文本内联,不经过 babel 转译。升级即可。


开发与发布

# 本地开发
npm run serve

# 构建库(输出到 dist/)
npm run lib

# 发布
npm publish

License

MIT

参考