实现效果

jquery 获取视频播放状态 js播放视频_html


功能实现

  1. 路由配置设置 推荐 和 关注 的视频播放列表子路由以及解决重复点击导航时,控制台出现报错的问题。
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '../views/Home.vue';

Vue.use(VueRouter);

const routes = [
  {
    path: '/',
    redirect: '/index/recommend',
  },
  {
    path: '/index',
    redirect: '/index/recommend',
  },
  {
    path: '/',
    name: 'Home',
    component: Home,
    children: [
      {
        path: '/index',
        name: 'index',
        component: () => import(/* webpackChunkName: "index" */ '../views/index/index.vue'),
        children: [
          {
            path: 'follows',
            name: 'follows',
            component: () => import(/* webpackChunkName: "follows" */ '../views/follow/index.vue'),
            children: [
              {
                path: 'reVideoList',
                name: 'reVideoList',
                component: () => import(/* webpackChunkName: "VideoList" */ '../common/components/videoList/VideoList.vue'),
              },
            ],
          },
          {
            path: 'recommend',
            name: 'recommend',
            component: () => import(/* webpackChunkName: "recommend" */ '../views/recommend/index.vue'),
            children: [
              {
                path: 'reVideoList',
                name: 'reVideoList',
                component: () => import(/* webpackChunkName: "VideoList" */ '../common/components/videoList/VideoList.vue'),
              },
            ],
          },
        ],
      },
      {
        path: '/friends',
        name: 'friends',
        component: () => import(/* webpackChunkName: "friends" */ '../views/friends/index.vue'),
      },
      {
        path: '/news',
        name: 'news',
        component: () => import(/* webpackChunkName: "news" */ '../views/news/index.vue'),
      },
      {
        path: '/mine',
        name: 'mine',
        component: () => import(/* webpackChunkName: "mine" */ '../views/mine/index.vue'),
      },
    ],
  },
  {
    path: '/release',
    name: 'release',
    component: () => import(/* webpackChunkName: "release" */ '../views/release/index.vue'),
  },
];

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes,
});

// 解决重复点击导航时,控制台出现报错
const VueRouterPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(to) {
  return VueRouterPush.call(this, to).catch(err => err);
};

export default router;
  1. 实现 VideoList 组件
  1. 创建 VideoList.vue 组件采用 vue-awesome-swiper 实现视频列表的全屏滚动。官网: vue-awesome-swiper 安装:
npm install swiper vue-awesome-swiper --save
# or
yarn add swiper vue-awesome-swiper

使用:

引入方式分为:Global Registration 和 Local Registration 两种引入方式 在这里我使用的是在组件中引入,全局引入注册只需要在 main.js 中导入即可,具体使用方式可以去官网查看。

<template>
  <div class="video-list">
    <swiper ref="mySwiper" :options="swiperOptions">
      <swiper-slide>
        <Videos></Videos>
      </swiper-slide>
      <swiper-slide>Slide 2</swiper-slide>
      <swiper-slide>Slide 3</swiper-slide>
      <swiper-slide>Slide 4</swiper-slide>
      <swiper-slide>Slide 5</swiper-slide>
      <div class="swiper-pagination" slot="pagination"></div>
    </swiper>
  </div>
</template>

<script>
  import { Swiper, SwiperSlide, directive } from 'vue-awesome-swiper';
  import 'swiper/swiper.min.css';
  import Videos from './Videos.vue';

  export default {
    name: 'carrousel',
    components: {
      Swiper,
      SwiperSlide,
      Videos,
    },
    directives: {
      swiper: directive,
    },
    data() {
      return {
        swiperOptions: {
          // 分页器配置
          pagination: {
            el: '.swiper-pagination',
            clickable: true,
          },
          // 设定初始化时slide的索引
          initialSlide: 0,
          // Slides的滑动方向,可设置水平(horizontal)或垂直(vertical)
          direction: 'vertical',
          // 鼠标覆盖Swiper时指针形状,设置为true时会变成抓手形状
          grabCursor: true,
          // Swiper使用flexbox布局(display: flex),开启这个设定会在Wrapper上添加等于slides相加的宽或高,
          // 在对flexbox布局的支持不是很好的浏览器中可能需要用到。
          setWrapperSize: true,
          // 自动高度。设置为true时,wrapper和container会随着当前slide的高度而发生变化。
          autoHeight: true,
          // 设置slider容器能够同时显示的slides数量(carousel模式)。
          slidesPerView: 1,
          // 开启鼠标滚轮控制Swiper切换。可设置鼠标选项,或true使用默认值。
          mousewheel: true,
          // 是否开启鼠标控制Swiper切换。设置为true时,能使用鼠标滑轮控制slide滑动。
          mousewheelControl: true,
          // 获取swiper容器的高度。
          height: window.innerHeight, // 因为抖音视频的高度是占满整个屏幕的高度
          // 抵抗率。边缘抵抗力的大小比例。值越小抵抗越大越难将slide拖离边缘,0时完全无法拖离。
          resistanceRatio: 0,
          // 将observe应用于Swiper的祖先元素。当Swiper的祖先元素变化时,例如window.resize,Swiper更新。
          observeParents: true,
        },
        // 标识翻页
        page: 1,
      };
    },
    computed: {
      swiper() {
        return this.$refs.mySwiper.$swiper;
      },
    },
    mounted() {
      console.log('Current Swiper instance object', this.swiper);
    },
  };
