vue+Swiper模仿抖音页面播放

开发需求又来了 要模仿抖音做视频播放还要上下滑动。 找了下资料Swiper可以。

先上效果图
在这里插入图片描述

原理主要是通过position:absolute 控制层级z-index来控制视频的播放,全局的video标签只有一个。
上代码:

<template>
  <div class="wrap">
    <div class="my-video works_wraps" v-show="show" :style="VideoItemHeightStyle">
      <video class="video" :src="showVideo.Video.videoPath"
             :poster="showVideo.Video.videoCover"
             webkit-playsinline="true"
             controlslist="nodownload"
             playsinline="true"
             x5-video-player-type="h5"
             x5-video-player-fullscreen="true"
             preload="metadata"
             loop="loop"
             @loadeddata="watchHandler"
             ref="video"
      >
        <!--@pause="onpause"-->
        <!--@play="onplay"-->
        <source :src="showVideo.Video.videoPath" type="video/mp4">
      </video>
    </div>

    <swiper :options="swiperOption" v-if="popularVideo.length > 0">
      <swiper-slide v-for="(item, index) in popularVideo">
        <div>
          <div class="works_wrap" v-show="!item.show" @click="clickSwiper(index)">
            <div class="poster">
              <img class="pic" :src="item.Video.videoCover">
            </div>
            <div class="playWorks"></div>
            <img class="play" src="../../../assets/images/find_play@2x.png" alt="">
          </div>

          <div class="side-bar">
            <div class="avatar">
              <img src="http://www.zhoubaba.club/assets/avatar/default.png" alt="" width="40" height="40"
                   @click.stop="chooseUser">
            </div>
            <div class="like" @click.stop="toggleLike(1)">
              <img v-if="like" src="../../../assets/images/find_heart_r@2x.png" alt="">
              <img v-if="!like" src="../../../assets/images/find_heart_w@2x.png" alt="">
              <span class="likenum">2</span>
            </div>
            <div class="share" style="font-size: 30px;">
              <img src="../../../assets/images/find_share@2x.png" alt="">
              <span class="sharenum">5</span>
            </div>
          </div>
          <div class="good-box" @click.stop="toGood">
            <div class="good-img">
              <img src="png" alt="">
            </div>
            <div class="text-wrap">
              <p class="desc">紫色网格床垫紫色网格床垫紫色网格床垫</p>
              <div><span class="price">¥1000.00</span><span class="old-price">原价:¥19946.00</span></div>
            </div>
            <div class="cart">
              <img src="../../../assets/images/find_cart@2x.png" alt="">
            </div>
          </div>
          <div class="play-video" v-if="item.show" @click="clickSwiper(index)"></div>
        </div>
      </swiper-slide>
    </swiper>
  </div>
</template>

<script>
  import video_detail_controller from "./video_detail_controller";

  export default video_detail_controller;
</script>

