New file |
| | |
| | | <template> |
| | | <view class="video-container"> |
| | | <!-- 视频列表 --> |
| | | <swiper |
| | | class="video-swiper" |
| | | vertical |
| | | circular |
| | | :current="currentIndex" |
| | | @change="onSwiperChange" |
| | | > |
| | | <swiper-item v-for="(item, index) in videoList" :key="item.id"> |
| | | <video |
| | | :id="'video'+index" |
| | | :src="item.url" |
| | | :autoplay="currentIndex === index" |
| | | :controls="false" |
| | | :loop="true" |
| | | :object-fit="item.objectFit" |
| | | class="video-item" |
| | | @play="onPlay(index)" |
| | | @pause="onPause(index)" |
| | | @ended="onEnded(index)" |
| | | ></video> |
| | | |
| | | <!-- 悬挂商品链接层 --> |
| | | <view class="goods-link-warp"> |
| | | <view class="goods-link"> |
| | | <view class="goods-container"> |
| | | <!-- 商品图片 --> |
| | | <image class="goods-image" :src="item.goods.image" mode="aspectFill"></image> |
| | | |
| | | <!-- 商品信息 --> |
| | | <view class="goods-info"> |
| | | <text class="goods-name">{{item.goods.name}}</text> |
| | | <view class="price-section"> |
| | | <text class="current-price">¥{{item.goods.price}}</text> |
| | | <text class="original-price" v-if="item.goods.originalPrice">¥{{item.goods.originalPrice}}</text> |
| | | </view> |
| | | <text class="sales-count">{{item.goods.sales}}人已购</text> |
| | | </view> |
| | | |
| | | <!-- 购买按钮 --> |
| | | <view class="buy-button"> |
| | | <text>购买</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | |
| | | <!-- 视频信息层 --> |
| | | <view class="video-info"> |
| | | <view> |
| | | <text class="video-author">@{{item.author}}</text> |
| | | </view> |
| | | <view style="width: 100%;word-wrap: break-word;white-space: normal;overflow-wrap: break-word;"> |
| | | <text class="video-title">{{item.title}}</text> |
| | | <text class="video-tag" v-for="(tag, index) in item.tags" :key="tag">#{{tag}}</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 右侧互动按钮 --> |
| | | <view class="action-buttons"> |
| | | <view class="avatar-container"> |
| | | <image class="avatar" :src="item.authorAvatar" mode="aspectFill"></image> |
| | | <!-- 关注图标 - 使用绝对定位 --> |
| | | <view class="follow-icon"> |
| | | <text class="iconfont"></text> |
| | | </view> |
| | | </view> |
| | | <view class="action-item" @click="toggleCollect(item)"> |
| | | <!-- <image :src="item.isCollected ? '/static/collected.png' : '/static/collect.png'"></image> --> |
| | | <text class="iconfont" v-if="item.collected"></text> |
| | | <text class="iconfont" v-else></text> |
| | | <text style="font-size: 10px;font-weight: lighter;">{{item.collectCount}}</text> |
| | | </view> |
| | | <view class="action-item" @click="showComments(item)"> |
| | | <text class="iconfont"></text> |
| | | <text style="font-size: 10px;font-weight: lighter;">{{item.commentCount}}</text> |
| | | </view> |
| | | </view> |
| | | </swiper-item> |
| | | </swiper> |
| | | </view> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | data() { |
| | | return { |
| | | isFullScreen: false, |
| | | windowHeight: 0, |
| | | currentIndex: 0, // 当前播放的视频索引 |
| | | videoList: [ |
| | | { |
| | | url: 'http://vjs.zencdn.net/v/oceans.mp4', |
| | | objectFit: 'contain', |
| | | title: '我了个', |
| | | author: 'xp', |
| | | authorAvatar: 'https://picsum.photos/200/200?random=2', |
| | | collected: true, |
| | | commentCount: 12, |
| | | collectCount: 45, |
| | | tags: ["五一", "爱美食", "士大夫速度和粉红色的恢复速度的口袋空空"], |
| | | goods: { |
| | | name: '推流', |
| | | price: '10', |
| | | originalPrice: '48.9', |
| | | sales: 1988, |
| | | image: 'https://picsum.photos/200/200?random=2' |
| | | } |
| | | }, |
| | | { |
| | | url: 'https://videos.pexels.com/video-files/30900524/13210612_1080_1920_30fps.mp4', |
| | | objectFit: 'cover', |
| | | title: '我了个', |
| | | author: 'xp', |
| | | authorAvatar: 'https://picsum.photos/200/200?random=2', |
| | | collected: false, |
| | | commentCount: 6, |
| | | collectCount: 45, |
| | | tags: ["我喜欢"], |
| | | goods: { |
| | | name: '推流', |
| | | price: '10', |
| | | originalPrice: '48.9', |
| | | sales: 1988, |
| | | image: 'https://picsum.photos/200/200?random=2' |
| | | } |
| | | }, |
| | | ], // 视频列表数据 |
| | | videoContexts: [], // 视频上下文对象集合 |
| | | loading: false, // 是否正在加载 |
| | | page: 1, // 当前页码 |
| | | pageSize: 10 // 每页数量 |
| | | } |
| | | }, |
| | | onLoad() { |
| | | // this.loadVideos(); |
| | | }, |
| | | onReady() { |
| | | // 初始化视频上下文 |
| | | this.initVideoContexts(); |
| | | }, |
| | | methods: { |
| | | // 初始化视频上下文 |
| | | initVideoContexts() { |
| | | this.videoContexts = this.videoList.map((_, index) => { |
| | | let videoContent = uni.createVideoContext(`video${index}`, this); |
| | | // videoContent.requestFullScreen({ direction: 0 }); |
| | | return videoContent; |
| | | }); |
| | | }, |
| | | |
| | | // 加载视频数据 |
| | | async loadVideos() { |
| | | if (this.loading) return; |
| | | this.loading = true; |
| | | |
| | | try { |
| | | const res = await uni.request({ |
| | | url: 'https://your-api.com/videos', |
| | | data: { |
| | | page: this.page, |
| | | pageSize: this.pageSize |
| | | } |
| | | }); |
| | | |
| | | if (this.page === 1) { |
| | | this.videoList = res.data.list; |
| | | } else { |
| | | this.videoList = [...this.videoList, ...res.data.list]; |
| | | } |
| | | |
| | | this.page++; |
| | | this.$nextTick(() => { |
| | | this.initVideoContexts(); |
| | | }); |
| | | } catch (e) { |
| | | console.error('加载视频失败', e); |
| | | } finally { |
| | | this.loading = false; |
| | | } |
| | | }, |
| | | |
| | | // 滑动切换视频 |
| | | onSwiperChange(e) { |
| | | const oldIndex = this.currentIndex; |
| | | this.currentIndex = e.detail.current; |
| | | |
| | | // 暂停上一个视频 |
| | | if (this.videoContexts[oldIndex]) { |
| | | this.videoContexts[oldIndex].pause(); |
| | | } |
| | | |
| | | // 播放当前视频 |
| | | if (this.videoContexts[this.currentIndex]) { |
| | | this.videoContexts[this.currentIndex].play(); |
| | | } |
| | | }, |
| | | |
| | | // 点赞/取消点赞 |
| | | toggleLike(item) { |
| | | item.isLiked = !item.isLiked; |
| | | item.likeCount += item.isLiked ? 1 : -1; |
| | | |
| | | uni.request({ |
| | | url: `https://your-api.com/video/${item.id}/like`, |
| | | method: item.isLiked ? 'POST' : 'DELETE' |
| | | }); |
| | | }, |
| | | |
| | | // 视频播放事件 |
| | | onPlay(index) { |
| | | console.log(`视频 ${index} 开始播放`); |
| | | }, |
| | | |
| | | // 视频暂停事件 |
| | | onPause(index) { |
| | | console.log(`视频 ${index} 暂停`); |
| | | }, |
| | | |
| | | // 视频结束事件 |
| | | onEnded(index) { |
| | | console.log(`视频 ${index} 播放结束`); |
| | | // 自动播放下一个(如果不在最后一个) |
| | | if (index < this.videoList.length - 1) { |
| | | this.currentIndex = index + 1; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .video-container { |
| | | width: 100%; |
| | | height: 100vh; |
| | | background-color: #000; |
| | | } |
| | | |
| | | .video-swiper { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | .video-item { |
| | | width: 100%; |
| | | height: 100%; |
| | | object-fit: cover; |
| | | } |
| | | |
| | | .video-info { |
| | | width: 70%; |
| | | position: absolute; |
| | | bottom: 50px; |
| | | left: 20px; |
| | | color: #f8f8f8; |
| | | z-index: 10; |
| | | letter-spacing: 1px; |
| | | } |
| | | |
| | | .action-buttons { |
| | | position: absolute; |
| | | right: 20px; |
| | | bottom: 150px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | z-index: 10; |
| | | } |
| | | |
| | | .action-item { |
| | | margin-bottom: 18px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | align-items: center; |
| | | color: #fff; |
| | | } |
| | | .avatar-container { |
| | | margin-bottom: 27px; |
| | | position: relative; /* 为绝对定位的子元素提供定位上下文 */ |
| | | width: 40px; |
| | | height: 40px; |
| | | display: inline-block; /* 使容器根据内容调整大小 */ |
| | | } |
| | | .avatar { |
| | | border: 2px solid #FFFFFF; |
| | | box-sizing: border-box; |
| | | width: 100%; |
| | | height: 100%; |
| | | border-radius: 50%; /* 关键属性,设置为50%即可实现圆形 */ |
| | | overflow: hidden; /* 确保图片不会超出圆形边界 */ |
| | | display: block; |
| | | } |
| | | .follow-icon { |
| | | position: absolute; |
| | | bottom: 0; /* 定位到底部 */ |
| | | left: 50%; /* 水平居中开始位置 */ |
| | | transform: translate(-50%, 50%); /* 水平居中并向下移动50% */ |
| | | |
| | | width: 18px; /* 图标大小 */ |
| | | height: 18px; |
| | | background-color: #FF5A5F; /* 图标背景色 */ |
| | | border-radius: 50%; |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 轻微阴影 */ |
| | | } |
| | | .video-tag { |
| | | margin-left: 5px; |
| | | font-weight: bold; |
| | | color: #eeeeee; |
| | | } |
| | | .video-author { |
| | | font-size: 1.2em; |
| | | } |
| | | /* 商品链接悬挂层样式 */ |
| | | .goods-link-warp { |
| | | position: absolute; |
| | | bottom: 100px; |
| | | left: 20px; |
| | | color: #f8f8f8; |
| | | z-index: 10; |
| | | } |
| | | .goods-link { |
| | | position: relative; |
| | | margin: 20rpx 0; |
| | | padding: 12rpx; |
| | | background-color: rgba(255, 255, 255, 0.9); |
| | | border-radius: 12rpx; |
| | | box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08); |
| | | } |
| | | |
| | | .goods-container { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .goods-image { |
| | | width: 120rpx; |
| | | height: 120rpx; |
| | | border-radius: 8rpx; |
| | | margin-right: 20rpx; |
| | | } |
| | | |
| | | .goods-info { |
| | | flex: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .goods-name { |
| | | font-size: 28rpx; |
| | | color: #333; |
| | | font-weight: bold; |
| | | display: -webkit-box; |
| | | -webkit-line-clamp: 2; |
| | | -webkit-box-orient: vertical; |
| | | overflow: hidden; |
| | | margin-bottom: 8rpx; |
| | | } |
| | | |
| | | .price-section { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 6rpx; |
| | | } |
| | | |
| | | .current-price { |
| | | font-size: 32rpx; |
| | | color: #ff2e4d; |
| | | font-weight: bold; |
| | | margin-right: 12rpx; |
| | | } |
| | | |
| | | .original-price { |
| | | font-size: 24rpx; |
| | | color: #999; |
| | | text-decoration: line-through; |
| | | } |
| | | |
| | | .sales-count { |
| | | font-size: 22rpx; |
| | | color: #999; |
| | | } |
| | | |
| | | .buy-button { |
| | | background: linear-gradient(to right, #ff5a5f, #ff2e4d); |
| | | color: white; |
| | | padding: 10rpx 24rpx; |
| | | border-radius: 20rpx; |
| | | font-size: 26rpx; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | </style> |