</script>

<style lang="less" scoped>
.video-list {
  height: 100%;
  .swiper-container {
    height: 100%;
    display: flex;
    background-color: #000;
    color: #fff;
    .swiper-slide {
      display: flex;
      justify-content: center;
      align-items: center;
    }
  }
}
</style>
  1. 创建 Videos.vue 组件
  1. 采用 vue-video-player 实现视频播放器。官网:vue-video-player 安装:
npm install vue-video-player --save
# or
yarn add vue-video-player

使用:

引入方式跟上面的插件一样。

  1. 通过 css 的 transform 属性 改变播放按钮的位置
  2. 修改按钮样式 通过 /deep/ 实现样式穿透。
<template>
  <div class="videos">
    <video-player
      class="video-player-box"
      ref="videoPlayer"
      :options="playerOptions"
      :playsinline="true"
    >
    </video-player>
  </div>
</template>

<script>
import 'video.js/dist/video-js.css';
import { videoPlayer } from 'vue-video-player';

export default {
    components: {
        videoPlayer,
    },
    data() {
      return {
        // videojs options
        playerOptions: {
            // 默认情况下将会消除任何音频。
            muted: true,
            // 如果true,浏览器准备好时开始回放。
            autoplay: false,
            // 导致视频一结束就重新开始。
            loop: true,
            preload: 'auto',
            // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器.
            fluid: true,
            sources: [{
                type: 'video/mp4', // 类型
                src: require('@/assets/videos/sucai.mp4'),
            }],
            // poster: '/static/images/author.jpg',
            // 视频宽度,获取客户端宽度
            width: document.documentElement.clientWidth,
            // 允许覆盖Video.js无法播放媒体源时显示的默认信息。
            notSupportedMessage: '此视频暂无法播放,请稍后再试',
            controlBar: false,
        },
      };
    },
    mounted() {
        console.log('this is current player instance object', this.player);
    },
};
</script>

<style lang="less" scoped>
.videos {
  height: 100%;
  width: 100%;
  padding-bottom: 50px;
  .video-player-box {
    height: 100%;
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    /deep/ .vjs-big-play-button {
      position: absolute;
      width: 80px;
      height: 80px;
      border: none;
      background-color: transparent;
      content: none;
      left: 50%;
      top: 55%;
      transform: translate(-50%, -50%);
      .vjs-icon-placeholder {
        font-size: 100px;
        color: rgba(255, 255, 255, 0.7);
      }
    }
    /deep/ .video-js {
      height: calc(100vh - 50px);
    }
  }
}
</style>
  1. 实现视频播放列表的循环渲染
  1. VideoList.vue 循环渲染在原来代码的基础上,修改 swiper-slide 进行 v-for 循环,并且添加模拟数据 dataList,将视频传递给子组件 <Videos/> 。
<template>
  <div class="video-list">
    <swiper ref="mySwiper" :options="swiperOptions">
      <swiper-slide v-for="(item , index) in dataList" :key="index">
        <Videos :video="item"></Videos>
      </swiper-slide>
      <div class="swiper-pagination" slot="pagination"></div>
    </swiper>
  </div>
</template>

