Skip to content

Commit

Permalink
feat: VideoPlayer
Browse files Browse the repository at this point in the history
  • Loading branch information
kailong321200875 committed Nov 19, 2023
1 parent 5bee1a0 commit 7b5bbed
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 3 deletions.
9 changes: 9 additions & 0 deletions mock/role/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,14 @@ const adminList = [
meta: {
title: 'router.imageCropping'
}
},
{
path: 'video-player',
component: 'views/Components/VideoPlayer',
name: 'VideoPlayer',
meta: {
title: 'router.videoPlayer'
}
}
]
},
Expand Down Expand Up @@ -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',
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
27 changes: 27 additions & 0 deletions src/components/VideoPlayer/index.ts
Original file line number Diff line number Diff line change
@@ -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)
}
59 changes: 59 additions & 0 deletions src/components/VideoPlayer/src/VideoPlayer.vue
Original file line number Diff line number Diff line change
@@ -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>
3 changes: 3 additions & 0 deletions src/components/VideoPlayerViewer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import VideoPlayerViewer from './src/VideoPlayerViewer.vue'

export { VideoPlayerViewer }
49 changes: 49 additions & 0 deletions src/components/VideoPlayerViewer/src/VideoPlayerViewer.vue
Original file line number Diff line number Diff line change
@@ -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>
3 changes: 2 additions & 1 deletion src/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
3 changes: 2 additions & 1 deletion src/locales/zh-CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@ export default {
iconPicker: '图标选择器',
request: '请求',
waterfall: '瀑布流',
imageCropping: '图片裁剪'
imageCropping: '图片裁剪',
videoPlayer: '视频播放器'
},
permission: {
hasPermission: '请设置操作权限值'
Expand Down
8 changes: 8 additions & 0 deletions src/router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
}
}
]
},
Expand Down
24 changes: 24 additions & 0 deletions src/views/Components/VideoPlayer.vue
Original file line number Diff line number Diff line change
@@ -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>

0 comments on commit 7b5bbed

Please sign in to comment.