Files
test-subject/src/pages/components/videopage/videopage.vue
2025-10-14 18:04:20 +08:00

618 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="videopage">
<Head></Head>
<video id="videoid" ref="videoRef" :src="videoData.videoUrl" :danmu-list="videoData.danmuList" enable-danmu loop
:muted="isMuted" :show-mute-btn="true" :controls="false" object-fit="contain" @tap="pausevideo"></video>
<!-- 播放按钮 - 使用浏览器复制的样式 -->
<view v-if="!isPlaying" class="uni-video-cover" @tap="pausevideo">
<view class="uni-video-cover-play-button uni-video-icon"></view>
</view>
<!-- 视频信息 -->
<view class="videoinfo">
<view class="vedioinfohead">
<text class="username">@{{ videoData.userName }}</text>
<text class="datetime">{{ formatDate(videoData.date) }}</text>
</view>
<view class="content-container">
<text class="content" :class="{ 'expanded': isExpanded }">{{ videoData.copywriting }}</text>
<view class="flodbtncontainer">
<image v-if="videoData.copywriting.length > 30" class="expand-btn" :class="{ 'rotated': isExpanded }"
:src="isExpanded ? '/static/imgs/foldicon/flodicon@3x.webp' : '/static/imgs/foldicon/flodicon@3x.webp'"
mode="aspectFit" @tap="toggleExpand"></image>
</view>
</view>
</view>
<!-- 右侧交互按钮 -->
<view class="interaction-panel">
<!-- 头像+关注 -->
<view class="user-section">
<image :src="videoData.userImg" class="user-avatar" mode="aspectFill"></image>
<view class="follow-btn-container" @tap="toggleFollow">
<image src="/static/imgs/followbtn/btn@3x.webp" mode="aspectFit"></image>
</view>
</view>
<!-- 点赞按钮 -->
<view class="action-btn" @tap="toggleLike">
<image src="/static/imgs/likeicon2/icon-2@3x.webp" class="action-icon" mode="aspectFit"></image>
<text class="action-count">{{ formatCount(videoData.likesum) }}</text>
</view>
<!-- 评论按钮 -->
<view class="action-btn" @tap="openComments">
<image src="/static/imgs/commenticon/icon-2@3x.webp" class="action-icon" mode="aspectFit"></image>
<text class="action-count">{{ formatCount(videoData.commentsum) }}</text>
</view>
<!-- 分享按钮 -->
<view class="action-btn" @tap="shareVideo">
<image src="/static/imgs/shareicon/icon-2@3x.webp" class="action-icon" mode="aspectFit"></image>
<text class="action-count">{{ formatCount(videoData.sharesum) }}</text>
</view>
<!-- 静音按钮 -->
<image :src="isMuted ? '/static/imgs/mutebtn/mutebtn@3x.webp' : '/static/imgs/unmutebtn/unmutebtn@3x.webp'"
class="mutebtn" mode="aspectFit" @tap="toggleMute"></image>
</view>
</view>
<!-- 评论区域 + 互动区域 -->
<Comments :comments="videoData.comments" :showInteraction="true" :collectsum="videoData.collectsum"
:likesum="videoData.likesum" />
</template>
<script setup>
import { ref, reactive, getCurrentInstance } from 'vue'
import { useCommonStore } from '@/stores/common.js'
import Head from '@/pages/components/head/head.vue'
import Comments from '@/pages/components/comments/comments.vue'
const common = useCommonStore()
const formatCount = common.formatCount
const formatDate = common.formatDate
// 折叠展开状态
const isExpanded = ref(false)
const videoRef = ref(null)
const ctx = ref(null)
// 静音状态
const isMuted = ref(false)
// 播放状态
const isPlaying = ref(true) // 默认播放状态
// 视频数据(包含弹幕)
const videoData = reactive({
userId: 1000012,
userName: '蔡徐坤',
userImg: '/static/logo.png',
date: '2024-01-15',
copywriting: '鸡你太美!练习时长两年半的个人练习生!鸡你太美!练习时长两年半的个人练习生!鸡你太美!练习时长两年半的个人练习生!',
current: 0,
isfollow: false,
likesum: 1145140,
collectsum: 114514,
commentsum: 114514,
sharesum: 1145,
videoUrl: '/static/videos/beauty.mp4',
comments: [
{
id: 101,
userName: 'Brad Lewin',
atUsers: ['JackyLove'],
content: '今天天气真不错~',
date: '2024-12-01',
likeCount: 99999,
showChild: false,
children: [
{ id: 201, userName: 'Alice', content: '快智能体是人类智慧的延伸,它们将成为我们最强大的工具,也是最亲密的朋友。智能体是人类智慧的延伸', atUsers: ['Brad Lewin', 'JackyLove'], date: '2024-12-01', likeCount: 2 },
{ id: 202, userName: 'Bob', content: '我同意你的观点。我记得喜欢这个版本。这个新版本对我来说Nothing好处', atUsers: [], date: '2024-12-01', likeCount: 1 }
]
},
{
id: 102,
userName: 'Leanne Simpson',
atUsers: ['Theshy'],
content: '有人一起开黑吗?',
date: '2024-12-02',
likeCount: 1145140,
showChild: false,
children: [
{ id: 203, userName: 'Carol', content: '带我一个', atUsers: [], date: '2024-12-02', likeCount: 3 }
]
},
{
id: 103,
userName: 'Tom Hardy',
atUsers: [],
content: '主评论3分享一张今晚的月亮。',
date: '2024-12-03',
likeCount: 999,
showChild: false,
children: []
}
],
danmuList: [
{ text: '鸡你太美!', color: '#FFFFFF', time: 1 },
{ text: '练习时长两年半', color: '#FF0000', time: 1 },
{ text: '个人练习生', color: '#00FF00', time: 1 },
{ text: '坤坤加油!', color: '#FFFF00', time: 3 },
{ text: '篮球高手', color: '#FFA500', time: 3 },
{ text: '坤坤跳舞真帅', color: '#FF69B4', time: 5 },
{ text: '这舞步绝了', color: '#00FFFF', time: 5 },
{ text: '音乐太洗脑了', color: '#FFD700', time: 7 },
{ text: '坤坤我爱你', color: '#FF1493', time: 7 },
{ text: '练习生之光', color: '#7CFC00', time: 9 },
{ text: '这节奏太上头', color: '#FF6347', time: 9 },
{ text: '坤坤的招牌动作', color: '#9370DB', time: 11 },
{ text: '鸡你太美循环中', color: '#20B2AA', time: 11 },
{ text: '两年半的功力', color: '#FF4500', time: 13 },
{ text: '坤坤的舞姿', color: '#DA70D6', time: 13 },
{ text: '这歌太魔性了', color: '#32CD32', time: 15 },
{ text: '练习生天花板', color: '#FF8C00', time: 15 },
{ text: '坤坤的台风', color: '#00BFFF', time: 17 },
{ text: '鸡你太美经典', color: '#FF00FF', time: 17 },
{ text: '坤坤的舞台魅力', color: '#FFDAB9', time: 19 },
{ text: '这舞步太经典', color: '#98FB98', time: 19 },
{ text: '坤坤的招牌笑容', color: '#FFB6C1', time: 21 },
{ text: '练习生传奇', color: '#87CEFA', time: 21 },
{ text: '坤坤的舞蹈功底', color: '#FFA07A', time: 23 },
{ text: '坤坤太帅了', color: '#FF1493', time: 25 },
{ text: '这舞步太丝滑', color: '#00CED1', time: 25 },
{ text: '坤坤的节奏感', color: '#FF69B4', time: 27 },
{ text: '鸡你太美神曲', color: '#32CD32', time: 27 },
{ text: '坤坤的舞台表现', color: '#FF4500', time: 29 },
{ text: '这舞蹈太经典', color: '#9370DB', time: 29 },
{ text: '坤坤的粉丝来了', color: '#FFD700', time: 2 },
{ text: '鸡你太美循环播放', color: '#00BFFF', time: 4 },
{ text: '坤坤的舞蹈功底', color: '#FF6347', time: 6 },
{ text: '这歌太魔性了', color: '#20B2AA', time: 8 },
{ text: '坤坤的招牌动作', color: '#FF8C00', time: 10 },
{ text: '练习时长两年半', color: '#FF00FF', time: 12 },
{ text: '坤坤的舞台魅力', color: '#98FB98', time: 14 },
{ text: '鸡你太美经典', color: '#FFB6C1', time: 16 },
{ text: '坤坤的舞姿', color: '#87CEFA', time: 18 },
{ text: '这节奏太上头', color: '#FFA07A', time: 20 },
{ text: '坤坤的台风', color: '#FF1493', time: 22 },
{ text: '鸡你太美神曲', color: '#00CED1', time: 24 },
{ text: '坤坤的舞蹈功底', color: '#FF69B4', time: 26 },
{ text: '这舞步太丝滑', color: '#32CD32', time: 28 },
{ text: '坤坤太帅了', color: '#FF4500', time: 30 }
]
})
// 切换展开状态
const toggleExpand = () => {
isExpanded.value = !isExpanded.value
}
//暂停/播放
const pausevideo = () => {
// 获取VideoContext实例
const videoCtx = uni.createVideoContext('videoid', getCurrentInstance());
// 检查视频状态并切换播放/暂停
if (videoCtx) {
// 使用一个状态变量来跟踪播放状态
if (isPlaying.value) {
videoCtx.pause()
isPlaying.value = false
} else {
videoCtx.play()
isPlaying.value = true
}
}
}
// 关注
const toggleFollow = () => {
common.openapp();
}
// 点赞
const toggleLike = () => {
common.openapp();
}
// 打开评论
const openComments = () => {
common.openapp();
}
// 分享视频
const shareVideo = () => {
common.openapp();
}
// 切换静音
const toggleMute = () => {
isMuted.value = !isMuted.value;
// 获取VideoContext实例
const videoCtx = uni.createVideoContext('videoid', getCurrentInstance());
if (videoCtx && typeof videoCtx.volume === 'function') {
// H5平台使用volume方法控制音量
videoCtx.volume(isMuted.value ? 0 : 1);
}
}
</script>
<style scoped>
.videopage {
width: 100%;
height: 100vh;
min-height: 684px;
max-height: 932px;
max-height: 932px;
display: flex;
flex-direction: column;
position: relative;
}
.videopage video {
width: 100%;
flex: 1;
object-fit: cover;
}
::v-deep .uni-video-cover {
background-color: transparent;
}
::v-deep .uni-video-cover-play-button {
width: 100% !important;
height: 100% !important;
display: flex;
align-items: center;
justify-content: center;
}
/* 弹幕区域 */
::v-deep .uni-video-danmu {
height: 15% !important;
height: 15% !important;
z-index: 2;
margin: 32px 0 0;
}
.user-nickname {
font-size: 16px;
font-weight: 600;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
}
.content {
font-size: 14px;
line-height: 1.4;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
}
.publish-time {
font-size: 12px;
color: rgba(255, 255, 255, 0.8);
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
}
/* 右侧交互面板 */
.interaction-panel {
position: absolute;
right: 16px;
bottom: 16px;
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
z-index: 2;
}
/* 用户信息区域 */
.user-section,
.action-btn,
.mutebtn {
cursor: pointer;
}
.user-section {
width: 48px;
height: 60px;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
}
.user-avatar {
width: 48px;
height: 48px;
border-radius: 50%;
border: 2px solid rgba(255, 255, 255, 0.8);
}
.follow-btn-container {
position: absolute;
bottom: 0;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(10px);
border-radius: 50%;
}
.follow-icon {
width: 20px;
height: 20px;
border-radius: 50%;
}
/* 交互按钮 */
.action-btn {
width: 30px;
height: 47px;
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
padding: 8px;
border-radius: 8px;
transition: background-color 0.3s;
}
.action-icon {
width: 30px;
height: 30px;
}
.action-count {
font-size: 12px;
color: #fff;
font-weight: 600;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}
.mutebtn {
width: 40px;
height: 40px;
}
/* 视频信息区域 */
.videoinfo {
width: 294px;
height: auto;
margin: 0 0 17px 16px;
position: absolute;
left: 0;
bottom: 0;
z-index: 2;
display: flex;
flex-wrap: wrap;
align-items: flex-start;
gap: 8px;
}
.vedioinfohead {
height: 24px;
display: flex;
gap: 8px;
}
.username {
font-family: PingFangSC;
font-size: 17px;
font-weight: 600;
font-stretch: normal;
font-style: normal;
line-height: normal;
letter-spacing: normal;
color: #fff;
display: flex;
align-items: center;
height: 24px;
white-space: nowrap;
flex-shrink: 0;
}
.datetime {
font-family: PingFangSC;
font-size: 11px;
font-weight: normal;
font-stretch: normal;
font-style: normal;
line-height: normal;
letter-spacing: normal;
color: rgba(255, 255, 255, 0.6);
display: flex;
align-items: center;
height: 24px;
white-space: nowrap;
flex-shrink: 0;
}
.content {
font-family: PingFangSC;
font-size: 13px;
font-weight: normal;
font-stretch: normal;
font-style: normal;
line-height: 1.69;
letter-spacing: normal;
color: rgba(255, 255, 255, 0.8);
max-width: 250px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
height: 22px;
flex-shrink: 0;
transition: all 0.3s ease;
}
.content.expanded {
white-space: normal;
overflow: visible;
text-overflow: clip;
height: auto;
max-height: none;
}
.content-container {
display: flex;
align-items: center;
gap: 4px;
max-width: 273px;
}
/* 自定义播放按钮 */
.custom-play-button {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 80px;
height: 80px;
background: rgba(0, 0, 0, 0.5);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
z-index: 10;
cursor: pointer;
transition: all 0.3s ease;
}
.custom-play-button:hover {
background: rgba(0, 0, 0, 0.7);
transform: translate(-50%, -50%) scale(1.1);
}
.play-icon {
font-size: 40px;
color: white;
margin-left: 5px;
}
/* 自定义播放按钮 */
.custom-play-button {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 80px;
height: 80px;
background: rgba(0, 0, 0, 0.5);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
z-index: 10;
cursor: pointer;
transition: all 0.3s ease;
}
.custom-play-button:hover {
background: rgba(0, 0, 0, 0.7);
transform: translate(-50%, -50%) scale(1.1);
}
.play-icon {
font-size: 40px;
color: white;
margin-left: 5px;
}
.flodbtncontainer {
height: 22px;
width: 16px;
display: flex;
align-self: flex-start;
flex-shrink: 0;
}
.expand-btn {
width: 16px;
height: 16px;
object-fit: contain;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
transition: transform 0.3s ease;
}
.expand-btn.rotated {
transform: rotate(180deg);
}
.uni-video-cover {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 1;
}
.uni-video-icon {
font-family: 'uni-video-icon';
text-align: center;
}
.uni-video-cover-play-button {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
line-height: 75px;
font-size: 56px;
color: rgba(255, 255, 255, 0.5);
cursor: pointer;
}
.uni-video-cover-play-button::after {
content: '\ea24';
}
.uni-video-cover {
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 1;
}
.uni-video-icon {
font-family: 'uni-video-icon';
text-align: center;
}
.uni-video-cover-play-button {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
line-height: 75px;
font-size: 56px;
color: rgba(255, 255, 255, 0.5);
cursor: pointer;
}
.uni-video-cover-play-button::after {
content: '\ea24';
}
</style>