feat: VideoPlayer
This commit is contained in:
parent
5bee1a0303
commit
7b5bbedbcc
|
@ -301,6 +301,14 @@ const adminList = [
|
||||||
meta: {
|
meta: {
|
||||||
title: 'router.imageCropping'
|
title: 'router.imageCropping'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'video-player',
|
||||||
|
component: 'views/Components/VideoPlayer',
|
||||||
|
name: 'VideoPlayer',
|
||||||
|
meta: {
|
||||||
|
title: 'router.videoPlayer'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -660,6 +668,7 @@ const testList: string[] = [
|
||||||
'/components/input-password',
|
'/components/input-password',
|
||||||
'/components/waterfall',
|
'/components/waterfall',
|
||||||
'/components/image-cropping',
|
'/components/image-cropping',
|
||||||
|
'/components/video-player',
|
||||||
'function',
|
'function',
|
||||||
'/function/multiple-tabs',
|
'/function/multiple-tabs',
|
||||||
'/function/multiple-tabs-demo/:id',
|
'/function/multiple-tabs-demo/:id',
|
||||||
|
|
|
@ -54,7 +54,8 @@
|
||||||
"vue-i18n": "9.7.0",
|
"vue-i18n": "9.7.0",
|
||||||
"vue-json-pretty": "^2.2.4",
|
"vue-json-pretty": "^2.2.4",
|
||||||
"vue-router": "^4.2.5",
|
"vue-router": "^4.2.5",
|
||||||
"vue-types": "^5.1.1"
|
"vue-types": "^5.1.1",
|
||||||
|
"xgplayer": "^3.0.10"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^18.4.2",
|
"@commitlint/cli": "^18.4.2",
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { VNode, createVNode, render } from 'vue'
|
||||||
|
import VideoPlayer from './src/VideoPlayer.vue'
|
||||||
|
import { isClient } from '@/utils/is'
|
||||||
|
import { VideoPlayerViewer } from '@/components/VideoPlayerViewer'
|
||||||
|
import { toAnyString } from '@/utils'
|
||||||
|
|
||||||
|
export { VideoPlayer }
|
||||||
|
|
||||||
|
let instance: Nullable<VNode> = null
|
||||||
|
|
||||||
|
export function createVideoViewer(options: { url: string; poster?: string; show?: boolean }) {
|
||||||
|
if (!isClient) return
|
||||||
|
const { url, poster } = options
|
||||||
|
|
||||||
|
const propsData: Partial<{ url: string; poster?: string; show?: boolean; id?: string }> = {}
|
||||||
|
const container = document.createElement('div')
|
||||||
|
const id = toAnyString()
|
||||||
|
container.id = id
|
||||||
|
propsData.url = url
|
||||||
|
propsData.poster = poster
|
||||||
|
propsData.show = true
|
||||||
|
propsData.id = id
|
||||||
|
|
||||||
|
document.body.appendChild(container)
|
||||||
|
instance = createVNode(VideoPlayerViewer, propsData)
|
||||||
|
render(instance, container)
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Player from 'xgplayer'
|
||||||
|
import { ref, unref, onMounted, watch, onBeforeUnmount, nextTick } from 'vue'
|
||||||
|
import 'xgplayer/dist/index.min.css'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
poster: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const playerRef = ref<Player>()
|
||||||
|
|
||||||
|
const videoEl = ref<HTMLDivElement>()
|
||||||
|
|
||||||
|
const intiPlayer = () => {
|
||||||
|
if (!unref(videoEl)) return
|
||||||
|
new Player({
|
||||||
|
autoplay: false,
|
||||||
|
...props,
|
||||||
|
el: unref(videoEl)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
intiPlayer()
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props,
|
||||||
|
async (newProps) => {
|
||||||
|
await nextTick()
|
||||||
|
if (newProps) {
|
||||||
|
unref(playerRef)?.setConfig(newProps)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
unref(playerRef)?.destroy()
|
||||||
|
})
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
playerExpose: () => unref(playerRef)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div ref="videoEl"></div>
|
||||||
|
</template>
|
|
@ -0,0 +1,3 @@
|
||||||
|
import VideoPlayerViewer from './src/VideoPlayerViewer.vue'
|
||||||
|
|
||||||
|
export { VideoPlayerViewer }
|
|
@ -0,0 +1,49 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { VideoPlayer } from '@/components/VideoPlayer'
|
||||||
|
import { ElOverlay } from 'element-plus'
|
||||||
|
import { ref, nextTick } from 'vue'
|
||||||
|
import { Icon } from '@/components/Icon'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
poster: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const visible = ref(props.show)
|
||||||
|
|
||||||
|
const close = async () => {
|
||||||
|
visible.value = false
|
||||||
|
await nextTick()
|
||||||
|
const wrap = document.getElementById(props.id)
|
||||||
|
if (!wrap) return
|
||||||
|
document.body.removeChild(wrap)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<ElOverlay v-show="visible" @click="close">
|
||||||
|
<div class="w-full h-full flex justify-center items-center relative" @click="close">
|
||||||
|
<div
|
||||||
|
class="w-44px h-44px color-[#fff] bg-[var(--el-text-color-regular)] rounded-full border-[#fff] flex justify-center items-center cursor-pointer absolute top-40px right-40px"
|
||||||
|
@click="close"
|
||||||
|
>
|
||||||
|
<Icon icon="ep:close" :size="24" />
|
||||||
|
</div>
|
||||||
|
<VideoPlayer :url="url" :poster="poster" />
|
||||||
|
</div>
|
||||||
|
</ElOverlay>
|
||||||
|
</template>
|
|
@ -178,7 +178,8 @@ export default {
|
||||||
iconPicker: 'Icon picker',
|
iconPicker: 'Icon picker',
|
||||||
request: 'Request',
|
request: 'Request',
|
||||||
waterfall: 'Waterfall',
|
waterfall: 'Waterfall',
|
||||||
imageCropping: 'Image cropping'
|
imageCropping: 'Image cropping',
|
||||||
|
videoPlayer: 'Video player'
|
||||||
},
|
},
|
||||||
permission: {
|
permission: {
|
||||||
hasPermission: 'Please set the operation permission value'
|
hasPermission: 'Please set the operation permission value'
|
||||||
|
|
|
@ -176,7 +176,8 @@ export default {
|
||||||
iconPicker: '图标选择器',
|
iconPicker: '图标选择器',
|
||||||
request: '请求',
|
request: '请求',
|
||||||
waterfall: '瀑布流',
|
waterfall: '瀑布流',
|
||||||
imageCropping: '图片裁剪'
|
imageCropping: '图片裁剪',
|
||||||
|
videoPlayer: '视频播放器'
|
||||||
},
|
},
|
||||||
permission: {
|
permission: {
|
||||||
hasPermission: '请设置操作权限值'
|
hasPermission: '请设置操作权限值'
|
||||||
|
|
|
@ -342,6 +342,14 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
|
||||||
meta: {
|
meta: {
|
||||||
title: t('router.imageCropping')
|
title: t('router.imageCropping')
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'video-player',
|
||||||
|
component: () => import('@/views/Components/VideoPlayer.vue'),
|
||||||
|
name: 'VideoPlayer',
|
||||||
|
meta: {
|
||||||
|
title: t('router.videoPlayer')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { VideoPlayer, createVideoViewer } from '@/components/VideoPlayer'
|
||||||
|
import { ContentWrap } from '@/components/ContentWrap'
|
||||||
|
import { ElButton, ElDivider } from 'element-plus'
|
||||||
|
|
||||||
|
const showVideo = () => {
|
||||||
|
createVideoViewer({
|
||||||
|
url: '//sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4',
|
||||||
|
poster: '//lf3-static.bytednsdoc.com/obj/eden-cn/nupenuvpxnuvo/xgplayer_doc/poster.jpg'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ContentWrap title="视频播放器">
|
||||||
|
<VideoPlayer
|
||||||
|
url="//sf1-cdn-tos.huoshanstatic.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4"
|
||||||
|
poster="//lf3-static.bytednsdoc.com/obj/eden-cn/nupenuvpxnuvo/xgplayer_doc/poster.jpg"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ElDivider />
|
||||||
|
<ElButton type="primary" @click="showVideo">弹窗展示</ElButton>
|
||||||
|
</ContentWrap>
|
||||||
|
</template>
|
Loading…
Reference in New Issue