之前的案例只支持图片的播放,经过粉丝的反馈说视频弄不出来,本节内容就教大家怎么做
首先看下效果图
页面布局
主要思路就是使用小程序提供的cover-view 和 cover-image 标签来做,在视频上面做绝对定位
这边有个坑大家要注意: 视频属性的最好都用 {{}} 扩起来,只是写false 或者 true 是不起效果的
<view class="page-body" animation="{{animationData}}">
<video id='myVideo' src='{{subject.coverUrl}}' controls="{{show}}" show-center-play-btn='{{show}}' show-play-btn='{{show}}' class='canvas' show-progress='{{show}}' loop='{{true}}' objectFit='cover' autoplay='{{autoplay}}' enable-progress-gesture='{{show}}' bindtouchstart='touchstart'
bindtouchmove='touchmove' bindtouchend='touchend' bindtouchcancel='touchcancel' bindtap='play' bindtimeupdate='timeupdate' bindplay='bindPlay' bindpause='bindPause' bindended='bindEnded'>
<!-- 右侧区域 -->
<cover-view class="tools">
<cover-view>
<cover-image class="userinfo-avatar" src="{{subject.avatarUrl}}"></cover-image>
</cover-view>
<cover-view>
<cover-image wx:if="{{subject.like}}" class="icon right-icon" src='/image/like_red.png' bindtap='like'>喜欢</cover-image>
<cover-image wx:if="{{!subject.like}}" class="icon right-icon" src='/image/like.png' bindtap='like'>喜欢</cover-image>
<cover-view class="text" bindtap='like'>{{subject.likes}}</cover-view>
</cover-view>
<cover-view>
<cover-image class="icon right-icon" src='/image/talk.png' bindtap='talk'>评论</cover-image>
<cover-view class="text" bindtap='apply'>{{subject.talks}}</cover-view>
</cover-view>
<cover-view>
<cover-image class="icon right-icon" src='/image/share.png' bindtap='share'>分享</cover-image>
<cover-view class="text">{{subject.shares}}</cover-view>
</cover-view>
</cover-view>
<!-- 暂停播放按钮 -->
<cover-view class='icon-box' bindtap='play'>
<cover-image class="icon-play" src='/image/play.png' hidden='{{isPlay}}'></cover-image>
</cover-view>
<!-- 进度条 -->
<cover-view class="jindu-back"></cover-view>
<cover-view class="jindu" style='width: {{percent}}%'></cover-view>
<!-- 描述 -->
<cover-view class="desc">
<cover-view>
<cover-view class="desc-text">{{subject.title}}</cover-view>
</cover-view>
</cover-view>
<!-- 底部 -->
<cover-view class="footer">
<cover-view class='apply'>
<cover-image class="icon" src='/image/add.png' bindtap='apply'></cover-image>
</cover-view>
</cover-view>
</video>
</view>
样式布局
思路很简单,把视频铺满全屏后,把内部的元素都定位好就可以了
page {
width: 100%;
height: 100%;
}
.page-body {
width: 100%;
height: 100%;
}
video {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
border: 0;
display: block;
}
/* 播放按钮 */
.icon-box {
position: relative;
margin: 0 auto;
width: 200rpx;
height: 100%;
}
.icon-play {
position: absolute;
display: block;
top: 50%;
transform: translate(0, -50%);
width: 200rpx;
height: 200rpx;
}
/* 进度条 */
.jindu {
position: absolute;
bottom: 110rpx;
height: 5rpx;
background-color: white;
}
.jindu-back {
position: absolute;
bottom: 110rpx;
width: 100%;
height: 5rpx;
background-color: gray;
}
/* 刷新按钮 */
.reload {
position: absolute;
left: 5rpx;
top: 10rpx;
height: 100px;
}
/* 右侧区域 */
.tools {
display: flex;
position: absolute;
right: 5rpx;
top: 250rpx;
height: 300px;
flex-direction: column;
}
/* 头像 */
.userinfo-avatar {
width: 100rpx;
height: 100rpx;
margin: 20rpx;
border-radius: 50%;
}
.icon {
width: 100rpx;
height: 100rpx;
}
.right-icon {
margin: 20rpx 20rpx 0rpx;
}
.text {
color: white;
width: 100rpx;
text-align: center;
margin: 0rpx 20rpx;
}
.desc {
position: absolute;
left: 20rpx;
bottom: 158rpx;
width: 600rpx;
}
.desc-text {
color: white;
white-space: pre-line;
}
/* 底部区域 */
.footer {
position: absolute;
bottom: 10rpx;
width: 100%;
}
.apply {
position: relative;
margin: 0 auto;
width: 100rpx;
color: #ff2c37;
}
/* 评论区域 */
.talks-layer {
position: absolute;
bottom: -100%;
height: 0;
width: 100%;
overflow: hidden;
/* background-color: blue; */
}
.layer-white-space {
height: 100%;
width: 100%;
/* background-color: green; */
}
.talks {
position: absolute;
height: 900rpx;
width: 100%;
bottom: 0rpx;
background-color: #2f2d2e;
border-top-left-radius: 5%;
border-top-right-radius: 5%;
/* background-color: red; */
}
.talk-header {
width: 100%;
height: 70rpx;
padding-top: 30rpx;
text-align: center;
}
.talk-body {
height: 700rpx;
}
.talk-footer {
position: absolute;
bottom: 0rpx;
width: 100%;
height: 100rpx;
background-color: #151515;
}
/* 顶部元素 */
.talk-count {
font-size: 0.8rem;
height: 40rpx;
color: #6b696a;
}
.talk-close {
position: absolute;
top: 40rpx;
right: 40rpx;
width: 40rpx;
height: 40rpx;
}
/* 中部元素 */
.talk-item {
display: flex;
flex-direction: row;
align-items: flex-start;
width: 100%;
color: white;
}
.talk-item-left {
display: flex;
flex-direction: row;
margin: 20rpx 30rpx;
}
.talk-item-face {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
}
.talk-item-right {
width: 100%;
border-bottom: solid 1rpx #6a6869;
margin-right: 30rpx;
margin-bottom: 30rpx;
}
.talk-item-nickname {
font-size: 0.7rem;
color: #aaa8a9;
margin-top: 20rpx;
margin-bottom: 10rpx;
}
.talk-item-content {
display: block;
margin-right: 30rpx;
width: 100%;
white-space: pre-line;
}
.talk-item-time {
font-size: 0.7rem;
color: #6a6869;
margin-bottom: 20rpx;
}
/* 底部元素 */
.talk-input {
width: 100%;
padding: 20rpx 40rpx;
color: white;
border-top-left-radius: 5%;
border-top-right-radius: 5%;
}
完整 js 代码
const app = getApp()
const api = require('../../utils/api.js')
var start;
Page({
/**
* 页面的初始数据
*/
data: {
show: false,
autoplay: true,
videoContext: null,
percent: 0,
isPlay: true,
count: 0,
pages: 0,
page: 1,
subject: {},
current: 0,
subjectList: [],
userInfo: {},
hasUserInfo: false,
inputTalk: '',
talks: [],
talksPage: 1,
talksPages: -1,
canIUse: wx.canIUse('button.open-type.getUserInfo'),
talksAnimationData: {}
},
changeSubject: function (current) {
current = current || 0;
var list = this.data.subjectList;
if (list.length <= current) {
return;
}
this.setData({
current: current,
subject: list[current]
})
// 自动加载
var diff = list.length - current;
if (diff <= 5) {
this.loadData(this.data.page + 1);
}
},
like: function (e) {
// 验证用户信息
if (!this.checkUserInfo()) return;
var subject = this.data.subject;
subject.like = true;
subject.likes = subject.likes + 1;
this.setData({
subject: subject
})
api.like({
subjectId: subject.subjectId
})
},
apply: function (e) {
wx.showToast({
icon: 'none',
title: "暂时还不能发布视频呦",
})
},
checkUserInfo: function () {
if (!app.globalData.userInfo) {
wx.showModal({
content: '请先授权访问你的基本信息',
success: function (res) {
if (res.confirm) {
wx.navigateTo({
url: 'getuserinfo',
})
}
}
})
return false;
}
return true;
},
talk: function (e) {
wx.showToast({
icon: 'none',
title: "敬请期待",
})
},
share: function (e) {
wx.showToast({
icon: 'none',
title: "敬请期待",
})
},
loadData: function (page, success) {
var that = this;
this.setData({
page: page
})
api.getRecommendList({
data: {
page: page,
rows: 5,
type: 'video'
},
success: function (res) {
var list = res.content;
if (list){
var listData = [];
for (var i = 0; i < that.data.subjectList.length; i++) {
listData.push(that.data.subjectList[i])
}
for (var i = 0; i < list.length; i++) {
listData.push(list[i])
}
that.setData({
count: res.count,
page: page,
pages: res.pages,
subjectList: listData
})
if (success) {
success();
}
}
}
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
var that = this;
// 登录回调
if (app.globalData.isLogin) {
that.loadData(1, that.changeSubject)
} else {
app.onLogin = function () {
that.loadData(1, that.changeSubject)
}
}
// 获取用户信息
if (app.globalData.userInfo) {
this.setData({
userInfo: app.globalData.userInfo,
hasUserInfo: true
})
} else if (this.data.canIUse) {
// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
// 所以此处加入 callback 以防止这种情况
app.onUserInfo = userInfo => {
that.setData({
userInfo: userInfo,
hasUserInfo: true
})
}
}
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
// 初始化播放器上下文
this.videoContext = wx.createVideoContext('myVideo')
wx.setNavigationBarTitle({
title: "微抖音",
})
},
// 视频播放时间更新
timeupdate: function (e) {
var val = e.detail.currentTime;
var max = e.detail.duration;
var percent = Math.round(val / max * 10000) / 100;
this.setData({ percent: percent })
},
// 点击播放按钮
play: function () {
if (this.data.isPlay) {
this.videoContext.pause();
} else {
this.videoContext.play()
}
},
// 开始播放
bindPlay: function () {
this.setData({ isPlay: true })
},
// 暂停播放
bindPause: function () {
this.setData({ isPlay: false })
},
// 播放完毕
bindEnded: function () {
this.setData({ isPlay: false })
},
// 播放上一个抖音
pre: function () {
this.changeSubject(this.data.current - 1);
},
// 播放下一个抖音
next: function () {
this.changeSubject(this.data.current + 1);
},
// 下面主要模仿滑动事件
touchstart: function (e) {
start = e.changedTouches[0];
// console.log("touchstart ", e.changedTouches[0])
},
touchmove: function (e) {
// console.log("touchmove ", e.changedTouches[0])
},
touchend: function (e) {
// console.log("touchend ", e.changedTouches[0])
this.getDirect(start, e.changedTouches[0]);
},
touchcancel: function (e) {
// console.log("touchcancel ", e.changedTouches[0])
this.getDirect(start, e.changedTouches[0]);
},
// 计算滑动方向
getDirect(start, end) {
var X = end.pageX - start.pageX,
Y = end.pageY - start.pageY;
if (Math.abs(X) > Math.abs(Y) && X > 0) {
console.log("left 2 right");
}
else if (Math.abs(X) > Math.abs(Y) && X < 0) {
console.log("right 2 left");
}
else if (Math.abs(Y) > Math.abs(X) && Y > 0) {
console.log("top 2 bottom");
this.pre()
}
else if (Math.abs(Y) > Math.abs(X) && Y < 0) {
console.log("bottom 2 top");
this.next()
}
}
})
更多内容请到官网https://100boot.cn的这里下载
更多精彩内容
微信小程序电商实战-入门篇
微信小程序电商实战-首页(上)
微信小程序电商实战-首页(下)
微信小程序电商实战-商品详情(上)
微信小程序电商实战-商品详情加入购物车(下)
微信小程序电商实战-商品列表流式布局
微信小程序实战篇:基于wxcharts.js绘制移动报表
微信小程序实战篇:实现抖音评论效果
微信小程序抖音实战-首页(上)
微信小程序实战篇:抖音案例使用手册
微信小程序抖音实战-首页(下)
微信小程序营销之大转盘(二)
关注我们
IT实战联盟是集产品、UI设计、前后端、架构、大数据和AI人工智能等为一体的实战交流服务平台!联盟嘉宾都为各互联网公司项目的核心成员,联盟主旨是“让实战更简单”,欢迎来撩~~~
注意:本文归作者所有,未经作者允许,不得转载