uniapp集成mui-player实现m3u8与flv视频流播放
本文介绍在uniapp H5项目中集成mui-player插件以播放m3u8和flv视频流的方法。通过封装公共组件,处理Hls.js与flv.js依赖,实现PC端与移动端自适应播放,支持清晰度切换、直播模式及自定义事件监听,提供完整代码示例。
背景
在基于uniapp开发的H5项目中,若需支持m3u8或flv格式的视频流播放,市面上现有的视频插件往往在样式定制与功能效果上难以满足需求。经过对比筛选,最终选定mui-player插件,因其具备较强的定制化能力且拥有完善的官方文档支持,官方文档地址为https://muiplayer.js.org/zh/guide/。
提示:建议开发者先阅读官方文档,随后再在页面中进行引入操作。
最终实现的效果如图片所示,PC端与移动端呈现不同的展示样式。PC端支持调节音量、播放速度、分辨率选择、全屏及画中画等功能,更多自定义功能可参考官网说明,其文档包含详细示例供参考;移动端与PC端功能基本一致,仅展现形式存在差异。


1、安装mui-player插件
npm i mui-player --save2、页面引入,可选择在需要展示视频的页面直接引入
也可将该播放器封装为公共组件,以便在多个页面复用。本文示例中将播放器作为公共组件,在组件内部进行引入。
// 播放器样式文件
import 'mui-player/dist/mui-player.min.css'
// npm安装方式引入mui-player
import MuiPlayer from 'mui-player'
// 要播放m3u8的视频就必须要引入hls.js
import Hls from 'hls.js'
// 要播放flv的视频就必须要引入flv.js
import Flv from 'flv.js'
// 要设置pc端视频的清晰度需要引入pc端扩展
import MuiPlayerDesktopPlugin from 'mui-player-desktop-plugin'3、template模板
<template>
<view id="mui-player">
<!-- 可在这里添加你想要覆盖在视频上面的内容,这里我加了一个关闭按钮,层级最高,不会影响视频的播放 -->
<image v-if="showCloseIcon" src="@/sub-live/static/close.png" class="pos-a full-close" @click.stop="videoClose">
</view>
</template>4、data中定义一个空的mp对象
data() {
return {
mp: {}
}
},5、需要向使用的页面传递的参数
props: {
// 视频流地址,必传
src: {
type: String,
default: ''
},
// 视频封面图,可选
poster: {
type: String,
default: ''
},
// 是否要展示关闭视频图标
showCloseIcon: {
type: Boolean,
default: false
},
// 当前视频是否是直播模式
live: {
type: Boolean,
default: false
},
// 兼容音频m3u8(有些音频地址也是m3u8,但是音频不需要播放样式,所以需要兼容)
isZero: {
type: Boolean,
default: false
},
// 设置pc/移动端清晰度选择
childConfig: {
type: Array,
default: () => [{
functions: '高清',
selected: true
},
{
functions: '标清'
},
{
functions: '流畅'
},
]
}
}6、mounted生命周期初始化
mounted() {
// 防止this的改变
const _this = this;
// 根据视频路径后缀判断当前为m3u8还是flv的视频流
var flieArr = _this.src.split('.');
var suffix = flieArr[flieArr.length - 1];
// m3u8格式
var a = suffix.indexOf('m3u8') !== -1
// flv格式
var b = suffix.indexOf('flv') !== -1
var c = {}
// m3u8格式的视频配置
if (a) {
c = {
type: 'hls',
loader: Hls,
config: {
debug: false,
}
}
}
// flv格式的视频配置
if (b) {
c = {
type: 'flv',
loader: Flv,
config: {
cors: true
},
}
}
// 设置宽高,兼容音频,音频时高度为1,必须设置高度,不然音频没发播放,初始化会失败
var sWidth = uni.getSystemInfoSync().screenWidth; // 获取屏幕宽度
var width = 1;
if (!_this.isZero) { // 不为音频
if (_this.$util.isMobile()) { // 移动端动态获取
width = sWidth;
} else {
width = 640; // pc端固定宽度为640
}
}
var height = 1;
if (!_this.isZero) {
height = parseInt(width * 9 / 16) // 可改成你想设置的视频的高度,博主这里设置为宽高比为16:9的视频
}
_this.mp = new MuiPlayer({
// 指定播放器容器
container: '#mui-player',
// 视频播放的资源地址
src: _this.src,
// 是否自动播放,亲测在ios某些机型上自动播放失效
autoplay: false,
// 是否静音播放
muted: false,
// 初始化播放器宽度
width: width,
// 初始化播放器高度
height: height,
// 播放器容器是否自适应视频高度
autoFit: false,
// 是否循环播放
loop: false,
// 视频封面的资源地址
poster: _this.poster,
// 是否开启直播模式,直播模式默认菜单配置不允许控制播放速度以及循环播放
live: _this.live,
// 配置声明启用同层播放
videoAttribute: [{
attrKey: 'webkit-playsinline',
attrValue: 'webkit-playsinline'
},
{
attrKey: 'playsinline',
attrValue: 'playsinline'
},
{
attrKey: 'x5-video-player-type',
attrValue: 'h5-page'
},
],
// flv以及m3u8视频资源的配置
parse: c,
// 自定义主题颜色
themeColor: _this.$config.INFO.THEME_COLOR,
// 非全屏模式下,是否显示播放器头部操作控件,具体可参考官方文档
pageHead: false,
plugins: [
// pc端清晰度设置
new MuiPlayerDesktopPlugin({
customSetting: _this.childConfig.length > 0 ? [{
functions: '清晰度',
model: 'select',
show: true,
zIndex: 0,
childConfig: _this.childConfig,
onToggle: function(data, selected) {
let onToggleLoad = function(state) {
_this.mp.once('ready', function() {
let _video = _this.mp.video();
let _execute = function() {
_video.currentTime = state
.currentTime;
state.paused ? _video.pause() :
_video.play();
}
if (_video.readyState == 0) {
_video.addEventListener(
'durationchange',
function(e) {
_execute();
}, {
once: true
})
} else {
_execute();
}
})
}
// 选择清晰度后重载视频
selected(function() {
let _video = _this.mp.video();
onToggleLoad({
currentTime: _video.currentTime,
paused: _video.paused
});
// 将当前选择的清晰度传递给父组件
_this.$emit('onToggleFn', data.functions)
});
}
}] : []
})
]
});
// 必须放在nextTick里面,等待dom渲染完成再监听视频的播放事件等,视频的其他事件也可在此处进行监听
_this.$nextTick(() => {
// 监听播放器已创建完成
_this.mp.on('ready', function(event) {
let _video = _this.mp.video();
_video.addEventListener("play",function(e){
//播放事件
_this.$emit('onPlayFn')
});
_video.addEventListener("ended",function(e){
//播放完成事件
_this.$emit('onEndedFn')
});
});
// 播放发生错误
_this.mp.on('error', function(event) {
console.log('error', event);
});
})
}7、组件销毁时,视频播放器也需同步销毁
destroyed() {
this.mp.destroy();
},8、可在组件内定义播放/暂停等事件供父组件调用(按需编写)
// 关闭视频,返回上一页
videoClose() {
uni.navigateBack();
},
// 播放视频
playVideo() {
let _video = this.mp.video(); // 获取视频示例
_video.paused ?_video.play(): _video.pause(); // 和原生video事件一致
},
// 暂停视频
pauseVideo(){
let _video = this.mp.video();
_video.pause();
}9、播放视频组件完整代码,可根据实际需求进行增删改
<template>
<view id="mui-player">
<image v-if="showCloseIcon" src="@/sub-live/static/close.png" class="pos-a full-close" @click.stop="videoClose">
</view>
</template>
<script>
import 'mui-player/dist/mui-player.min.css'
import MuiPlayer from 'mui-player'
import Hls from 'hls.js'
import Flv from 'flv.js'
import MuiPlayerDesktopPlugin from 'mui-player-desktop-plugin'
export default {
props: {
src: {
type: String,
default: ''
},
poster: {
type: String,
default: ''
},
showCloseIcon: {
type: Boolean,
default: false
},
live: {
type: Boolean,
default: false
},
// 兼容音频m3u8
isZero: {
type: Boolean,
default: false
},
childConfig: {
type: Array,
default: () => [{
functions: '高清',
selected: true
},
{
functions: '标清'
},
{
functions: '流畅'
},
]
}
},
data() {
return {
mp: {}
}
},
watch: {
src(newVal, oldVal) {
this.mp.reloadUrl(newVal);
}
},
mounted() {
const _this = this;
var flieArr = _this.src.split('.');
var suffix = flieArr[flieArr.length - 1];
// m3u8格式
var a = suffix.indexOf('m3u8') !== -1
// flv格式
var b = suffix.indexOf('flv') !== -1
var c = {}
if (a) {
c = {
type: 'hls',
loader: Hls,
config: {
debug: false,
}
}
}
if (b) {
c = {
type: 'flv',
loader: Flv,
config: {
cors: true
},
}
}
var sWidth = uni.getSystemInfoSync().screenWidth;
var width = 1;
if (!_this.isZero) {
if (_this.$util.isMobile()) {
width = sWidth;
} else {
width = 640;
}
}
var height = 1;
if (!_this.isZero) {
height = parseInt(width * 9 / 16)
}
_this.mp = new MuiPlayer({
// 指定播放器容器
container: '#mui-player',
// 视频播放的资源地址
src: _this.src,
autoplay: false,
muted: false,
width: width,
// 初始化播放器高度
height: height,
// 播放器容器是否自适应视频高度
autoFit: false,
// loop
loop: false,
// 视频封面的资源地址
poster: _this.poster,
// 是否开启直播模式,直播模式默认菜单配置不允许控制播放速度以及循环播放
live: _this.live,
// 配置声明启用同层播放
videoAttribute: [{
attrKey: 'webkit-playsinline',
attrValue: 'webkit-playsinline'
},
{
attrKey: 'playsinline',
attrValue: 'playsinline'
},
{
attrKey: 'x5-video-player-type',
attrValue: 'h5-page'
},
],
parse: c,
// 自定义主题颜色
themeColor: _this.$config.INFO.THEME_COLOR,
// 非全屏模式下,是否显示播放器头部操作控件
pageHead: false,
plugins: [
new MuiPlayerDesktopPlugin({
customSetting: _this.childConfig.length > 0 ? [{
functions: '清晰度',
model: 'select',
show: true,
zIndex: 0,
childConfig: _this.childConfig,
onToggle: function(data, selected) {
let onToggleLoad = function(state) {
_this.mp.once('ready', function() {
let _video = _this.mp.video();
let _execute = function() {
_video.currentTime = state
.currentTime;
state.paused ? _video.pause() :
_video.play();
}
if (_video.readyState == 0) {
_video.addEventListener(
'durationchange',
function(e) {
_execute();
}, {
once: true
})
} else {
_execute();
}
})
}
selected(function() {
let _video = _this.mp.video();
onToggleLoad({
currentTime: _video.currentTime,
paused: _video.paused
});
_this.$emit('onToggleFn', data.functions)
});
}
}] : []
})
]
});
_this.$nextTick(() => {
// 监听播放器已创建完成
_this.mp.on('ready', function(event) {
let _video = _this.mp.video();
_video.addEventListener("play",function(e){
//播放事件
_this.$emit('onPlayFn')
});
_video.addEventListener("ended",function(e){
//播放完成事件
_this.$emit('onEndedFn')
});
});
// 播放发生错误
_this.mp.on('error', function(event) {
console.log('error', event);
});
})
},
destroyed() {
console.log('destroyed');
this.mp.destroy();
},
methods: {
videoClose() {
uni.navigateBack();
},
playVideo() {
let _video = this.mp.video();
_video.paused ?_video.play(): _video.pause();
},
pauseVideo(){
let _video = this.mp.video();
_video.pause();
}
},
}
</script>
<style lang="scss" scoped>
#mui-player{
z-index: 2;
}
.full-close {
top: 22rpx;
right: 22rpx;
width: 44rpx;
height: 44rpx;
cursor: pointer;
z-index: 8;
}
</style>10、父组件调用播放器,按需进行修改
<!-- #ifdef H5 -->
<common-player ref="muiplayer" :showCloseIcon="true" :poster="liveDetailInfo.thumb"
:live="liveDetailInfo.start_time <= nowTime && nowTime <= liveDetailInfo.end_time ? true : false"
:src="liveDetailInfo.rewriteVideoUrl" :childConfig="liveDetailInfo.qxdConfig"
@onToggleFn="qxdToggle" @onEndedFn="ended" @onPlayFn="playFn">
</common-player>
<!-- #endif -->总结:
该播放器基于开源的mui-player实现,因此建议优先查阅文档。文档内容详尽,但需进行较大范围的增删改操作,以定制出符合自身需求的功能形态。
到此这篇关于uniapp使用mui-player插件播放m3u8/flv视频流的文章就介绍到这了,更多相关uniapp播放m3u8/flv视频流内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!
免登录快速分享代码:适合面试协作的轻量级JS在线运行工具推荐
2026-11-05 14:45:59
JS空字符串和纯空格转浮点数的结果是什么
2026-11-05 11:04:42
JS在线格式化缩进混乱怎么办?配置项调整技巧
2026-11-04 23:27:25
JS怎么获取秒级时间戳
2026-11-03 21:45:29
JS时间戳怎么从毫秒转换为秒
2026-11-03 20:04:14