<script>
  import { Swiper, SwiperSlide, directive } from 'vue-awesome-swiper';
  import 'swiper/swiper.min.css';
  import Videos from './Videos.vue';

  export default {
    name: 'carrousel',
    components: {
      Swiper,
      SwiperSlide,
      Videos,
    },
    directives: {
      swiper: directive,
    },
    data() {
      return {
        dataList: [
          {
            id: '1',
            url: 'http://video.jishiyoo.com/3720932b9b474f51a4cf79f245325118/913d4790b8f046bfa1c9a966cd75099f-8ef4af9b34003bd0bc0261cda372521f-ld.mp4',
          },
          {
            id: '2',
            url: 'http://video.jishiyoo.com/1eedc49bba7b4eaebe000e3721149807/d5ab221b92c74af8976bd3c1473bfbe2-4518fe288016ee98c8783733da0e2da4-ld.mp4',
          },
          {
            id: '3',
            url: 'http://video.jishiyoo.com/549ed372c9d14b029bfb0512ba879055/8e2dc540573d496cb0942273c4a4c78c-15844fe70971f715c01d57c0c6595f45-ld.mp4',
          },
          {
            id: '4',
            url: 'http://video.jishiyoo.com/161b9562c780479c95bbdec1a9fbebcc/8d63913b46634b069e13188b03073c09-d25c062412ee3c4a0758b1c48fc8c642-ld.mp4',
          },
        ],
        // 标识翻页
        page: 1,
      };
    },
  };
</script>
  1. Videos.vue 组件视频播放Video 是 VideoList 的子组件,通过父子组件传值的方法 在 Videos 组件的 props 属性中接受父组件传过来的值。
<template>
  <div class="videos">
    <video-player
      class="video-player-box"
      ref="videoPlayer"
      :options="playerOptions"
      :playsinline="true"
    >
    </video-player>
  </div>
</template>

<script>
import 'video.js/dist/video-js.css';
import { videoPlayer } from 'vue-video-player';

export default {
    components: {
        videoPlayer,
    },
    props: ['video'], // 接收父组件传递过来的数据
    data() {
      return {
        // videojs options
        playerOptions: {
            // ... 其他无关代码省略
            sources: [{
                type: 'video/mp4', // 类型
                src: this.video.url, // 获取VideoList组件传递过来的视频地址
            }],
        },
      };
    },
};
</script>

以上只是部分代码,请自行整合,完整代码见 Github


问题记录

  1. Vue 重复点击相同路由,出现 Uncaught (in promise) NavigationDuplicated: Avoided redundant navigation to current location: "/index/recommend/reVideoList".问题描述:重复点击导航时,控制台出现如上报错信息。问题原因:产生这个错误信息的原因很简单,就是因为重复点击相同的路由造成的。在 vue router v3.1 版本之后 ,回调形式改成 Promise api了,返回的是 Promise,如果没有捕获到错误,控制台始终会出现如上图的警告。解决方案:
  1. 方案一、降低 router 版本npm i vue-router@3.0 -S
  2. 在 router/index.js 文件夹下增加下列代码
// src/router/index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);		
const router = new Router({
  // routes...配置信息
})
 
const VueRouterPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(to) {
  return VueRouterPush.call(this, to).catch(err => err);
};
  1. 捕获异常
this.$router.push(route).catch(err => {
  console.log('输出报错',err)
})
  1. 跳转时,判断跳转路由和当前路由是否一致,避免重复跳转产生问题
toXXX (item) {
  if (this.$route.path !== item.url) {
    this.$router.push({ path: item.url })
  }
}
  1. 补齐router第三个参数
// 补齐router.push()的第三个参数
this.$router.push(route, () => {}, (e) => {
    console.log('输出报错',e) 
})
  1. 使用 videojs 播放视频提示 (CODE:4 MEDIA_ERR_SRC_NOT_SUPPORTED) No compatible source was found for this video.问题描述:使用 Videos 播放本地视频时无法播放。解决方案:
  1. 将文件放到服务器上,就是别用本地文件的方式打开;
  2. 播放本地视频文件,使用 require 导入即可;
require('@/assets/videos/index/01.mp4'),
  1. 用的是 chrome,将网站的 flash 设置成默认允许,然后刷新下,就可以了。
  2. 如果没有服务器,可以使用下面文件中提供的播放源播放。
  1. 如何更改 Video 组件的播放按钮的样式?在 vue 组件中,在 style 设置为 scoped 的时候,里面在写样式对子组件是不生效的,如果想让某些样式对所有子组件都生效,可以使用 /deep/ 深度选择器来实现样式穿透。

总结

通过本章节,可以轻松实现视频列表公共组件的封装。

下面几点是在开发项目时需要注意的点:

  1. 使用 vue-awesome-swiper 插件实现了全屏滚动;
  2. 使用 vue-video-player 插件实现了移动端视频播放;
  3. 采用 /deep/ 实现样式穿透;
  4. 采用 transform 实现位置的移动
  5. 使用第三方组件时是否采用全局注册的方式。