<style lang="scss" rel="stylesheet/scss" scoped>
  .works_wraps {
    position: absolute;
    z-index: 1;
    left: 0;
    top: 0;
    right: 0;
    height: 100%;
    visibility: visible;
    display: flex;
    justify-content: center;
    align-items: center;
    background: none;
    overflow: hidden;
    .video {
      object-fit: fill;
      width: 100%;
      height: 100%;
    }
  }

  .up-enter-active, .up-leave-active {
    transition: all .5s
  }

  .up-enter, .up-leave-to {
    opacity: 0;
    transform: translateY(100%);
  }

  .wrap {
    background: #fff;
    width: 100%;
    height: 100%;
    .icon-search {
      position: absolute;
      right: 10px;
      top: 10px;
      padding: 10px;
      font-size: 24px;
      z-index: 222;
    }
    .scroll-wrap {
      position: absolute;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
    }
  }

  .mack {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: #000000;
    opacity: 0.8;
    z-index: 98;
    display: none;
  }

  .works_wrap {
    position: absolute;
    z-index: 1;
    left: 0;
    top: 0;
    right: 0;
    height: 100%;
    visibility: visible;
    display: flex;
    justify-content: center;
    align-items: center;
    background: none;
    overflow: hidden;
    .play {
      position: absolute;
      z-index: 11;
      left: calc(55% - 3rem);
      top: calc(50% - 3rem);
      width: 3rem;
      height: 3rem;
    }
  }

  .swiper-slide .works_wrap .poster {
    /*background: #000000;*/
    position: relative;
    z-index: 10;
    width: 100%;
    height: 100%;
    visibility: visible;
    display: flex;
    justify-content: center;
    align-items: center;
  }

  .swiper-slide .works_wrap .poster .pic {
    width: 100%;
    height: 100%;
    vertical-align: middle;
  }

  .swiper-slide .works_wrap .playWorks {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 100%;
    z-index: 9;
    background-size: auto 50px;
    background: #fff;
  }

  .good-box {
    position: absolute;
    display: flex;
    z-index: 10;
    left: 0;
    bottom: 5rem;
    width: 85%;
    height: 5rem;
    background: #FFFFFF;
    border-radius: 0 12px 12px 0;
    padding: .5rem .8rem;
    .good-img {
      margin-right: .5rem;
      width: 4rem;
      height: 4rem;
      flex: 0 0 4rem;
      img {
        width: 100%;
        height: 100%;
      }
    }
    .text-wrap {
      flex: 1;
      display: flex;
      flex-direction: column;
      text-align: left;
      line-height: 2rem;
      width: 70%;
      font-weight: bold;
    }
    .desc {
      font-size: 16px;
      color: #333333;
      text-overflow: ellipsis;
      white-space: nowrap;
      overflow: hidden;
    }
    .price {
      font-size: 16px;
      color: #f15353;
      margin-right: .5rem;
    }
    .old-price {
      text-decoration: line-through;
      color: #8c8c8c;
      font-size: 12px;
    }
    .cart {
      flex: 0 0 1.5rem;
      width: 1.5rem;
      height: 1.5rem;
      line-height: 5rem;
      img {
        width: 100%;
        height: 100%;
      }
    }
  }

  .side-bar {
    position: absolute;
    z-index: 10;
    right: 15px;
    bottom: 7rem;
    display: flex;
    flex-direction: column;
    height: 160px;
    justify-content: space-between;
    .avatar {
      position: relative;
      border-radius: 50%;
      background: none;
      border: 1px solid rgb(232, 232, 233);
      img {
        border-radius: 50%;
      }
      .follow {
        text-align: center;
        position: absolute;
        bottom: 0;
        left: 50%;
        transform: translateX(-50%) translateY(50%);
        width: 16px;
        height: 16px;
        font-size: 16px;
        border-radius: 50%;
        background: rgb(252, 52, 93);
      }
    }
  }

  .like {
    position: relative;
    img {
      width: 40px;
      height: 40px;
    }
    .likenum {
      font-size: 10px;
      position: absolute;
      bottom: -5px;
      left: 50%;
      transform: translateX(-50%) translateY(100%);
      color: rgb(232, 232, 233);
    }
  }

  .share {
    position: relative;
    img {
      width: 40px;
      height: 40px;
    }
    .sharenum {
      font-size: 10px;
      position: absolute;
      bottom: -5px;
      left: 50%;
      transform: translateX(-50%) translateY(100%);
      color: rgb(232, 232, 233);
    }
  }

  .side-bar > div {
    width: 40px;
    height: 40px;
    font-size: 40px;
    color: rgb(232, 232, 233);
    transition: all .3s;
  }

  .play-video {
    position: absolute;
    z-index: 9;
    top: 0;
    width: 100%;
    height: 100%;
    left: 0;
  }


</style>

import { Toast, MessageBox } from "mint-ui";

