You need to enable JavaScript to run this app.
导航
最佳实践
最近更新时间:2024.03.06 19:52:42首次发布时间:2024.03.06 19:52:42

本文通过 2 个组件定义和 1 个功能实现来介绍如何使用播放器。

竖屏模式

在竖屏场景下,直播通常有以下三种表现方式。

  • 上半屏播放:以画面宽铺满、高自适应的模式展示画面,画面顶部位于小程序顶部导航栏的下方。
  • 居中播放:以画面宽铺满、高自适应的模式展示画面,小程序顶部导航栏悬浮在画面上方。
  • 全屏播放:以画面高铺满、宽溢出的方式铺满全屏展示画面,小程序顶部导航悬浮在画面上方。

上半屏播放

{
  "usingComponents": {
    "ve-live-player": "veplayer-live-mp-wx/ve-live-player/ve-live-player",
    "nav": "../components/nav/nav",
    "message": "../components/message/message",
    "mp-icon": "weui-miniprogram/icon/icon"
  },
  "navigationStyle": "custom"
}
<!-- index.wxml -->
<view class="wrap">
  <image class="image" src="/assets/bg.jpeg" />
  <nav color="#000" />
  <ve-live-player
    id="player"
    ve-class="player"
    autoplay
    src="https://pull-demo.volcfcdnrd.com/live/st-4536523.flv"
    width="100vw"
    height="200px"
    object-fit="{{objectFit}}"
    fit-video-size="{{fitVideoSize}}"
  >
    <mp-icon
      wx:if="{{fullscreen}}"
      style="position: absolute; top: 12px; left: 12px"
      icon="back"
      color="#fff"
      size="{{12}}"
      bind:tap="exitFullscreen"
    ></mp-icon>
    <mp-icon
      wx:if="{{!fullscreen}}"
      style="position: absolute; bottom: 4px; right: 4px;"
      icon="max-window"
      color="#fff"
      size="{{20}}"
      bind:tap="requestFullscreen"
    ></mp-icon>
    <message wx:if="{{fullscreen}}" />
  </ve-live-player>
  <message wx:if="{{!fullscreen}}" />
</view>
/** index.wxss */
.wrap {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}

.image {
  position: absolute;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  object-fit: cover;
}
// index.js
import { getVeLivePlayer } from 'veplayer-live-mp-wx';

Page({
  data: {
    fullscreen: false,
    fitVideoSize: 'fixWidth',
    objectFit: 'fillCrop',
  },
  onLoad() {
    const veLivePlayer = getVeLivePlayer(this, '#player');
    this.veLivePlayer = veLivePlayer;
    this.veLivePlayer.on('fullscreenChange', fullscreen => {
      this.setData({
        fullscreen,
        fitVideoSize: fullscreen ? 'fixed' : 'fixWidth',
        objectFit: fullscreen ? 'contain' : 'fillCrop',
      });
    });
  },
  requestFullscreen() {
    this.veLivePlayer.requestFullscreen({
      direction: 90,
    });
  },
  exitFullscreen() {
    this.veLivePlayer.exitFullscreen();
  },
});

居中播放

{
  "usingComponents": {
    "ve-live-player": "veplayer-live-mp-wx/ve-live-player/ve-live-player",
    "nav": "../components/nav/nav",
    "message": "../components/message/message",
    "mp-icon": "weui-miniprogram/icon/icon"
  },
  "navigationStyle": "custom"
}
<!-- index.wxml -->
<view class="wrap">
  <nav color="#000" />
  <image class="image" src="/assets/bg.jpeg" />
  <ve-live-player
    class="player"
    autoplay
    src="https://pull-demo.volcfcdnrd.com/live/st-4536523.flv"
    width="100vw"
    height="200px"
    fit-video-size="fixWidth"
  />
  <message />
