文章最后更新时间:2026年01月04日
NPlayer简介
NPlayer 是由 Typescript 加 Sass 编写,无任何第三方运行时依赖,兼容 IE11,支持移动端、支持 SSR、支持直播。高度可定制,所有图标、主题色等都可以替换,并且提供了内置组件方便二次开发。你可以自定义任意多个断点,不仅仅是兼容移动端,只要愿意,你可以非常轻松的兼容手机竖屏、手机横屏、平板等设备。它还拥有插件系统,弹幕功能就是使用插件形式提供,使用时按需引入即可。该播放器还可以接入任何流媒体,如 HLS、dash 和 flv 等。

优势:
轻量化
完全开源
兼容性超清
支持滑屏操作,包括触碰和滑动快进退等
NPlayer安装
<script src="/js/NPlayer.min.js"></script><div id="player"></div>
NPlayer初始化
const player = new NPlayer.Player({src: 'https://xmsdn.com/static/demo.M3U8',poster: 'https://xmsdn.com/static/demo.jpg',...});player.mount('#player');//绑定IDNPlayer参数
播放器构造函数参数。
import Player from 'nplayer'const player = new Player({ // 这里})console.log(player.opts)| 参数 | 描述 |
|---|---|
| container | 播放器挂载容器元素,同 mount 方法参数,如果 mount 没有传入参数时,将使用该参数,当该参数为字符串时,将会自动查找对应元素 |
| src | 视频地址,同 video 元素的 src 属性 |
| video | 自己提供 video 元素 |
| videoProps | video 元素的属性 |
| videoSources | video source 子元素数组,请查看 快速开始 |
| live | 是否是直播模式 |
| autoSeekTime | 视频加载成功时自动跳转到的时间点(跳转后该参数会自动设为 0),你可以用这个参数实现记忆上次用户观看时间 |
| thumbnail | 请查看 预览缩略图 |
| controls | 请查看 控制条 |
| bpControls | 设置不同断点下的控制条项布局,请查看 控制条 |
| settings | 请查看 设置菜单 |
| contextMenus | 请查看 右键菜单 |
| contextMenuToggle | 是否偶数次单击右键时显示浏览器默认右键菜单 |
| plugins | 插件列表,详情请查看 插件 |
| i18n | 当前播放器语言,如 en、zh |
| shortcut | 是否开启快捷键功能 |
| seekStep | 单次快进、快退的步长,快捷键中会使用到 |
| volumeStep | 单次增加、降低音量的步长,快捷键中会使用到 |
| themeColor | 主题色,请查看 定制主题 |
| posterBgColor | 海报背景色,请查看 定制主题 |
| progressBg | 进度条背景,请查看 定制主题 |
| progressDot | 进度条上的点,请查看 定制主题 |
| volumeProgressBg | 音量条背景,请查看 定制主题 |
| volumeBarLength | 音量条长度,请查看 定制主题 |
| volumeVertical | 垂直音量条,请查看 定制主题 |
| loadingEl | 自定义视频 loading 元素,请查看 定制主题 |
| openEdgeInIE | 是否在 Win10 的 IE 中自动打开 Edge,请查看 IE 11 兼容 |
| poster | 海报图片地址,请查看 海报 |
| posterEnable | 是否启用海报功能 |
| posterPlayEl | 自定义海报播放按钮,请查看 定制主题 |
默认参数#
{ shortcut: true, seekStep: 10, volumeStep: 0.1, volumeBarLength: 100, settings: ['speed'], contextMenus: ['loop', 'pip', 'version'], contextMenuToggle: true, openEdgeInIE: true, posterEnable: true, videoProps: { preload: 'auto', playsinline: 'true', }, controls: [ ['play', 'volume', 'time', 'spacer', 'airplay', 'settings', 'web-fullscreen', 'fullscreen'], ['progress'], ], bpControls: { 650: [ ['play', 'progress', 'time', 'web-fullscreen', 'fullscreen'], [], ['spacer', 'airplay', 'settings'], ], }}NPlayer多层级
NPlayer 由 6 个不同功能的层级组成,每个层级有自己的 z-index。
| 层级 | z-indx | 描述 |
|---|---|---|
| video 视频元素 | - | 视频元素没有设置 z-index |
| control 控制条 | 10 | 视频底部控制条 |
| poster 海报 | 20 | 视频海报 |
| loading 加载中 | 30 | 视频加载时出现的加载中元素 |
| contextmenu 右键菜单 | 40 | NPlayer 右键菜单 |
| toast 提示框 | 50 | 提示框 |
z-index 高的组件会覆盖低的组件。当要实现自己组件时可以参考上表中的 z-index,将它放入合适层级。如,弹幕插件默认层级 z-index 是 5,那它将出现在 control 下方,video 元素上方。
流媒体支持
HLS
NPlayer 可以非常方便的接入流媒体协议,如果想使用 HLS 可以引入 hls.js。
import Hls from 'hls'import Player from 'player'const hls = new Hls()const player = new Player()hls.attachMedia(player.video)hls.on(Hls.Events.MEDIA_ATTACHED, function () { hls.loadSource('https://test-streams.mux.dev/x36xhzz/x36xhzz.M3U8')})player.mount(document.body)更多关于 hls.js 使用方法,请查看 hls.js 官方文档 。
hls 是视频点播很常用的协议,本教程还提供了使用 hls.js 实现清晰度切换功能,详情请查看 清晰度切换 。
DASH
和 HLS 非常相似的是 DASH 协议,要使用 DASH 协议可以使用 dash.js 。
import dash from 'dashjs'import Player from 'player'const player = new Player()dash .MediaPlayer() .create() .initialize( player.video, 'https://www:llbk.cn:8001/out.mpd', true // 自动播放 )
更多关于 dash.js 请查看 dash.js 官方文档 。
任何流媒体
按照这个套路,其实任何这些流媒体都可以接入(flv, WebTorrent 等等)。因为它们只需要一个 video 元素就行,我们可以通过 player.video 属性访问到 video 元素。
除了让 NPlayer 自动创建 video 元素,还可以自己提供 video 元素
import Hls from 'hls'import Player from 'player'const video = document.createElement('video')const hls = new Hls()const player = new Player({ video })hls.attachMedia(player.video)hls.on(Hls.Events.MEDIA_ATTACHED, function () { hls.loadSource('https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8')})player.mount(document.body)弹幕插件
该插件可以给 NPlayer 添加弹幕功能。它可以保持大量弹幕而不卡顿,并且支持非常多的设置,比如弹幕防碰撞、弹幕速度、字体、速度、透明度、显示区域等。
引入弹幕插件
<script src="/js/danmaku.min.js"></script>import Player from 'nplayer'import Danmaku from '@nplayer/danmaku'const danmakuOptions = { items: [ { time: 1, text: '弹幕~' } ]}const player = new Player({ plugins: [new Danmaku(danmakuOptions)]})player.mount(document.body)控制条#
弹幕插件会注册 danmaku-send 和 danmaku-settings 这两项。
通过 autoInsert 参数可以控制是否自动插入,自动插入逻辑是,找到 spacer 项,将它替换成 danmaku-send 和 danmaku-settings,如果找不到 spacer 则不会自动插入。
new Player({ controls: [['play', 'spacer', 'danmaku-settings'], ['progress']], plugins: [ new Danmaku({ autoInsert: false, }) ]})
你可以将 autoInsert 设置为 false,然后手动设置控制条项,如上代码,手动加入了弹幕设置项,移除了弹幕发送项。
弹幕对象#
弹幕插件还会在 player 对象上注册一个 danmaku 对象。你可以通过 player.danmaku 访问该对象。
console.log(player.danmaku)
弹幕列表#
弹幕列表可以通过 items 参数传入,一个弹幕对象签名如下。
interface BulletOption { color?: string; // 弹幕颜色 text: string; // 弹幕文字 time: number; // 弹幕出现时间 type?: 'top' | 'bottom' | 'scroll'; // 弹幕类型,默认为滚动类型 isMe?: boolean; // 是否是当前用户发送的 force?: boolean; // 是否强制展示该弹幕(弹幕较多,并且是防碰撞模式时,可能会丢弃一部分弹幕)}弹幕列表必须按照 time 从小到大排序。如果获取的弹幕是无序的,那么在传入之前需要自己 .sort((a, b) => a.time - b.time) 一下。你还可以通过 danmaku 对象的 appendItems 和 resetItems 等方法,添加和重置弹幕。
清晰度切换
这个例子是使用 ControlItem 来实现视频的清晰度切换功能,这里使用 HLS,来切换视频清晰度。
import Player, { Popover } from "nplayer"import Hls from "hls.js"// 1. 首先创建一个控制条项const Quantity = { el: document.createElement("div"), init() { this.btn = document.createElement("div") this.btn.textContent = "画质"; this.el.appendChild(this.btn) this.popover = new Popover(this.el) this.btn.addEventListener("click", () => this.popover.show()) // 点击按钮的时候展示 popover this.el.style.display = "none" // 默认隐藏 this.el.classList.add("quantity") }}// 2. 我们把它放到 spacer 后面window.player = new Player({ controls: [ [ "play", "volume", "time", "spacer", Quantity, "airplay", "settings", "web-fullscreen", "fullscreen" ], ["progress"] ]})// 3. 创建 HLS 实例const hls = new Hls()hls.on(Hls.Events.MEDIA_ATTACHED, function () { hls.on(Hls.Events.MANIFEST_PARSED, function () { // 4. 给清晰度排序,清晰度越高的排在最前面 hls.levels.sort((a, b) => b.height - a.height) const frag = document.createDocumentFragment() // 5. 给与清晰度对应的元素添加,点击切换清晰度功能 const listener = (i) => (init) => { const last = Quantity.itemElements[Quantity.itemElements.length - 1] const prev = Quantity.itemElements[Quantity.value] || last const el = Quantity.itemElements[i] || last prev.classList.remove("quantity_item-active") el.classList.add("quantity_item-active") Quantity.btn.textContent = el.textContent if (init !== true && !window.player.paused) setTimeout(() => window.player.play()) // 因为 HLS 切换清晰度会使正在播放的视频暂停,我们这里让它再自动恢复播放 Quantity.value = hls.currentLevel = hls.loadLevel = i Quantity.popover.hide() } // 6. 添加清晰度对应元素 Quantity.itemElements = hls.levels.map((l, i) => { const el = document.createElement("div") el.textContent = l.name + "P" if (l.height === 1080) el.textContent += " 超清" if (l.height === 720) el.textContent += " 高清" if (l.height === 480) el.textContent += " 清晰" el.classList.add("quantity_item") el.addEventListener("click", listener(i)) frag.appendChild(el) return el }) const el = document.createElement("div") el.textContent = "自动" el.addEventListener("click", listener(-1)) el.classList.add("quantity_item") frag.appendChild(el) Quantity.itemElements.push(el) // 这里再添加一个 `自动` 选项,HLS 默认是根据网速自动切换清晰度 Quantity.popover.panelEl.appendChild(frag) Quantity.el.style.display = "block" listener(hls.currentLevel)(true) // 初始化当前清晰度 }); // 绑定 video 元素成功的时候,去加载视频 hls.loadSource("https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8");})hls.attachMedia(window.player.video)window.player.mount("#app").quantity { position: relative; padding: 0 8px; cursor: pointer; font-size: 14px; font-weight: bold; white-space: nowrap; opacity: 0.8;}.quantity:hover { opacity: 1;}.quantity_item { padding: 5px 20px; font-weight: normal;}.quantity_item:hover { background: rgba(255, 255, 255, 0.3);}.quantity_item-active { color: var(--theme-color);}NPlayer监听
有下面 5 个事件相关的方法。
| 方法 | 描述 |
|---|---|
| on(evt: string, fn: Function) | 监听事件 |
| once(event: string, fn: Function) | 监听事件,但是只调用一次回调函数 |
| emit(evt: string, ...args: any[]) | 触发事件 |
| off(evt: string, fn?: Function) | 解除事件监听 |
| removeAllListeners(evt?: string) | 移除所有事件监听 |
你可以使用这些方法监听内置事件或触发自定义事件。
NPlayer事件
NPlayer 事件名是大驼峰形式的字符串。
| 事件名 | 描述 |
|---|---|
| EnterFullscreen | 进入全屏 |
| ExitFullscreen | 退出全屏 |
| WebEnterFullscreen | 进入网页全屏 |
| WebExitFullscreen | 退出网页全屏 |
| LoadingShow | 视频 loading 显示 |
| LoadingHide | 视频 loading 隐藏 |
| ControlShow | 控制条显示 |
| ControlHide | 控制条隐藏 |
| ControlItemUpdate | 更新控制条项目位置时触发,调用 player.updateControlItems() |
| EnterPip | 进入画中画 |
| ExitPip | 退出画中画 |
| UpdateSize | 更新播放器尺寸,比如 window resize 会触发,当外部将播放器元素大小变化时,可以手动触发该事件,防止播放器组件错位 |
| UpdateOptions | 更新配置 |
| AfterInit | 播放器初始化完成时触发 |
| Mounted | 播放器挂载 |
| BeforeDispose | 播放器销毁前,当调用 dispose 方法触发 |
| OpenEdge | 在 IE 中自动打开 edge 浏览器,访问该网页时触发 |
| Play | 同 video play 事件 |
| Pause | 同 video pause 事件 |
| Ended | 同 video ended 事件 |
| Waiting | 同 video waiting 事件 |
| Stalled | 同 video stalled 事件 |
| Canplay | 同 video canplay 事件 |
| LoadedMetadata | 同 video loadedmetadata 事件 |
| Error | 同 video error 事件 |
| Seeked | 同 video seeked 事件 |
| TimeUpdate | 同 video timeupdate 事件 |
| VolumeChange | 同 video volumechange 事件 |
| RateChange | 同 video ratechange 事件 |
| DurationChange | 同 video durationchange 事件 |
| Progress | 同 video progress 事件 |
| BpChange | 当播放器大小变换到特定断点时触发,bpControls 参数中设置的断点 |