let videoFirst = 0;  //第一次初始化
export default {
  data() {
    let that = this;
    return {
      swiperOption: {
        direction: 'vertical',
        observer: true,
        width: window.innerWidth,
        height : window.innerHeight,
        watchOverflow: true,
        autoHeight: true,
        autoplay: false,
        pagination: false,
        on: {
          reachEnd (){
            if(videoFirst === 1){
              that.popularVideo.push({"Video":{"userId":"4617f00b-295d-48b4-8d06-70a92b5e32e5","userAvatar":"/assets/avatar/default.png","userNickname":"95d-4","videoId":"d0a5e902-2912-45f6-848e-2f3d874519f4","videoCover":"http://image2.pearvideo.com/main/20181121/11335845-200032-0.png","videoDesc":"11月19日,盖茨发表长文向大家推荐美剧《硅谷》,称其是为数不多的好作品,自己惊讶于很少有现代流行文化作品能很好地向外界呈现硅谷。盖茨还放话,只要它续更,我愿意一直追下去!","videoPath":"https://dev6.yunzmall.com/attachment/videos/12/2019/07/Uq5OQi89qxi9zA95X9g5Uu8gUgA8gG.mp4"},"WSLCNum":{"shareNum":"3","watchNum":"27","commentNum":"17","likeNum":"12"}});
            }
            console.log(that.popularVideo,"popularVideo");
            // 手指触碰拖动最后一张时执行
          },
          slideChangeTransitionEnd (){
            // console.log(this.realIndex,"this");
            that.$refs.video.pause();
            that.showVideo = that.popularVideo[this.realIndex];
            if(this.realIndex === 0){
              that.popularVideo[this.realIndex].show = false;
              that.popularVideo[this.realIndex+1].show = false;
            } else {
              that.popularVideo[this.realIndex-1].show = false;
              that.popularVideo[this.realIndex].show = false;
              that.popularVideo[this.realIndex+1].show = false;
            }
            that.show = false;
            // that.clickSwiper(this.realIndex);
            //切换结束时,告诉我现在是第几个slide
          },
        },
      },
      popularVideo: [],
      showVideo: {"Video":{"userId":"4617f00b-295d-48b4-8d06-70a92b5e32e5","userAvatar":"/assets/avatar/default.png","userNickname":"95d-4","videoId":"d0a5e902-2912-45f6-848e-2f3d874519f4","videoCover":"http://image2.pearvideo.com/main/20181121/11335845-200032-0.png","videoDesc":"11月19日,盖茨发表长文向大家推荐美剧《硅谷》,称其是为数不多的好作品,自己惊讶于很少有现代流行文化作品能很好地向外界呈现硅谷。盖茨还放话,只要它续更,我愿意一直追下去!","videoPath":"https://dev4.yunzmall.com/attachment/videos/8/2019/07/B745SC4Rj073340O85rs54v04g5vt4.mp4"},"WSLCNum":{"shareNum":"3","watchNum":"27","commentNum":"17","likeNum":"12"}},
      show: false,
      like: false,
      likeNum: 0,
      isPlay: false,
      amount_id: "",
    };
  },
  activated() {
    window.scroll(0, 0);
  },
  mounted(){
    setTimeout(()=>{
      this.popularVideo = [{"Video":{"userId":"4617f00b-295d-48b4-8d06-70a92b5e32e5","userAvatar":"/assets/avatar/default.png","userNickname":"95d-4","videoId":"d0a5e902-2912-45f6-848e-2f3d874519f4","videoCover":"https://image.pearvideo.com/cont/20181121/cont-1480090-11711388.jpg","videoDesc":"11月19日,盖茨发表长文向大家推荐美剧《硅谷》,称其是为数不多的好作品,自己惊讶于很少有现代流行文化作品能很好地向外界呈现硅谷。盖茨还放话,只要它续更,我愿意一直追下去!","videoPath":"https://dev4.yunzmall.com/attachment/videos/8/2019/07/B745SC4Rj073340O85rs54v04g5vt4.mp4"},"WSLCNum":{"shareNum":"3","watchNum":"27","commentNum":"17","likeNum":"12"}},{"Video":{"userId":"4617f00b-295d-48b4-8d06-70a92b5e32e5","userAvatar":"/assets/avatar/default.png","userNickname":"95d-4","videoId":"d0a5e902-2912-45f6-848e-2f3d874519f4","videoCover":"http://image2.pearvideo.com/main/20181121/11335845-200032-0.png","videoDesc":"11月19日,盖茨发表长文向大家推荐美剧《硅谷》,称其是为数不多的好作品,自己惊讶于很少有现代流行文化作品能很好地向外界呈现硅谷。盖茨还放话,只要它续更,我愿意一直追下去!","videoPath":"https://dev6.yunzmall.com/attachment/videos/12/2019/07/el9AIwcHBALAo2w9b29XXW1xBz9727.mp4"}},{"Video":{"userId":"4617f00b-295d-48b4-8d06-70a92b5e32e5","userAvatar":"/assets/avatar/default.png","userNickname":"95d-4","videoId":"d0a5e902-2912-45f6-848e-2f3d874519f4","videoCover":"http://image2.pearvideo.com/main/20181121/11335845-200032-0.png","videoDesc":"11月19日,盖茨发表长文向大家推荐美剧《硅谷》,称其是为数不多的好作品,自己惊讶于很少有现代流行文化作品能很好地向外界呈现硅谷。盖茨还放话,只要它续更,我愿意一直追下去!","videoPath":"https://dev5.yunzmall.com/attachment/videos/2/2019/05/LszWwVEewJeWWWcZ46nbcwNCqEWJqQ.mp4"},"WSLCNum":{"shareNum":"3","watchNum":"27","commentNum":"17","likeNum":"12"}}]
    },300);
    videoFirst = 1;
  },
  computed: {
    VideoItemHeightStyle() {
      let clientWidth =  window.innerWidth;
      let clientHeight = window.innerHeight;
      return {
        height: clientHeight + "px",
        width: clientWidth + "px"
      };
    }
  },
  methods: {
    clickSwiper(index) {
      if (this.popularVideo[index].show && this.amount_id === this.popularVideo[index].Video.videoId) {
        this.show = false;
        this.popularVideo[index].show = false;
        this.$refs.video.pause();
        return;
      }
      this.show = true;
      this.amount_id = this.popularVideo[index].Video.videoId;
      this.$set(this.popularVideo[index], "show", true);

      this.$refs.video.play();
      // console.log(this.$refs.video);
    },
    watchHandler() {
      // this.$axios
    }
  }
};

主要参考了这几篇博客:
https://www.cnblogs.com/mihoutaoguniang/p/5958394.html 基于html5,父级块中添加video,不能全屏播放的问题解决。
https://www.jianshu.com/p/5a770e984d5c 如何退出微信X5同层播放器?
http://smartued.com/index.php/FE/WeChatHtml5video.html H5 微信播放视频全屏问题踩坑实录
https://www.xuanfengge.com/h5-video-play.html 移动端HTML5视频播放优化实践
还有Swiper4的官方文档

Logo

前往低代码交流专区

更多推荐