绿满眶商城微信小程序-uniapp
xiangpei
2025-05-15 92aaeeae67aa4c1251efb3d5139a330bbc8171ee
首页视频及样式
2个文件已修改
1个文件已添加
431 ■■■■■ 已修改文件
App.vue 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages.json 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/tabbar/index/home.vue 400 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
App.vue
@@ -250,4 +250,21 @@
    .flex1 {
        flex: 1; //必须父级设置flex
    }
    /* 在线链接服务仅供平台体验和调试使用,平台不承诺服务的稳定性,企业客户需下载字体包自行发布使用并做好备份。 */
    @font-face {
      font-family: 'iconfont';  /* Project id 4921691 */
      src:
           url('//at.alicdn.com/t/c/font_4921691_eb4ujoqj71a.woff2?t=1747275566974') format('woff2'),
           url('//at.alicdn.com/t/c/font_4921691_eb4ujoqj71a.woff?t=1747275566974') format('woff'),
           url('//at.alicdn.com/t/c/font_4921691_eb4ujoqj71a.ttf?t=1747275566974') format('truetype');
    }
    .iconfont {
          /* font-family需要和自定义的相同 */
           font-family: "iconfont" !important;
           font-size: 2em;
           font-style: normal;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }
</style>
pages.json
@@ -4,7 +4,16 @@
        "^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
    },
    "pages": [
        // 第一个就是首页
        {
            "path" : "pages/tabbar/index/home",
            "style" :
            {
                // "navigationBarTitleText" : "视频",
                "enablePullDownRefresh" : false,
                "navigationStyle": "custom"
            }
        },
        {
            "path": "pages/tabbar/home/index",
            "style": {
@@ -93,6 +102,7 @@
                            "navigationBarTitleText": "专题"
                    }
        }
    ],
    "subPackages": [
@@ -825,7 +835,7 @@
        "borderStyle": "black",
        "backgroundColor": "#ffffff",
        "list": [{
                "pagePath": "pages/tabbar/home/index",
                "pagePath": "pages/tabbar/index/home",
                "iconPath": "static/tabbar/home.png",
                "selectedIconPath": "static/tabbar/home-s.png",
                "text": "首页"
pages/tabbar/index/home.vue
New file
@@ -0,0 +1,400 @@
<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">&#xe629;</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">&#xe605;</text>
            <text class="iconfont" v-else>&#xe601;</text>
            <text style="font-size: 10px;font-weight: lighter;">{{item.collectCount}}</text>
          </view>
         <view class="action-item" @click="showComments(item)">
            <text class="iconfont">&#xe7f7;</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>