app/components/vlog/tuijian.nvue

1365 lines
43 KiB
Plaintext
Raw Normal View History

2025-04-25 18:10:54 +08:00
<template>
<view class="container">
<image
v-if="isShowAixin"
src="@/static/img/index/aixining.png"
:style="'position: fixed; margin-left: ' + aixinLeft + 'px; margin-top: ' + aixinTop + 'px; width: 70px; height: 65px; transform: rotate(' + Rotate + 'deg);'"
></image>
<view
:style="'width: ' + windowWidth + 'px; height: ' + boxStyle.height + 'px;'"
v-if="isShow1"
>
<list
@scroll="scrolls"
:show-scrollbar="false"
ref="videoComp"
:pagingEnabled="true"
:scrollable="true"
>
<!-- 刷新模块 -->
<!-- <refresh
class="refresh"
@refresh="onrefresh"
@pullingdown="onpullingdown"
:display="refreshing ? 'show' : 'hide'"
>
<loading style="background-color: #ffffff">
<image
src="@/static/img/index/logins.gif"
:style="'width: 80upx; height: 40upx; margin-top: 80upx; margin-bottom: 30upx; margin-left: ' + (windowWidth - 200) + 'px;'"
></image>
</loading>
</refresh> -->
<!-- 循环数据 -->
<cell
v-for="(item, i) in dataList"
:key="i"
>
<!-- 用div把视频模组套起来 -->
<view
:style="'width: ' + windowWidth + 'px; height: ' + boxStyle.height + 'px;'"
:ref="'item' + i"
>
<image
v-if="k !== i"
:src="item.firstFrameImg"
:mode="item.width >= item.height ? 'aspectFit' : 'scaleToFill'"
:style="'width: ' + windowWidth + 'px; height: ' + boxStyle.height + 'px; position: absolute;'"
></image>
<view v-if="k - i <= 1">
<view class="root">
<!--
具体视频参数可以参考官方文档
说明:
1.v-if很关键这里主要是为了减少 dom 元素【这样才不会加载视频多了闪退】,
这里 Math.abs(k-i)<=5 也就是往上预加载 5 个视频,往下预加载 5
个视频这样做的目的是为了让视频能够提前加载但是不播放,在真正滑到位
置的时候播放视频。
【2.0.1就是 1 Math.abs(k-i)<=1请勿修改记住要不然会提前播放很多视频】
2.要注意 @play="playIngs" 里面的 playIngs 方法,这个方法只是在视频播放的时候
起效果,我们控制视频播放不是用这个的。这个的主要作用是给视频封面的。我们先用
下面的视频封面盖住视频,等到视频播放的时候,我们不要急着直接播放,而是延迟一下下,
300-600ms左右。因为视频播放需要一点点时间这点时间里会黑屏这个时候我们就用
下面的封面盖住,这样用户就不会有从黑屏到有画面的感觉了,但是如果遇到视频太大,缓冲
时间太长,还是会出现短暂的黑屏,大部分是不会有黑屏的(这样盖住的话)。
【更新记录2.0版】已经解决了视频黑屏问题,和加载速度慢的情况,如果还是出现了黑屏,
意味着此时手滑动的速度,已经超过了视频加载的速度,对于这个问题,建议修改 preloadNumber
变量,当它的值大一点的时候就会提前加载视频,这样用户在滑到视频的时候就不会有停顿感了
【注意】:老用户在 video 中增加和修改
1:muted="!item.playIng"
2@timeupdate="timeupdate($event,i)"
3把 199 行注释了,
4:id="item.id"
5修改uni.createVideoContext(this.dataList[this.k].id + '' + this.k,this) 为
uni.createVideoContext(this.dataList[this.k].id,this)
6在 timeupdate 方法里加入if(index == this.k){把里面的加一个总的判断}
3.其他的下面有详解
-->
<video
:id="item.id"
:loop="true"
:src="item.url"
:muted="item.isplay"
@play="playIngs(i)"
:enable-progress-gesture="false"
:page-gesture="false"
:controls="false"
:http-cache="true"
:show-loading="false"
:show-fullscreen-btn="false"
:show-center-play-btn="false"
:style="boxStyle"
2025-05-07 17:45:16 +08:00
:object-fit="item.width >= item.height ? 'contain' : 'cover'"
2025-04-25 18:10:54 +08:00
@timeupdate="timeupdate($event, i)"
:poster="item.firstFrameImg"
></video>
2025-05-07 17:45:16 +08:00
<!-- 这里是封面 26是进度条的高度 -->
2025-04-25 18:10:54 +08:00
<image
v-if="!item.playIng"
:src="item.firstFrameImg"
2025-05-07 17:45:16 +08:00
:mode="item.width >= item.height ? 'aspectFit' : 'aspectFit'"
:style="'width: ' + windowWidth + 'px; height: ' + boxStyle.height + 26 + 'px; position: absolute;'"
2025-04-25 18:10:54 +08:00
></image>
<!--
mode: 图片裁剪、缩放的模式
mode 有 14 种模式,其中 5 种是缩放模式9 种是裁剪模式。
https://uniapp.dcloud.io/component/image
-->
</view>
<!-- 直接用 view 就行了,一样是可以覆盖原生组件的 -->
<!-- 这个是暂停时出现的图标 -->
<view
class="videoHover"
@click="tapVideoHover(item.state, $event)"
@touchstart="touchstartHover"
:style="boxStyle"
>
<image
v-if="item.state == 'pause'"
class="playState"
src="@/static/img/index/play.png"
></image>
</view>
<view class="userInfo">
<!-- 1.头像 -->
<view class="touxbox">
<image
v-if="item.isShowProgressBarTime == false"
@click="tozuozhe(item.vlogerId)"
class="userAvatar"
:src="item.vlogerFace"
mode="aspectFill"
></image>
<!-- 1.1 头像下面的加号 -->
<!-- v-if="!item.doIFollowVloger && userId != thisVlogerId" -->
<image
v-if="!item.doIFollowVloger && userId != item.vlogerId"
src="/static/images/icon-follow.png"
class="follow-me"
@click="followMe(item.vlogerId)"
></image>
</view>
<!-- 2.点赞 -->
<view
v-if="item.isShowProgressBarTime == false"
@click="cLike(item.like)"
style="opacity: 0.9; margin-top: 17px"
>
<image
v-if="item.doILikeThisVlog"
@click="likeOrDislikeVlog(item)"
src="@/static/img/index/xin.png"
style="width: 40px; height: 40px; position: absolute; right: 6px"
></image>
<image
v-if="!item.doILikeThisVlog"
@click="likeOrDislikeVlog(item)"
src="@/static/img/index/xin-2.png"
style="width: 40px; height: 40px; position: absolute; right: 6px"
></image>
<text
style="color: #ffffff; margin-top: 5px; font-size: 14px; text-align: center; margin-top: 40px; font-weight: bold"
:class="{ likeNumActive: item.doILikeThisVlog }"
>
{{ getGraceNumber(item.likeCounts) }}
</text>
</view>
<!-- 3.评论 -->
<view
v-if="item.isShowProgressBarTime == false"
class="comment"
@click="toComment(item)"
style="opacity: 0.9; margin-top: 17px"
>
<image
src="/static/images/icon-comments.png"
style="width: 35px; height: 35px; position: absolute; right: 7px"
></image>
<text style="color: #ffffff; margin-top: 5px; font-size: 14px; font-weight: bold; text-align: center; margin-top: 40px">
{{ getGraceNumber(item.commentsCounts) }}
</text>
</view>
<!-- 4.分享 -->
<view
v-if="item.isShowProgressBarTime == false"
2025-04-30 14:28:07 +08:00
@click="share(item)"
2025-04-25 18:10:54 +08:00
style="opacity: 0.9; margin-top: 17px"
>
<image
src="@/static/img/index/share-fill.png"
style="width: 40px; height: 40px; position: absolute; right: 5px"
></image>
<text style="color: #ffffff; margin-top: 5px; font-size: 14px; text-align: center; font-weight: bold; margin-top: 40px">分享</text>
</view>
2025-05-14 04:25:36 +08:00
<!-- 5.举报 -->
<view
v-if="item.isShowProgressBarTime == false"
@click="toJubao(item)"
style="opacity: 0.9; margin-top: 17px"
>
<image
src="@/static/img/jubao.png"
style="width: 40px; height: 40px; position: absolute; right: 5px"
></image>
<text style="color: #ffffff; margin-top: 5px; font-size: 14px; text-align: center; font-weight: bold; margin-top: 40px">举报</text>
</view>
<!-- 6.转轮 -->
2025-04-25 18:10:54 +08:00
<block v-if="platform == 'ios' && false">
<view
v-if="item.isShowProgressBarTime == false"
@click="dealVoice"
style="margin-top: 17px"
>
<view style="width: 48px; height: 48px; border-radius: 50px; position: absolute; right: 2.5px">
<image
:style="'width: 48px; height: 48px; border-radius: 50px; transform: rotate(' + rotates + 'deg);'"
src="@/static/img/index/bfq.png"
mode="aspectFill"
></image>
<!-- 这里放所用音乐的图 -->
<image
v-if="showPlay"
:style="
'width: 30px; height: 30px; margin-top: 9px; margin-left: 9px; position: absolute; border-radius: 50px; transform: rotate(' +
rotates +
'deg);'
"
:src="item.vlogerFace"
mode="aspectFill"
></image>
</view>
</view>
<view
v-if="platform == 'ios'"
style="margin-top: 48px"
></view>
</block>
<block v-if="platform !== 'ios' && false">
<view
v-if="item.isShowProgressBarTime == false"
@click="dealVoice"
style="margin-top: 15px; width: 48px; height: 48px"
>
<text style="font-size: 0.1px; opacity: 0">.</text>
<view style="width: 48px; height: 48px; border-radius: 50px; position: absolute">
<image
:style="'width: 48px; height: 48px; border-radius: 50px; transform: rotate(' + rotates + 'deg);'"
src="@/static/img/index/bfq.png"
mode="aspectFill"
></image>
<image
v-if="showPlay"
:style="
'width: 30px; height: 30px; margin-top: 9px; margin-left: 9px; position: absolute; border-radius: 50px; transform: rotate(' +
rotates +
'deg);'
"
:src="item.vlogerFace"
mode="aspectFill"
></image>
</view>
</view>
</block>
</view>
<!-- 最底下的文字部分 -->
<view
class="content"
v-if="dataList.length !== 0 && dataList[k].isShowProgressBarTime == false"
>
<text
class="userName"
:style="'width: ' + (windowWidth - 90) + 'px;'"
>
{{ item.vlogerName }}
</text>
<!-- i={{i}} -->
<text
class="words"
:style="'width: ' + (windowWidth - 90) + 'px;'"
>
{{ item.content }}
</text>
<!-- -{{ k + 1 }} -->
</view>
<!-- 1.视频预览时的图片currenttimes就是获取当前滑块的时间点如果不需要可以注释掉 -->
<!-- 2.如果使用下面的视频预览的话要注意的是视频链接最好是阿里云上的,因为
https://xxxxxxxxx.mp4?x-oss-process=video/snapshot,t_1000,f_jpg
这个是阿里云的东西,至于其他的视频截帧我还没有试过。
-->
<!-- 3.阿里云视频截帧地址https://help.aliyun.com/document_detail/64555.html -->
<!-- 这里放雪碧图,这版先不弄 -->
<!--
<image
v-if="item.isShowimage == true"
:src="item.firstFrameImg"
mode="aspectFill"
:style="
'width: 120upx; height: 160upx; border-radius: 10upx; position: absolute; bottom: ' +
(ProgressBarBottom + 160) +
'upx; left: ' +
(currentPositions - 15) +
'px;'
"
></image>
-->
</view>
</view>
</cell>
</list>
<!-- 1.注意进度条这类拖拽的东西不能放进block\cell这些循环体中的要不然touchmove方法会捕捉有误 -->
<view
v-if="dataList.length !== 0 && dataList[k].isShowProgressBarTime == true"
:style="'position: absolute; bottom: ' + (ProgressBarBottom + this.windowWidth * 0.2) / 2 + 'px; left: ' + (windowWidth * 2 - this.windowWidth * 1.35) / 2 + 'px;'"
>
<text style="font-size: 22px; font-weight: bold; color: #f1f1f1">{{ changeTime }} / {{ videoTimes }}</text>
</view>
<!-- 这里就是进度条了:纯手工进度条,调整位置的话就把他们的 bottom 改成一下就行了 -->
<view
v-if="isDragging == false"
@touchmove="touchmove"
@touchend="touchend"
@touchstart="touchstart"
:style="{ bottom: 0 + 'px', position: 'absolute', left: 0 }"
>
<!-- 1.这一步必须加,为了适配低端机型 -->
<text :style="'width: ' + windowWidth + 'px; opacity: 0;'">.</text>
<!-- 2.这是未加载的时的右边的灰色部分 -->
<view
:style="
'width: ' +
windowWidth +
'px; height: 4upx; background-color: #C8C7CC; position: absolute; bottom: ' +
ProgressBarBottom +
'upx; opacity: ' +
ProgressBarOpacity +
';'
"
></view>
<!-- 3.这里我采用的分离式办法:就是让滑动样式和不滑动的样式分开,这样相互不干扰,可以避免进度条闪动的问题 -->
<!-- 4.注意isShowProgressBarTime 加入了返回数据中 -->
<view
v-if="dataList.length !== 0 && dataList[k].isShowProgressBarTime == false"
:style="
'width: ' +
currentPosition +
'px; height: 4upx; background-color: #FFFFFF; position: absolute; bottom: ' +
ProgressBarBottom +
'upx; left: 0; opacity: ' +
(ProgressBarOpacity - 0.1) +
';'
"
></view>
<view
v-if="dataList.length !== 0 && dataList[k].isShowProgressBarTime == true"
:style="
'width: ' +
currentPositions +
'px; height: 8upx; background-color: #FFFFFF; position: absolute; bottom: ' +
ProgressBarBottom +
'upx; left: 0; opacity: ' +
(ProgressBarOpacity + 0.05) +
';'
"
></view>
<view
v-if="dataList.length !== 0 && dataList[k].isShowProgressBarTime == false"
:style="
'width: 4px; height: 4px; background-color: #FFFFFF; border-radius: 10px; position: absolute; bottom: ' +
(ProgressBarBottom - 2) +
'upx; left: ' +
currentPosition +
'px; opacity: ' +
ProgressBarOpacity +
';'
"
></view>
<view
v-if="dataList.length !== 0 && dataList[k].isShowProgressBarTime == true"
:style="
'width: ' +
dotWidth +
'px; height: ' +
dotWidth +
'px; background-color: #FFFFFF; border-radius: 10px; position: absolute; bottom: ' +
(ProgressBarBottom - 5) +
'upx; left: ' +
(currentPositions - 5) +
'px; opacity: ' +
ProgressBarOpacity +
';'
"
></view>
</view>
</view>
<!-- 评论 -->
<view>
<!-- 底部窗口popup -->
<uni-popup
ref="pinglun"
type="comment"
>
<uni-popup-comments
:thisVlogerId="pinglunInfo.vlogerId"
:thisVlogId="pinglunInfo.vlogId"
2025-05-04 03:37:34 +08:00
:from="'tuijian'"
2025-04-25 18:10:54 +08:00
></uni-popup-comments>
</uni-popup>
<!-- 分享 -->
<uni-popup
ref="share"
background-color="#fff"
type="share"
>
<uni-popup-share
:thisVlogerId="pinglunInfo.vlogerId"
:thisVlogId="pinglunInfo.vlogId"
:vlogUrl="pinglunInfo.url"
:isPrivate="pinglunInfo.isPrivate"
2025-04-30 14:28:07 +08:00
:vlogItem="pinglunInfo"
2025-04-25 18:10:54 +08:00
></uni-popup-share>
</uni-popup>
</view>
</view>
</template>
<script>
import storage from '@/utils/storage.js'; //缓存
2025-05-07 17:45:16 +08:00
import { graceNumber, clickFeedBack } from '@/utils/tools.js';
2025-04-25 18:10:54 +08:00
import api from '@/config/api.js';
2025-05-07 17:45:16 +08:00
import { vlogList, vlogLike, vlogUnLike, vlogComment, vlogFollow, vlogTotalLikedCounts, vlogQueryDoIFollowVloger, vlogDetail } from '@/api/vlog';
2025-04-25 18:10:54 +08:00
/*
引入评论组件
*/
// import douyinScrollview from '@/components/douyin-scrollview/douyin-scrollview.nvue';
export default {
data() {
return {
//下面打🌟号的是必须要的基础字段
//下面打💗号的是拥有滑动条的必须字段
dataList: [], //用于数据循环的列表🌟💗
wHeight: 0, //获取的屏幕高度🌟💗
boxStyle: {
//视频,图片封面样式🌟💗
height: 0,
width: 0
},
Heights: 0,
k: 0, //默认为0🌟💗
playIngIds: [], //正在播放的视频id列队列队用于处理滑动过快导致的跳频问题🌟💗
ready: false, //可忽略
isDragging: false, //false代表停止滑动🌟💗
refreshing: true, //用于下拉刷新🌟💗
windowWidth: 0, //获取屏幕宽度🌟💗
windowHeight: 0,
dex: [0, 0], //用于判断是上滑还是下滑第一个存旧值第二个存新值【目前在1.0.7已经废弃】
currents: 0, //用于左右滑动0代表视频界面1代表右滑界面🌟💗
platform: '', //用于获取操作系统ios、android🌟💗
playIng: false, //用于视频初始化时是否播放,默认不播放🌟💗
videoTime: '', //视频总时长,这个主要用来截取时间数值💗
videoTimes: '', //视频时长用这个来获取时间值例如00:30这个时间值💗
changeTime: '', //显示滑动进度条时变化的时间💗
isShowimage: false, //是否显示封面【1.0.4已废弃,但是意思需要记住】
currenttimes: 0, //当前时间💗
isShowProgressBarTime: false, //是否拖动进度条如果拖动true则显示进度条时间否则不显示false【1.0.4已废弃,但是意思需要记住】
ProgressBarOpacity: 0.7, //进度条不拖动时的默认值,就是透明的💗
dotWidth: 0, //播放的小圆点,默认没有💗
deleteHeight: 0, //测试高度🌟💗
percent: 0, //百分小数💗
currentPosition: 0, //滑块当前位置💗//2.0已弃用,现已用于后端参数
currentPositions: 0, //滑块当前位置的副本💗//2.0已弃用,现已用于后端参数
newTime: 0, //跟手滑动后的最新时间💗
timeNumber: 0, //🌟💗
ProgressBarBottom: 0, //进度条离底部的距离💗
object_fit: 'contain', //视频样式默认包含🌟💗
mode: 'aspectFit', //图片封面样式🌟💗
timeout: '', //🌟用来阻止 setTimeout()方法
voice: '', //🌟用来阻止 setTimeout()方法
oldVideo: '',
isAutoplay: false, //是否开启自动播放(默认不开启)
autoplayText: '开启自动播放',
timers: '',
// 引入评论 - 参数
heightNum: 1.18,
// 双击点赞参数
touchNum: 0,
aixinLeft: 0,
aixinTop: 0,
isShowAixin: false,
Rotate: 0,
isShow1: false, //控制渲染变量1
isShow2: false, //控制渲染变量2 专门控制 uni-popup
showPlay: false, //转轮显示控制
rotates: 0, //转轮旋转角度
rotateTime: '', //转轮递归事件控制
xrotats: '',
player: '',
// 新增内容
page: 1,
2025-05-04 03:37:34 +08:00
channel: null, // 处理进度条
channelComment: null, // 处理评论数量显示
2025-04-25 18:10:54 +08:00
userId: '',
pinglunInfo: {
vlogerId: '', // 博主id
vlogId: '', // 视频id
url: '',
isPrivate: 0
}
};
},
// components: {
// douyinScrollview
// },
watch: {
k(k, old_k) {
//监听 k 值的变化,可以控制视频的播放与暂停
console.log(k);
// 清理定时器
this.clearToTime();
this.dataList[old_k].playIng = false; //如果视频暂停,就加载封面
this.dataList[old_k].isplay = true;
uni.createVideoContext(this.dataList[old_k].id, this).play();
clearTimeout(this.oldVideo);
this.oldVideo = setTimeout(() => {
uni.createVideoContext(this.dataList[old_k].id, this).seek(0);
uni.createVideoContext(this.dataList[old_k].id, this).pause();
console.log('预留第' + (old_k + 1) + '个视频:' + this.dataList[old_k].id);
}, 500);
this.dataList[k].state = 'play';
console.log('已经暂停 --> 第' + (old_k + 1) + '个视频~'); //提示
clearTimeout(this.player);
this.player = setTimeout(() => {
uni.createVideoContext(this.dataList[k].id, this).play();
}, 50);
if (k == this.dataList.length - 1) {
(async () => {
await this.getData();
var p = k;
++p;
this.dataList[p].isplay = true;
setTimeout(() => {
uni.createVideoContext(this.dataList[p].id, this).play();
clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
uni.createVideoContext(this.dataList[p].id, this).seek(0);
uni.createVideoContext(this.dataList[p].id, this).pause();
console.log('预加载第' + (p + 1) + '个视频:' + this.dataList[p].id);
}, 1500);
}, 20);
})();
}
//【此处处理进度条卡住的问题】
if (uni.getSystemInfoSync().platform !== 'ios') {
setTimeout(() => {
uni.createVideoContext(this.dataList[k].id, this).pause();
uni.createVideoContext(this.dataList[k].id, this).play();
}, 100);
}
this.xrotats = setTimeout(() => {
this.showPlay = true;
this.rotateX();
}, 200);
}
},
// created() {
// this.channel = new BroadcastChannel('video-progress');
// },
created() {
this.channel = new BroadcastChannel('video-progress');
2025-05-04 03:37:34 +08:00
this.channelComment = new BroadcastChannel('comment-counts');
this.channelComment.onmessage = (event) => {
const { type, data } = event.data;
if (type == 'comment-counts') {
2025-05-07 17:45:16 +08:00
// 刷新评论数据,点赞数据
2025-05-04 03:37:34 +08:00
if (data.from == 'tuijian') {
this.refreshVlogCounts();
this.freshCommentCounts();
}
2025-05-07 17:45:16 +08:00
// 刷新当前视频关注的状态
if (data.from == 'refresh') {
console.log('刷新推荐列表关注状态');
this.reFollowPlayList(data.vlogerId, data.flag);
}
// 刷新点赞状态
if (data.from == 'refreshLike') {
console.log('触发刷新点赞状态');
// 刷新点赞状态
this.refreshLike(data.vlogId, data.flag);
// 刷新点赞数据
this.refreshVlogCounts();
}
2025-05-14 04:25:36 +08:00
// 初始化视频数据,处理举报
if (data.init == 'tuijian') {
console.log('触发初始化视频数据');
this.get();
}
// 处理拉黑
if (data.lahei == true) {
console.log('触发初始化视频数据');
this.init();
}
2025-05-04 03:37:34 +08:00
}
};
2025-04-25 18:10:54 +08:00
this.platform = uni.getSystemInfoSync().platform;
var model = uni.getSystemInfoSync().model;
if (this.platform == 'ios' && (model !== 'iPhone6' || model !== 'iPhone6s' || model !== 'iPhone7' || model !== 'iPhone8')) {
2025-05-07 17:45:16 +08:00
this.deleteHeight = 0; //有 tabbar的 修改这里可以改变视频高度
// this.deleteHeight = uni.getSystemInfoSync().statusBarHeight + 26; //进度条高度16点高度10,默认50
2025-04-25 18:10:54 +08:00
/*
引入评论参数
*/
this.heightNum = 1.27;
} else {
2025-05-07 17:45:16 +08:00
// this.deleteHeight = 50 + 16;
this.deleteHeight = 0;
// this.deleteHeight = uni.getSystemInfoSync().statusBarHeight + 16; // 安卓只处理进度条高度10
2025-04-25 18:10:54 +08:00
/*
引入评论参数
*/
this.heightNum = 1.18;
}
// 控制渲染 -- start
this.isShow1 = true;
setTimeout(() => {
this.isShow2 = true;
}, 400);
// 控制渲染 -- end
this.windowWidth = uni.getSystemInfoSync().screenWidth; //获取屏幕宽度
this.boxStyle.width = this.windowWidth + 'px'; //给宽度加px
2025-05-07 17:45:16 +08:00
// this.wHeight = uni.getSystemInfoSync().screenHeight; //获取屏幕高度
this.wHeight = uni.getSystemInfoSync().windowHeight; //获取屏幕可用高度
console.log(uni.getSystemInfoSync());
2025-04-25 18:10:54 +08:00
console.log(this.wHeight);
this.boxStyle.height = this.wHeight - this.deleteHeight; //改变视频高度
console.log(this.boxStyle);
this.get(); //这一步,加载视频数据
this.rotateX();
},
onReady() {},
methods: {
2025-05-14 04:25:36 +08:00
toJubao(item) {
var myUserInfo = storage.getVlogUserInfo();
if (myUserInfo == null) {
uni.navigateTo({
url: '/pages/passport/login',
animationType: 'slide-in-bottom'
});
return;
}
//举报
uni.navigateTo({
url: `/pages/report/index?vlogId=${item.vlogId}&from=tuijian`
});
},
2025-05-04 03:37:34 +08:00
async refreshVlogCounts() {
// 查询当前点赞数,重新赋值给当前视频
var me = this;
var vlog = me.dataList[this.k];
var result = await vlogTotalLikedCounts(vlog.vlogId);
if (result.data.status == 200) {
var counts = result.data.data;
this.dataList[this.k].likeCounts = counts;
}
},
async freshCommentCounts() {
var me = this;
var vlog = me.dataList[this.k];
var result = await vlogComment(vlog.vlogId);
if (result.data.status == 200) {
var counts = result.data.data;
this.dataList[this.k].commentsCounts = counts;
}
},
2025-04-25 18:10:54 +08:00
// 关注博主
async followMe(vlogerId) {
2025-05-07 17:45:16 +08:00
clickFeedBack();
2025-04-25 18:10:54 +08:00
var myUserInfo = storage.getVlogUserInfo();
if (myUserInfo == null) {
uni.navigateTo({
url: '/pages/passport/login',
animationType: 'slide-in-bottom'
});
return;
}
var userId = myUserInfo.id;
var result = await vlogFollow(userId, vlogerId);
if (result.data.status == 200) {
// 关注成功后修改当前数据的状态
this.dataList[this.k].doIFollowVloger = true;
2025-05-07 17:45:16 +08:00
this.reFollowPlayList(vlogerId, true);
this.channelComment.postMessage({
type: 'comment-counts',
data: { from: 'initGuanzhu' }
});
2025-04-25 18:10:54 +08:00
} else {
uni.showToast({
title: result.data.msg,
icon: 'none',
duration: 3000
});
}
},
2025-05-07 17:45:16 +08:00
// 关注/取消关注,后刷新关注状态
reFollowPlayList(vlogerId, flag) {
var me = this;
var playerList = me.dataList;
// 关注以后循环当前playerList修改对应粉丝关系的doIFollowVloger改为true
for (var i = 0; i < playerList.length; i++) {
var vlog = playerList[i];
if (vlog.vlogerId == vlogerId) {
vlog.doIFollowVloger = flag;
}
}
},
// 点赞取消点赞,后刷新点赞状态
refreshLike(vlogId, flag) {
var me = this;
var playerList = me.dataList;
// 关注以后循环当前playerList修改对应粉丝关系的doIFollowVloger改为true
for (var i = 0; i < playerList.length; i++) {
var vlog = playerList[i];
if (vlog.vlogId == vlogId) {
vlog.doILikeThisVlog = flag;
}
}
},
2025-04-25 18:10:54 +08:00
// 把超过1000或10000的数字调整比如1.3k/6.8w
getGraceNumber(num) {
return graceNumber(num);
},
async likeOrDislikeVlog(item) {
2025-05-07 17:45:16 +08:00
clickFeedBack();
2025-05-02 17:22:45 +08:00
var info = storage.getVlogUserInfo();
if (info != null) {
this.userId = info.id;
}
2025-04-25 18:10:54 +08:00
// 没登录拒绝操作
if (this.userId == '') {
uni.navigateTo({
url: '/pages/passport/login',
animationType: 'slide-in-bottom'
});
return;
}
var isLike = item.doILikeThisVlog;
if (isLike == false) {
// 喜欢
var result = await vlogLike({
userId: this.userId,
vlogerId: item.vlogerId,
vlogId: item.vlogId
});
console.log(result);
if (result.data.status == 200) {
2025-05-07 17:45:16 +08:00
// item.likeCounts++;
2025-04-25 18:10:54 +08:00
item.doILikeThisVlog = !item.doILikeThisVlog;
2025-05-07 17:45:16 +08:00
this.refreshVlogCounts();
2025-04-25 18:10:54 +08:00
} else {
uni.showToast({
title: result.data.msg,
icon: 'none',
duration: 3000
});
}
} else {
// 取消喜欢
var result = await vlogUnLike({
userId: this.userId,
vlogerId: item.vlogerId,
vlogId: item.vlogId
});
if (result.data.status == 200) {
2025-05-07 17:45:16 +08:00
// item.likeCounts--;
this.refreshVlogCounts();
2025-04-25 18:10:54 +08:00
item.doILikeThisVlog = !item.doILikeThisVlog;
} else {
uni.showToast({
title: result.data.msg,
icon: 'none',
duration: 3000
});
}
}
},
// --------------------
showVd() {
console.log('回到前台');
2025-05-07 17:45:16 +08:00
if (this.dataList.length != 0) {
// if (uni.getSystemInfoSync().platform == 'ios') {
// this.dataList[this.k].state = 'play';
// uni.createVideoContext(this.dataList[this.k].id, this).play();
// } else {
// this.dataList[this.k].state = 'play';
// uni.createVideoContext(this.dataList[this.k].id, this).play();
// }
2025-04-25 18:10:54 +08:00
this.dataList[this.k].state = 'play';
uni.createVideoContext(this.dataList[this.k].id, this).play();
}
},
hideVd() {
this.dataList[this.k].state = 'pause'; //界面隐藏也要停止播放视频
uni.createVideoContext(this.dataList[this.k].id, this).pause(); //暂停以后继续播放
console.log('到后台');
},
dealVoice() {
// uni.showToast({
// title: '处理声音',
// icon: 'none'
// });
},
clearToTime() {
//清理定时器
for (let i = 0; i < 20; i++) {
clearTimeout(this.rotateTime);
clearTimeout(this.xrotats);
this.showPlay = false;
this.rotates = 0;
}
},
clearTime() {
//清理定时器
for (let i = 0; i < 20; i++) {
clearTimeout(this.rotateTime);
clearTimeout(this.xrotats);
}
},
rotateX() {
// clearTimeout(this.rotateTime);
this.rotateTime = setTimeout(() => {
this.rotateX();
this.rotates += 1;
}, 30);
},
autoPlay() {
this.isAutoplay = !this.isAutoplay;
if (!this.isAutoplay) {
this.autoplayText = '开启自动播放';
uni.showToast({
title: '关闭自动播放',
icon: 'none',
duration: 3000
});
} else {
this.autoplayText = '关闭自动播放';
uni.showToast({
title: '开启自动播放',
icon: 'none',
duration: 3000
});
}
},
async getData() {
// loadmore
let myUserInfo = storage.getVlogUserInfo();
let userId = '';
if (myUserInfo != null) {
userId = myUserInfo.id;
}
const res = await vlogList(this.page, 10, userId);
console.log(res);
if (res.data.status == 200) {
var msg = res.data.data.rows;
var List = JSON.parse(JSON.stringify(this.dataList));
if (msg.length > 0) {
this.page = this.page + 1;
}
for (let i = 0; i < msg.length; i++) {
msg[i].id = msg[i].vlogId;
msg[i].playIng = false;
msg[i].isShowimage = false;
msg[i].isShowProgressBarTime = false;
msg[i].isplay = true;
msg[i].state = 'pause';
List.push(msg[i]);
}
this.dataList = List;
}
},
touchstart(event) {
this.channel.postMessage({
type: 'drag-start',
data: false
});
this.dataList[this.k].isShowimage = true; //刚触摸的时候就要显示预览视频图片了
this.dataList[this.k].isShowProgressBarTime = true; //显示时间线
this.ProgressBarOpacity = 1; //让滑块显示起来更明显一点
this.dotWidth = 10; //让点显示起来更明显一点
},
touchend(event) {
this.channel.postMessage({
type: 'drag-end',
data: true
});
//当手松开后,跳到最新时间
uni.createVideoContext(this.dataList[this.k].id, this).seek(this.newTime);
if (this.dataList[this.k].state == 'pause') {
this.dataList[this.k].state = 'play';
uni.createVideoContext(this.dataList[this.k].id, this).play();
}
this.dataList[this.k].isShowProgressBarTime = false; //触摸结束后,隐藏时间线
this.dataList[this.k].isShowimage = false; //触摸结束后,隐藏时间预览
this.ProgressBarOpacity = 0.5; //隐藏起来进度条,不那么明显了
this.dotWidth = 0; //隐藏起来进度条,不那么明显了
},
touchmove(event) {
event.stopPropagation();
//当手移动滑块时,计算位置、百分小数、新的时间
var msg = [];
if (this.videoTime !== '') {
msg = this.videoTime.split(':');
}
var timeNumber = Number(msg[0]) * 60 + Number(msg[1]);
this.currentPositions = event.changedTouches[0].screenX;
this.percent = this.currentPositions / this.windowWidth;
this.newTime = this.percent * timeNumber;
this.currenttimes = parseInt(this.newTime);
let theTime = this.newTime;
let middle = 0; // 分
if (theTime > 60) {
middle = parseInt(theTime / 60);
theTime = parseInt(theTime % 60);
}
this.changeTime = `${Math.round(middle) > 9 ? Math.round(middle) : '0' + Math.round(middle)}:${
Math.round(theTime) > 9 ? Math.round(theTime) : '0' + Math.round(theTime)
}`;
},
timeupdate(event, index) {
//计算滑块当前位置,计算当前百分小数
// console.log(index)
if (index == this.k) {
// console.log(event)
var currenttime = event.detail.currentTime;
this.timeNumber = Math.round(event.detail.duration);
this.getTime();
this.percent = currenttime / this.timeNumber;
this.currentPosition = this.windowWidth * this.percent;
let theTime = currenttime;
let middle = 0; // 分
if (theTime > 60) {
middle = parseInt(theTime / 60);
theTime = parseInt(theTime % 60);
}
this.changeTime = `${Math.round(middle) > 9 ? Math.round(middle) : '0' + Math.round(middle)}:${
Math.round(theTime) > 9 ? Math.round(theTime) : '0' + Math.round(theTime)
}`;
clearTimeout(this.voice);
this.voice = setTimeout(() => {
this.dataList[this.k].isplay = false;
}, 200);
setTimeout(() => {
this.dataList[this.k].playIng = true;
}, 650);
//自动切换视频
if (this.isAutoplay) {
//true,代表自动播放
if (Math.round(currenttime) == this.timeNumber - 1) {
const dom = uni.requireNativePlugin('dom');
let doms = 'item' + (this.k + 1);
setTimeout(() => {
let el = this.$refs[doms][0];
dom.scrollToElement(el, {
offset: 0,
animated: true
});
}, 500);
}
}
}
},
getTime() {
//得到时间函数
this.videoTime = this.formatSeconds(this.timeNumber);
// console.log(that.videoTime)
var msg = [];
if (this.videoTime !== '') {
msg = this.videoTime.split(':');
}
this.videoTimes = `${msg[0] > 9 ? msg[0] : '0' + msg[0]}:${msg[1] > 9 ? msg[1] : '0' + msg[1]}`;
},
formatSeconds(value) {
//获取时间函数
let theTime = parseInt(value); // 秒
let middle = 0; // 分
if (theTime > 60) {
middle = parseInt(theTime / 60);
theTime = parseInt(theTime % 60);
}
return `${middle > 9 ? middle : middle}:${theTime > 9 ? theTime : theTime}`;
},
playIngs(index) {
//
},
moreVideo(index) {},
toVideo(index) {},
erweima() {},
tozuozhe(userId) {
var myInfo = storage.getVlogUserInfo();
var myId = '';
2025-05-04 03:37:34 +08:00
if (myInfo != null) {
2025-04-25 18:10:54 +08:00
myId = myInfo.id;
}
if (userId == myId) {
uni.switchTab({
url: '/pages/me/me'
});
} else {
uni.navigateTo({
url: '/pages/me/vlogerInfo?userPageId=' + userId
});
}
},
stop() {
// console.log('stop')
},
scrolls(event) {
this.isDragging = event.isDragging;
if (!event.isDragging) {
//isDragging判断用户是不是在滑动滑动true停止滑动false。我们要用户停止滑动时才给 k 赋值,这样就可以避免很多麻烦
var i = Math.round(Math.abs(event.contentOffset.y) / (this.wHeight - this.deleteHeight + 1)); //先用绝对值取出滑动的距离,然后除以屏幕高度,取一个整,就知道你现在滑动到哪一个视频了
if (i !== this.k) {
//这里加判断是因为这个方法会执行很多次,会造成重复请求,所以这里写一个限制
let num = 300;
clearTimeout(this.timers);
this.timers = setTimeout(() => {
this.k = i; //判断了用户没有滑动,确认了用户的确是在看这个视频,然后就赋值啦
this.dataList[this.k].state = 'play';
console.log('正在播放 --> 第' + (this.k + 1) + '个视频~');
}, num);
}
}
},
init() {
this.page = 1;
this.dataList = [];
this.k = 0;
},
async get() {
// 这个方法主要就是用来第一次进入视频播放时用来处理的
// this.dataList = userList;//这个就是赋值加载视频啦
this.init();
let myUserInfo = storage.getVlogUserInfo();
if (myUserInfo != null) {
this.userId = myUserInfo.id;
}
const res = await vlogList(this.page, 10, this.userId);
console.log(res);
if (res.data.status == 200) {
var msg = res.data.data.rows;
for (let i = 0; i < msg.length; i++) {
msg[i].id = msg[i].vlogId;
msg[i].playIng = false;
msg[i].isShowimage = false;
msg[i].isShowProgressBarTime = false;
msg[i].isplay = true;
msg[i].state = 'pause';
}
if (msg.length > 0) {
this.dataList = JSON.parse(JSON.stringify(msg));
this.dataList[0].state = 'play';
this.page = this.page + 1;
setTimeout(() => {
//这里的延迟是为了避免执行时间太快而直接跳过执行的 bug
uni.createVideoContext(this.dataList[0].id, this).seek(0);
uni.createVideoContext(this.dataList[0].id, this).play();
}, 200);
this.dataList[0].isplay = false;
setTimeout(() => {
this.dataList[0].playIng = true;
}, 500);
var p = 0;
this.showPlay = true;
setTimeout(() => {
++p;
if (this.dataList.length > 1) {
this.dataList[p].isplay = true;
setTimeout(() => {
uni.createVideoContext(this.dataList[p].id, this).seek(0);
uni.createVideoContext(this.dataList[p].id, this).pause();
console.log('预加载第' + (p + 1) + '个视频:' + this.dataList[p].id);
}, 800);
}
}, 50);
}
} else {
uni.showToast({
title: result.data.msg,
icon: 'none',
duration: 3000
});
}
},
onpullingdown() {
// console.log('正在下拉刷新,此时手还在触摸没有松开')
this.refreshing = true;
},
onrefresh() {
// console.log('下拉刷新完毕,此时手松开了')
setTimeout(() => {
this.refreshing = false;
}, 1000);
},
// 双击点赞效果
touchstartHover(event) {
if (this.touchNum >= 1) {
// console.log('双击 -- X坐标'+ event.touches[0].screenX);
// console.log('双击 -- Y坐标'+ event.touches[0].screenY);
this.aixinLeft = event.touches[0].screenX - 50;
this.aixinTop = event.touches[0].screenY - 50;
this.isShowAixin = true;
let max = 40;
let min = -40;
this.Rotate = Math.floor(Math.random() * (max - min + 1)) + min;
setTimeout(() => {
this.isShowAixin = false;
}, 700);
this.onTabItemTaps();
}
},
//点击播放&&暂停
tapVideoHover(state, event) {
this.dataList[this.k].isShowimage = false;
this.dataList[this.k].isShowProgressBarTime = false;
this.ProgressBarOpacity = 0.5;
this.dotWidth = 0;
console.log('state--', state);
// 1.启用双击点赞 --- start
this.touchNum++;
setTimeout(() => {
if (this.touchNum == 1) {
if (state == 'play' || state == 'continue') {
this.dataList[this.k].state = 'pause';
} else {
this.dataList[this.k].state = 'continue';
}
if (this.dataList[this.k].state == 'continue') {
uni.createVideoContext(this.dataList[this.k].id, this).play(); //暂停以后继续播放
this.clearTime();
setTimeout(() => {
this.rotateX();
}, 50);
}
if (this.dataList[this.k].state == 'pause') {
uni.createVideoContext(this.dataList[this.k].id, this).pause(); //暂停以后继续播放
this.clearTime();
}
}
if (this.touchNum >= 2) {
this.doubleLike();
}
this.touchNum = 0;
}, 200);
// --------------- ending
// 2. 不启用双击点赞 start
// if(state=='play'||state=='continue'){
// this.dataList[this.k].state = 'pause';
// }else{
// this.dataList[this.k].state = 'continue';
// }
// if(this.dataList[this.k].state == 'continue'){
// uni.createVideoContext(this.dataList[this.k].id,this).play();//暂停以后继续播放
// }
// if(this.dataList[this.k].state == 'pause'){
// uni.createVideoContext(this.dataList[this.k].id,this).pause();//暂停以后继续播放
// }
// --------------- ending
},
doubleLike() {
if (this.dataList[this.k].like == false) {
this.dataList[this.k].like_n += 1;
this.dataList[this.k].like = true;
}
/*
点赞
*/
},
toComment(item) {
// 注意点击评论之后会执行这里
/*
1先加载缓冲
2获取当前视频 ID 信息
3🌟🌟🌟🌟重要🌟🌟🌟🌟
- 一定要记得看 index.vue 里面
uni.setStorageSync("user",this.peopleList[i]);
这个东西,用于存储当前用户信息。在 插件里面会使用到这个东西,
记得写一下。
4打开评论
*/
this.pinglunInfo = item;
uni.showToast({
title: '加载中...',
icon: 'none',
position: 'bottom',
duration: 300
});
// uni.setStorageSync('videoID', this.dataList[index].id);
this.$refs.pinglun.open('bottom');
uni.hideTabBar({
animation: true
});
},
2025-04-30 14:28:07 +08:00
share(item) {
this.pinglunInfo = item;
2025-04-25 18:10:54 +08:00
this.$refs.share.open();
uni.hideTabBar({
animation: true
});
},
cLike(sss) {
this.dataList[this.k].like = !this.dataList[this.k].like;
const video = this.dataList[this.k];
sss ? (video.like_n -= 1) : (video.like_n += 1);
/*
点赞
*/
},
moveHandle() {},
onTabItemTaps() {
// #ifdef APP-PLUS
if (uni.getSystemInfoSync().platform == 'ios') {
let UIImpactFeedbackGenerator = plus.ios.importClass('UIImpactFeedbackGenerator');
let impact = new UIImpactFeedbackGenerator();
impact.prepare();
impact.init(1);
impact.impactOccurred();
var item = this.dataList[this.k];
this.likeOrDislikeVlog(item);
}
if (uni.getSystemInfoSync().platform == 'android') {
uni.vibrateShort({
success: () => {
console.log('点击震动');
var item = this.dataList[this.k];
this.likeOrDislikeVlog(item);
}
});
}
// #endif
}
}
};
</script>
<style scoped>
.touxbox {
justify-content: center;
align-items: center;
}
.follow-me {
width: 40rpx;
height: 40rpx;
border-radius: 40px;
position: absolute;
left: 30rpx;
bottom: 15rpx;
}
.container {
background-color: #000000;
}
.item {
/* width : 750rpx; */
background-color: #000000;
position: relative;
}
.videoHover {
position: absolute;
top: 0;
left: 0;
flex: 1;
background-color: rgba(0, 0, 0, 0.1);
justify-content: center;
align-items: center;
/* border-style: dashed;
border-color: #DD524D;
border-width: 1px; */
}
.playState {
width: 160rpx;
height: 160rpx;
opacity: 0.2;
}
.userInfo {
position: absolute;
bottom: 80px;
right: 10px;
flex-direction: column;
}
.userAvatar {
border-radius: 500%;
margin-bottom: 15px;
border-style: solid;
border-width: 2px;
border-color: #ffffff;
}
.userAvatar {
width: 100rpx;
height: 100rpx;
}
.likeIco,
.shareIco,
.commentIco {
width: 60rpx;
height: 60rpx;
margin-top: 15px;
}
.likeNum,
.commentNum,
.shareTex {
color: #ffffff;
font-size: 30rpx;
text-align: center;
margin: 5px;
}
.likeNumActive {
color: red;
}
.content {
width: 610rpx;
z-index: 99;
position: absolute;
bottom: 30px;
/* background-color: #007AFF; */
/* justify-content: center; */
padding: 15rpx;
flex-direction: column;
justify-content: flex-start;
color: #ffffff;
}
.userName {
font-size: 30rpx;
color: #ffffff;
margin-top: 80upx;
}
.words {
margin-top: 10rpx;
color: #ffffff;
font-size: 28rpx;
font-weight: 400;
lines: 5;
text-overflow: ellipsis;
}
.root {
/* background-color: #000000; */
background-color: #00ffff;
}
</style>