Files
MER-2.2_2601/mer_uniapp/pages/discover/discover_video/appVideo/index.nvue
2026-03-08 20:07:52 +08:00

1483 lines
44 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="container">
<!-- #ifdef APP -->
<!--
注意:这是 App 所用页面,请勿引入微信小程序或浏览器运行,最好运行在真机
1. 视频运行在云服务上,本地加载很慢,会导致一些问题出现。
2. 视频 id 切记是字符串类型,并且提前转义!要不然会出现黑屏加载不出视频。
-->
<view :style="'width: '+ windowWidth +'px; height: '+ boxStyle.height +'px;'" v-if="isShow1">
<!--
1.这里的 swiper 不是用来控制视频滑动的,而是用来控制左右滑动的,如果不需要的可以改成 view
2.为了 视频无限加载,已经把 21 行的 appear 去掉了,加上了 loadmore 方法第10行
3.由于方法比较多,可以采取下面的方式查看代码:
1Mac按住 option 键,然后点击方法名,即可跳转到方法
2windows按住 Alt 键,然后鼠标左击,即可跳转到方法
-->
<list @loadmore="loadmores" @scroll="scrolls" :loadmoreoffset="wHeight*1" :show-scrollbar="false"
ref="listBox" :pagingEnabled="true" :scrollable="true">
<!-- 刷新模块 -->
<refresh class="refresh" @refresh="onrefresh" @pullingdown="onpullingdown"
:display="refreshing ? 'show' : 'hide'">
<loading style="background-color: #FFFFFF;">
<image src="../../static/images/logins.gif"
:style="'width: 80upx; height: 40upx; margin-top: 80upx; margin-bottom: 30upx; margin-left: '+ (windowWidth - 200) +'px;'">
</image>
</loading>
</refresh>
<!-- 循环数据 -->
<cell v-for="(list,i) in dataList" :key="i">
<!-- 用div把视频模组套起来 -->
<div :style="'width: '+ windowWidth +'px; height: '+ boxStyle.height +'px;'" @disappear="stop()">
<view v-if="Math.abs(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 :ref="'list'+i" :id="list.id" :loop="true" :src="list.video" :muted="list.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"
:object-fit="object_fit" @timeupdate="timeupdate($event,i)"></video>
<!-- 这里是封面 -->
<!-- <image
v-if="!item.playIng"
:src="item.src+'?x-oss-process=video/snapshot,t_100,f_jpg'"
:mode="mode"
:style="'width: '+ windowWidth +'px; height: '+ (wHeight - deleteHeight) +'px; position: absolute;'"
></image> -->
<!--
mode: 图片裁剪、缩放的模式
mode 有 14 种模式,其中 5 种是缩放模式9 种是裁剪模式。
https://uniapp.dcloud.io/component/image
-->
</view>
<!-- 直接用 view 就行了,一样是可以覆盖原生组件的 -->
<!-- 这个是暂停时出现的图标 -->
<!-- 播放状态pause 的时候就会暂停 -->
<view class="videoHover" @click.stop="tapVideoHover(list.state,$event)" :style="boxStyle">
<image v-if="list.state=='pause'" class="playState" src="../../static/images/play.png">
</image>
</view>
<!--审核状态 -->
<view v-if="list.auditStatus == 0 || list.auditStatus == 2 || list.auditStatus == 3"
class="video-status">
<view v-if="list.auditStatus == 2 || list.auditStatus == 3" class="status-title">
<image class="image" :src="urlDomain+'crmebimage/presets/weitg.png'"></image>
<!-- <text class="iconfont icon-tishi"></text> -->
<text class="title">{{list.auditStatus == 2 ? '审核未通过' : '平台关闭'}},内容仅自己可见</text>
</view>
<view v-else class="status-title">
<image class="image" :src="urlDomain+'crmebimage/presets/shen.png'"></image>
<text class="title">正在审核,内容仅自己可见</text>
</view>
<view class="status_info">
<text
class="refusal">{{(list.auditStatus == 2 || list.auditStatus == 3) ? list.refusal : '发布的内容审核通过后,将在首页展示!'}}</text>
</view>
</view>
<!-- 最底下的文字部分 -->
<view v-if="isShowCent && dataList.length !== 0" class="content">
<view class="cart">
<text class="cartName">@{{list.authorName}}</text>
</view>
<view class="words mb20" :style="'width: '+ (windowWidth - 120) +'px;'">
<view v-if="list.isMore || list.content.length<=29">
<text class="info">{{list.content}}</text>
<view class="close">
<text v-if="list.isMore" class="more" @click="moreTap(list)">收起</text>
</view>
</view>
<view class="wordsCon" v-else>
<text class="info">{{list.content.slice(0,29)}}...</text>
<text class="more" @click.stop="moreTap(list)">展开</text>
</view>
<view class="topicList acea-row product_cate"
v-if="list.topicList && list.topicList.length">
<view class="pro-view" @click="goTopic(item.id)" v-for="item in list.topicList"
:key="item.id">
<text class="icon">#</text><text class="text">{{item.name}}</text>
</view>
</view>
</view>
<view v-if="k==i && list.productList.length>0" class="product mb20">
<scroll-view class="scroll-view" scroll-x="true"
style="white-space: nowrap; display: flex;" scroll-with-animation>
<view class="product-item" v-for="(goods,idx) in list.productList" :key="idx">
<view class="item-count acea-row" @click="goDetail(goods)">
<view class="picture">
<image class="image" :src="goods.productImage"></image>
</view>
<view class="product-text">
<text class="names line1 line-heightOne">{{goods.productName}}</text>
<text v-if="goods.isPay===1" class="buy">作者买过</text>
<view class="product-price">
<view class="price"><text class="sm">¥</text><text
class="money">{{goods.price}}</text></view>
<text class="buy-btn">购买</text>
</view>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
<view v-if="isShowCent" class="userInfo">
<!-- 1.头像 -->
<navigator hover-class="none"
:url="'/pages/discover/discover_user/index?id='+list.authorId" class="pictrue">
<image class="userAvatar" :src="list.authorAvatar || urlDomain+'crmebimage/presets/morenT.png'"
mode="aspectFill"></image>
<view v-if="!list.isConcerned && list.authorId!==uid" class="guanzhu"
@click.stop="followAuthor(list)">
<text class="iconfont icon-ic_increase">+</text>
</view>
<view v-else class="yiguanzhu"><text class="iconfont"></text></view>
</navigator>
<!-- 2.点赞 -->
<view @click="likeToggle(list);" style="margin-top: 5px;" class="flex-column"
:class="{'likeNumActive':list.userIsLike}">
<image v-if="list.userIsLike" :src="urlDomain+'crmebimage/presets/xin.png'"
style="width: 28px; height: 28px;"></image>
<image v-if="!list.userIsLike" :src="urlDomain+'crmebimage/presets/xin-2.png'"
style="width: 28px; height: 28px;"></image>
<text class="info-text">{{list.likeNum > 0 ? list.likeNum : '点赞'}}</text>
</view>
<!-- 3.评论 -->
<view v-if="list.platReplySwitch" class="comment flex-column" @click="toComment(list)"
style="margin-top: 18px;">
<image :src="urlDomain+'crmebimage/presets/evaluate.png'"
style="width: 54rpx; height: 50rpx;"></image>
<text class="info-text">{{list.replyNum>0 ? list.replyNum : '评论'}}</text>
</view>
<!-- 4.分享 -->
<view v-if="list.auditStatus == 1" @click="appShare('WXSceneSession',list.id)"
class="flex-column" style="margin-top: 17px;">
<image :src="urlDomain+'crmebimage/presets/share-fill.png'"
style="width: 54rpx; height: 50rpx;"></image>
<text class="info-text">分享</text>
</view>
<!-- 5.自己的视频 -->
<view v-if="list.authorId == uid" style="margin-top: 17px;">
<view class="video-my">
<view class="video-dian" @click.stop="showManage = !showManage">
<text class="dian"></text>
<text class="dian"></text>
<text class="dian"></text>
</view>
</view>
</view>
<!-- 6提到的商品 -->
<view v-if="list.productList.length>0 && k === i" @click.stop="openMore(list)"
class="mention" style="opacity: 0.9; margin-top: 18px;">
<image class="image" src="../../static/images/collection.png"></image>
<text class="count">{{list.productList.length}}</text>
</view>
<!-- 7.收起内容 -->
<view @click="onHideCent" class="flex-column"
style="margin-top: 35rpx;align-items: center;">
<image :src="urlDomain+'crmebimage/presets/shou.png'"
style="width: 56rpx; height: 56rpx;"></image>
</view>
</view>
<!-- 8.展开内容 -->
<view v-else @click="onHideCent" class="onShow">
<image :src="urlDomain+'crmebimage/presets/zhan.png'"
style="width: 56rpx; height: 56rpx;"></image>
</view>
<view class="manage" v-if="showManage">
<navigator hover-class="none"
:url="'/pages/discover/discover_release/index?noteId='+list.id" class="items">
<image :src="urlDomain+'crmebimage/presets/bianji.png'"
style="width: 16px; height: 16px;"></image>
<text class="text">编辑</text>
</navigator>
<view class="items" @click.stop="deleteTopic(list)">
<image :src="urlDomain+'crmebimage/presets/shan.png'"
style="width: 16px; height: 16px;"></image>
<text class="text">删除</text>
</view>
<view class="items" @click.stop="replySwitch(list)">
<image v-if="list.replyStatus ==1" :src="urlDomain+'crmebimage/presets/jinping.png'"
style="width: 16px; height: 16px;"></image>
<image v-else :src="urlDomain+'crmebimage/presets/yunping.png'"
style="width: 16px; height: 16px;"></image>
<text class="text">{{list.replyStatus ==1 ? '禁止评论' : '开启评论'}}</text>
</view>
</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.src+'?x-oss-process=video/snapshot,t_'+ currenttimes +'000,f_jpg'"
mode="aspectFill"
:style="'width: 120upx; height: 160upx; border-radius: 10upx; position: absolute; bottom: '+ (ProgressBarBottom + 160) +'upx; left: '+ (currentPositions - 15) +'px;'"
></image> -->
</view>
</div>
</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>
<!-- #endif -->
<!-- 评论 -->
<uni-popup type="bottom" ref="comment" @touchmove.stop.prevent="moveHandle" v-if="isShow2">
<view
:style="'width: '+ windowWidth +'px; height: 500px; background-color: #fff; border-top-left-radius: 20px; border-top-right-radius: 20px;'">
<discoverComment v-if="showComment" ref="comments" :noteId="noteDetail.id" :noteDetails="noteDetail"
@close.stop="close">
</discoverComment>
</view>
</uni-popup>
<!-- 他提到的宝贝弹窗 -->
<uni-popup type="bottom" ref="pinglunMentioned">
<view
:style="'width: '+ windowWidth +'px;background-color: #F5F5F5;height:1200rpx; border-top-left-radius: 10px; border-top-right-radius: 10px;overflow-y: scroll;'">
<mentioned ref="mentioned" :list="proList" @close="popup" fromType="video" :goodsStyle="goodsStyle"></mentioned>
</view>
</uni-popup>
</view>
</template>
<script>
import {
HTTP_H5_URL
} from '@/config/app.js';
import {
goProductDetail
} from '@/libs/order.js'
import {
mapGetters
} from "vuex";
import {
discoverFollowAuthor,
discoverNoteLike
} from '@/libs/follow.js';
import {
toLogin
} from '@/libs/login.js';
import {
noteDetailApi,
noteRecommendApi,
noteReplySwitchApi,
noteDelApi
} from '@/api/discover.js';
import Cache from '@/utils/cache'
import mentioned from '../../components/mentioned';
import discoverComment from './comment.nvue';
import util from '@/utils/util';
import { goodsStyle } from "../default";
import {
Debounce
} from '@/utils/validate.js'
let sysHeight = uni.getSystemInfoSync().statusBarHeight;
export default {
computed: mapGetters(['userInfo', 'isLogin', 'uid']),
data() {
return {
goodsStyle: goodsStyle, //商品样式
//下面打🌟号的是必须要的基础字段
//下面打💗号的是拥有滑动条的必须字段
dataList: [], //用于数据循环的列表🌟💗
wHeight: 0, //获取的屏幕高度🌟💗
boxStyle: { //视频,图片封面样式🌟💗
'height': 0,
'width': 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: 20, //进度条离底部的距离💗
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: "",
noteId: 0,
where: {
page: 1,
limit: 5,
noteId: ''
},
showManage: false,
isShowCent: true,
urlDomain: Cache.get("imgHost"),
showComment: false, //评论弹窗
noteDetail: {}, //详情
proList: [], //商品列表
fromTo: ''
}
},
components: {
//tuiBottomPopup,
mentioned,
discoverComment
},
watch: {
async k(k, old_k) { //监听 k 值的变化,可以控制视频的播放与暂停
// 清理定时器
this.clearToTime();
this.dataList[old_k].state = 'stop' //如果是被滑走的视频,就停止播放
this.dataList[old_k].playIng = false //如果视频暂停,就加载封面
this.dataList[old_k].isplay = true
uni.createVideoContext(this.dataList[old_k].id.toString(), this).play()
this.oldVideo = await setTimeout(() => {
uni.createVideoContext(this.dataList[old_k].id.toString(), this).seek(0)
uni.createVideoContext(this.dataList[old_k].id.toString(), this).pause()
}, 500)
// 2.0版本已经去掉了下面这一句,视频不用暂停,只需要把声音禁止就行
// uni.createVideoContext(this.dataList[old_k]._id + '' + old_k,this).stop()//如果视频暂停那么旧视频停止这里的this.dataList[old_k]._id + '' + old_k后面加 old_k 是为了每一个视频的 id 值不同,这样就可以大程度的避免串音问题
this.dataList[k].state = 'play'
uni.createVideoContext(this.dataList[k].id.toString(), this).play();
this.xrotats = setTimeout(() => {
this.showPlay = true;
this.rotateX();
}, 200)
clearTimeout(this.voice)
this.voice = await setTimeout(() => {
this.dataList[k].isplay = false
}, 300)
await setTimeout(() => {
this.dataList[k].playIng = true
}, 850)
//【2.0版本更新内容】- start
var p = k;
if (this.loadend) return;
++p;
this.dataList[p].isplay = true
await setTimeout(async () => {
uni.createVideoContext(this.dataList[p].id.toString(), this).play()
clearTimeout(this.timeout)
this.timeout = await setTimeout(() => {
uni.createVideoContext(this.dataList[p].id.toString(), this).seek(0)
uni.createVideoContext(this.dataList[p].id.toString(), this).pause()
}, 1500)
}, 500)
//【2.0版本更新内容】- end
//【此处处理进度条卡住的问题】
if (uni.getSystemInfoSync().platform !== 'ios') {
await setTimeout(() => {
uni.createVideoContext(this.dataList[k].id.toString(), this).pause()
uni.createVideoContext(this.dataList[k].id.toString(), this).play()
}, 100)
}
}
},
onShow() {
if (this.dataList.length !== 0) {
this.dataList[this.k].state = 'play';
uni.createVideoContext(this.dataList[this.k].id, this).play()
}
},
onHide() {
this.dataList[this.k].state = 'pause'; //界面隐藏也要停止播放视频
uni.createVideoContext(this.dataList[this.k].id, this).pause(); //暂停以后继续播放
},
onLoad(options) {
this.noteId = options.noteId ? Number(options.noteId) : '';
this.fromTo = options.fromTo || '';
this.platform = uni.getSystemInfoSync().platform;
var model = uni.getSystemInfoSync().model
if (this.platform == 'ios' && (model !== 'iPhone6' || model !== 'iPhone6s' || model !== 'iPhone7' || model !==
'iPhone8')) {
this.deleteHeight = 32 //有 tabbar的 修改这里可以改变视频高度
/*
引入评论参数
*/
this.heightNum = 1.27
} else {
this.deleteHeight = 0
/*
引入评论参数
*/
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
this.wHeight = uni.getSystemInfoSync().screenHeight; //获取屏幕高度
this.boxStyle.height = this.wHeight - this.deleteHeight; //改变视频高度
this.get() //这一步,加载视频数据
if (options.fromTo !== 'home') this.getData();
this.rotateX();
},
onReady() {},
methods: {
// 删除内容
deleteTopic(item) {
let that = this;
uni.showModal({
content: '确定要删除该内容么?',
cancelColor: '#f55850',
success: function(res) {
if (res.confirm) {
noteDelApi(item.id).then(res => {
util.Tips({
title: '删除成功'
});
setTimeout(function() {
uni.redirectTo({
url: '/pages/discover/discover_user/index'
})
}, 1000);
}).catch(err => {
uni.showToast({
title: err,
icon: 'none'
})
});
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
},
//禁止评论
replySwitch(item) {
if (!item.platReplySwitch && item.replyStatus === 3) {
util.Tips({
title: '平台设置不可评论'
});
} else {
noteReplySwitchApi(item.id).then(res => {
if (item.replyStatus === 1) {
this.$set(item, 'replyStatus', 2)
util.Tips({
title: '禁止成功'
});
} else {
this.$set(item, 'replyStatus', 1)
util.Tips({
title: '开启成功'
});
}
}).catch(err => {
uni.showToast({
title: err,
icon: 'none'
})
});
}
},
//打开评论
toComment(item, index) {
this.noteDetail = item;
this.showComment = true
this.$refs.comment.open('bottom')
},
/*查看提到的宝贝*/
openMore(item) {
this.proList = item.productList;
this.$refs.pinglunMentioned.open('bottom');
//this.popupShow = true;
},
popup() {
this.$refs.pinglunMentioned.close();
},
loadmores() {
if (options.fromTo !== 'home') this.getData();
},
//分享
appShare(scene, id) {
uni.showLoading({
title: '加载中',
mask: true
});
let uid = this.uid ? this.uid : 0;
let data = this.dataList[this.k];
let routes = getCurrentPages(); // 获取当前打开过的页面路由数组
//let curRoute = routes[routes.length - 1].$page.fullPath // 获取当前页面路由,也就是最后一个打开的页面路由
uni.share({
provider: "weixin",
scene: scene,
type: 0,
href: `${HTTP_H5_URL}/pages/discover/discover_video/routineVideo/index?&noteId=${id}&sd=${this.uid}`,
title: data.title || '',
summary: data.content || '',
imageUrl: data.cover || '',
success: function(res) {
uni.showToast({
title: '分享成功',
icon: 'success'
})
uni.hideLoading();
},
fail: function(err) {
uni.hideLoading();
uni.showToast({
title: '分享失败',
icon: 'none',
duration: 2000
})
}
});
uni.hideLoading();
},
moreTap(item) {
item.isMore = !item.isMore;
},
//去话题
goTopic(id) {
uni.navigateTo({
url: `/pages/discover/discover_note_topic/index?topicId=${id}`
})
},
//收起内容
onHideCent() {
this.isShowCent = !this.isShowCent;
},
// 去详情页
goDetail(item) {
goProductDetail(item.productId, 0, '');
},
//返回
returns: function() {
uni.navigateBack();
},
// 关注作者
followAuthor(item) {
if (this.isLogin) {
discoverFollowAuthor(item.authorId).then(() => {
this.$set(item, 'isConcerned', !item.isConcerned);
});
} else {
toLogin();
}
},
//点赞
likeToggle: Debounce(function(item) {
if (this.isLogin) {
discoverNoteLike(item.id).then(() => {
this.$set(item, 'userIsLike', !item.userIsLike);
if (!item.userIsLike) {
item.likeNum--;
item.likeNum = item.likeNum == 0 ? 0 : item.likeNum
} else {
item.likeNum++;
}
});
} else {
toLogin();
}
}),
toBilibili() {
// #ifdef H5
window.open('https://www.bilibili.com/video/BV1gi4y12745')
// #endif
},
selectVideo() {
uni.navigateTo({
url: '/pages/selectVideo/selectVideo'
})
},
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
})
}
},
getData() {
if (this.loadend) return;
this.loading = true;
this.where.noteId = this.noteId;
noteRecommendApi(this.where).then(res => {
this.loading = false;
this.where.page = this.where.page + 1;
this.loadend = this.where.page > res.data.totalPage;
var msg = res.data.list
for (let i = 0; i < msg.length; i++) {
msg[i].id = msg[i].id.toString();
this.dataList.push(msg[i])
}
}).catch(err => {
this.loading = false;
uni.showToast({
title: err,
icon: 'none'
})
});
},
touchstart(event) {
this.dataList[this.k].isShowimage = true //刚触摸的时候就要显示预览视频图片了
this.dataList[this.k].isShowProgressBarTime = true //显示时间线
this.ProgressBarOpacity = 1 //让滑块显示起来更明显一点
this.dotWidth = 10 //让点显示起来更明显一点
},
touchend() { //当手松开后,跳到最新时间
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) { //当手移动滑块时,计算位置、百分小数、新的时间
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) { //计算滑块当前位置,计算当前百分小数
if (index == this.k) {
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)}`
//自动切换视频
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);
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) {
//
},
tozuozhe() {
this.currents = 1 //点击头像以后就会切换
},
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) { //这里加判断是因为这个方法会执行很多次,会造成重复请求,所以这里写一个限制
if (uni.getSystemInfoSync().platform == 'ios') {
this.k = i //判断了用户没有滑动,确认了用户的确是在看这个视频,然后就赋值啦
this.dataList[this.k].state = 'play'
} else {
clearTimeout(this.timers);
this.timers = setTimeout(() => {
this.k = i //判断了用户没有滑动,确认了用户的确是在看这个视频,然后就赋值啦
this.dataList[this.k].state = 'play'
}, 80)
}
}
}
},
get() {
noteDetailApi(this.noteId).then(async (res) => {
this.noteDetail = res.data
res.data.id = res.data.id.toString()
this.noteDetail.id = this.noteDetail.id.toString()
this.loading = false
this.dataList.push(res.data)
this.dataList[0].state = "play";
await setTimeout(() => {
//这里的延迟是为了避免执行时间太快而直接跳过执行的 bug
uni.createVideoContext(this.dataList[0].id.toString(), this).seek(0)
uni.createVideoContext(this.dataList[0].id.toString(), this).play()
}, 200)
this.dataList[0].isplay = false
await setTimeout(() => {
this.dataList[0].playIng = true
}, 500)
var p = 0;
this.showPlay = true;
}).catch(err => {
uni.showToast({
title: err,
icon: 'none'
})
});
},
onpullingdown() {
this.refreshing = true
},
onrefresh() {
setTimeout(() => {
this.refreshing = false
}, 1000)
},
// 双击点赞效果
touchstartHover(event) {
if (this.touchNum >= 1) {
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
// 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;
}
/*
点赞
*/
},
//关闭评论
close() {
this.$refs.comment.close();
},
wxh5Video() {
uni.navigateTo({
url: '../wxh5previewVideo/wxh5previewVideo'
})
},
previewVideo() {
uni.navigateTo({
url: '../previewVideo/previewVideo'
})
},
toTwoVideo() {
uni.navigateTo({
url: '../new_index/new_index'
})
},
tolistVideo() {
uni.navigateTo({
url: '../nvueSwiper/nvueSwiper'
})
},
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();
}
if (uni.getSystemInfoSync().platform == "android") {
uni.vibrateShort({
success: () => {
console.log('点击震动');
}
});
}
// #endif
}
}
}
</script>
<style lang="scss" scoped>
.onShow {
position: absolute;
bottom: 55rpx;
right: 40rpx;
}
.mb20 {
margin-bottom: 20rpx;
}
.line1 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
//display: inline-block;
}
.names {
font-size: 24rpx;
width: 286rpx;
color: #fff;
height: 30rpx;
lines: 1;
text-overflow: ellipsis;
}
.product_cate {
flex-direction: row;
flex-wrap: wrap;
.pro-view {
margin-bottom: 20rpx;
flex-direction: row;
align-items: center;
border-radius: 30rpx;
border-radius: 29rpx;
.text {
color: #ffffff;
font-size: 24rpx;
}
.icon {
font-size: 26rpx;
font-weight: bold;
margin-right: 4rpx;
color: #ffffff;
}
}
}
.noVideo {
position: fixed;
top: 400rpx;
z-index: 9;
width: 750rpx;
flex-direction: row;
justify-content: center;
.pictrue {
width: 414rpx;
height: 256rpx;
}
.tips {
text-align: center;
margin-top: 14rpx;
font-size: 26rpx;
color: #999;
}
}
// .container {background: #000000;}
.item {
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;
}
.playState {
width: 160rpx;
height: 160rpx;
opacity: 0.2;
}
.video-status {
width: 690rpx;
position: absolute;
left: 30rpx;
background: rgba(0, 0, 0, .55);
border-radius: 10rpx;
top: 150rpx;
padding: 30rpx;
.status-title {
flex-direction: row;
align-items: center;
.title {
margin-left: 20rpx;
color: #ffffff;
font-size: 28rpx;
}
}
.refusal {
color: #ffffff;
font-size: 22rpx;
margin: 15rpx 0 0 48rpx;
}
.image {
width: 28rpx;
height: 28rpx;
}
}
.userInfo {
position: absolute;
bottom: 30px;
right: 10px;
display: flex;
align-items: center;
flex-direction: column;
.pictrue {
flex-direction: column;
justify-content: center;
align-items: center;
position: relative;
// margin-bottom: 18rpx;
.guanzhu {
width: 42rpx;
height: 42rpx;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
background: #E93323;
border-radius: 100%;
position: relative;
top: -20rpx;
left: 3rpx;
.iconfont {
font-size: 30rpx;
color: #fff;
}
}
.yiguanzhu {
width: 42rpx;
height: 42rpx;
}
}
}
.video-my {
position: relative;
align-items: center;
justify-content: center;
flex-direction: row;
}
.video-dian {
position: relative;
width: 33px;
height: 33px;
align-items: center;
justify-content: center;
flex-direction: row;
left: 3px;
.dian {
width: 7px;
height: 7px;
background-color: #fff;
border-radius: 100%;
margin-right: 3px;
&:last-child {
margin-right: 0;
}
}
}
.manage {
width: 115px;
background: #ffffff;
box-shadow: 0 1px 8px rgba(0, 0, 0, 0.1);
padding: 0 8px;
position: absolute;
bottom: 10px;
right: 60px;
border-radius: 8px;
.manage-gou {
display: flex;
width: 13px;
height: 13px;
background: #ffffff;
transform: rotate(140deg);
position: absolute;
top: 30px;
right: -6px;
box-shadow: -1px -1px 1px rgba(0, 0, 0, 0.05);
}
.items {
border-bottom: 1px solid #EEEEEE;
padding: 10px 0;
display: flex;
align-items: center;
flex-direction: row;
.text {
color: #282828;
font-size: 13px;
margin-left: 20rpx;
}
&:last-child {
border-bottom-color: transparent;
}
.image {
width: 32rpx;
height: 32rpx;
margin: 0 16rpx 0;
}
}
}
.userAvatar {
border-radius: 500%;
border-style: solid;
border-width: 2px;
border-color: #ffffff;
width: 80rpx;
height: 80rpx;
}
.info-text {
display: flex;
margin-top: 10rpx;
color: #ffffff;
font-size: 22rpx;
text-align: center;
&.likeNumActive {
color: #E93323;
}
}
.likeIco,
.shareIco,
.commentIco {
width: 60rpx;
height: 60rpx;
margin-top: 15px;
}
.likeNum,
.commentNum,
.shareTex {
color: #ffffff;
font-size: 30rpx;
text-align: center;
margin: 5px;
}
.mention {
width: 46px;
height: 46px;
position: relative;
bottom: 0;
.image {
width: 30px;
height: 30px;
position: absolute;
right: 8px;
}
.count {
padding: 2px 6px;
background: #fff;
border-radius: 100%;
display: flex;
align-items: center;
justify-content: center;
color: #E93323;
position: absolute;
right: 6px;
top: 0;
font-size: 10px;
}
}
.content {
width: 590rpx;
position: absolute;
bottom: 20px;
/* justify-content: center; */
padding: 15rpx;
flex-direction: column;
justify-content: flex-start;
color: #ffffff;
.cart {
height: 48rpx;
flex-direction: row;
.cartName {
font-size: 28rpx;
color: #fff;
}
}
.product {
flex-direction: row;
margin-bottom: 20rpx;
.scroll-view {
flex-direction: row;
}
.product-item {
width: 444rpx;
height: 136rpx;
background: rgba(0, 0, 0, .55);
border-radius: 12rpx;
padding: 16rpx 15rpx;
margin-right: 30rpx;
}
.item-count {
font-size: 20rpx;
flex-direction: row;
justify-content: space-between;
.picture {
width: 104rpx;
height: 104rpx;
border-radius: 16rpx;
.image {
width: 104rpx;
height: 104rpx;
border-radius: 10rpx;
}
}
.names {
font-size: 24rpx;
width: 286rpx;
color: #fff;
}
.product-text {
width: 286rpx;
justify-content: space-between;
.buy {
width: 75rpx;
padding: 4rpx 7rpx;
background: #5D5747;
border-radius: 3px 3px 3px 3px;
font-size: 16rpx;
display: inline-block;
}
.product-price {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
.price {
display: flex;
flex-direction: row;
.sm,
.money {
color: #ffffff;
font-size: 24rpx;
}
}
.buy-btn {
padding: 6rpx 20rpx;
// display: flex;
// align-items: center;
// justify-content: center;
color: #fff;
border-radius: 26rpx;
background: #E93323;
font-size: 20rpx;
}
}
}
}
}
}
.timeCon {
flex-direction: row;
align-items: center;
.userName {
font-size: 30rpx;
color: #ffffff;
}
}
.words {
margin-top: 20rpx;
.close {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
margin-right: 20rpx;
.imgClose {
width: 18rpx;
height: 10rpx;
margin-left: 10rpx;
}
}
.wordsCon {
position: relative;
.more {
position: absolute;
bottom: 0;
right: 40rpx;
font-size: 26rpx;
color: #ffffff;
font-weight: bold;
}
.img {
width: 18rpx;
height: 10rpx;
margin-left: 4rpx;
position: absolute;
bottom: 7rpx;
right: 20rpx;
}
}
.info {
color: #fff;
font-size: 28rpx;
}
.more {
font-size: 26rpx;
color: #ffffff;
font-weight: bold;
}
}
.root {
background-color: #000000;
}
</style>