feat: VideoPlayer
This commit is contained in:
parent
5bee1a0303
commit
7b5bbedbcc
|
@ -301,6 +301,14 @@ const adminList = [
|
|||
meta: {
|
||||
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/waterfall',
|
||||
'/components/image-cropping',
|
||||
'/components/video-player',
|
||||
'function',
|
||||
'/function/multiple-tabs',
|
||||
'/function/multiple-tabs-demo/:id',
|
||||
|
|
|
@ -54,7 +54,8 @@
|
|||
"vue-i18n": "9.7.0",
|
||||
"vue-json-pretty": "^2.2.4",
|
||||
"vue-router": "^4.2.5",
|
||||
"vue-types": "^5.1.1"
|
||||
"vue-types": "^5.1.1",
|
||||
"xgplayer": "^3.0.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@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',
|
||||
request: 'Request',
|
||||
waterfall: 'Waterfall',
|
||||
imageCropping: 'Image cropping'
|
||||
imageCropping: 'Image cropping',
|
||||
videoPlayer: 'Video player'
|
||||
},
|
||||
permission: {
|
||||
hasPermission: 'Please set the operation permission value'
|
||||
|
|
|
@ -176,7 +176,8 @@ export default {
|
|||
iconPicker: '图标选择器',
|
||||
request: '请求',
|
||||
waterfall: '瀑布流',
|
||||
imageCropping: '图片裁剪'
|
||||
imageCropping: '图片裁剪',
|
||||
videoPlayer: '视频播放器'
|
||||
},
|
||||
permission: {
|
||||
hasPermission: '请设置操作权限值'
|
||||
|
|
|
@ -342,6 +342,14 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
|
|||
meta: {
|
||||
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