jiuyiUniapp/jiuyi2/components/index/indexVideo.vue

820 lines
18 KiB
Vue
Raw Normal View History

2024-12-18 15:46:27 +08:00
<script setup>
/**
* 首页视频组件
* @property {Object} item 视频数据对象
* @property {Number} index 当前视频列表索引
* @property {Number} current 当前预览索引
*/
import {
onMounted,
ref,
reactive,
getCurrentInstance,
watch,
defineEmits,
computed,
nextTick
} from 'vue';
const {
proxy
} = getCurrentInstance()
// 顶部状态栏
import statusBar from '@/components/header/statusBar.vue'
// 工具库
import util from '@/common/js/util';
//
import api from '@/api/index.js';
2025-01-02 01:01:23 +08:00
// 视频进度条
import videoProgress from '@/components/index/videoProgress';
2024-12-18 15:46:27 +08:00
const props = defineProps({
// 当前视频对象
item: {
type: Object,
},
// 列表中的视频下标
index: {
type: Number,
},
// 当前列表的index
current: {
type: Number,
},
// 当前tab的index
tabIndex: {
type: Number,
},
// 模式 list列表 detail详情
mode: {
type: String,
default: 'list'
},
// 是否我自己 0不是 1是
isMine: {
type: [String, Number],
default: 0,
2025-01-02 01:01:23 +08:00
},
width: {
type: Number,
default: 0,
},
height: {
type: Number,
default: 0,
},
2025-01-19 13:55:21 +08:00
// 是否统计 0不是 1是
statistic: {
type: [String, Number],
default: 0,
},
2024-12-18 15:46:27 +08:00
})
2025-02-15 08:59:41 +08:00
2024-12-18 15:46:27 +08:00
//
2025-01-02 01:01:23 +08:00
const emit = defineEmits(['showTime', 'showComment', 'showCollect', 'showFastCollect', 'showShareFirend', 'onPlay',
2025-02-15 16:10:05 +08:00
'onPause', 'like', 'detailMenu', 'onEnd', 'longtap', 'dataCenter', 'showProduct', 'proBuy'
2025-01-02 01:01:23 +08:00
])
2024-12-18 15:46:27 +08:00
// 视频上下文对象
const videoCtx = ref(null)
// 是否播放
const playState = ref(true)
// 是否显示快速收藏列表
const collectFirst = ref(false)
// 视频时间
2025-01-02 01:01:23 +08:00
const videoTime = ref({
2024-12-18 15:46:27 +08:00
// 总长
duration: 0,
// 当前时间
currentTime: 0,
})
2025-01-02 01:01:23 +08:00
// 记录点击的数组
const tapList = reactive([])
// 点击时间戳
const tapTimer = ref(null)
// 是否在计数
const isTap = ref(false)
// 长按
const isLong = ref(false)
// 收藏按钮判定
const collectBtnActive = ref(false)
2025-01-16 20:18:22 +08:00
// 是否显示广告
const showAd = ref(false)
2024-12-18 15:46:27 +08:00
// 设置时间
const alarmTime = computed(() => {
let result = uni.$store.state.alarmTime
return result
})
2025-01-02 01:01:23 +08:00
// 填充
const fit = computed(() => {
const ratio1 = parseInt(props.width) / parseInt(props.height)
const ratio2 = props.item.breadth / props.item.height
let result = 'contain'
if (Math.abs(formatNumber(ratio2) - formatNumber(ratio1)) < 1) result = 'cover'
return result
})
2025-02-03 09:05:19 +08:00
const userinfo = uni.$store.state.userinfo
2024-12-18 15:46:27 +08:00
2025-01-03 18:11:02 +08:00
watch(() => props.current, (nV) => {
if (nV == props.index) play()
else pause()
})
2024-12-18 15:46:27 +08:00
// 挂载后调用
onMounted(() => {
// 视频上下文对象
videoCtx.value = uni.createVideoContext(`video${props.tabIndex}${props.index}`)
})
2025-01-02 01:01:23 +08:00
// 格式化
function formatNumber(result) {
result = parseFloat(result) * 10
return result
}
// 手指触摸视频容器
function onTouchStart() {
// 是否计数
if (isTap.value) {
return
tapList.length = 0
changeVideoPlay()
} else {
isTap.value = true
// 时间
let time = new Date().getTime()
tapList.push(time)
}
clearTimeout(tapTimer.value)
}
// 手指离开视频容器
function onTouchEnd() {
// 如果不是重复点击的状态
2025-01-02 23:36:48 +08:00
if (isTap.value) {
2025-01-02 01:01:23 +08:00
isTap.value = false
let time = new Date().getTime()
let diff = time - tapList[tapList.length - 1]
// 判断长按
2025-01-02 23:36:48 +08:00
if (diff > 350) {
// 取消视频倍速播放的状态
if (isLong.value) {
isLong.value = false
videoCtx.value.playbackRate(1)
}
// 清空计数
tapList.length = 0
return
}
2025-01-02 01:01:23 +08:00
//
tapTimer.value = setTimeout(() => {
let a = tapList.length
tapList.length = 0
2025-02-17 19:26:33 +08:00
// 目标点赞
let targetLike = {
0: 1,
1: 0
} [props.item.isLike]
2025-01-02 01:01:23 +08:00
switch (a) {
2025-01-02 23:36:48 +08:00
case 1:
2025-01-02 01:01:23 +08:00
changeVideoPlay()
break;
case 2:
console.log('公开赞')
2025-02-17 19:26:33 +08:00
if (props.item.likeType == 0) {
emit('like', {
likeType: 0,
index: props.index,
isLike: targetLike
})
} else {
emit('like', {
likeType: 0,
index: props.index,
isLike: 0
})
}
2025-01-02 01:01:23 +08:00
break;
case 3:
console.log('隐私赞')
2025-02-17 19:26:33 +08:00
if (props.item.likeType == 1) {
emit('like', {
likeType: 1,
index: props.index,
isLike: targetLike
})
} else {
emit('like', {
likeType: 1,
index: props.index,
isLike: 0
})
}
2025-01-02 01:01:23 +08:00
break;
}
}, 200)
}
}
2025-01-02 23:36:48 +08:00
// 手指中断视频容器
function onTouchCancel() {
isTap.value = false
tapList.length = 0
clearTimeout(tapTimer.value)
}
2025-01-02 01:01:23 +08:00
// 切换视频播放
function changeVideoPlay() {
2024-12-18 15:46:27 +08:00
// 根据播放状态切换播放暂停
if (playState.value) pause()
else play()
}
// 视频播放
function play() {
let pages = getCurrentPages();
let page = pages[pages.length - 1];
if (props.index != props.current || !['pages/index/index', 'pages/index/videoDetail'].includes(page.route)) return
videoCtx.value.play()
}
// 视频暂停
function pause() {
videoCtx.value.pause()
}
// 视频播放回调
function onVideoPlay() {
playState.value = true
emit('onPlay')
}
// 视频暂停回调
function onVideoPause() {
playState.value = false
emit('onPause')
}
// 打开评论
function handleComment() {
emit('showComment', props.item)
}
// 打开计时闹钟
function handleTime() {
emit('showTime')
}
// 打开收藏弹窗
function showCollect() {
util.isLogin().then(rs => {
emit('showCollect', props.item)
}).catch(() => {
uni.navigateTo({
url: '/pages/login/loginPhone'
})
})
}
// 切换快速收藏
2025-01-02 01:01:23 +08:00
function handleCollectFirst(ev) {
// 获取当前元素的宽高
const changedTouches = ev.changedTouches[0]
let x = getNumber(props.width) - getNumber(changedTouches.screenX) + getNumber(changedTouches.pageX)
let y = getNumber(changedTouches.screenY) - getNumber(changedTouches.pageY)
emit('showFastCollect', {
item: props.item,
position: {
x,
y,
}
})
2024-12-18 15:46:27 +08:00
return
2025-01-02 01:01:23 +08:00
}
/**
* 手指触摸收藏
* @param {Object} ev
*/
function handleCollectStar(ev) {
collectBtnActive.value = true
util.isLogin().then(rs => {
//
setTimeout(() => {
// 判断是否抬起
if (!collectBtnActive.value) {
// 收藏状态
if (!props.item.isCollect) {
// 单击出菜单
handleCollectFirst(ev)
return
} else cancelCollect()
} else {
setTimeout(() => {
// 长按出弹窗
showCollect()
}, 350)
}
}, 350)
}).catch(() => {
uni.navigateTo({
url: '/pages/login/loginPhone'
})
})
}
/**
* 手指触摸结束
* @param {Object} str
*/
function handleCollectEnd() {
collectBtnActive.value = false
}
// 获取数字
function getNumber(str) {
let result = Math.floor(Number(str))
return result
}
// 取消收藏
function cancelCollect() {
const detail = {
...props.item
}
// 取消收藏
2025-01-13 21:59:03 +08:00
api.video.deleteVideo({
data: {
2025-01-02 01:01:23 +08:00
// 视频id
2025-01-13 21:59:03 +08:00
videoId: detail.id,
2025-01-02 01:01:23 +08:00
},
}).then(rs => {
if (rs.code == 200) {
2025-01-13 21:59:03 +08:00
uni.$emit('updateVideo', {
...detail,
...rs.data,
})
2025-01-02 01:01:23 +08:00
return
}
//
util.alert({
content: rs.msg,
showCancel: false,
})
})
2024-12-18 15:46:27 +08:00
}
// 分享到好友
function handleShareFirend() {
util.isLogin().then(rs => {
emit('showShareFirend', props.item)
}).catch(() => {
uni.navigateTo({
url: '/pages/login/loginPhone'
})
})
}
/**
* 点赞
* @param {Number} index 操作的视频下标
2025-01-13 00:25:06 +08:00
* @param {Number|String} likeType 点赞类型 0.公开赞 1.隐私赞
2025-02-03 09:05:19 +08:00
* @param {Number|String} isLike 0.点赞 1.取消点赞
2024-12-18 15:46:27 +08:00
*/
2025-02-03 09:05:19 +08:00
function handleLike(index, likeType, isLike) {
2024-12-18 15:46:27 +08:00
util.isLogin().then(rs => {
emit('like', {
index,
2025-01-13 00:25:06 +08:00
likeType,
2025-01-25 21:43:01 +08:00
isLike,
2024-12-18 15:46:27 +08:00
})
}).catch(() => {
uni.navigateTo({
url: '/pages/login/loginPhone'
})
})
}
/**
* 私密赞
* @param {Object} index
*/
function handlePrivateLike(index) {
util.isLogin().then(rs => {
util.alert({
title: '提示',
content: '请确认,是否为隐私赞(隐私赞仅自己和作者可见)?',
confirmText: '隐私赞',
cancelText: '公开赞',
}).then(rs => {
if (rs.confirm) emit('like', {
index,
2025-01-13 00:25:06 +08:00
likeType: 1,
2025-02-03 09:05:19 +08:00
isLike: 0,
2024-12-18 15:46:27 +08:00
})
else emit('like', {
index,
2025-01-13 00:25:06 +08:00
likeType: 2,
2025-02-03 09:05:19 +08:00
isLike: 0,
2024-12-18 15:46:27 +08:00
})
})
}).catch(() => {
uni.navigateTo({
url: '/pages/login/loginPhone'
})
})
}
/**
* 详情菜单
* @param {Object} item
*/
function handleDetailMenu(item) {
emit('detailMenu')
}
// 播放变化
function handleTimeupdate(ev) {
2025-01-02 01:01:23 +08:00
videoTime.value = ev.detail
2025-01-16 20:18:22 +08:00
// 如果有商品id 并且 当前播放时间大于商家设定的广告弹出时间
if (props.item.productId && (videoTime.value.currentTime > props.item.popupTime)) {
showAd.value = true
}
2025-01-02 01:01:23 +08:00
// console.log('videoTime.value', videoTime.value)
2024-12-18 15:46:27 +08:00
}
2025-01-02 01:01:23 +08:00
// 进度条拖拽结束
function onProgressEnd(ev) {
videoCtx.value.seek(parseInt(ev.time))
2024-12-18 15:46:27 +08:00
}
2025-01-02 01:01:23 +08:00
2024-12-18 15:46:27 +08:00
/**
* 查看用户主页
* @param {Object} item
*/
function handleUser(item) {
uni.navigateTo({
url: util.setUrl('/pages/index/videoHome', {
userId: item.userId
})
})
}
// 视频出现缓冲
function handleWaiting(ev) {
if (props.index == props.current) play()
else pause()
}
// 长按
function longtap(ev) {
2025-01-02 01:01:23 +08:00
if (isLong.value) return
2025-01-02 23:36:48 +08:00
play()
2025-01-02 01:01:23 +08:00
isLong.value = true
videoCtx.value.playbackRate(2)
2024-12-18 15:46:27 +08:00
}
2025-02-15 08:59:41 +08:00
// 前往数据中心
2025-01-19 13:55:21 +08:00
function handleData() {
emit('dataCenter', props.item)
}
2025-02-15 08:59:41 +08:00
// 点击商品广告
function handleShowProduct() {
emit('showProduct', props.item)
}
2025-02-15 16:10:05 +08:00
// 点击商品广告购买
function handleProBuy() {
emit('proBuy', props.item)
}
2024-12-18 15:46:27 +08:00
//
defineExpose({
play,
pause,
videoTime,
item: props.item,
playState,
videoCtx: () => videoCtx.value,
})
</script>
<template>
2025-01-02 01:01:23 +08:00
<view class="container f1 pr" ref="videoBoxRef">
2024-12-18 15:46:27 +08:00
<!-- 视频层 -->
2025-01-02 01:01:23 +08:00
<view class="main f1">
<view class="videoBox f1" @touchmove.stop="" @touchstart="onTouchStart" @touchend="onTouchEnd"
2025-01-02 23:36:48 +08:00
@touchcancel="onTouchCancel" @longpress="longtap">
2025-01-02 01:01:23 +08:00
<statusBar />
2025-01-03 18:11:02 +08:00
<!-- 视频 增加判断防止重复加载 -->
<template v-if="item.videoUrl">
<video class="video f1" :id="'video' + tabIndex + index" :src="item.videoUrl"
:poster="item.coverUrl" :http-cache="true" :show-fullscreen-btn="false"
:enable-progress-gesture="false" :controls="false" @play="onVideoPlay" @pause="onVideoPause"
:show-center-play-btn="false" @timeupdate="handleTimeupdate" @waiting="handleWaiting"
:play-strategy="2" :loop="true" :object-fit="fit" />
</template>
2025-01-02 01:01:23 +08:00
</view>
2024-12-18 15:46:27 +08:00
<!-- 视频进度条 -->
2025-01-02 01:01:23 +08:00
<view class="videoProgress" @touchmove.stop="" @touchstart.stop="" @touchend.stop="">
<videoProgress :time="videoTime" @change="onProgressEnd" :viewWidth="width" />
</view>
2024-12-18 15:46:27 +08:00
</view>
2025-01-02 23:36:48 +08:00
<!-- 倍速播放提示 -->
<view class="speedBox" v-if="isLong">
<view class="speed ptb5 plr10">
<text class="f22 cfff">2倍速播放中...</text>
</view>
</view>
2024-12-18 15:46:27 +08:00
<!-- 暂停蒙版 -->
<view class="pausePanel pfull fmid" v-if="!playState">
<!-- 暂停按钮 -->
<image class="pauseImg" src="@/static/pause.png" mode="aspectFit" />
</view>
<!-- 右侧操作区 -->
<view class="panelRight pa t0 b0 r0">
<statusBar />
<view class="head"></view>
<view class="f1 jcr pl5 pt40 pr20">
<!-- 操作台 -->
<view class="operate f1">
2025-01-23 00:57:47 +08:00
<!-- 数据中心 -->
<view class="item fmid" @click="handleData" v-if="0">
2025-01-19 13:55:21 +08:00
<view class="col">
<image class="wh50" src="/static/statistic.png" mode="aspectFit" />
</view>
<view class="txt mt20"></view>
</view>
2024-12-18 15:46:27 +08:00
<!-- 用户头像 -->
<navigator :url="util.setUrl('/pages/index/videoHome',{userId:item.userId})" class="item pr mb10">
<view class="col">
2025-01-02 23:36:48 +08:00
<image class="wh80 cir" :src="item.avatar" mode="aspectFill" />
2025-02-17 19:26:33 +08:00
<view class="focus pa" v-if="item.isAttention !== 0">
2024-12-18 15:46:27 +08:00
<image class="wh40" src="@/static/indexAtt.png" mode="aspectFit" />
</view>
</view>
</navigator>
<!-- 点赞 -->
<view class="item">
<view class="col">
<view class="pr">
2025-02-17 19:26:33 +08:00
<template v-if="item.isLike == 0">
2025-01-13 00:25:06 +08:00
<!-- 公开赞 -->
<image class="wh50" src="/static/indexLike1.png" mode="aspectFit"
2025-01-25 21:43:01 +08:00
v-if="item.likeType == 0" @click="handleLike(index,0, 1)" />
2025-01-13 00:25:06 +08:00
<!-- 私密赞的图标 -->
<image class="wh50" src="/static/privateLike.png" mode="aspectFit"
2025-01-25 21:43:01 +08:00
v-else-if="item.likeType == 1" @click="handleLike(index,1,1)" />
2025-01-13 00:25:06 +08:00
</template>
<template v-else>
<image class="wh50" src="/static/indexLike.png" mode="aspectFit"
@click="handleLike(index, 0, 0)" @longpress="handlePrivateLike(index)" />
</template>
2024-12-18 15:46:27 +08:00
</view>
2025-02-03 20:36:02 +08:00
<!-- 只有公开赞显示点赞数 -->
<view class="txt mt10" v-if="item.isLike && item.likeType == 0">
2025-01-13 00:25:06 +08:00
<text class="text">{{ item.likeCount }}</text>
2024-12-18 15:46:27 +08:00
</view>
2025-02-03 20:36:02 +08:00
<view class="txt mt10" v-else>
<text class="text">点赞</text>
</view>
2024-12-18 15:46:27 +08:00
</view>
</view>
<!-- 留言 -->
<view class="item" @click="handleComment">
<view class="col">
<image class="wh50" src="@/static/indexMsg.png" mode="aspectFit" />
<view class="txt mt10">
2025-01-13 00:25:06 +08:00
<text class="text">{{ item.reviewCount }}</text>
2024-12-18 15:46:27 +08:00
</view>
</view>
</view>
<!-- 收藏 -->
<view class="item df fdr">
2025-01-02 01:01:23 +08:00
<view class="col" @touchstart="handleCollectStar" @touchend="handleCollectEnd" ref="collectBtn">
<image class="wh50" src="@/static/indexCollect1.png" mode="aspectFit"
v-if="item.isCollect" />
2024-12-18 15:46:27 +08:00
<image class="wh50" src="@/static/indexCollect.png" mode="aspectFit" v-else />
<view class="txt mt10">
2025-02-03 20:36:02 +08:00
<text class="text">收藏</text>
<!-- <text class="text">{{ item.collectCount }}</text> -->
2024-12-18 15:46:27 +08:00
</view>
</view>
</view>
<!-- 分享 -->
<view class="item" @click="handleShareFirend">
<view class="col">
<image class="wh50" src="@/static/indexShare.png" mode="aspectFit" />
<view class="txt mt10">
<text class="text">分享</text>
</view>
</view>
</view>
<!-- 闹钟 -->
<view class="item money" @click="handleTime" v-if="mode == 'list'">
<view class="col">
<image class="wh80" src="/static/indexMoney1.png" mode="aspectFit" v-if="alarmTime" />
<image class="wh80" src="/static/indexMoney.png" mode="aspectFit" v-else />
</view>
</view>
<!-- 详情菜单 -->
<view class="item money" @click="handleTime" v-if="mode == 'detail' && isMine == 1">
<view class="col wh90 fmid tac" @click="handleDetailMenu">
<uni-icons type="more-filled" color="#d8d8d8" size="70rpx" />
</view>
</view>
</view>
</view>
</view>
<!-- 底部用户信息 -->
<view class="panelBottom pa l0 r0 b0 pl40 pb30">
<!-- 商品信息 -->
2025-02-15 08:59:41 +08:00
<view class="goods df fdr mb20 br10" :class="{'active': showAd}" v-if="showAd"
@click.stop="handleShowProduct">
2024-12-18 15:46:27 +08:00
<!-- 商品图片 -->
2025-01-16 20:18:22 +08:00
<image class="image wh100 mr15 br10" :src="item.productImage" mode="aspectFill" />
2024-12-18 15:46:27 +08:00
<view class="df fdc jcsb f1">
2025-01-16 20:18:22 +08:00
<view class="name">
2025-02-13 22:24:30 +08:00
<text class="text c333 f30">{{item.productName}}</text>
2024-12-18 15:46:27 +08:00
</view>
<view class="info df fdr aic mr10">
2025-02-13 22:24:30 +08:00
<text class="price mr10 c333 f28 b">{{item.productPrice}}</text>
<text class="c666 f1 f20">已售{{item.sales}}</text>
2025-01-16 20:18:22 +08:00
<!-- <uni-icons type="close" color="#fff" /> -->
2024-12-18 15:46:27 +08:00
</view>
2025-02-13 22:24:30 +08:00
<view class="btn sm warm">
2025-02-15 16:10:05 +08:00
<text class="cfff f24 tac" @click.stop="handleProBuy">立即购买</text>
2025-02-13 22:24:30 +08:00
</view>
2024-12-18 15:46:27 +08:00
</view>
</view>
<!-- 用户 -->
<view class="user" @click="handleUser(item)">
2025-01-02 23:36:48 +08:00
<text class="cfff f36">@{{ item.userNickname }}</text>
2024-12-18 15:46:27 +08:00
</view>
<!-- 简介 -->
<view class="desc mt5">
<text class="t2hd cfff f28">{{ item.title }}</text>
</view>
</view>
</view>
</template>
2025-01-02 01:01:23 +08:00
<style lang="scss" scoped>
2024-12-18 15:46:27 +08:00
// 视频盒子
2025-01-02 01:01:23 +08:00
.container {
2024-12-18 15:46:27 +08:00
background-color: #000;
}
// 视频时长
.duration {
margin-top: 120rpx;
width: 750rpx;
background-color: rgba(255, 255, 255, .3);
// 时间时长
.line {
width: 0;
height: 2rpx;
background-color: rgba(255, 255, 255, .8);
transition-duration: .25s;
}
}
2025-01-02 23:36:48 +08:00
// 倍速播放
.speedBox {
position: absolute;
top: 200rpx;
left: 0;
right: 0;
align-items: center;
// 倍速
.speed {
background-color: rgba(0, 0, 0, .8);
border-radius: 5rpx;
opacity: .6;
}
}
2024-12-18 15:46:27 +08:00
// 暂停蒙层
.pausePanel {
background-color: rgba(0, 0, 0, .5);
//
.pauseImg {
width: 140rpx;
height: 140rpx;
}
}
// 右侧屏幕
.panelRight {
align-items: flex-end;
.text {
text-align: center;
color: #fff;
font-size: 24rpx;
}
// 操作台
.operate {
flex: 1;
justify-content: flex-end;
align-items: flex-end;
text-align: center;
padding-bottom: 130rpx;
.item {
margin: 5rpx 0;
padding: 10rpx 5rpx;
&.money {
padding: 0;
}
//
.col {
align-items: center;
justify-content: center;
width: 80rpx;
}
}
}
// 关注的小加号
.focus {
align-items: center;
left: 0;
right: 0;
bottom: 0;
}
}
// 底部
.panelBottom {
2025-02-13 22:24:30 +08:00
padding-right: 100rpx;
2024-12-18 15:46:27 +08:00
2025-01-16 20:18:22 +08:00
// 图片
.image {
2025-02-13 22:24:30 +08:00
width: 200rpx;
height: 200rpx;
2025-01-16 20:18:22 +08:00
}
// 产品
2024-12-18 15:46:27 +08:00
.goods {
padding: 10rpx;
2025-02-13 22:24:30 +08:00
width: 550rpx;
2024-12-18 15:46:27 +08:00
margin-bottom: 20rpx;
2025-02-13 22:24:30 +08:00
background-color: #fff;
2025-01-16 20:18:22 +08:00
opacity: 0;
transition-duration: .5s;
//
&.active {
opacity: 1;
}
}
// 产品图片
.name .text {
lines: 2;
text-overflow: ellipsis;
2024-12-18 15:46:27 +08:00
}
}
2025-01-16 20:18:22 +08:00
// 视频播放进度条
2025-01-02 01:01:23 +08:00
.videoProgress {
position: absolute;
left: 0;
right: 0;
bottom: 0;
2024-12-18 15:46:27 +08:00
}
</style>