11.21提交
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
@use "sass:math";
|
||||
$primary: #5C91EF;
|
||||
|
||||
//css函数
|
||||
// /* #ifdef APP-NVUE */
|
||||
// @function tovmin($rpx) {
|
||||
// //$rpx为需要转换的字号
|
||||
// @return #{$rpx}rpx;
|
||||
|
||||
// }
|
||||
// /* #endif
|
||||
|
||||
// /* #ifndef APP-NVUE */
|
||||
// @function tovmin($rpx) {
|
||||
// //$rpx为需要转换的字号
|
||||
// /* #ifdef VUE2 */
|
||||
// @return #{math.div($rpx * 100, 750)}vmin;
|
||||
// /* #endif */
|
||||
// /* #ifdef VUE3 */
|
||||
// @return #{calc($rpx * 100 / 750)}vmin;
|
||||
// /* #endif */
|
||||
// }
|
||||
// /* #endif */
|
||||
.sunny-video {
|
||||
position: relative;
|
||||
.banner-view {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
.imgPal {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
.speedText {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
z-index: 5;
|
||||
padding: 5px;
|
||||
/* #ifndef APP-NVUE */
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
.text {
|
||||
display: flex;
|
||||
width: 40px;
|
||||
font-size: 16px;
|
||||
color: $primary;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.vertical {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
&.vertical-full {
|
||||
.speed-box {
|
||||
padding: 25px 0;
|
||||
}
|
||||
}
|
||||
.vertical_left{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
}
|
||||
.speed-box {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
/* #ifdef APP-NVUE */
|
||||
// v1.1.3
|
||||
padding: 10px 0;
|
||||
/* #endif */
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
|
||||
.speed-text {
|
||||
width: 80px;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
/* #ifdef APP-NVUE */
|
||||
padding: 5px 0px;
|
||||
/* #endif */
|
||||
/* #ifndef APP-NVUE */
|
||||
// v1.1.3
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
&.act {
|
||||
color: $primary;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 试看结束盒子
|
||||
.trialEndBox {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 999;
|
||||
// backdrop-filter: blur(14px);
|
||||
background-color: rgba(0, 0, 0, 0.9);
|
||||
|
||||
.tipText {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.closeBtn {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 175px;
|
||||
height: 37.5px;
|
||||
margin: 16px 0 0;
|
||||
font-size: 15px;
|
||||
line-height: 37.5px;
|
||||
border-radius: 40px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
background-color: $primary;
|
||||
}
|
||||
}
|
||||
|
||||
// 位置提示
|
||||
.mplayer-toast {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
bottom: 45px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
border-radius: 2px;
|
||||
opacity: 0;
|
||||
// transition: opacity .3s;
|
||||
padding: 6px 8px;
|
||||
&.mplayer-show {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
/* #ifdef APP-PLUS */
|
||||
margin: 5px 8px 8px;
|
||||
/* #endif */
|
||||
/* #ifdef APP-NVUE */
|
||||
margin: 0;
|
||||
|
||||
/* #endif */
|
||||
.btn_text {
|
||||
color: $primary;
|
||||
margin-left: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.kong {
|
||||
width: 8rpx;
|
||||
height: 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
// @ts-nocheck
|
||||
import playIcon from '../../static/play.png'
|
||||
|
||||
export default {
|
||||
/** 视频地址 */
|
||||
src: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/** 视频标题 */
|
||||
title: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/** 视频封面 */
|
||||
poster: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/** 视频高度 */
|
||||
videoHeight: {
|
||||
type: [String, Number],
|
||||
default: '230px'
|
||||
},
|
||||
/** 视频宽度 v1.1.3 */
|
||||
videoWidth: {
|
||||
type: [String, Number],
|
||||
default: '750rpx'
|
||||
},
|
||||
/** v2.0.0 当视频大小与 video 容器大小不一致时,视频的表现形式。contain:包含,fill:填充,cover:覆盖 */
|
||||
objectFit:{
|
||||
type: String,
|
||||
default: 'contain'
|
||||
},
|
||||
/** 播放图片按钮宽高 */
|
||||
playImgHeight: {
|
||||
type: [String, Number],
|
||||
default: '70rpx'
|
||||
},
|
||||
/** 暂停按钮 */
|
||||
playImg: {
|
||||
type: String,
|
||||
default: () => playIcon
|
||||
},
|
||||
/** 是否显示静音按钮 */
|
||||
showMuteBtn: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/** 播放完毕是否退出全屏 */
|
||||
isExitFullScreen: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
/** 主题色 */
|
||||
primaryColor: {
|
||||
type: String,
|
||||
default: '#5C91EF'
|
||||
},
|
||||
/** 试看提示的文字 */
|
||||
tipText: {
|
||||
type: String,
|
||||
default: '试看已结束,本片是会员专享内容'
|
||||
},
|
||||
/** 试看按钮的文字 */
|
||||
btnText: {
|
||||
type: String,
|
||||
default: '成为会员免费观看'
|
||||
},
|
||||
/** 视频试看时间(秒) */
|
||||
trialTime: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
/** 倍速盒子宽度 v1.1.3 */
|
||||
speedBoxWidth: {
|
||||
type: [String, Number],
|
||||
default: '160rpx'
|
||||
},
|
||||
/** 是否循环播放 v1.1.3 */
|
||||
loop: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/** 是否静音播放 v1.1.3 */
|
||||
muted: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/** 是否自动播放 */
|
||||
autoplay: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/** 历史观看位置 v1.2.0 */
|
||||
seekTime: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
/** 视频唯一ID v1.2.1 */
|
||||
videoId: {
|
||||
type: String,
|
||||
default: 'sunnyVideo'
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,459 @@
|
||||
<template>
|
||||
<video class="sunny-video"
|
||||
:id="videoId"
|
||||
:title="title"
|
||||
:src="src"
|
||||
:show-center-play-btn="false"
|
||||
:controls="state.controls"
|
||||
:enable-play-gesture="state.enablePlayGesture"
|
||||
:muted="muted"
|
||||
:show-mute-btn="showMuteBtn"
|
||||
:autoplay="autoplay"
|
||||
:object-fit="objectFit"
|
||||
:style="{width: addUnit(videoWidth), height: addUnit(videoHeight)}"
|
||||
@play="play"
|
||||
@pause="emit('pause')"
|
||||
@ended="ended"
|
||||
@error="(e) => emit('playError', e)"
|
||||
@timeupdate="timeupdate"
|
||||
@fullscreenchange="fullscreenchange"
|
||||
>
|
||||
<cover-view v-if="!state.isPlay" class="banner-view">
|
||||
<cover-image
|
||||
class="banner"
|
||||
:style="{width: addUnit(videoWidth), height: addUnit(videoHeight)}"
|
||||
:src="poster"
|
||||
@click="changePlay"
|
||||
/>
|
||||
<cover-image
|
||||
class="imgPal"
|
||||
:style="[playImgStyle]"
|
||||
:src="playImg"
|
||||
@click="changePlay"
|
||||
/>
|
||||
</cover-view>
|
||||
<!-- 当前倍速标记 -->
|
||||
<cover-view
|
||||
v-if="state.isPlay&&!state.isShowRateBox"
|
||||
class="speedText"
|
||||
:style="[speedStyle]"
|
||||
@click="state.isShowRateBox = true"
|
||||
>
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<text class="text">{{state.rateText}}X</text>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<cover-view class="text">{{state.rateText}}X</cover-view>
|
||||
<!-- #endif -->
|
||||
</cover-view>
|
||||
<!-- 倍速选择 -->
|
||||
<cover-view
|
||||
v-if="state.isShowRateBox"
|
||||
class="vertical"
|
||||
:class="{'vertical-full':state.isFullScreen}"
|
||||
:style="[speedBoxMaskStyle]"
|
||||
>
|
||||
<cover-view
|
||||
class="vertical_left"
|
||||
:style="[speedBoxLeftStyel]"
|
||||
@click="state.isShowRateBox=false"
|
||||
/>
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<view
|
||||
class="speed-box"
|
||||
:style="[speedBoxStyle]"
|
||||
>
|
||||
<text
|
||||
class="speed-text"
|
||||
:class="{act:item.isSelect}"
|
||||
v-for="(item,index) in rateList"
|
||||
:key="item.name"
|
||||
@click="changeRate(item,index)"
|
||||
>{{item.name}}X</text>
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<cover-view
|
||||
class="speed-box"
|
||||
:style="[speedBoxStyle]"
|
||||
>
|
||||
<cover-view
|
||||
class="speed-text"
|
||||
:class="{act:item.isSelect}"
|
||||
v-for="(item,index) in rateList"
|
||||
:key="item.name"
|
||||
@click="changeRate(item,index)"
|
||||
>{{item.name}}X</cover-view>
|
||||
</cover-view>
|
||||
<!-- #endif -->
|
||||
</cover-view>
|
||||
<!-- 试看盒子 -->
|
||||
<cover-view v-if="state.visibleTrialEndBox" class="trialEndBox" :style="[trialEndBoxStyle]">
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<text class="tipText">{{tipText}}</text>
|
||||
<text class="closeBtn" @click.stop="handleClickTrialEnd">{{btnText}}</text>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<cover-view class="tipText">{{tipText}}</cover-view>
|
||||
<cover-view class="closeBtn" @click.stop="handleClickTrialEnd">{{btnText}}</cover-view>
|
||||
<!-- #endif -->
|
||||
</cover-view>
|
||||
<!-- 进度记录跳转提示 -->
|
||||
<cover-view class="mplayer-toast" :class="{'mplayer-show':state.showMplayerToast}">
|
||||
<!-- #ifdef H5 -->
|
||||
<text class="text">
|
||||
记忆你上次看到{{convertSecondsToHMS(seekTime)}}<text class="btn_text" @click="handelSeek">跳转</text>
|
||||
</text>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef H5 | APP-NVUE -->
|
||||
<cover-view v-if="state.showMplayerToast" class="text">
|
||||
{{'已为您定位至'+convertSecondsToHMS(seekTime)}}
|
||||
<!-- #ifdef MP-WEIXIN -->
|
||||
<cover-view class="kong" />
|
||||
<!-- #endif -->
|
||||
</cover-view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<text class="text">已为您定位至{{convertSecondsToHMS(seekTime)}}</text>
|
||||
<!-- #endif -->
|
||||
</cover-view>
|
||||
</video>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
// @ts-nocheck
|
||||
import { defineComponent, ref, toRefs, reactive, computed, onMounted, getCurrentInstance, nextTick } from './vue-composition-api'
|
||||
import VideoProps from './props'
|
||||
import {getPx, addUnit, convertSecondsToHMS} from './utils'
|
||||
import type { StateData, rateListData } from './type'
|
||||
|
||||
const name = 'sunny-video'
|
||||
export default defineComponent({
|
||||
name,
|
||||
props: VideoProps,
|
||||
emits: ['play', 'pause', 'ended', 'timeupdate', 'trialEnd', 'playError', 'changeSeek', 'fullscreenchange', 'handleBtn'],
|
||||
setup(props, {emit}) {
|
||||
const { proxy } = getCurrentInstance()
|
||||
const { screenWidth, screenHeight } = uni.getSystemInfoSync()
|
||||
const state = reactive<StateData>({
|
||||
isPlay: false,
|
||||
controls: false,
|
||||
enablePlayGesture: false,
|
||||
countPlay: 0,
|
||||
isFullScreen: false,
|
||||
rateText: '1.0',
|
||||
isShowRateBox: false,
|
||||
visibleTrialEndBox: false,
|
||||
showMplayerToast: false
|
||||
})
|
||||
const rateList = ref<rateListData[]>([{
|
||||
name: '0.5',
|
||||
isSelect: false
|
||||
}, {
|
||||
name: '0.8',
|
||||
isSelect: false
|
||||
}, {
|
||||
name: '1.0',
|
||||
isSelect: true
|
||||
}, {
|
||||
name: '1.25',
|
||||
isSelect: false
|
||||
}, {
|
||||
name: '1.5',
|
||||
isSelect: false
|
||||
}
|
||||
// #ifdef MP-WEIXIN
|
||||
, {
|
||||
name: '2.0',
|
||||
isSelect: false
|
||||
}
|
||||
// #endif
|
||||
])
|
||||
const videoCtx = ref(null)
|
||||
const {isFullScreen} = toRefs(state)
|
||||
/** 播放按钮样式 */
|
||||
const playImgStyle = computed(()=>{
|
||||
const wh = getPx(props.playImgHeight)
|
||||
const style = {
|
||||
width: addUnit(wh),
|
||||
height: addUnit(wh),
|
||||
top: `${getPx(props.videoHeight)/2}px`,
|
||||
left: `${getPx(props.videoWidth)/2}px`,
|
||||
transform:`translate(-${getPx(wh)/2}px,-${getPx(wh)/2}px)`
|
||||
}
|
||||
return style
|
||||
})
|
||||
const speedStyle = ref({})
|
||||
const speedBoxMaskStyle = ref({})
|
||||
const speedBoxLeftStyel = ref({})
|
||||
const speedBoxStyle = ref({})
|
||||
const trialEndBoxStyle = ref({})
|
||||
|
||||
/** 设置样式 */
|
||||
const setStyles = () => {
|
||||
/** 当前倍速样式 */
|
||||
(function speedStyleFn (){
|
||||
let tops = getPx(props.videoHeight) / 2
|
||||
if(isFullScreen.value){
|
||||
tops = getPx(props.videoWidth) / 2
|
||||
}
|
||||
Object.assign(speedStyle.value, {top: tops - 15 + 'px'})
|
||||
})();
|
||||
/** 倍速盒子背景遮罩 */
|
||||
(function speedBoxMaskStyleFn(){
|
||||
let style = {
|
||||
width: addUnit(props.videoWidth),
|
||||
height: addUnit(props.videoHeight)
|
||||
}
|
||||
if(isFullScreen.value){
|
||||
style = {
|
||||
width: `${screenHeight}px`,
|
||||
height: `${screenWidth}px`
|
||||
}
|
||||
}
|
||||
Object.assign(speedBoxMaskStyle.value, style)
|
||||
})();
|
||||
/** 倍速盒子左侧遮罩 */
|
||||
(function speedBoxLeftStyelFn(){
|
||||
const w = getPx(props.speedBoxWidth)
|
||||
const pw = getPx(props.videoWidth)
|
||||
let style = {
|
||||
width: `${pw - w}px`,
|
||||
height: addUnit(props.videoHeight)
|
||||
}
|
||||
if(isFullScreen.value){
|
||||
style = {
|
||||
width: `${screenHeight - w}px`,
|
||||
height: `${screenWidth}px`
|
||||
}
|
||||
}
|
||||
Object.assign(speedBoxLeftStyel.value, style)
|
||||
proxy.$forceUpdate()
|
||||
})();
|
||||
|
||||
/** 倍速盒子样式 */
|
||||
(function speedBoxStyleFn(){
|
||||
let style = {
|
||||
width: addUnit(props.speedBoxWidth),
|
||||
height: addUnit(props.videoHeight)
|
||||
}
|
||||
if(isFullScreen.value){
|
||||
style = {
|
||||
width: addUnit(props.speedBoxWidth),
|
||||
height: `${screenWidth}px`
|
||||
}
|
||||
}
|
||||
Object.assign(speedBoxStyle.value, style)
|
||||
})();
|
||||
/** 试看样式 */
|
||||
(function trialEndBoxStyleFn() {
|
||||
let style = {
|
||||
width: addUnit(props.videoWidth),
|
||||
height: addUnit(props.videoHeight)
|
||||
}
|
||||
if(isFullScreen.value){
|
||||
style = {
|
||||
width: `${screenHeight}px`,
|
||||
height: `${screenWidth}px`
|
||||
}
|
||||
}
|
||||
Object.assign(trialEndBoxStyle.value, style)
|
||||
})();
|
||||
proxy.$forceUpdate()
|
||||
}
|
||||
|
||||
onMounted(()=>{
|
||||
videoCtx.value = uni.createVideoContext(props.videoId, proxy)
|
||||
setStyles()
|
||||
})
|
||||
|
||||
/**
|
||||
* 播放视频
|
||||
*/
|
||||
function changePlay() {
|
||||
nextTick(()=>{
|
||||
videoCtx.value.play()
|
||||
if (state.countPlay <= 0 && props.seekTime > 0) {
|
||||
// 没有播放过并且需要跳转视频
|
||||
// #ifndef H5
|
||||
seek(props.seekTime)
|
||||
// #endif
|
||||
state.showMplayerToast = true
|
||||
setTimeout(() => {
|
||||
state.showMplayerToast = false
|
||||
}, 3000)
|
||||
}
|
||||
state.countPlay++
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 跳转到指定位置,单位 s
|
||||
* @param {Object} position
|
||||
* @description V1.1.1
|
||||
*/
|
||||
function seek(position:number | string) {
|
||||
nextTick(() => {
|
||||
videoCtx.value.seek(position)
|
||||
emit('changeSeek', position)
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 切换倍速
|
||||
* @param {Object} item 当前点击项
|
||||
* @param {Object} index 倍速索引
|
||||
*/
|
||||
function changeRate(item:rateListData, index:number) {
|
||||
if (item.isSelect) return state.isShowRateBox = false
|
||||
rateList.value.forEach((v, i) => {
|
||||
i == index ? v.isSelect = true : v.isSelect = false
|
||||
})
|
||||
videoCtx.value.playbackRate(+item.name)
|
||||
state.rateText = item.name
|
||||
state.isShowRateBox = false
|
||||
}
|
||||
/**
|
||||
* 当开始/继续播放时触发play事件 - 会触发emit事件
|
||||
* @param {EventHandle} e
|
||||
*/
|
||||
function play(e) {
|
||||
state.isPlay = true
|
||||
state.controls = true
|
||||
state.enablePlayGesture = true
|
||||
emit('play', e)
|
||||
};
|
||||
/**
|
||||
* 视频播放进度变化 - 会触发emit事件
|
||||
* @param {Object} e event.detail = {currentTime, duration}
|
||||
*/
|
||||
function timeupdate(e) {
|
||||
emit('timeupdate', e)
|
||||
// 是否判断需要视频试看 V1.1.0
|
||||
if (props.trialTime <= 0) return
|
||||
if (e.detail.currentTime >= props.trialTime) {
|
||||
emit('trialEnd')
|
||||
showTrialEnd()
|
||||
state.enablePlayGesture = false
|
||||
state.controls = false
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 控制试看模块显示 V1.1.0
|
||||
*/
|
||||
function showTrialEnd() {
|
||||
state.visibleTrialEndBox = true
|
||||
videoCtx.value.pause()
|
||||
}
|
||||
/**
|
||||
* 点击试看结束按钮 V1.1.6
|
||||
* @param {Event} e
|
||||
*/
|
||||
function handleClickTrialEnd(e) {
|
||||
if (e.hasOwnProperty('touches')) {
|
||||
emit('handleBtn')
|
||||
}
|
||||
}
|
||||
/**
|
||||
* H5用户手动跳转指定位置播放 v1.2.0
|
||||
*/
|
||||
function handelSeek() {
|
||||
seek(props.seekTime)
|
||||
videoCtx.value.play()
|
||||
state.showMplayerToast = false
|
||||
}
|
||||
/**
|
||||
* 全屏操作 - 会触发emit
|
||||
*/
|
||||
function fullscreenchange(e) {
|
||||
state.isFullScreen = e.detail.fullScreen
|
||||
setStyles()
|
||||
emit('fullscreenchange', e.detail)
|
||||
}
|
||||
/**
|
||||
* 监听视频结束 - 会触发emit事件
|
||||
*/
|
||||
function ended() {
|
||||
emit('ended')
|
||||
if (!props.isExitFullScreen) return
|
||||
videoCtx.value.exitFullScreen(); //退出全屏
|
||||
};
|
||||
/**
|
||||
* 控制试看模块隐藏 V1.1.0
|
||||
*/
|
||||
function closeTrialEnd() {
|
||||
state.visibleTrialEndBox = false
|
||||
changePlay()
|
||||
}
|
||||
/**
|
||||
* 手动全屏方法 v1.1.8
|
||||
* @param {Object} direction direction取为 vertical 或 horizontal
|
||||
* @description H5和抖音小程序不支持{direction}参数
|
||||
*/
|
||||
function requestFullScreen(direction: 'vertical' | 'horizontal' = 'horizontal') {
|
||||
videoCtx.value.requestFullScreen({
|
||||
direction
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 手动退出全屏 v1.1.8
|
||||
*/
|
||||
function exitFullScreen() {
|
||||
videoCtx.value.exitFullScreen()
|
||||
}
|
||||
/**
|
||||
* v1.1.8
|
||||
* 显示状态栏,仅在iOS全屏下有效
|
||||
* 平台差异:仅微信小程序、百度小程序、QQ小程序
|
||||
*/
|
||||
function showStatusBar() {
|
||||
videoCtx.value.showStatusBar()
|
||||
}
|
||||
/**
|
||||
* v1.1.8
|
||||
* 隐藏状态栏,仅在iOS全屏下有效
|
||||
* 平台差异:仅微信小程序、百度小程序、QQ小程序
|
||||
*/
|
||||
function hideStatusBar() {
|
||||
videoCtx.value.hideStatusBar()
|
||||
}
|
||||
/**
|
||||
* 停止视频 v1.1.8
|
||||
*/
|
||||
function handelStop() {
|
||||
videoCtx.value.stop()
|
||||
}
|
||||
|
||||
return {
|
||||
emit,
|
||||
addUnit,
|
||||
convertSecondsToHMS,
|
||||
state,
|
||||
play,
|
||||
ended,
|
||||
timeupdate,
|
||||
changePlay,
|
||||
speedStyle,
|
||||
playImgStyle,
|
||||
speedBoxStyle,
|
||||
speedBoxMaskStyle,
|
||||
speedBoxLeftStyel,
|
||||
rateList,
|
||||
trialEndBoxStyle,
|
||||
fullscreenchange,
|
||||
handleClickTrialEnd,
|
||||
handelSeek,
|
||||
changeRate,
|
||||
closeTrialEnd,
|
||||
requestFullScreen,
|
||||
exitFullScreen,
|
||||
showStatusBar,
|
||||
hideStatusBar,
|
||||
handelStop
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import './index.scss';
|
||||
</style>
|
||||
@@ -0,0 +1,32 @@
|
||||
// @ts-nocheck
|
||||
export interface Props {
|
||||
|
||||
}
|
||||
|
||||
export type rateListData = {
|
||||
/** 名称 */
|
||||
name: string
|
||||
/** 是否选中 */
|
||||
isSelect: boolean
|
||||
}
|
||||
|
||||
export interface StateData {
|
||||
/** 视频是否播放过 */
|
||||
isPlay: boolean
|
||||
/** 是否显示原生控件 */
|
||||
controls: boolean
|
||||
/** 是否开启播放手势,即双击切换播放/暂停 */
|
||||
enablePlayGesture: boolean
|
||||
/** 视频播放次数 */
|
||||
countPlay: number | string
|
||||
/** 全屏状态 */
|
||||
isFullScreen: boolean
|
||||
/** 当前倍速 */
|
||||
rateText: string
|
||||
/** 是否显示倍速盒子 */
|
||||
isShowRateBox: boolean
|
||||
/** 控制试看结束内容显示隐藏 */
|
||||
visibleTrialEndBox: boolean
|
||||
/** 控制H5历史播放位置的显示隐藏 */
|
||||
showMplayerToast: boolean
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// @ts-nocheck
|
||||
|
||||
/**
|
||||
* @description 用于获取用户传递值的px值 如果用户传递了"xxpx"或者"xxrpx",取出其数值部分,如果是"xxxrpx"还需要用过uni.upx2px进行转换
|
||||
* @param {number|string} value 用户传递值的px值
|
||||
* @param {boolean} unit
|
||||
* @returns {number|string}
|
||||
*/
|
||||
export const getPx = (value, unit = false)=> {
|
||||
if (testNumber(value)) {
|
||||
return unit ? `${value}px` : Number(value)
|
||||
}
|
||||
// 如果带有rpx,先取出其数值部分,再转为px值
|
||||
if (/(rpx|upx)$/.test(value)) {
|
||||
return unit ? `${uni.upx2px(parseInt(value))}px` : Number(uni.upx2px(parseInt(value)))
|
||||
}
|
||||
return unit ? `${parseInt(value)}px` : parseInt(value)
|
||||
}
|
||||
/**
|
||||
* @description 添加单位,如果有rpx,upx,%,px等单位结尾或者值为auto,直接返回,否则加上px单位结尾
|
||||
* @param {string|number} value 需要添加单位的值
|
||||
* @param {string} unit 添加的单位名 比如px
|
||||
*/
|
||||
export const addUnit =(value = 'auto', unit = 'px')=> {
|
||||
value = String(value)
|
||||
// number判断是否为数值
|
||||
return testNumber(value) ? `${value}${unit}` : value
|
||||
}
|
||||
/**
|
||||
* 验证十进制数字
|
||||
*/
|
||||
function testNumber(value) {
|
||||
return /^[\+-]?(\d+\.?\d*|\.\d+|\d\.\d+e\+\d+)$/.test(value)
|
||||
}
|
||||
/**
|
||||
* @description 获取系统信息同步接口
|
||||
* @link 获取系统信息同步接口 https://uniapp.dcloud.io/api/system/info?id=getsysteminfosync
|
||||
*/
|
||||
export const sys=()=> {
|
||||
return uni.getSystemInfoSync()
|
||||
}
|
||||
/**
|
||||
* 将秒转时分秒
|
||||
* @param {number} 数字
|
||||
*/
|
||||
export const convertSecondsToHMS =(seconds)=> {
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
const minutes = Math.floor((seconds % 3600) / 60);
|
||||
const remainingSeconds = seconds % 60;
|
||||
|
||||
// 在数字小于10时,在前面补零
|
||||
const minutesStr = minutes < 10 ? "0" + minutes : minutes;
|
||||
const secondsStr = remainingSeconds < 10 ? "0" + remainingSeconds : remainingSeconds;
|
||||
|
||||
if (hours === 0) {
|
||||
return minutesStr + ":" + secondsStr;
|
||||
} else {
|
||||
const hoursStr = hours < 10 ? "0" + hours : hours;
|
||||
return hoursStr + ":" + minutesStr + ":" + secondsStr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// @ts-nocheck
|
||||
|
||||
// #ifdef VUE3
|
||||
export * from 'vue';
|
||||
// #endif
|
||||
|
||||
// #ifndef VUE3
|
||||
export * from '@vue/composition-api';
|
||||
|
||||
// #ifdef APP-NVUE
|
||||
import Vue from 'vue'
|
||||
import VueCompositionAPI from '@vue/composition-api'
|
||||
Vue.use(VueCompositionAPI)
|
||||
// #endif
|
||||
|
||||
// #endif
|
||||
Reference in New Issue
Block a user