video.uvue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. <template>
  2. <view class="uni-flex-item">
  3. <video class="video" ref="video" id="video" :header="header" :src="src" :autoplay="autoplay" :loop="loop"
  4. :muted="muted" :initial-time="initialTime" :duration="duration" :controls="controls" :danmu-btn="danmuBtn"
  5. :enable-danmu="enableDanmu" :page-gesture="pageGesture" :direction="direction" :show-progress="showProgress"
  6. :show-fullscreen-btn="showFullscreenBtn" :show-play-btn="showPlayBtn" :show-center-play-btn="showCenterPlayBtn"
  7. :show-loading="showLoading" :enable-progress-gesture="enableProgressGesture" :object-fit="objectFit"
  8. :poster="poster" :show-mute-btn="showMuteBtn" :title="title" :enable-play-gesture="enablePlayGesture"
  9. :vslide-gesture="vslideGesture" :vslide-gesture-in-fullscreen="vslideGestureInFullscreen" :codec="codec"
  10. :http-cache="httpCache" :play-strategy="playStrategy" :danmu-list="danmuList" @play="onPlay" @pause="onPause"
  11. @ended="onEnded" @timeupdate="onTimeUpdate" @waiting="onWaiting" @error="onError" @progress="onProgress"
  12. @fullscreenclick="onFullScreenClick" @controlstoggle="onControlsToggle" @fullscreenchange="onFullScreenChange">
  13. <image v-if="subCompEnable && subCompShow" class="img-fast-backward"
  14. src="../../../static/test-video/fast-backward.png" @tap="fastBackward"></image>
  15. <image v-if="subCompEnable && subCompShow" class="img-fast-forward"
  16. src="../../../static/test-video/fast-forward.png" @tap="fastForward"></image>
  17. <input id="input-send-danmu" class="input-send-danmu" v-if="subCompEnable && subCompShow" placeholder="请输入弹幕内容"
  18. placeholder-style="color: white;" confirm-type="send" @confirm="onSendDanmuConfirm"
  19. @keyboardheightchange="onSendDanmuKeyboardHeightChange" @blur="onSendDanmuBlur"></input>
  20. </video>
  21. <scroll-view class="uni-padding-wrap uni-common-mt uni-flex-item">
  22. <view class="uni-btn-v">
  23. <navigator url="/pages/component/video/video-format">
  24. <button type="primary" @click="pause">视频格式示例</button>
  25. </navigator>
  26. </view>
  27. <view class="uni-flex uni-btn-v" style="justify-content: space-between;align-items: center;">
  28. <text class="uni-title" style="width: 80%;">子组件实现快进、快退、发送弹幕功能(全屏后显示)</text>
  29. <switch :checked="subCompEnable" @change="onSubCompEnableChange" />
  30. </view>
  31. <view class="uni-title">
  32. <text class="uni-title-text">API示例</text>
  33. </View>
  34. <view class="uni-btn-v">
  35. <button type="primary" @click="play">播放</button>
  36. </view>
  37. <view class="uni-btn-v">
  38. <button type="primary" @click="pause">暂停</button>
  39. </view>
  40. <view class="uni-btn-v">
  41. <input class="input" placeholder="输入要跳转的位置,单位s" type="number" @input="onSeekInput"></input>
  42. <button type="primary" @click="seek(this.pos)">跳转到指定位置</button>
  43. </view>
  44. <view class="uni-btn-v">
  45. <enum-data title="选择进入全屏时的视频方向" :items="directionItemTypes"
  46. @change="onRequestFullScreenDirectionChange"></enum-data>
  47. <button type="primary" @click="requestFullScreen">进入全屏</button>
  48. </view>
  49. <view class="uni-btn-v">
  50. <button type="primary" @click="exitFullScreen">退出全屏</button>
  51. </view>
  52. <view class="uni-btn-v">
  53. <button type="primary" @click="stop">停止</button>
  54. </view>
  55. <view class="uni-btn-v">
  56. <input class="input" placeholder="输入弹幕" value="{ 'text': '要显示的文本', 'color': '#FF0000' }" type="string"
  57. @input="onSendDanmuInput"></input>
  58. <button type="primary" :disabled="!enableDanmu" @click="sendDanmu">发送弹幕</button>
  59. </view>
  60. <view class="uni-btn-v">
  61. <enum-data title="选择倍速" :items="rateItemTypes" @change="onPlaybackRateChange"></enum-data>
  62. <button type="primary" @click="playbackRate">设置倍速</button>
  63. </view>
  64. <view class="uni-title">
  65. <text class="uni-title-text">属性示例</text>
  66. </view>
  67. <input class="input margin-10" type="string" placeholder="设置播放资源" @confirm="onSrcComfirm"></input>
  68. <input class="input margin-10" type="number" placeholder="设置初始播放位置(播放前设置有效)"
  69. @confirm="onInitialTimeComfirm"></input>
  70. <input class="input margin-10" type="number" placeholder="设置视频时长(播放前设置有效)" @confirm="onDurationComfirm"></input>
  71. <input class="input margin-10" type="string" placeholder="设置视频封面" @confirm="onPosterComfirm"></input>
  72. <input class="input margin-10" type="string" placeholder="设置视频标题(仅限非 Web 平台)" @confirm="onTitleComfirm"></input>
  73. <input class="input margin-10" type="string" placeholder="设置header(json格式)" @confirm="onHeaderComfirm"></input>
  74. <boolean-data title="设置是否展示弹幕(播放前设置有效)" :defaultValue="enableDanmu" @change="onEnableDanmuChange"></boolean-data>
  75. <boolean-data title="设置是否自动播放(播放前设置有效)" :defaultValue="autoplay" @change="onAutoplayChange"></boolean-data>
  76. <boolean-data title="设置是否循环播放(播放完成后生效)" :defaultValue="loop" @change="onLoopChange"></boolean-data>
  77. <boolean-data title="设置是否静音播放" :defaultValue="muted" @change="onMutedChange"></boolean-data>
  78. <boolean-data title="设置是否显示默认播放控件" :defaultValue="controls" @change="onControlsChange"></boolean-data>
  79. <boolean-data title="设置是否显示弹幕按钮" :defaultValue="danmuBtn" @change="onDanmuBtnChange"></boolean-data>
  80. <boolean-data title="设置是否显示进度条" :defaultValue="showProgress" @change="onShowProgressChange"></boolean-data>
  81. <boolean-data title="设置是否显示全屏按钮" :defaultValue="showFullscreenBtn"
  82. @change="onShowFullscreenBtnChange"></boolean-data>
  83. <boolean-data title="设置是否显示视频底部控制栏的播放按钮" :defaultValue="showPlayBtn" @change="onShowPlayBtnChange"></boolean-data>
  84. <boolean-data title="设置是否显示静音按钮(仅限非 Web 平台)" :defaultValue="showMuteBtn"
  85. @change="onShowMuteBtnChange"></boolean-data>
  86. <boolean-data title="设置是否显示视频中间的播放按钮" :defaultValue="showCenterPlayBtn"
  87. @change="onShowCenterPlayBtnChange"></boolean-data>
  88. <boolean-data title="设置是否显示loading控件" :defaultValue="showLoading" @change="onShowLoadingChange"></boolean-data>
  89. <boolean-data title="设置是否开启控制进度的手势" :defaultValue="enableProgressGesture"
  90. @change="onEnableProgressGestureChange"></boolean-data>
  91. <boolean-data title="设置是否开启播放手势,双击播放暂停(仅限非 Web 平台)" :defaultValue="enablePlayGesture"
  92. @change="onEnablePlayGestureChange"></boolean-data>
  93. <!-- #ifndef WEB -->
  94. <boolean-data title="非全屏模式下,设置是否开启亮度与音量调节手势 page-gesture" :defaultValue="pageGesture"
  95. @change="onPageGestureChange"></boolean-data>
  96. <!-- #endif -->
  97. <boolean-data title="非全屏模式下,设置是否开启亮度与音量调节手势 vslide-gesture(仅限非 Web 平台)" :defaultValue="vslideGesture"
  98. @change="onVslideGestureChange"></boolean-data>
  99. <boolean-data title="全屏模式下,设置是否开启亮度与音量调节手势(仅限非 Web 平台)" :defaultValue="vslideGestureInFullscreen"
  100. @change="onVslideGestureInFullscreenChange"></boolean-data>
  101. <enum-data title="设置视频大小与video容器大小不一致时,视频的表现形式" :items="objectFitItemTypes"
  102. @change="onObjectFitChange"></enum-data>
  103. <!-- #ifndef APP-HARMONY -->
  104. <boolean-data title="设置是否对http、https视频源开启本地缓存(仅 App 平台,播放前设置有效)" :defaultValue="httpCache"
  105. @change="onHttpCacheChange"></boolean-data>
  106. <enum-data title="设置解码器(仅 App 平台,播放前设置有效)" :items="codecItemTypes" @change="onCodecChange"></enum-data>
  107. <enum-data title="设置播放策略(仅 App 平台,播放前设置有效)" :items="playStrategyItemTypes"
  108. @change="onPlayStrategyChange"></enum-data>
  109. <!-- #endif -->
  110. </scroll-view>
  111. </view>
  112. </template>
  113. <script>
  114. import { ItemType } from '@/components/enum-data/enum-data-types';
  115. // #ifdef APP-ANDROID
  116. import ViewGroup from 'android.view.ViewGroup';
  117. // #endif
  118. export default {
  119. onReady() {
  120. this.videoContext = uni.createVideoContext('video');
  121. // this.videoContext = uni.createVideoContext('video', this);
  122. },
  123. data() {
  124. return {
  125. videoContext: null as VideoContext | null,
  126. // 属性
  127. src: "https://qiniu-web-assets.dcloud.net.cn/video/sample/2minute-demo.mp4",
  128. autoplay: false,
  129. loop: false,
  130. muted: false,
  131. initialTime: 0,
  132. duration: 0,
  133. controls: true,
  134. danmuList: [{
  135. text: '要显示的文本',
  136. color: '#FF0000',
  137. time: 3
  138. }, {
  139. text: '要显示的文本2',
  140. color: '#31ff23',
  141. time: 5
  142. }, {
  143. text: '要显示的文本3',
  144. color: '#f13ef8',
  145. time: 7
  146. }, {
  147. text: '要显示的文本4',
  148. color: '#4972f8',
  149. time: 9
  150. }, {
  151. text: '要显示的文本5',
  152. color: '#000000',
  153. time: 11
  154. }] as Array<Danmu>,
  155. danmuBtn: false,
  156. enableDanmu: true,
  157. pageGesture: false,
  158. direction: -1,
  159. directionItemTypes: [{ "value": 0, "name": "0(正常竖向)" }, { "value": 1, "name": "90(屏幕逆时针90度)" }, { "value": 2, "name": "-90(屏幕顺时针90度)" }] as ItemType[],
  160. directionItems: [0, 90, -90],
  161. showProgress: true,
  162. showFullscreenBtn: true,
  163. showPlayBtn: true,
  164. showCenterPlayBtn: true,
  165. showLoading: true,
  166. enableProgressGesture: true,
  167. objectFit: "contain",
  168. objectFitItemTypes: [{ "value": 0, "name": "contain(包含)" }, { "value": 1, "name": "fill(填充)" }, { "value": 2, "name": "cover(覆盖)" }] as ItemType[],
  169. objectFitItems: ["contain", "fill", "cover"],
  170. poster: "https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/uni-android.png",
  171. showMuteBtn: false,
  172. title: "video-component",
  173. enablePlayGesture: false,
  174. vslideGesture: false,
  175. vslideGestureInFullscreen: true,
  176. codec: "hardware",
  177. codecItemTypes: [{ "value": 0, "name": "hardware(硬解码)" }, { "value": 1, "name": "software(软解码)" }] as ItemType[],
  178. codecItems: ["hardware", "software"],
  179. httpCache: true,
  180. playStrategy: 0,
  181. playStrategyItemTypes: [{ "value": 0, "name": "0(普通模式)" }, { "value": 1, "name": "1(平滑播放模式)" }, { "value": 1, "name": "2(M3U8优化模式)" }] as ItemType[],
  182. playStrategyItems: [0, 1, 2],
  183. header: {
  184. 'User-Agent': 'User-Agent test',
  185. 'header': 'header test',
  186. 'cookie': 'cookie test'
  187. } as UTSJSONObject,
  188. // API
  189. pos: 0,
  190. requestFullScreenOptions: null as RequestFullScreenOptions | null,
  191. danmu: {
  192. text: '要显示的文本',
  193. color: '#FF0000'
  194. } as Danmu,
  195. rate: 1,
  196. rateItemTypes: [{ "value": 0, "name": "0.5" }, { "value": 1, "name": "0.8" }, { "value": 2, "name": "1.0" }, { "value": 3, "name": "1.25" }, { "value": 4, "name": "1.5" }] as ItemType[],
  197. rateItems: [0.5, 0.8, 1.0, 1.25, 1.5],
  198. subCompEnable: false,
  199. subCompShow: false,
  200. curPos: 0,
  201. endPos: 0,
  202. // 自动化测试
  203. autoTest: false,
  204. isPlaying: false,
  205. isPause: false,
  206. isError: false,
  207. eventPlay: null as UTSJSONObject | null,
  208. eventPause: null as UTSJSONObject | null,
  209. eventEnded: null as UTSJSONObject | null,
  210. eventTimeupdate: null as UTSJSONObject | null,
  211. eventFullscreenchange: null as UTSJSONObject | null,
  212. eventWaiting: null as UTSJSONObject | null,
  213. eventError: null as UTSJSONObject | null,
  214. eventProgress: null as UTSJSONObject | null,
  215. eventFullscreenclick: null as UTSJSONObject | null,
  216. eventControlstoggle: null as UTSJSONObject | null
  217. }
  218. },
  219. onLoad() {
  220. },
  221. methods: {
  222. // API
  223. play: function () {
  224. console.log("play");
  225. this.videoContext?.play();
  226. },
  227. pause: function () {
  228. console.log("pause");
  229. // #ifdef MP
  230. this.videoContext?.pause();
  231. // #endif
  232. // #ifndef MP
  233. (uni.getElementById("video") as UniVideoElement).pause(); //as写法测试。注意id不对时as会崩溃
  234. // #endif
  235. },
  236. seek: function (pos : number) {
  237. console.log("seek -> " + pos);
  238. this.videoContext?.seek(pos);
  239. },
  240. onSeekInput: function (event : UniInputEvent) {
  241. this.pos = parseInt(event.detail.value);
  242. },
  243. requestFullScreen: function () {
  244. console.log("requestFullScreen -> " + this.requestFullScreenOptions);
  245. this.videoContext?.requestFullScreen(this.requestFullScreenOptions);
  246. },
  247. exitFullScreen: function () {
  248. console.log("exitFullScreen");
  249. this.videoContext?.exitFullScreen();
  250. },
  251. stop: function () {
  252. console.log("stop");
  253. // #ifdef MP
  254. this.videoContext?.stop();
  255. // #endif
  256. // #ifndef MP
  257. uni.getElementById<UniVideoElement>("video")?.stop(); //泛型写法测试
  258. // #endif
  259. },
  260. sendDanmu: function () {
  261. console.log("sendDanmu -> " + this.danmu);
  262. this.videoContext?.sendDanmu(this.danmu);
  263. },
  264. onSendDanmuInput: function (event : UniInputEvent) {
  265. let json = JSON.parse<Danmu>(event.detail.value)
  266. if (json == null) return;
  267. this.danmu = json as Danmu;
  268. },
  269. playbackRate: function () {
  270. console.log("playbackRate -> " + this.rate);
  271. this.videoContext?.playbackRate(this.rate);
  272. },
  273. onPlaybackRateChange: function (value : number) {
  274. this.rate = this.rateItems[value];
  275. },
  276. fastBackward: function () {
  277. let pos = this.curPos - 15;
  278. if (pos < 0) pos = 0;
  279. this.seek(pos);
  280. },
  281. fastForward: function () {
  282. let pos = this.curPos + 15;
  283. if (pos > this.endPos) pos = this.endPos;
  284. this.seek(pos);
  285. },
  286. onSendDanmuConfirm: function (event : UniInputConfirmEvent) {
  287. this.videoContext?.sendDanmu({
  288. text: event.detail.value,
  289. color: '#ff0000'
  290. } as Danmu);
  291. },
  292. onSendDanmuKeyboardHeightChange: function (event : UniInputKeyboardHeightChangeEvent) {
  293. const element = uni.getElementById('input-send-danmu') as UniElement;
  294. if (event.detail.height.toInt() == 0) {
  295. element.style.setProperty('bottom', '50px');
  296. } else {
  297. element.style.setProperty('bottom', event.detail.height + element.getBoundingClientRect().height);
  298. }
  299. },
  300. onSendDanmuBlur: function (_ : UniInputBlurEvent) {
  301. (uni.getElementById('input-send-danmu') as UniElement).style.setProperty('bottom', '50px');
  302. },
  303. // 属性
  304. onSrcComfirm: function (event : UniInputConfirmEvent) {
  305. let value = event.detail.value;
  306. if (value == '') return;
  307. this.src = value;
  308. console.log("src -> " + this.src)
  309. },
  310. onAutoplayChange: function (value : boolean) {
  311. this.autoplay = value;
  312. console.log("autoplay -> " + this.autoplay)
  313. },
  314. onLoopChange: function (value : boolean) {
  315. this.loop = value;
  316. console.log("loop -> " + this.loop)
  317. },
  318. onMutedChange: function (value : boolean) {
  319. this.muted = value;
  320. console.log("muted -> " + this.muted)
  321. },
  322. onInitialTimeComfirm: function (event : UniInputConfirmEvent) {
  323. let value = parseInt(event.detail.value)
  324. if (isNaN(value)) value = 0;
  325. this.initialTime = value;
  326. console.log("initialTime -> " + this.initialTime)
  327. },
  328. onDurationComfirm: function (event : UniInputConfirmEvent) {
  329. let value = parseInt(event.detail.value)
  330. if (isNaN(value)) value = 0;
  331. this.duration = value;
  332. console.log("duration -> " + this.duration)
  333. },
  334. onControlsChange: function (value : boolean) {
  335. this.controls = value;
  336. console.log("controls -> " + this.controls)
  337. },
  338. onEnableDanmuChange: function (value : boolean) {
  339. this.enableDanmu = value;
  340. console.log("enableDanmu -> " + this.enableDanmu)
  341. },
  342. onDanmuBtnChange: function (value : boolean) {
  343. this.danmuBtn = value;
  344. console.log("danmuBtn -> " + this.danmuBtn)
  345. },
  346. onPageGestureChange: function (value : boolean) {
  347. this.pageGesture = value;
  348. console.log("pageGesture -> " + this.pageGesture)
  349. },
  350. onRequestFullScreenDirectionChange: function (value : number) {
  351. let direction = this.directionItems[value];
  352. this.requestFullScreenOptions = {
  353. direction
  354. } as RequestFullScreenOptions;
  355. },
  356. onShowProgressChange: function (value : boolean) {
  357. this.showProgress = value;
  358. console.log("showProgress -> " + this.showProgress)
  359. },
  360. onShowFullscreenBtnChange: function (value : boolean) {
  361. this.showFullscreenBtn = value;
  362. console.log("showFullscreenBtn -> " + this.showFullscreenBtn)
  363. },
  364. onShowPlayBtnChange: function (value : boolean) {
  365. this.showPlayBtn = value;
  366. console.log("showPlayBtn -> " + this.showPlayBtn)
  367. },
  368. onShowCenterPlayBtnChange: function (value : boolean) {
  369. this.showCenterPlayBtn = value;
  370. console.log("showCenterPlayBtn -> " + this.showCenterPlayBtn)
  371. },
  372. onShowLoadingChange: function (value : boolean) {
  373. this.showLoading = value;
  374. console.log("showLoading -> " + this.showLoading)
  375. },
  376. onEnableProgressGestureChange: function (value : boolean) {
  377. this.enableProgressGesture = value;
  378. console.log("enableProgressGesture -> " + this.enableProgressGesture)
  379. },
  380. onObjectFitChange: function (value : number) {
  381. this.objectFit = this.objectFitItems[value];
  382. console.log("objectFit -> " + this.objectFit)
  383. },
  384. onPosterComfirm: function (event : UniInputConfirmEvent) {
  385. let value = event.detail.value;
  386. if (value == '') return;
  387. this.poster = value;
  388. console.log("poster -> " + this.poster)
  389. },
  390. onShowMuteBtnChange: function (value : boolean) {
  391. this.showMuteBtn = value;
  392. console.log("showMuteBtn -> " + this.showMuteBtn)
  393. },
  394. onTitleComfirm: function (event : UniInputConfirmEvent) {
  395. let value = event.detail.value;
  396. if (value == '') return;
  397. this.title = value;
  398. console.log("title -> " + this.title)
  399. },
  400. onEnablePlayGestureChange: function (value : boolean) {
  401. this.enablePlayGesture = value;
  402. console.log("enablePlayGesture -> " + this.enablePlayGesture)
  403. },
  404. onVslideGestureChange: function (value : boolean) {
  405. this.vslideGesture = value;
  406. console.log("vslideGesture -> " + this.vslideGesture)
  407. },
  408. onVslideGestureInFullscreenChange: function (value : boolean) {
  409. this.vslideGestureInFullscreen = value;
  410. console.log("vslideGestureInFullscreen -> " + this.vslideGestureInFullscreen)
  411. },
  412. onCodecChange: function (value : number) {
  413. this.codec = this.codecItems[value];
  414. console.log("codec -> " + this.codec)
  415. },
  416. onHttpCacheChange: function (value : boolean) {
  417. this.httpCache = value;
  418. console.log("httpCache -> " + this.httpCache)
  419. },
  420. onPlayStrategyChange: function (value : number) {
  421. this.playStrategy = this.playStrategyItems[value];
  422. console.log("playStrategy -> " + this.playStrategy)
  423. },
  424. onHeaderComfirm: function (event : UniInputConfirmEvent) {
  425. let json = JSON.parse(event.detail.value)
  426. if (json == null) return;
  427. this.header = json as UTSJSONObject;
  428. console.log("header -> " + JSON.stringify(this.header))
  429. },
  430. onSubCompEnableChange: function (event : UniSwitchChangeEvent) {
  431. this.subCompEnable = event.detail.value;
  432. },
  433. // 事件
  434. onPlay: function (res : UniEvent) {
  435. console.log(res.type);
  436. this.isPlaying = true;
  437. this.isPause = false;
  438. if (this.autoTest) {
  439. this.eventPlay = {
  440. "tagName": res.target?.tagName,
  441. "type": res.type
  442. };
  443. }
  444. },
  445. onPause: function (res : UniEvent) {
  446. console.log(res.type);
  447. this.isPlaying = false;
  448. this.isPause = true;
  449. if (this.autoTest) {
  450. this.eventPause = {
  451. "tagName": res.target?.tagName,
  452. "type": res.type
  453. };
  454. }
  455. },
  456. onEnded: function (res : UniEvent) {
  457. console.log(res.type);
  458. if (this.autoTest) {
  459. this.eventEnded = {
  460. "tagName": res.target?.tagName,
  461. "type": res.type
  462. };
  463. }
  464. },
  465. onTimeUpdate: function (res : UniVideoTimeUpdateEvent) {
  466. console.log(res.type + " -> " + JSON.stringify(res.detail));
  467. this.curPos = res.detail.currentTime;
  468. this.endPos = res.detail.duration;
  469. if (this.autoTest) {
  470. this.eventTimeupdate = {
  471. "tagName": res.target?.tagName,
  472. "type": res.type,
  473. "currentTime": Math.trunc(res.detail.currentTime),
  474. "duration": Math.trunc(res.detail.duration)
  475. };
  476. }
  477. },
  478. onFullScreenChange: function (res : UniVideoFullScreenChangeEvent) {
  479. console.log(res.type + " -> " + JSON.stringify(res.detail));
  480. this.subCompShow = res.detail.fullScreen;
  481. if (this.autoTest) {
  482. this.eventFullscreenchange = {
  483. "tagName": res.target?.tagName,
  484. "type": res.type,
  485. "fullScreen": res.detail.fullScreen,
  486. "direction": res.detail.direction
  487. };
  488. }
  489. },
  490. onWaiting: function (res : UniEvent) {
  491. console.log(res.type);
  492. if (this.autoTest) {
  493. this.eventWaiting = {
  494. "tagName": res.target?.tagName,
  495. "type": res.type
  496. };
  497. }
  498. },
  499. onError: function (res : UniVideoErrorEvent) {
  500. console.log(res.type + " -> " + JSON.stringify(res.detail));
  501. this.isError = true;
  502. if (this.autoTest) {
  503. this.eventError = {
  504. "tagName": res.target?.tagName,
  505. "type": res.type,
  506. "errCode": res.detail.errCode
  507. };
  508. }
  509. },
  510. onProgress: function (res : UniVideoProgressEvent) {
  511. console.log(res.type + " -> " + JSON.stringify(res.detail));
  512. if (this.autoTest) {
  513. this.eventProgress = {
  514. "tagName": res.target?.tagName,
  515. "type": res.type,
  516. "isBufferedValid": res.detail.buffered >= 0
  517. };
  518. }
  519. },
  520. onFullScreenClick: function (res : UniVideoFullScreenClickEvent) {
  521. console.log(res.type + " -> " + JSON.stringify(res.detail));
  522. if (this.autoTest) {
  523. this.eventFullscreenclick = {
  524. "tagName": res.target?.tagName,
  525. "type": res.type,
  526. "screenX": Math.trunc(res.detail.screenX),
  527. "screenY": Math.trunc(res.detail.screenY),
  528. "screenWidth": Math.trunc(res.detail.screenWidth),
  529. "screenHeight": Math.trunc(res.detail.screenHeight)
  530. };
  531. }
  532. },
  533. onControlsToggle: function (res : UniVideoControlsToggleEvent) {
  534. console.log(res.type + " -> " + JSON.stringify(res.detail));
  535. if (this.autoTest) {
  536. this.eventControlstoggle = {
  537. "tagName": res.target?.tagName,
  538. "type": res.type,
  539. "show": res.detail.show
  540. };
  541. }
  542. },
  543. // 自动化测试
  544. downloadSource() {
  545. uni.downloadFile({
  546. url: 'https://qiniu-web-assets.dcloud.net.cn/video/sample/2minute-demo.mp4',
  547. success: (res) => {
  548. this.src = res.tempFilePath;
  549. },
  550. fail: (_) => {
  551. this.isError = true;
  552. }
  553. })
  554. },
  555. getWindowInfo() : GetWindowInfoResult {
  556. return uni.getWindowInfo();
  557. },
  558. // #ifdef APP-ANDROID
  559. hasSubComponent() : boolean {
  560. const view = uni.getElementById('video')?.getAndroidView<ViewGroup>();
  561. return view == null ? false : view.getChildAt(0) instanceof ViewGroup;
  562. }
  563. // #endif
  564. }
  565. }
  566. </script>
  567. <style>
  568. .video {
  569. width: 100%;
  570. height: 200px;
  571. }
  572. .input {
  573. height: 40px;
  574. background: #FFF;
  575. padding: 8px 13px;
  576. }
  577. .margin-10 {
  578. margin: 10px;
  579. }
  580. .img-fast-backward {
  581. width: 40px;
  582. height: 40px;
  583. top: 50%;
  584. left: 12%;
  585. transform: translate(-50%, -50%);
  586. position: absolute;
  587. }
  588. .img-fast-forward {
  589. width: 40px;
  590. height: 40px;
  591. top: 50%;
  592. right: 12%;
  593. transform: translate(50%, -50%);
  594. position: absolute;
  595. }
  596. .input-send-danmu {
  597. height: 40px;
  598. padding: 8px 13px;
  599. margin: 0 var(--status-bar-height);
  600. bottom: 50px;
  601. position: absolute;
  602. background-color: rgba(0, 0, 0, 0.5);
  603. color: #FFF;
  604. }
  605. </style>