</view>
/** index.wxss */
.wrap {
  width: 100vw;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.image {
  position: absolute;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  object-fit: cover;
}

.player {
  position: relative;
  z-index: 1;
}
// index.js
import { getVeLivePlayer } from 'veplayer-live-mp-wx';

Page({});

全屏播放

{
  "usingComponents": {
    "ve-live-player": "veplayer-live-mp-wx/ve-live-player/ve-live-player",
    "nav": "../components/nav/nav",
    "message": "../components/message/message",
    "mp-icon": "weui-miniprogram/icon/icon"
  },
  "navigationStyle": "custom"
}
<!-- index.wxml -->
<view class="wrap">
  <ve-live-player
    ve-class="player"
    autoplay
    src="https://pull-demo.volcfcdnrd.com/live/st-4536524.flv"
    object-fit="fillCrop"
  >
    <nav />
    <message />
  </ve-live-player>
</view>
/** index.wxss */
.wrap {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}

.wrap .player {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
}
// index.js
Page({});

横屏模式

横屏模式指画面位于小程序顶部导航栏下方,居中自适应的展示画面,画面底部支持定义定 tab。

横屏模式代码示例如下。

{
  "usingComponents": {
    "ve-live-player": "veplayer-live-mp-wx/ve-live-player/ve-live-player",
    "nav": "../components/nav/nav",
    "message": "../components/message/message",
    "mp-icon": "weui-miniprogram/icon/icon"
  },
  "navigationStyle": "custom"
}
<!-- index.wxml -->
<view class="wrap">
  <nav color="#000" />
  <ve-live-player
    id="player"
    ve-class="player"
    autoplay
    src="https://pull-demo.volcfcdnrd.com/live/st-4536523.flv"
    width="100vw"
    height="200px"
    object-fit="{{objectFit}}"
    fit-video-size="{{fitVideoSize}}"
  >
    <view class="control">
      <view>
        <mp-icon
          icon='{{paused?"play":"pause"}}'
          color="#fff"
          size="{{20}}"
          bind:tap="handlePlay"
        ></mp-icon>
        <mp-icon
          style="margin-left: 8px"
          icon="refresh"
          color="#fff"
          size="{{16}}"
          bind:tap="handleRefresh"
        ></mp-icon>
      </view>
      <view>
        <mp-icon
          icon='{{muted?"volume-off":"volume-up"}}'
          color="#fff"
          size="{{20}}"
          bind:tap="handleMute"
        ></mp-icon>
        <mp-icon
          icon='{{fullscreen ? "close" : "max-window"}}'
          color="#fff"
          style="margin-left: 8px"
          size="{{16}}"
          bind:tap="handleFullscreen"
        >
          <message wx:if="{{fullscreen}}" />
          <message wx:if="{{!fullscreen}}" />
        </mp-icon>
      </view>
    </view>
  </ve-live-player>
  <view class="bottom">
    <view class="tab-list">
      <view
        wx:for="{{tabList}}"
        wx:key="index"
        wx:for-item="item"
        class="tab-item"
        >{{item.text}}</view
      >
    </view>
    <view class="content"
      >火山引擎是字节跳动旗下的云服务平台,将字节跳动快速发展过程中积累的增长方法、技术能力和应用工具开放给外部企业,提供云基础、视频与内容分发、数智平台VeDI、人工智能、开发与运维等服务,帮助企业在数字化升级中实现持续增长。</view
    >
  </view>
</view>
/** index.wxss */
.wrap {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.image {
  position: absolute;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  object-fit: cover;
}

.control {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 4px 16px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  background-color: rgba(0, 0, 0, 0.5);
}

.bottom {
  flex-grow: 1;
}

.tab-list {
  display: flex;
  border-bottom: 1px solid #ccc;
  align-items: center;
  justify-content: space-between;
}

.tab-item {
  width: 33.333333333%;
  padding: 12px 20px;
  text-align: center;
}

.tab-item:first-child {
  background-color: #eee;
  font-weight: bold;
}

.tab-item:not(:first-child) {
  border-left: 1px solid #ccc;
}

.content {
  padding: 5px 8px;
  font-size: 16px;
  line-height: 24px;
}
// index.js
import { getVeLivePlayer } from 'veplayer-live-mp-wx';

Page({
  data: {
    fullscreen: false,
    fitVideoSize: 'fixWidth',
    objectFit: 'fillCrop',
    paused: false,
    muted: false,
    tabList: [
      {
        text: 'tab1',
      },
      {
        text: 'tab2',
      },
      {
        text: 'tab3',
      },
    ],
  },
  onLoad() {
    const veLivePlayer = getVeLivePlayer(this, '#player');
    this.veLivePlayer = veLivePlayer;
    this.veLivePlayer.on('fullscreenChange', fullscreen => {
      this.setData({
        fullscreen,
        fitVideoSize: fullscreen ? 'fixed' : 'fixWidth',
        objectFit: fullscreen ? 'contain' : 'fillCrop',
      });
    });
    this.veLivePlayer.on('playing', () => {
      this.setData({
        paused: false,
      });
    });
    this.veLivePlayer.on('pause', () => {
      this.setData({
        paused: true,
      });
    });
  },
  handleFullscreen() {
    if (this.data.fullscreen) {
      this.veLivePlayer.exitFullscreen();
    } else {
      this.veLivePlayer.requestFullscreen({
        direction: 90,
      });
    }
  },
  handlePlay() {
    const paused = !this.data.paused;
    if (paused) {
      this.veLivePlayer.pause();
    } else {
      this.veLivePlayer.play();
    }
  },
  handleMute() {
    const muted = !this.data.muted;
    if (muted) {
      this.veLivePlayer.mute();
    } else {
      this.veLivePlayer.unmute();
    }
    this.setData({
      muted,
    });
  },
  handleRefresh() {
    this.veLivePlayer.replay();
  },
});

低延迟拉流

配置播放器时使用 RTC 场景模式并设置最大和最小缓冲区,可实现更低延迟拉流,代码示例如下所示。

<!-- index.wxml -->
<ve-live-player
  autoplay
  src="https://pull-demo.volcfcdnrd.com/live/st-4536526.flv"
  mode="RTC"
  min-cache="{{0.2}}"
  max-cache="{{0.8}}"
/>
// index.js
Page({});

公共组件实现示例

导航组件 nav

新建 nav.json 文件定义导航组件配置。

// nav.json
{
  "component": true,
  "usingComponents": {
    "mp-navigation-bar": "weui-miniprogram/navigation-bar/navigation-bar",
    "mp-icon": "weui-miniprogram/icon/icon"
  }
}

新建 nav.wxml 文件定义导航组件界面结构。

<!-- nav.wxml -->
<mp-navigation-bar ext-class="nav-bar" color="{{color}}">
  <view slot="center" class="center">
    <view class="avatar">
      <mp-icon type="field" icon="me" size="{{24}}" color="{{color}}" />
    </view>
    <text style="margin-left: 8px;">小 A</text>
  </view>
</mp-navigation-bar>

新建 nav.wxss 文件定义导航组件样式。

/* nav.wxss */
.center {
  display: flex;
  align-items: center;
}

新建 nav.js 文件定义导航组件逻辑和行为。

// nav.js
Component({
  properties: {
    color: {
      type: String,
      value: '#fff',
    },
  },
});

消息组件 message

新建 message.json 文件定义消息组件配置。

// message.json
{
  "component": true
}

新建 message.wxml 文件定义消息组件界面结构。

<!-- message.wxml -->
<view class="message-wrap">
  <view class="message-list">
    <view
      class="message-list-item"
      wx:for="{{list}}"
      wx:key="index"
      wx:for-item="item"
    >
      <text style="color: khaki">{{item.name}}:</text>
      <text style="margin-left: 8px; color: {{item.color}}"
        >{{item.content}}</text
      >
    </view>
    <view class="message-input">
      <input placeholder="聊两句..." placeholder-style="color: #fff" />
    </view>
  </view>
</view>

新建 message.wxss 文件定义消息组件样式。

/* message.wxss */
.message-wrap {
  position: absolute;
  left: 0;
  bottom: 0;
  padding: 16px 8px;
}

.message-list {
  max-width: 80%;
}

.message-list-item,
.message-input {
  font-size: 12px;
  padding: 4px 8px;
  background-color: rgba(0, 0, 0, 0.5);
  border-radius: 6px;
  margin-top: 8px;
  width: fit-content;
}

.message-input {
  color: #fff;
  width: 100px;
}

新建 message.js 文件定义消息组件逻辑和行为。

// message.js
Component({
  data: {
    list: [
      {
        name: '温馨提示',
        color: 'khaki',
        content:
          '欢迎来到直播间!如直播间出现违法违规、色情低俗、抽烟喝酒、诱导欺诈行为,请及时举报。管理员 24 小时在线巡查并接受举报,感谢你与平台一起努力,守护我们共同的社区',
      },
      {
        name: '用户B',
        color: '#fff',
        content: '你好,我是用户B!',
      },
      {
        name: '主播',
        color: '#fff',
        content: '@用户B 欢迎来到我的直播间',
      },
    ],
  },
});