video.nvue 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123
  1. <template>
  2. <view class="es">
  3. <view :style="'width: '+ windowWidth +'px; height: '+ boxStyle.height +'px;background:#000;padding-top:'+statusBarHeight+'px'">
  4. <view class="emptybox x-c" :style="'width: '+ windowWidth +'px; height: '+ boxStyle.height +'px;' " v-if="isEmpty">
  5. <image class="emptybox-img" src="https://www.mescroll.com/img/mescroll-empty.png" mode="aspectFill"></image>
  6. <text class="emptybox-tip">~空空如也~</text>
  7. </view>
  8. <list loadmoreoffset="100" @scroll="scrolls" :show-scrollbar="false" v-if="dataList&&dataList.length > 0" :style="'height: '+ (videoStyle.height) +'px;' " ref="listBox" :pagingEnabled="true" :scrollable="true">
  9. <refresh @pullingdown='onpullingdown' @refresh="onrefresh" :display=" refreshing ? 'show' : 'hide' " class="refresh x-c " :style="'width: '+ windowWidth +'px;'">
  10. <loading-indicator style="width: 22px;height: 22px;color:#fff;"></loading-indicator>
  11. <text class="es-fs-32 es-ml-8 es-c-white">{{refreshText}}</text>
  12. </refresh>
  13. <cell v-for="(item,i) in dataList" :key="i">
  14. <view :style="'width: '+ windowWidth +'px;height:'+ (videoStyle.height)+'px;'" :ref="'item'+i" style="position: relative;">
  15. <view v-if="(k-i)<=1" style="position: relative;" >
  16. <view class="root" >
  17. <video :id="item.id" :loop="true" :src="item.src" :poster="item.cover"
  18. @play="playIngs(item,i)" :enable-progress-gesture="false" :page-gesture="false"
  19. :controls="false" :show-loading="false" :initial-time="0"
  20. :show-fullscreen-btn="false" :show-center-play-btn="false" :style="videoStyle"
  21. :object-fit="object_fit" @timeupdate="timeupdate($event,i)"
  22. @fullscreenchange="onFullscreenChange" @waiting="onWaiting()" @progress="onProgress()"
  23. @ended="endedPlayNext()" @canplay="onVideoCanPlay" @canplaythrough="onVideoCanPlayThrough"
  24. @loadeddata="onLoadeddata" @loadedmetadata="onLoadedMetadata" @error="onError"
  25. >
  26. </video>
  27. </view>
  28. <view class="videoHover" @click="tapVideoHover(item.state,$event)"
  29. @touchstart="touchstartHover" :style="boxStyle">
  30. <image v-if="item.state=='pause' && item.isShowPlayIcon" class="playState" src="/static/image/course/play.png"></image>
  31. </view>
  32. <!-- 审核通过的才能有相关操作 -->
  33. <view class="right es-c-white" v-if="item.isAudit!=-1&&item.isAudit!=0">
  34. <view class="item1 es es-ac es-pc es-mt-33" @tap="handleAvatar(item)">
  35. <view class="es-icon-100 es-br">
  36. <image class="es-icon-100" style="border-radius: 50rpx;" :src="item.headImg"></image>
  37. </view>
  38. </view>
  39. <view class="item1 es es-ver es-ac es-pc es-mt-33" @tap="doLike(item,i)">
  40. <view class="es-icon-84">
  41. <image class="es-icon-84" :src="item.like==1?'/static/images/other/video/zan1_on.png':'/static/images/other/video/zan1.png'"></image>
  42. </view>
  43. <view><text class="es-c-white es-fs-22 es-fw-500">{{item.likeNum}}</text></view>
  44. </view>
  45. <view class="item1 es es-ver es-ac es-pc es-mt-33" @tap="openComment(item)">
  46. <view class="es-icon-84">
  47. <image class="es-icon-84" src="/static/images/other/video/comment1.png"></image>
  48. </view>
  49. <view><text class="es-c-white es-fs-22 es-fw-500">{{item.smsNum}}</text></view>
  50. </view>
  51. <view class="item1 es es-ver es-ac es-pc es-mt-33" @tap="doFavorite(item,i)">
  52. <view class="es-icon-84">
  53. <image class="es-icon-84" :src="item.favorite==1?'/static/images/other/video/fav1_on.png':'/static/images/other/video/fav1.png'" ></image>
  54. </view>
  55. <view><text class="es-c-white es-fs-22 es-fw-500">{{item.favoriteNum}}</text></view>
  56. </view>
  57. <!-- <view class="item1 es es-ver es-ac es-pc es-mt-33" @tap="openShare(item)">
  58. <view class="es-icon-84">
  59. <image :class="animate ? 'animate-icon':'animate-scale'" src="@/static/image/home1/weixin_icon.png" mode="aspectFill"></image>
  60. </view>
  61. <view><text class="es-c-white es-fs-22 es-fw-500">{{item.shares}}</text></view>
  62. </view> -->
  63. <!-- <view class="item1 es es-ac es-pc es-mt-33">
  64. <view class="es-br ">
  65. <text class="es-c-white es-fs-34">{{item.uploadType}}</text>
  66. </view>
  67. </view> -->
  68. </view>
  69. <view class="left" v-if="item.isShowGoods && item.productId!=null" >
  70. <view class="es-w-40 es-h-40" @tap.stop="closePro(item,i)" style="position: absolute;right:0rpx;top:74rpx;z-index:999">
  71. <image class="es-w-40 es-h-40" src="@/static/images/close40.png"></image>
  72. </view>
  73. <view class="es-h-74 es es-ac">
  74. <view class="es-f1 es es-ac" id="w">
  75. <view class="bg" style="width: 320rpx;" >
  76. <image src="@/static/images/other/video/bg.png" style="height: 74rpx;width: 100%;" ></image>
  77. </view>
  78. <view class="es-w-30"></view>
  79. </view>
  80. </view>
  81. <view class="goods" @tap="goToPro(item)">
  82. <view class="icon" style="width: 290rpx;height: 290rpx;">
  83. <image :src="item.imgUrl" style="width: 290rpx;height: 290rpx;" class="es-br-10"></image>
  84. </view>
  85. <view class="es-omit es-mt-19" style="width: 290rpx;"><text class="es-fw es-fs-30">{{item.packageName}}</text></view>
  86. </view>
  87. </view>
  88. <view class="bottom">
  89. <text class="txtTitle" :class="showExpand?'ellipsis':''" :style="defTitStyle" :id="'txtTitle'+i" :ref="'txtTitle'+i">{{item.title}}</text>
  90. <text v-if="showExpand" class="expandBtn" @tap="clickExpand">{{ titIsExpand?'收起':'展开' }}</text>
  91. </view>
  92. </view>
  93. </view>
  94. </cell>
  95. </list>
  96. </view>
  97. <view :style="'background-color:'+bgColor+';'" class="tabbar1" @click="navBack()">
  98. <uni-icons type="left" size="20" color="#fff"></uni-icons><text style="color:#fff">返回</text>
  99. </view>
  100. <view class="redpacked x-c es-br-ban" v-if="!iserr" @click.stop="tapRedpacked">
  101. <gb-progress class="es x-c es-br-ban" :radius="43" :startPosDegree="0" originalColor="#222222"
  102. processColor="#ED7263" innerbgColor="#222222" :process="process" :barWidth="5">
  103. <image class="es-w-50 es-h-50" src="@/static/images/ad/redpacked.png" mode="widthFix" ></image>
  104. </gb-progress>
  105. </view>
  106. <!-- 分享弹窗 -->
  107. <u-popup :show="showShare" @close="showShare = false" >
  108. <share-box :shareItem="shareItem" @closeShare='showShare = false' ></share-box>
  109. </u-popup>
  110. </view>
  111. </template>
  112. <script>
  113. import { getVideoList } from "@/api/expert.js"
  114. import { doFavorite,doLike } from '@/api/shortvideo'
  115. import { addIntegral } from '@/api/integral'
  116. import { isLogin } from '@/utils/common'
  117. import { showLoginPage } from '@/utils/login'
  118. import shareBox from "@/components/share-box/share-boxN.vue"
  119. // #ifdef APP-PLUS
  120. const dom = weex.requireModule('dom');
  121. // const dom = uni.requireNativePlugin('dom')
  122. // #endif
  123. export default {
  124. components: {
  125. shareBox
  126. },
  127. data() {
  128. return {
  129. talentUserId: '',
  130. animate: true,
  131. animateInterval: null,
  132. bgColor: '',
  133. isEmpty: false,
  134. dataList: [], //用于数据循环的列表
  135. wHeight: 0, //获取的屏幕高度
  136. boxStyle: { //视频父视图样式
  137. 'height': 0,
  138. 'width': 0,
  139. },
  140. videoStyle: { //视频,图片封面样式
  141. 'height': 0,
  142. 'width': 0,
  143. 'marginTop':0
  144. },
  145. Heights: 0,
  146. k: 0, //默认为0
  147. playIngIds: [], //正在播放的视频id列队,列队用于处理滑动过快导致的跳频问题
  148. ready: false, //可忽略
  149. isDragging: false, //false代表停止滑动
  150. refreshing: false, //用于下拉刷新
  151. windowWidth: 0, //获取屏幕宽度
  152. windowHeight: 0,
  153. dex: [0, 0], //用于判断是上滑还是下滑,第一个存旧值,第二个存新值【目前在1.0.7已经废弃】
  154. currents: 0, //用于左右滑动,0代表视频界面,1代表右滑界面
  155. platform: '', //用于获取操作系统:ios、android
  156. playIng: false, //用于视频初始化时是否播放,默认不播放
  157. videoTime: '', //视频总时长,这个主要用来截取时间数值
  158. videoTimes: '', //视频时长,用这个来获取时间值,例如:00:30这个时间值
  159. changeTime: '', //显示滑动进度条时变化的时间
  160. isShowimage: false, //是否显示封面【1.0.4已废弃,但是意思需要记住】
  161. currenttimes: 0, //当前时间
  162. isShowProgressBarTime: false, //是否拖动进度条,如果拖动(true)则显示进度条时间,否则不显示(false)【1.0.4已废弃,但是意思需要记住】
  163. ProgressBarOpacity: 0.7, //进度条不拖动时的默认值,就是透明的
  164. dotWidth: 0, //播放的小圆点,默认没有
  165. deleteHeight: 0, //测试高度
  166. statusBarHeight:0,
  167. percent: 0, //百分小数
  168. currentPosition: 0, //滑块当前位置//2.0已弃用,现已用于后端参数
  169. currentPositions: 0, //滑块当前位置的副本//2.0已弃用,现已用于后端参数
  170. newTime: 0, //跟手滑动后的最新时间
  171. timeNumber: 0, //
  172. ProgressBarBottom: 20, //进度条离底部的距离
  173. object_fit: 'contain', //视频样式默认包含 contain :包含 fill:填充 cover:覆盖
  174. mode: 'aspectFit', //图片封面样式
  175. timeout: "", //用来阻止 setTimeout()方法
  176. voice: "", //用来阻止 setTimeout()方法
  177. oldVideo: "",
  178. isAutoplay: false, //是否开启自动播放(默认不开启)
  179. autoplayText: "开启自动播放",
  180. timers: "",
  181. leftTimers:"",
  182. // 引入评论 - 参数
  183. heightNum: 1.18,
  184. // 双击点赞参数
  185. touchNum: 0,
  186. aixinLeft: 0,
  187. aixinTop: 0,
  188. isShowAixin: false,
  189. Rotate: 0,
  190. isShowTab:true,
  191. isShow1: false, //控制渲染变量1
  192. isShow2: false, //控制渲染变量2 : 专门控制 uni-popup
  193. showPlay: false, //转轮显示控制
  194. rotates: 0, //转轮旋转角度
  195. rotateTime: "", //转轮递归事件控制
  196. xrotats: "",
  197. player: "",
  198. top:0,
  199. w:0,
  200. showLeft:true,
  201. keyword:"",
  202. pageNum:1,
  203. pageSize:10,
  204. isLastPage:false,
  205. refreshText: '↓ 下拉刷新',
  206. tabIndex: 0, // tab下标
  207. current: 0,
  208. mtabs: [
  209. {id: "tab00",name: ''},
  210. {id: "tab01",name: ''}
  211. // {id: "tab00",name: '推荐'},
  212. // {id: "tab01",name: '热点'}
  213. // {id: "tab02",name: '直播'},
  214. // {id: "tab03",name: '健康'}
  215. ],
  216. specVisible: false,
  217. esComment:null,
  218. showExpand:false,
  219. titIsExpand:false,
  220. lines:2,
  221. lineCount:0,
  222. titOpacity:0,
  223. defTitStyle:{'opacity':0},
  224. showShare:false,
  225. shareItem:{ imageUrl:"",title:"",path:""},
  226. viewVideoNum:0,
  227. //圆环倒计时
  228. iserr:false,
  229. interval:null,
  230. process:0,
  231. processDatas:[],
  232. isCounting:true,
  233. isPostBack:true,
  234. countItem:{"process":0,"isLoad":false},
  235. doLikeDisabled:false,
  236. doFavDisabled:false,
  237. // 点击某个视频进入的列表
  238. curFlag: false,
  239. // 1表示达人主页点进来的
  240. curFlagType: 0,
  241. }
  242. },
  243. created: function() {
  244. // setTimeout(e => {
  245. // uni.createSelectorQuery().select('#w').boundingClientRect(r2 => {
  246. // this.w = r2.width;
  247. // }).exec();
  248. // }, 50)
  249. },
  250. onLoad(options) {
  251. this.talentUserId= options.talentUserId
  252. const curPageNum = Number(options.curPageNum || 1)
  253. this.pageNum = curPageNum
  254. this.curFlagType = options.curFlagType
  255. let i = Number(options.k || 0)
  256. if(i > this.k) {
  257. this.curFlag = true
  258. if(curPageNum>1) {
  259. i = i - (curPageNum-1)*this.pageSize
  260. }
  261. }
  262. const systemInfo = uni.getSystemInfoSync();
  263. this.statusBarHeight=systemInfo.statusBarHeight;
  264. this.windowWidth = systemInfo.screenWidth //获取屏幕宽度
  265. this.boxStyle.width = this.windowWidth + 'px' //给宽度加px
  266. let tabBarHeight = systemInfo.screenHeight - systemInfo.safeArea.bottom;
  267. this.wHeight=systemInfo.windowHeight; //获取屏幕高度
  268. this.boxStyle.height = this.wHeight - this.deleteHeight; //改变视频高度
  269. this.videoStyle.width=this.boxStyle.width;
  270. this.videoStyle.height=this.boxStyle.height - this.statusBarHeight;
  271. this.getData('onLoad',i);
  272. uni.getSystemInfo({success: (res) => {
  273. this.top = res.safeArea.top;
  274. }
  275. });
  276. let that=this;
  277. uni.$on('refreshVideoComment', (data) => {
  278. let item=that.dataList[that.k];
  279. item.smsNum=data.smsNum;
  280. that.dataList[that.k]=item;
  281. that.$forceUpdate(); // 如果你需要强制刷新,可以调用 $forceUpdate()
  282. });
  283. },
  284. onShow(){
  285. if(!isLogin()){
  286. uni.navigateTo({
  287. url: '/pages/auth/loginIndex'
  288. })
  289. return;
  290. }
  291. this.animate = true
  292. this.changeAnimate()
  293. const systemInfo = uni.getSystemInfoSync();
  294. if(this.dataList.length !== 0){
  295. this.dataList[this.k].state = 'play';
  296. uni.createVideoContext(this.dataList[this.k].id,this).play();
  297. }
  298. },
  299. onHide(){
  300. clearInterval(this.animateInterval)
  301. this.animateInterval = null
  302. this.dataList[this.k].state = 'pause';//界面隐藏也要停止播放视频
  303. uni.createVideoContext(this.dataList[this.k].id,this).pause();//暂停以后继续播放
  304. //this.showToast('回到后台');
  305. },
  306. beforeDestroy() {
  307. if(this.animateInterval) {
  308. clearInterval(this.animateInterval)
  309. this.animateInterval = null
  310. }
  311. this.dataList[this.k].state = 'pause';//界面隐藏也要停止播放视频
  312. uni.createVideoContext(this.dataList[this.k].id,this).pause();//暂停以后继续播放
  313. uni.$off("refreshVideoComment");
  314. },
  315. watch:{
  316. k(k,old_k){
  317. //监听 k 值的变化,可以控制视频的播放与暂停
  318. if(!this.curFlag) {
  319. // 清理定时器
  320. //this.dataList[old_k].state = 'stop'//如果是被滑走的视频,就停止播放
  321. this.dataList[old_k].playIng = false//如果视频暂停,就加载封面
  322. this.dataList[old_k].isplay = true
  323. // console.log("qxj 旧视频暂停");
  324. uni.createVideoContext(this.dataList[old_k].id,this).seek(0);
  325. uni.createVideoContext(this.dataList[old_k].id,this).play();
  326. clearTimeout(this.oldVideo)
  327. this.oldVideo = setTimeout(()=>{
  328. uni.createVideoContext(this.dataList[old_k].id,this).pause()
  329. // console.log('预留第' + (old_k + 1) + '个视频:' + this.dataList[old_k].id,this.dataList[k].id)
  330. },10);
  331. }
  332. // clearTimeout(this.timeout)
  333. // this.timeout = setTimeout(()=>{
  334. // uni.createVideoContext(this.dataList[k+1].id,this).seek(0);
  335. // uni.createVideoContext(this.dataList[k+1].id,this).pause();
  336. // console.log('预加载第' + (k+1) + '个视频:' + this.dataList[k+1].id)
  337. // },50);
  338. // 2.0版本已经去掉了下面这一句,视频不用暂停,只需要把声音禁止就行
  339. // uni.createVideoContext(this.dataList[old_k].id + '' + old_k,this).stop()//如果视频暂停,那么旧视频停止,这里的this.dataList[old_k].id + '' + old_k,后面加 old_k 是为了每一个视频的 id 值不同,这样就可以大程度的避免串音问题
  340. this.dataList[k].state = 'play'
  341. // console.log('已经暂停 --> 第' + (old_k + 1) + '个视频~')//提示
  342. clearTimeout(this.player);
  343. this.player = setTimeout(()=>{
  344. uni.createVideoContext(this.dataList[k].id,this).play();
  345. },0);
  346. // 判断是否等于所有视频的长度
  347. if(k == this.dataList.length-1) {
  348. (async ()=>{
  349. console.log("qxj wath isLastPage:"+this.isLastPage);
  350. var p = k;
  351. if(this.isLastPage){
  352. // this.pageNum=1;
  353. // await this.getData();
  354. //var p = k;
  355. }else{
  356. this.pageNum++;
  357. await this.getData();
  358. }
  359. console.log("qxj after getData listCount:"+this.dataList.length);
  360. // this.dataList[p].isplay = true
  361. // setTimeout(()=>{
  362. // uni.createVideoContext(this.dataList[p].id,this).play()
  363. // clearTimeout(this.timeout)
  364. // this.timeout = setTimeout(()=>{
  365. // uni.createVideoContext(this.dataList[p].id,this).seek(0)
  366. // uni.createVideoContext(this.dataList[p].id,this).pause()
  367. // console.log('预加载第' + (p + 1) + '个视频:' + this.dataList[p].id)
  368. // },1000)
  369. // },20)
  370. })();
  371. }
  372. //【此处处理进度条卡住的问题】
  373. if(uni.getSystemInfoSync().platform !== 'ios'){
  374. setTimeout(()=>{
  375. uni.createVideoContext(this.dataList[k].id,this).pause()
  376. uni.createVideoContext(this.dataList[k].id,this).play()
  377. },100)
  378. }
  379. this.xrotats = setTimeout(()=>{
  380. this.showPlay = true;
  381. },200)
  382. }
  383. },
  384. methods: {
  385. handleAvatar(item) {
  386. if(this.curFlagType == 1) {
  387. uni.navigateBack()
  388. } else {
  389. uni.navigateTo({
  390. url:'/pages/expert/index?userId='+item.userId
  391. })
  392. }
  393. },
  394. changeAnimate() {
  395. this.animateInterval = setInterval(()=>{
  396. this.animate = !this.animate
  397. },500)
  398. },
  399. onpullingdown(e) {
  400. if (this.refreshing) return;
  401. if (Math.abs(e.pullingDistance) > Math.abs(e.viewHeight)) {
  402. this.refreshText = '释放更新'
  403. this.isShowTab=false;
  404. } else {
  405. this.refreshText = '下拉更新'
  406. this.isShowTab=true;
  407. }
  408. },
  409. onrefresh(e) {
  410. this.refreshing = true;
  411. this.isShowTab=false;
  412. setTimeout(()=>{
  413. this.refreshing = false;
  414. },100)
  415. // console.log('onRefreshing...');
  416. // this.refreshing = true;
  417. // this.isShowTab=false;
  418. // this.pageNum=1;
  419. // this.getData();
  420. // if (this.refreshing) return;
  421. },
  422. getData(flag,index){
  423. let that=this;
  424. const params={
  425. keyword:this.keyword,
  426. userId:this.talentUserId,
  427. pageNum:this.pageNum,
  428. pageSize:this.pageSize,
  429. };
  430. this.isEmpty = false
  431. getVideoList(params).then(res => {
  432. this.refreshing = false;
  433. this.isShowTab=true;
  434. if(res.code==200&& res.data &&res.data.list&&res.data.list.length > 0){
  435. if(this.pageNum==1 || flag =='onLoad') {
  436. this.dataList = []
  437. }
  438. const datas=res.data.list;
  439. this.isLastPage=res.data.isLastPage;
  440. datas.forEach(e=>{
  441. e.videoId=e.id;
  442. e.id = 'A'+e.id+''+parseInt(Math.random()*1000);
  443. //e.src=e.src.replace("obs.shouzhujue.com","obs.jy.cc");
  444. //e.src=e.src.replace("cdn.ylrzcloud.com","tcpv.ylrzcloud.com");
  445. this.dataList.push(e);
  446. });
  447. if(flag =='onLoad') {
  448. const eventParam = {
  449. isDragging: false
  450. }
  451. this.scrolls(eventParam,'scroll',index)
  452. }
  453. const i = flag =='onLoad'? this.k : 0
  454. if(this.pageNum==1 || flag =='onLoad'){
  455. setTimeout(e=>{
  456. this.tapVideoHover("reset");
  457. this.checkTextLines(0);
  458. },100)
  459. this.leftTimers=setTimeout(e=>{
  460. this.dataList[0].isShowGoods=true;
  461. },3000);
  462. }
  463. if(this.isPostBack){
  464. this.isPostBack=false;
  465. this.getBrowse();
  466. }
  467. }else{
  468. this.isEmpty = true
  469. this.dataList = []
  470. this.refreshing = false;
  471. this.isShowTab=true;
  472. }
  473. },
  474. rej => {
  475. uni.hideLoading()
  476. }
  477. ).catch(()=>{
  478. uni.hideLoading()
  479. //联网失败, 结束加载
  480. this.refreshing = false;
  481. this.isShowTab=true;
  482. });
  483. },
  484. touchstart(event) {
  485. this.dataList[this.k].isShowimage = true //刚触摸的时候就要显示预览视频图片了
  486. this.dataList[this.k].isShowProgressBarTime = true //显示时间线
  487. this.ProgressBarOpacity = 1 //让滑块显示起来更明显一点
  488. this.dotWidth = 10 //让点显示起来更明显一点
  489. },
  490. touchend() { //当手松开后,跳到最新时间
  491. console.log('touchEnd');
  492. uni.createVideoContext(this.dataList[this.k].id, this).seek(this.newTime)
  493. if (this.dataList[this.k].state == 'pause') {
  494. this.dataList[this.k].state = 'play'
  495. uni.createVideoContext(this.dataList[this.k].id, this).play();
  496. console.log('touchEnd 播放数据',this.k,this.dataList[this.k].id);
  497. }
  498. this.dataList[this.k].isShowProgressBarTime = false //触摸结束后,隐藏时间线
  499. this.dataList[this.k].isShowimage = false //触摸结束后,隐藏时间预览
  500. this.ProgressBarOpacity = 0.5 //隐藏起来进度条,不那么明显了
  501. this.dotWidth = 0 //隐藏起来进度条,不那么明显了
  502. },
  503. touchmove(event) { //当手移动滑块时,计算位置、百分小数、新的时间
  504. var msg = []
  505. if (this.videoTime !== '') {
  506. msg = this.videoTime.split(':')
  507. }
  508. var timeNumber = Number(msg[0]) * 60 + Number(msg[1])
  509. this.currentPositions = event.changedTouches[0].screenX
  510. this.percent = this.currentPositions / this.windowWidth
  511. this.newTime = this.percent * timeNumber
  512. this.currenttimes = parseInt(this.newTime)
  513. let theTime = this.newTime
  514. let middle = 0; // 分
  515. if (theTime > 60) {
  516. middle = parseInt(theTime / 60);
  517. theTime = parseInt(theTime % 60);
  518. }
  519. this.changeTime = `${Math.round(middle)>9?Math.round(middle):'0'+Math.round(middle)}:${Math.round(theTime)>9?Math.round(theTime):'0'+Math.round(theTime)}`
  520. },
  521. tapVideoHover(state,event){
  522. this.dataList[this.k].isShowimage = false
  523. this.dataList[this.k].isShowProgressBarTime = false
  524. this.ProgressBarOpacity = 0.5
  525. this.dotWidth = 0
  526. // 1.启用双击点赞 --- start
  527. if(state=='play'||state=='continue'){
  528. this.dataList[this.k].state = 'pause';
  529. }
  530. else if(state=='reset'){
  531. this.dataList[this.k].state = 'reset';
  532. }
  533. else{
  534. this.dataList[this.k].state = 'continue';
  535. }
  536. this.dataList[this.k].isShowPlayIcon = true;
  537. //console.log('xxx',this.dataList[this.k].state);
  538. if(this.dataList[this.k].state == 'continue'){
  539. //console.log('播放数据',this.dataList[this.k].id);
  540. uni.createVideoContext(this.dataList[this.k].id,this).play();//暂停以后继续播放
  541. }
  542. if(this.dataList[this.k].state == 'pause'){
  543. uni.createVideoContext(this.dataList[this.k].id,this).pause();//暂停以后继续播放
  544. }
  545. // console.log("暂停以后继续播放====",this.k,this.dataList[this.k])
  546. if(this.dataList[this.k].state == 'reset'){
  547. uni.createVideoContext(this.dataList[this.k].id,this).seek(0);
  548. uni.createVideoContext(this.dataList[this.k].id,this).play();//暂停以后继续播放
  549. this.dataList[this.k].state = 'continue';
  550. }
  551. },
  552. scrolls (event,type,index) {
  553. this.isDragging = event.isDragging;
  554. if (!event.isDragging) {//isDragging:判断用户是不是在滑动,滑动:true,停止滑动:false。我们要用户停止滑动时才给 k 赋值,这样就可以避免很多麻烦
  555. var i = 0//先用绝对值取出滑动的距离,然后除以屏幕高度,取一个整,就知道你现在滑动到哪一个视频了
  556. if(type&&type=='scroll'){
  557. i = index
  558. } else {
  559. i = Math.round(Math.abs(event.contentOffset.y) / (this.wHeight - this.deleteHeight - this.statusBarHeight + 1))
  560. }
  561. if(i !== this.k){
  562. //这里加判断是因为这个方法会执行很多次,会造成重复请求,所以这里写一个限制
  563. let num = 0;
  564. clearTimeout(this.timers);
  565. this.timers = setTimeout(()=>{
  566. this.k = i;//判断了用户没有滑动,确认了用户的确是在看这个视频,然后就赋值啦
  567. if(type&&type=='scroll') {
  568. this.$nextTick(()=>{
  569. try {
  570. const el = this.$refs['item'+this.k][0]
  571. dom.scrollToElement(el, {
  572. animated: false
  573. })
  574. this.curFlag = false
  575. } catch(err) {
  576. console.log(err)
  577. }
  578. })
  579. }
  580. this.dataList[this.k].state = 'play';
  581. console.log('正在播放 --> 第' + (this.k + 1) + '个视频~');
  582. this.checkTextLines(i);
  583. this.getBrowse();
  584. },num);
  585. if(!isLogin()){
  586. if(this.viewVideoNum%2==0){
  587. showLoginPage();
  588. }
  589. this.viewVideoNum++;
  590. }
  591. clearTimeout(this.leftTimers);
  592. this.leftTimers=setTimeout(e=>{
  593. this.dataList[this.k].isShowGoods=true;
  594. },3000);
  595. }
  596. }
  597. },
  598. handleDoLike(item,index){
  599. if (this.doLikeDisabled) return;
  600. this.doLikeDisabled = true;
  601. this.doLike(item, i);
  602. setTimeout(() => {
  603. this.doLikeDisabled = false;
  604. }, 1000); // 1秒后重新启用方法
  605. },
  606. doLike(item,index){
  607. if(!isLogin()){
  608. showLoginPage();
  609. return;
  610. }
  611. doLike(item.videoId).then(res => {
  612. if(res.code==200){
  613. if(item.like==0){
  614. item.like=1;
  615. item.likeNum+=1;
  616. }else{
  617. item.like=0;
  618. item.likeNum-=1;
  619. }
  620. this.dataList[index]=item;
  621. this.$forceUpdate(); // 如果你需要强制刷新,可以调用 $forceUpdate()
  622. }else{
  623. this.showToast(res.msg);
  624. }
  625. },
  626. rej => {}
  627. );
  628. },
  629. doFavorite(item,index){
  630. if(!isLogin()){
  631. showLoginPage();
  632. return;
  633. }
  634. doFavorite(item.videoId).then(res => {
  635. if(res.code==200){
  636. if(item.favorite==0){
  637. item.favorite=1;
  638. item.favoriteNum+=1;
  639. }else{
  640. item.favorite=0;
  641. item.favoriteNum-=1;
  642. }
  643. this.dataList[index]=item;
  644. this.$forceUpdate(); // 如果你需要强制刷新,可以调用 $forceUpdate()
  645. }
  646. else{
  647. this.showToast(res.msg);
  648. }
  649. },
  650. rej => {}
  651. );
  652. },
  653. addIntegral(){
  654. if(!isLogin()){
  655. return;
  656. }
  657. addIntegral(2).then(res => {
  658. if(res.code==200){
  659. uni.showToast({icon:'none',title:res.msg,duration:3000,position:'bottom'});
  660. }
  661. },
  662. rej => {}
  663. );
  664. },
  665. tabChange (index) {
  666. this.tabIndex=index;
  667. },
  668. playIngs(item,i){
  669. item.state='play'
  670. item.isShowPlayIcon = true
  671. },
  672. openComment(item){
  673. const subNVue = uni.getSubNVueById('videoComment');
  674. subNVue.show('slide-in-bottom', 250);
  675. uni.$emit('videoComment', {
  676. videoId: item.videoId,
  677. smsNum:item.smsNum,
  678. subNVueName: 'videoComment'
  679. });
  680. },
  681. closePro(item,index){
  682. item.isShowGoods=false;
  683. this.dataList[index]=item;
  684. this.$forceUpdate();
  685. },
  686. goToPro(item){ //跳转疗法页面
  687. uni.navigateTo({
  688. url: "/pages/store/packageDetails?packageId="+item.productId
  689. });
  690. },
  691. click:function(){
  692. },
  693. onClickItem(e) {
  694. if (this.tabIndex !== e.currentIndex) {
  695. this.tabIndex = e.currentIndex
  696. }
  697. },
  698. getRichText(content) {
  699. content = new HTMLParser(content.trim())
  700. return content
  701. },
  702. checkTextLines(index) {
  703. var system = uni.getSystemInfoSync();
  704. let textWidth=system.screenWidth-uni.upx2px(150+20);
  705. let fontSize=uni.upx2px(30);
  706. let screenWidth=system.screenWidth;
  707. let that=this;
  708. let txtTitle=this.$refs["txtTitle"+index][0];
  709. if(txtTitle) {
  710. this.defTitStyle={'opacity':0}
  711. this.showExpand=false;
  712. uni.createSelectorQuery().select("#txtTitle"+index).boundingClientRect(rect => {
  713. setTimeout(e=>{
  714. this.defTitStyle={'opacity':1};
  715. this.showExpand=rect.height>40;
  716. },50);
  717. }).exec();
  718. }
  719. },
  720. linechange(event){
  721. const lineCount = event.detail.lineCount //行数
  722. this.lineCount = lineCount
  723. if(lineCount>3){ //如果大于3行,显示展开阅读
  724. this.showExpand = true
  725. }
  726. },
  727. clickExpand(){
  728. this.titIsExpand=!this.titIsExpand;
  729. this.defTitStyle={'opacity':1,'lines':this.titIsExpand?1000:2};
  730. },
  731. openShare(item){
  732. this.shareItem.videoId = item.videoId;
  733. this.shareItem.title=item.title;
  734. this.shareItem.imageUrl=item.cover;
  735. this.shareItem.compressImage = 1
  736. this.shareItem.summary="";
  737. let cdn=uni.getStorageSync('h5Path');
  738. this.shareItem.url=cdn+"/pages/course/video/living-applet?videoId="+item.videoId;
  739. this.showShare=true;
  740. },
  741. getBrowse() { // 倒计时
  742. this.countItem=this.processDatas[this.k];
  743. if(this.countItem==null){
  744. this.countItem={"process":0,"isLoad":false};
  745. this.process=0;
  746. }
  747. this.process=this.countItem.isLoad?100:0;
  748. if(this.interval==null){
  749. this.interval = setInterval(() => {
  750. if (this.process < 100) {
  751. if (this.isCounting) {
  752. this.process = this.process + 1;
  753. this.countItem.process=this.process;
  754. if(this.processDatas[this.k]!=undefined){
  755. this.processDatas.splice(this.k,1,this.countItem);
  756. }else{
  757. this.processDatas.push(this.countItem);
  758. }
  759. }
  760. }
  761. else {
  762. if(!this.countItem.isLoad){
  763. this.addIntegral();
  764. }
  765. clearInterval(this.interval);
  766. this.interval=null;
  767. this.countItem.isLoad=true;
  768. if(this.processDatas[this.k]!=undefined){
  769. this.processDatas.splice(this.k,1,this.countItem);
  770. }else{
  771. this.processDatas.push(this.countItem);
  772. }
  773. }
  774. }, 100);
  775. }
  776. },
  777. onProgress() {
  778. //console.log("------qxj onProgress");
  779. },
  780. timeupdate(){
  781. //console.log("------qxj onTimeupdate");
  782. },
  783. onLoadeddata() {
  784. console.log('------qxj 视频缓冲完成');
  785. },
  786. onVideoCanPlay() {
  787. console.log('------qxj 视频可以开始播放,但可能需要缓冲');
  788. },
  789. onVideoCanPlayThrough() {
  790. console.log('------qxj 视频可以无暂停地播放');
  791. },
  792. onLoadedMetadata(e) {
  793. //console.log("------qxj onLoadedMetadata");
  794. },
  795. endedPlayNext(){
  796. //console.log("------qxj endedPlayNext");
  797. },
  798. onWaiting(){
  799. ////console.log("------qxj onWaiting");
  800. //this.tapVideoHover("");
  801. },
  802. onError(){
  803. console.log("------qxj onError 当前视频播放出错");
  804. uni.showToast({title: "当前视频播放出错",icon: 'none',position:'bottom'});
  805. },
  806. showToast(title){
  807. uni.showToast({icon:'none',title: title ,duration:3000});
  808. },
  809. tapRedpacked(){
  810. },
  811. navBack() {
  812. uni.navigateBack()
  813. }
  814. }
  815. }
  816. </script>
  817. <style scoped lang="scss">
  818. .animate-icon {
  819. width:70rpx;
  820. height:70rpx;
  821. transition-duration: 0.5s;
  822. transform:scale(1);
  823. transition-timing-function: linear;
  824. }
  825. .animate-scale{
  826. width:70rpx;
  827. height:70rpx;
  828. transition-duration: 0.5s;
  829. transform:scale(0.88);
  830. transition-timing-function: linear;
  831. }
  832. .emptybox {
  833. align-items: center;
  834. &-img {
  835. width: 320rpx;
  836. height: 240rpx;
  837. }
  838. &-tip {
  839. margin-top: 80rpx;
  840. font-size: 30rpx;
  841. color: gray;
  842. }
  843. }
  844. .view-animation{
  845. transition-duration: 0.2s;
  846. transition-property: height;
  847. }
  848. .container {
  849. background-color: #000000;
  850. }
  851. .item {
  852. /* width : 750rpx; */
  853. background-color: #000000;
  854. position: relative;
  855. }
  856. .videoHover {
  857. position: absolute;
  858. top: 0;
  859. left: 0;
  860. flex: 1;
  861. background-color: rgba(0, 0, 0, 0.1);
  862. justify-content: center;
  863. align-items: center;
  864. /* border-style: dashed;
  865. border-color: #DD524D;
  866. border-width: 1px; */
  867. }
  868. .playState {
  869. width: 80rpx;
  870. height: 80rpx;
  871. opacity: 0.9;
  872. }
  873. .userInfo {
  874. position: absolute;
  875. bottom: 80px;
  876. right: 10px;
  877. flex-direction: column;
  878. }
  879. .userAvatar {
  880. border-radius: 500%;
  881. margin-bottom: 15px;
  882. border-style: solid;
  883. border-width: 2px;
  884. border-color: #ffffff;
  885. }
  886. .userAvatar {
  887. width: 100rpx;
  888. height: 100rpx;
  889. }
  890. .likeIco,
  891. .shareIco,
  892. .commentIco {
  893. width: 60rpx;
  894. height: 60rpx;
  895. margin-top: 15px;
  896. }
  897. .likeNum,
  898. .commentNum,
  899. .shareTex {
  900. color: #ffffff;
  901. font-size: 30rpx;
  902. text-align: center;
  903. margin: 5px;
  904. }
  905. .likeNumActive {
  906. color: red;
  907. }
  908. .content {
  909. width: 610rpx;
  910. z-index: 99;
  911. position: absolute;
  912. bottom: 30px;
  913. /* background-color: #007AFF; */
  914. /* justify-content: center; */
  915. padding: 15rpx;
  916. flex-direction: column;
  917. justify-content: flex-start;
  918. color: #ffffff;
  919. }
  920. .userName {
  921. font-size: 30rpx;
  922. color: #ffffff;
  923. margin-top: 80upx;
  924. }
  925. .words {
  926. margin-top: 10rpx;
  927. font-size: 30rpx;
  928. color: #ffffff;
  929. }
  930. .root {
  931. background-color: #000000;
  932. /* background-color: #00ffff; */
  933. }
  934. .person {
  935. position: absolute;
  936. right: 0;
  937. height: 88rpx;
  938. }
  939. .person .num {
  940. background-color: rgba(255, 100, 3, 1);
  941. height: 58rpx;
  942. border-radius: 100rpx 0 0 100rpx;
  943. padding: 0 20rpx;
  944. }
  945. .right,.left {
  946. position: absolute;
  947. bottom: 180rpx;
  948. padding-bottom: env(safe-area-inset-bottom);
  949. }
  950. .right {
  951. right: 30rpx;
  952. bottom: 100rpx;
  953. }
  954. .right .item1 {
  955. width: 100rpx;
  956. }
  957. .right image {
  958. width: 100%;
  959. height: 100%;
  960. }
  961. .left {left: 20rpx;}
  962. .goods .icon,.goods .icon image {
  963. width: 290rpx;
  964. height: 290rpx;
  965. }
  966. .bg {
  967. /* background-image: url(/static/images/other/video/bg.png); */
  968. position: absolute;
  969. left: 0;
  970. top: 0;
  971. width: 100%;
  972. height: 74rpx;
  973. }
  974. .goods {
  975. width: 330rpx;
  976. background-color: rgba(255, 255, 255, 0.4);
  977. padding: 20rpx;
  978. border-radius: 20rpx;
  979. margin-top: 20rpx;
  980. }
  981. .tabbar1{
  982. position: absolute;
  983. top: 44px;
  984. left: 30rpx;
  985. z-index: 999;
  986. display: inline-flex;
  987. flex-direction: row;
  988. align-items: center;
  989. padding: 8rpx 16rpx;
  990. border-radius: 30rpx;
  991. background-color:rgba(0,0,0,0.2) ;
  992. color: #fff;
  993. font-weight: 400;
  994. font-size: 26rpx;
  995. }
  996. .border1{
  997. border-width: 1px;border-color: green;border-style: solid;
  998. }
  999. .border2{
  1000. border-width: 1px;border-color: yellow;border-style: solid;
  1001. }
  1002. .refresh {
  1003. display: flex;
  1004. flex-direction: row;
  1005. justify-content: center;
  1006. height: 50px;
  1007. }
  1008. .bottom {
  1009. position: absolute;
  1010. left: 0;
  1011. bottom: 60rpx;
  1012. right: 150rpx;
  1013. padding-bottom: env(safe-area-inset-bottom);
  1014. }
  1015. .txtTitle{
  1016. line-height: 20px;
  1017. /* 超出两行显示省略号,如果是text标签需要设置为1 */
  1018. color: #fff;
  1019. font-weight: 500;
  1020. font-size: 30rpx;
  1021. margin-left:20rpx;
  1022. }
  1023. .ellipsis{
  1024. lines:2;
  1025. /* 确保文本不会自动换行 */
  1026. /* white-space: nowrap; */
  1027. /* 设置文本溢出时显示省略号 */
  1028. text-overflow: ellipsis;
  1029. /* 限制显示的行数为2 */
  1030. overflow: hidden;
  1031. white-space: nowrap; /* 不换行 */
  1032. padding-right: 20px; /* 设置右边距为20px,实现末尾缩进 */
  1033. box-sizing: border-box; /* 包含padding在内的总宽度 */
  1034. }
  1035. .expandBtn{
  1036. position: absolute;
  1037. right: 0rpx;
  1038. bottom: 0rpx;
  1039. font-weight: 600;
  1040. color: #fff;
  1041. font-size: 30rpx;
  1042. /* background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1) 50%); */
  1043. }
  1044. .redpacked{
  1045. position: fixed;
  1046. width: 86rpx;
  1047. height: 86rpx;
  1048. top: 300rpx;
  1049. z-index: 999;
  1050. left: 30rpx;
  1051. background-color: rgba(0, 0, 0, 0.4);
  1052. }
  1053. </style>