文章最后更新时间:2024年05月30日已超过518天没有更新。

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://www.18ma.cn/static/demo.M3U8',
poster: 'https://www.18ma.cn/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 元素上方。
流媒体支持
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, 'http://127.0.0.1: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 参数中设置的断点 |

发表评论