Commit 32cb530ce9556f0ade4ef7d06d8b74924e771205

Authored by fengwotao
1 parent 086c4b50

perf(external/Composes): 修改摄像头排布

1 <template> 1 <template>
2 - <div class="go-content-box" :style="{ width: w + 'px', height: h + 'px' }">  
3 - <video 2 + <video
4 crossOrigin="anonymous" 3 crossOrigin="anonymous"
5 - :id="`my-player${index}`" ref="videoRef" class="video-js my-video vjs-theme-city vjs-big-play-centered">  
6 - <source :src="sourceSrc" />  
7 - </video>  
8 - </div> 4 + :id="`my-player${index}`"
  5 + ref="videoRef"
  6 + class="video-js my-video vjs-theme-city vjs-big-play-centered"
  7 + >
  8 + <source :src="sourceSrc" />
  9 + </video>
9 </template> 10 </template>
10 <script setup lang="ts"> 11 <script setup lang="ts">
11 import { onMounted, ref, onUnmounted, watch } from 'vue' 12 import { onMounted, ref, onUnmounted, watch } from 'vue'
@@ -97,14 +98,8 @@ defineExpose({ @@ -97,14 +98,8 @@ defineExpose({
97 </script> 98 </script>
98 99
99 <style lang="scss" scoped> 100 <style lang="scss" scoped>
100 -.go-content-box {  
101 - display: flex;  
102 - align-items: center;  
103 - justify-content: center;  
104 - .my-video {  
105 - width: 100% !important;  
106 - height: 100% !important;  
107 - position: relative;  
108 - } 101 +.my-video {
  102 + width: 100%;
  103 + height: 100%;
109 } 104 }
110 </style> 105 </style>
  1 +<template>
  2 + <div class="go-content-box" :style="{ width: w + 'px', height: h + 'px' }">
  3 + <video
  4 + crossOrigin="anonymous"
  5 + :id="`my-player${index}`" ref="videoRef" class="video-js my-video vjs-theme-city vjs-big-play-centered">
  6 + <source :src="sourceSrc" />
  7 + </video>
  8 + </div>
  9 +</template>
  10 +<script setup lang="ts">
  11 +import { onMounted, ref, onUnmounted, watch } from 'vue'
  12 +import videojs from 'video.js'
  13 +import type { VideoJsPlayerOptions } from 'video.js'
  14 +import 'video.js/dist/video-js.min.css'
  15 +
  16 +const props = defineProps({
  17 + sourceSrc: {
  18 + type: String
  19 + },
  20 + name: {
  21 + type: String
  22 + },
  23 + avatar: {
  24 + type: String
  25 + },
  26 + w: {
  27 + type: Number,
  28 + default: 300
  29 + },
  30 + h: {
  31 + type: Number,
  32 + default: 300
  33 + },
  34 + index: {
  35 + type: Number
  36 + }
  37 +})
  38 +
  39 +// video标签
  40 +const videoRef = ref<HTMLElement | null>(null)
  41 +
  42 +// video实例对象
  43 +let videoPlayer: videojs.Player | null = null
  44 +
  45 +//options配置
  46 +const options: VideoJsPlayerOptions = {
  47 + language: 'zh-CN', // 设置语言
  48 + controls: true, // 是否显示控制条
  49 + preload: 'auto', // 预加载
  50 + autoplay: true, // 是否自动播放
  51 + fluid: false, // 自适应宽高
  52 + poster: props?.avatar || '',
  53 + src: props?.sourceSrc || '', // 要嵌入的视频源的源 URL
  54 + muted: true,
  55 + userActions: {
  56 + hotkeys: true
  57 + }
  58 +}
  59 +
  60 +// 初始化videojs
  61 +const initVideo = () => {
  62 + if (videoRef.value) {
  63 + // 创建 video 实例
  64 + videoPlayer = videojs(videoRef.value, options)
  65 + }
  66 +}
  67 +
  68 +watch(
  69 + () => props.sourceSrc,
  70 + (newData: any) => {
  71 + // props.sourceSrc = newData
  72 + videoPlayer?.src(newData) as any
  73 + videoPlayer?.play()
  74 + },
  75 + {
  76 + immediate: true
  77 + }
  78 +)
  79 +
  80 +onMounted(() => {
  81 + initVideo()
  82 +})
  83 +
  84 +onUnmounted(() => {
  85 + handleVideoDispose()
  86 +})
  87 +
  88 +//播放
  89 +const handleVideoPlay = () => videoPlayer?.play()
  90 +
  91 +const handleVideoDispose = () => videoPlayer?.dispose() && videoPlayer?.pause()
  92 +//暂停
  93 +defineExpose({
  94 + handleVideoPlay,
  95 + handleVideoDispose
  96 +})
  97 +</script>
  98 +
  99 +<style lang="scss" scoped>
  100 +.go-content-box {
  101 + display: flex;
  102 + align-items: center;
  103 + justify-content: center;
  104 + .my-video {
  105 + width: 100% !important;
  106 + height: 100% !important;
  107 + position: relative;
  108 + }
  109 +}
  110 +</style>
@@ -8,7 +8,7 @@ @@ -8,7 +8,7 @@
8 </n-input-group> 8 </n-input-group>
9 </setting-item> 9 </setting-item>
10 <setting-item> 10 <setting-item>
11 - <n-button v-if="optionData.dataset.length < 5" size="small" @click="optionData.dataset.push({ url: '' })"> 11 + <n-button v-if="optionData.dataset.length < 9" size="small" @click="optionData.dataset.push({ url: '' })">
12 + 12 +
13 </n-button> 13 </n-button>
14 </setting-item> 14 </setting-item>
1 <template> 1 <template>
2 <div class="banner-box" ref="root"> 2 <div class="banner-box" ref="root">
3 - <div class="wrapper">  
4 - <div v-for="(item, index) in option.dataset" :key="index + item" :class="item.className" :style="item.sty">  
5 - <CameraItem  
6 - ref="cameraRef"  
7 - :name="item.name"  
8 - :avatar="item.avatar"  
9 - :key="item + index"  
10 - :sourceSrc="item.url"  
11 - :w="w"  
12 - :h="h"  
13 - :index="index"  
14 - />  
15 - <span class="video-title">{{ item.name }}</span>  
16 - </div>  
17 - </div>  
18 - <a href="javascript:;" class="left" @click="changeSlide('left')"></a>  
19 - <a href="javascript:;" class="right" @click="changeSlide('right')"></a> 3 + <n-grid x-gap="12" :y-gap="12" :cols="computedCols">
  4 + <n-gi v-for="(item, index) in option.dataset" :key="index + item">
  5 + <div class="camera-container">
  6 + <CameraItem
  7 + ref="cameraRef"
  8 + :name="item.name"
  9 + :avatar="item.avatar"
  10 + :key="item + index"
  11 + :sourceSrc="item.url"
  12 + :index="index"
  13 + />
  14 + </div>
  15 + </n-gi>
  16 + </n-grid>
20 </div> 17 </div>
21 </template> 18 </template>
22 <script setup lang="ts"> 19 <script setup lang="ts">
23 -import { PropType, watch, toRefs, shallowReactive, onMounted, ref } from 'vue' 20 +import { PropType, toRefs, watch, shallowReactive, ref, computed } from 'vue'
24 import { CreateComponentType } from '@/packages/index.d' 21 import { CreateComponentType } from '@/packages/index.d'
25 import 'video.js/dist/video-js.min.css' 22 import 'video.js/dist/video-js.min.css'
26 import { option as configOption } from './config' 23 import { option as configOption } from './config'
@@ -33,68 +30,34 @@ const props = defineProps({ @@ -33,68 +30,34 @@ const props = defineProps({
33 } 30 }
34 }) 31 })
35 32
36 -const { w, h } = toRefs(props.chartConfig.attr) 33 +const { h } = toRefs(props.chartConfig.attr)
  34 +
  35 +const responsiveComputeValue = ref(0)
37 36
38 const option = shallowReactive({ 37 const option = shallowReactive({
39 dataset: configOption.dataset 38 dataset: configOption.dataset
40 }) 39 })
41 40
42 -const cameraRef = ref<InstanceType<typeof CameraItem>>()  
43 -  
44 -let initial = ref(0) 41 +const computedCols = computed(() => {
  42 + if (option.dataset.length <= 1) return 1
  43 + if (option.dataset.length <= 4) return 2
  44 + return 3
  45 +})
45 46
46 -let interval = ref(2500) 47 +const cameraRef = ref<InstanceType<typeof CameraItem>>()
47 48
48 -const computedFunc = (initial: number, source: any) => {  
49 - if (initial < 0) initial = 0  
50 - if (Array.isArray(source)) {  
51 - let len = source.length,  
52 - temp1 = initial - 2 < 0 ? initial - 2 + len : initial - 2,  
53 - temp2 = initial - 1 < 0 ? initial - 1 + len : initial - 1,  
54 - temp3 = initial,  
55 - temp4 = initial + 1 >= len ? initial + 1 - len : initial + 1,  
56 - temp5 = initial + 2 >= len ? initial + 2 - len : initial + 2  
57 - return source?.map((item: any, index: number) => {  
58 - let transform = `translateX(-50%) scale(0.7)`,  
59 - zIndex = 0,  
60 - className = 'slide'  
61 - switch (index) {  
62 - case temp3:  
63 - transform = `translateX(-50%) scale(1)`  
64 - className = ['slide', 'activate'] as any  
65 - zIndex = 300  
66 - break  
67 - case temp1:  
68 - transform = `translateX(-80%) scale(0.7)`  
69 - zIndex = 100  
70 - break  
71 - case temp5:  
72 - transform = `translateX(100%) scale(0.7)`  
73 - zIndex = 100  
74 - break  
75 - case temp2:  
76 - transform = `translateX(-100%) scale(0.85)`  
77 - zIndex = 200  
78 - break  
79 - case temp4:  
80 - transform = `translateX(58%) scale(0.85)`  
81 - zIndex = 200  
82 - break  
83 - }  
84 - item.sty = {  
85 - transform,  
86 - zIndex  
87 - }  
88 - item.className = className  
89 - return item  
90 - })  
91 - } 49 +const responsive = (value: number) => {
  50 + responsiveComputeValue.value = value
  51 + if (option.dataset.length <= 2) responsiveComputeValue.value = value
  52 + if (option.dataset.length > 2 && option.dataset.length <= 4) responsiveComputeValue.value = value / 2.03
  53 + if (option.dataset.length > 4 && option.dataset.length <= 9) responsiveComputeValue.value = value / 3.1
92 } 54 }
93 55
94 watch( 56 watch(
95 () => props.chartConfig.option.dataset, 57 () => props.chartConfig.option.dataset,
96 newData => { 58 newData => {
97 option.dataset = newData 59 option.dataset = newData
  60 + responsive(h.value)
98 }, 61 },
99 { 62 {
100 immediate: true, 63 immediate: true,
@@ -102,101 +65,19 @@ watch( @@ -102,101 +65,19 @@ watch(
102 } 65 }
103 ) 66 )
104 67
105 -option.dataset = computedFunc(initial.value, option.dataset)  
106 -  
107 watch( 68 watch(
108 - () => initial.value,  
109 - newV => {  
110 - option.dataset = computedFunc(newV, option.dataset) 69 + () => h.value,
  70 + newData => responsive(newData),
  71 + {
  72 + immediate: true
111 } 73 }
112 ) 74 )
113 -  
114 -// 处理自动轮播  
115 -let timer: any = null  
116 -  
117 -const autoPlay = () => {  
118 - timer = setInterval(() => {  
119 - initial.value++  
120 - if (initial.value >= option.dataset.length) {  
121 - initial.value = 0  
122 - }  
123 - }, interval.value)  
124 -}  
125 -  
126 -// 鼠标移入移除效果  
127 -let root = ref(null)  
128 -  
129 -onMounted(() => {  
130 - clearInterval(timer)  
131 - autoPlay()  
132 - const box: any = root.value  
133 - box.onmouseenter = () => clearInterval(timer)  
134 - box.onmouseleave = () => autoPlay()  
135 -})  
136 -  
137 -// 点击左右按钮切换图片  
138 -function changeVideo(dir: string) {  
139 - if (dir === 'left') {  
140 - clearInterval(timer)  
141 - initial.value++  
142 - initial.value >= option.dataset.length ? (initial.value = 0) : false  
143 - return  
144 - }  
145 - initial.value--  
146 - initial.value < 0 ? (initial.value = option.dataset.length - 1) : false  
147 -}  
148 -  
149 -// 左右切换图片设置防抖效果  
150 -function changeSlide(dir: string) {  
151 - changeVideo(dir)  
152 -}  
153 </script> 75 </script>
154 76
155 <style lang="scss" scoped> 77 <style lang="scss" scoped>
156 .banner-box { 78 .banner-box {
157 - .wrapper {  
158 - height: 100%;  
159 - display: flex;  
160 - overflow: hidden;  
161 - .slide {  
162 - width: 20%;  
163 - height: 100%;  
164 - position: absolute;  
165 - left: 10%;  
166 - transform: translateX(-50%);  
167 - transition: 0.5s;  
168 - box-shadow: 0 0 4px black;  
169 - .video-title {  
170 - width: v-bind('w+"px"');  
171 - font-size: 30px;  
172 - color: white;  
173 - position: absolute;  
174 - bottom: 6%;  
175 - left: 10%;  
176 - z-index: 999;  
177 - }  
178 - }  
179 - }  
180 - .arrow {  
181 - position: absolute;  
182 - top: 50%;  
183 - transform: translateY(-50%);  
184 - z-index: 9;  
185 - width: 50px;  
186 - height: 50px;  
187 - background-size: contain;  
188 - background-color: white;  
189 - opacity: 0.5;  
190 - }  
191 - a.left {  
192 - @extend .arrow;  
193 - background-image: url(./static/left.svg);  
194 - left: 0px;  
195 - }  
196 - a.right {  
197 - @extend .arrow;  
198 - background-image: url(./static/right.svg);  
199 - right: 0px; 79 + .camera-container {
  80 + height: v-bind('`${responsiveComputeValue}px`');
200 } 81 }
201 } 82 }
202 </style> 83 </style>
  1 +<template>
  2 + <div class="banner-box" ref="root">
  3 + <div class="wrapper">
  4 + <div
  5 + v-for="(item, index) in option.dataset"
  6 + :key="index + item"
  7 + :class="item.className"
  8 + :style="item.sty"
  9 + >
  10 + <CameraItem
  11 + ref="cameraRef"
  12 + :name="item.name"
  13 + :avatar="item.avatar"
  14 + :key="item + index"
  15 + :sourceSrc="item.url"
  16 + :w="w"
  17 + :h="h"
  18 + :index="index"
  19 + />
  20 + <span class="video-title">{{ item.name }}</span>
  21 + </div>
  22 + </div>
  23 + <a href="javascript:;" class="left" @click="changeSlide('left')"></a>
  24 + <a href="javascript:;" class="right" @click="changeSlide('right')"></a>
  25 + </div>
  26 +</template>
  27 +<script setup lang="ts">
  28 +import { PropType, watch, toRefs, shallowReactive, onMounted, ref } from 'vue'
  29 +import { CreateComponentType } from '@/packages/index.d'
  30 +import 'video.js/dist/video-js.min.css'
  31 +import { option as configOption } from './config'
  32 +import { CameraItem } from './components'
  33 +
  34 +const props = defineProps({
  35 + chartConfig: {
  36 + type: Object as PropType<CreateComponentType>,
  37 + required: true
  38 + }
  39 +})
  40 +
  41 +const { w, h } = toRefs(props.chartConfig.attr)
  42 +
  43 +const option = shallowReactive({
  44 + dataset: configOption.dataset
  45 +})
  46 +
  47 +const cameraRef = ref<InstanceType<typeof CameraItem>>()
  48 +
  49 +let initial = ref(0)
  50 +
  51 +let interval = ref(2500)
  52 +
  53 +const computedFunc = (initial: number, source: any) => {
  54 + if (initial < 0) initial = 0
  55 + if (Array.isArray(source)) {
  56 + let len = source.length,
  57 + temp1 = initial - 2 < 0 ? initial - 2 + len : initial - 2,
  58 + temp2 = initial - 1 < 0 ? initial - 1 + len : initial - 1,
  59 + temp3 = initial,
  60 + temp4 = initial + 1 >= len ? initial + 1 - len : initial + 1,
  61 + temp5 = initial + 2 >= len ? initial + 2 - len : initial + 2
  62 + return source?.map((item: any, index: number) => {
  63 + let transform = `translateX(-50%) scale(0.7)`,
  64 + zIndex = 0,
  65 + className = 'slide'
  66 + switch (index) {
  67 + case temp3:
  68 + transform = `translateX(-50%) scale(1)`
  69 + className = ['slide', 'activate'] as any
  70 + zIndex = 300
  71 + break
  72 + case temp1:
  73 + transform = `translateX(-80%) scale(0.7)`
  74 + zIndex = 100
  75 + break
  76 + case temp5:
  77 + transform = `translateX(100%) scale(0.7)`
  78 + zIndex = 100
  79 + break
  80 + case temp2:
  81 + transform = `translateX(-100%) scale(0.85)`
  82 + zIndex = 200
  83 + break
  84 + case temp4:
  85 + transform = `translateX(58%) scale(0.85)`
  86 + zIndex = 200
  87 + break
  88 + }
  89 + item.sty = {
  90 + transform,
  91 + zIndex
  92 + }
  93 + item.className = className
  94 + return item
  95 + })
  96 + }
  97 +}
  98 +
  99 +watch(
  100 + () => props.chartConfig.option.dataset,
  101 + newData => {
  102 + option.dataset = newData
  103 + },
  104 + {
  105 + immediate: true,
  106 + deep: true
  107 + }
  108 +)
  109 +
  110 +option.dataset = computedFunc(initial.value, option.dataset)
  111 +
  112 +watch(
  113 + () => initial.value,
  114 + newV => {
  115 + option.dataset = computedFunc(newV, option.dataset)
  116 + }
  117 +)
  118 +
  119 +// 处理自动轮播
  120 +let timer: any = null
  121 +
  122 +const autoPlay = () => {
  123 + timer = setInterval(() => {
  124 + initial.value++
  125 + if (initial.value >= option.dataset.length) {
  126 + initial.value = 0
  127 + }
  128 + }, interval.value)
  129 +}
  130 +
  131 +// 鼠标移入移除效果
  132 +let root = ref(null)
  133 +
  134 +onMounted(() => {
  135 + clearInterval(timer)
  136 + autoPlay()
  137 + const box: any = root.value
  138 + box.onmouseenter = () => clearInterval(timer)
  139 + box.onmouseleave = () => autoPlay()
  140 +})
  141 +
  142 +// 点击左右按钮切换图片
  143 +function changeVideo(dir: string) {
  144 + if (dir === 'left') {
  145 + clearInterval(timer)
  146 + initial.value++
  147 + initial.value >= option.dataset.length ? (initial.value = 0) : false
  148 + return
  149 + }
  150 + initial.value--
  151 + initial.value < 0 ? (initial.value = option.dataset.length - 1) : false
  152 +}
  153 +
  154 +// 左右切换图片设置防抖效果
  155 +function changeSlide(dir: string) {
  156 + changeVideo(dir)
  157 +}
  158 +</script>
  159 +
  160 +<style lang="scss" scoped>
  161 +.banner-box {
  162 + .wrapper {
  163 + height: 100%;
  164 + display: flex;
  165 + overflow: hidden;
  166 + .slide {
  167 + width: 20%;
  168 + height: 100%;
  169 + position: absolute;
  170 + left: 10%;
  171 + transform: translateX(-50%);
  172 + transition: 0.5s;
  173 + box-shadow: 0 0 4px black;
  174 + .video-title {
  175 + width: v-bind('w+"px"');
  176 + font-size: 30px;
  177 + color: white;
  178 + position: absolute;
  179 + bottom: 6%;
  180 + left: 10%;
  181 + z-index: 999;
  182 + }
  183 + }
  184 + }
  185 + .arrow {
  186 + position: absolute;
  187 + top: 50%;
  188 + transform: translateY(-50%);
  189 + z-index: 9;
  190 + width: 50px;
  191 + height: 50px;
  192 + background-size: contain;
  193 + background-color: white;
  194 + opacity: 0.5;
  195 + }
  196 + a.left {
  197 + @extend .arrow;
  198 + background-image: url(./static/left.svg);
  199 + left: 0px;
  200 + }
  201 + a.right {
  202 + @extend .arrow;
  203 + background-image: url(./static/right.svg);
  204 + right: 0px;
  205 + }
  206 +}
  207 +</style>