index.nvue 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042
  1. <template>
  2. <view class="container">
  3. <!--
  4. 注意:这是 App 所用页面,请勿引入微信小程序或浏览器运行,最好运行在真机
  5. 1. new_index.nvue、index.nvue这两个是App页面
  6. 2. index.nvue - 页面预加载使用 - 在线预加载方案
  7. 3. 另外:data.js 是上一版本留下的假数据,这一版改成了 URL 请求了(如不需要可以删除,也可作为后端请求参考)
  8. 4. 请各位大神多多留手,我已经把请求内存开到最大了
  9. 5. 视频 id 切记是字符串类型
  10. 6. 这里仅 App 端引入了 App 端专用评论,小程序 、H5 引入的时候 可以作为参考
  11. App、小程序、H5评论请参考插件:https://ext.dcloud.net.cn/plugin?id=7875
  12. -->
  13. <!-- 头部导航 -->
  14. <view class="header">
  15. <view class="items" @click.stop="navTap(2)">
  16. <text class="tName">推荐</text>
  17. <view class="tLine" v-if="currentNav==2"></view>
  18. </view>
  19. <view class="items" @click.stop="navTap(1)">
  20. <text class="tName">最新</text>
  21. <view class="tLine" v-if="currentNav==1"></view>
  22. </view>
  23. </view>
  24. <!-- <view @click="tolistVideo" style="position: fixed; margin-top: 100upx; right: 40upx;">
  25. <text style="padding: 10upx; padding-left: 40upx; padding-right: 40upx; border-radius: 20upx; background-color: #F8F8F8; font-size: 14px;">H5/小程序</text>
  26. </view>
  27. <view @click="autoPlay" style="position: fixed; margin-top: 100upx; left: 40upx;">
  28. <text style="padding: 10upx; padding-left: 40upx; padding-right: 40upx; border-radius: 20upx; background-color: #F8F8F8; color: #007AFF; font-weight: bold; font-size: 14px;">{{autoplayText}}</text>
  29. </view>
  30. <view @click="previewVideo" style="position: fixed; margin-top: 200upx; right: 40upx;">
  31. <text style="padding: 10upx; padding-left: 40upx; padding-right: 40upx; border-radius: 20upx; background-color: #F8F8F8; font-size: 14px;">App端-预览视频界面</text>
  32. </view>
  33. <view @click="wxh5Video" style="position: fixed; margin-top: 300upx; right: 40upx;">
  34. <text style="padding: 10upx; padding-left: 40upx; padding-right: 40upx; border-radius: 20upx; background-color: #F8F8F8; font-size: 14px;">微信/H5端-预览视频界面</text>
  35. </view> -->
  36. <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>
  37. <view :style="'width: '+ windowWidth +'px; height: '+ boxStyle.height +'px;'">
  38. <!--
  39. 1.这里的 swiper 不是用来控制视频滑动的,而是用来控制左右滑动的,如果不需要的可以改成 view
  40. 2.为了 视频无限加载,已经把 21 行的 appear 去掉了,加上了 loadmore 方法(第10行)
  41. 3.由于方法比较多,可以采取下面的方式查看代码:
  42. (1)Mac:按住 option 键,然后点击方法名,即可跳转到方法
  43. (2)windows:按住 Alt 键,然后鼠标左击,即可跳转到方法
  44. -->
  45. <list @loadmore="getData" @scroll="scrolls" :loadmoreoffset="wHeight*3" :show-scrollbar="false" ref="listBox" :pagingEnabled="true" :scrollable="true">
  46. <!-- 刷新模块 -->
  47. <refresh class="refresh" @refresh="onrefresh" @pullingdown="onpullingdown" :display="refreshing ? 'show' : 'hide'">
  48. <loading style="background-color: #FFFFFF;">
  49. <image src="../static/img/index/logins.gif" :style="'width: 80upx; height: 40upx; margin-top: 80upx; margin-bottom: 30upx; margin-left: '+ (windowWidth - 200) +'px;'"></image>
  50. </loading>
  51. </refresh>
  52. <!-- 循环数据 -->
  53. <cell v-for="(item,i) in dataList" :key="i">
  54. <!-- 用div把视频模组套起来 -->
  55. <div :style="'width: '+ windowWidth +'px; height: '+ boxStyle.height +'px;'" @disappear="stop()">
  56. <view v-if="Math.abs(k-i)<=1">
  57. <view class="root">
  58. <!--
  59. 具体视频参数可以参考官方文档
  60. 说明:
  61. 1.v-if很关键,这里主要是为了减少 dom 元素【这样才不会加载视频多了闪退】,
  62. 这里 Math.abs(k-i)<=5 也就是往上预加载 5 个视频,往下预加载 5
  63. 个视频这样做的目的是为了让视频能够提前加载但是不播放,在真正滑到位
  64. 置的时候播放视频。
  65. 【2.0.1就是 1 Math.abs(k-i)<=1:请勿修改,记住,要不然会提前播放很多视频】
  66. 2.要注意 @play="playIngs" 里面的 playIngs 方法,这个方法只是在视频播放的时候
  67. 起效果,我们控制视频播放不是用这个的。这个的主要作用是给视频封面的。我们先用
  68. 下面的视频封面盖住视频,等到视频播放的时候,我们不要急着直接播放,而是延迟一下下,
  69. 300-600ms左右。因为视频播放需要一点点时间,这点时间里会黑屏,这个时候我们就用
  70. 下面的封面盖住,这样用户就不会有从黑屏到有画面的感觉了,但是如果遇到视频太大,缓冲
  71. 时间太长,还是会出现短暂的黑屏,大部分是不会有黑屏的(这样盖住的话)。
  72. 【更新记录:2.0版】已经解决了视频黑屏问题,和加载速度慢的情况,如果还是出现了黑屏,
  73. 意味着此时手滑动的速度,已经超过了视频加载的速度,对于这个问题,建议修改 preloadNumber
  74. 变量,当它的值大一点的时候就会提前加载视频,这样用户在滑到视频的时候就不会有停顿感了
  75. 【注意】:老用户在 video 中增加和修改
  76. (1):muted="!item.playIng",
  77. (2)@timeupdate="timeupdate($event,i)"
  78. (3)把 199 行注释了,
  79. (4):id="item.id",
  80. (5)修改:uni.createVideoContext(this.dataList[this.k].id + '' + this.k,this) 为
  81. uni.createVideoContext(this.dataList[this.k].id,this)
  82. (6)在 timeupdate 方法里加入,if(index == this.k){把里面的加一个总的判断}
  83. 3.其他的下面有详解
  84. -->
  85. <video
  86. :ref="'item'+i"
  87. :id="item.id"
  88. :loop="true"
  89. :src="item.video_url"
  90. :muted="item.isplay"
  91. @play="playIngs(i)"
  92. :enable-progress-gesture="false"
  93. :page-gesture="false"
  94. :controls="false"
  95. :http-cache="true"
  96. :show-loading="false"
  97. :show-fullscreen-btn="false"
  98. :show-center-play-btn="false"
  99. :style="boxStyle"
  100. :object-fit="object_fit"
  101. @timeupdate="timeupdate($event,i)"
  102. ></video>
  103. <!-- 这里是封面 -->
  104. <image
  105. v-if="!item.playIng"
  106. :src="item.video_url+'?x-oss-process=video/snapshot,t_100,f_jpg'"
  107. :mode="mode"
  108. :style="'width: '+ windowWidth +'px; height: '+ (wHeight - deleteHeight) +'px; position: absolute;'"
  109. ></image>
  110. <!--
  111. mode: 图片裁剪、缩放的模式
  112. mode 有 14 种模式,其中 5 种是缩放模式,9 种是裁剪模式。
  113. https://uniapp.dcloud.io/component/image
  114. -->
  115. </view>
  116. <!-- 直接用 view 就行了,一样是可以覆盖原生组件的 -->
  117. <!-- 这个是暂停时出现的图标 -->
  118. <view class="videoHover" @click="tapVideoHover(item.state,$event)" @touchstart="touchstartHover" :style="boxStyle">
  119. <image v-if="item.state=='pause'" class="playState" src="../static/img/index/play.png"></image>
  120. </view>
  121. <view class="userInfo">
  122. <!-- 1.头像 -->
  123. <image v-if="item.isShowProgressBarTime == false" @click="tozuozhe" class="userAvatar" :src="item.type_image" mode="aspectFill"></image>
  124. <!-- 2.点赞 -->
  125. <view v-if="item.isShowProgressBarTime == false" @click="cLike(item);" style="opacity: 0.9; margin-top: 5px;">
  126. <image v-if="item.is_like" src="../static/img/index/xin.png" style="width: 29px; height: 29px; position: absolute; right: 6px;"></image>
  127. <image v-if="!item.is_like" src="../static/img/index/xin-2.png" style="width: 29px; height: 29px; position: absolute; right: 6px;"></image>
  128. <text style="color: #FFFFFF; margin-top: 5px; font-size: 12px; text-align: center; margin-top: 32px; font-weight: 400;">{{item.like_num}}</text>
  129. </view>
  130. <!-- 3.评论 -->
  131. <view v-if="item.isShowProgressBarTime == false" class="comment" @click="toComment(item)" style="opacity: 0.9; margin-top: 18px;">
  132. <image src="../static/img/index/evaluate.png" style="width: 54rpx; height: 50rpx; position: absolute; right: 7px;"></image>
  133. <text style="color: #FFFFFF; font-size: 12px; font-weight: 400; text-align: center; margin-top: 29px;">{{item.comment_num}}</text>
  134. </view>
  135. <!-- 收藏 -->
  136. <view @click="cCollect(item);" style="opacity: 0.9; margin-top: 18px;">
  137. <image v-if="item.is_collect" src="../static/img/index/collection02.png" style="width: 29px; height: 29px; position: absolute; right: 6px;"></image>
  138. <image v-if="!item.is_collect" src="../static/img/index/collection01.png" style="width: 29px; height: 29px; position: absolute; right: 6px;"></image>
  139. <text style="color: #FFFFFF; margin-top: 5px; font-size: 12px; text-align: center; margin-top: 36px; font-weight: 400;">{{item.collect_num}}</text>
  140. </view>
  141. <!-- 4.分享 -->
  142. <view v-if="item.isShowProgressBarTime == false" @click="appShare('WXSceneSession')" style="opacity: 0.9; margin-top: 17px;">
  143. <image src="../static/img/index/share-fill.png" style="width: 40px; height: 40px; position: absolute; right: 5px;"></image>
  144. <text style="color: #FFFFFF; margin-top: 5px; font-size: 14px; text-align: center; font-weight: bold; margin-top: 40px;">分享</text>
  145. </view>
  146. </view>
  147. <!-- 最底下的文字部分 -->
  148. <view class="content" v-if="dataList.length !== 0 && dataList[k].isShowProgressBarTime == false">
  149. <view class="cart" @click="goCart(item)" v-if="dataList.product_num>0">
  150. <image class="cartPic" src="../static/img/index/shopping-car.png"></image>
  151. <text class="cartName">购物</text>
  152. <text class="line"></text>
  153. <text class="cartName">视频款请点击这里购买</text>
  154. </view>
  155. <view class="timeCon" :style="'width: '+ (windowWidth - 90) +'px;'">
  156. <text class="userName">{{item.type_name}}</text>
  157. <text class="time">.{{item.date}}</text>
  158. </view>
  159. <view class="words" :style="'width: '+ (windowWidth - 120) +'px;'">
  160. <view v-if="item.isMore || item.desc.length<=29">
  161. <text class="info">{{item.desc}}</text>
  162. <view class="close">
  163. <text v-if="item.isMore" class="more" @click="moreTap(item)">收起</text>
  164. <image v-if="item.isMore" class="imgClose" src="../static/img/index/drop-down.png"></image>
  165. </view>
  166. </view>
  167. <view class="wordsCon" v-else>
  168. <text class="info">{{item.desc.slice(0,29)}}...</text>
  169. <text class="more" @click="moreTap(item)">更多</text>
  170. <image class="img" src="../static/img/index/drop-down.png"></image>
  171. </view>
  172. </view>
  173. </view>
  174. <!-- 1.视频预览时的图片,currenttimes:就是获取当前滑块的时间点,如果不需要,可以注释掉 -->
  175. <!-- 2.如果使用下面的视频预览的话要注意的是视频链接最好是阿里云上的,因为
  176. https://xxxxxxxxx.mp4?x-oss-process=video/snapshot,t_1000,f_jpg
  177. 这个是阿里云的东西,至于其他的视频截帧我还没有试过。
  178. -->
  179. <!-- 3.阿里云视频截帧地址:https://help.aliyun.com/document_detail/64555.html -->
  180. <image
  181. v-if="item.isShowimage == true"
  182. :src="item.src+'?x-oss-process=video/snapshot,t_'+ currenttimes +'000,f_jpg'"
  183. mode="aspectFill"
  184. :style="'width: 120upx; height: 160upx; border-radius: 10upx; position: absolute; bottom: '+ (ProgressBarBottom + 160) +'upx; left: '+ (currentPositions - 15) +'px;'"
  185. ></image>
  186. </view>
  187. </div>
  188. </cell>
  189. </list>
  190. <!-- 1.注意:进度条这类拖拽的东西不能放进block\cell这些循环体中的,要不然touchmove方法会捕捉有误 -->
  191. <!-- <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;'">
  192. <text style="font-size: 22px; font-weight: bold; color: #F1F1F1;">{{changeTime}} / {{videoTimes}}</text>
  193. </view> -->
  194. <!-- 这里就是进度条了:纯手工进度条,调整位置的话就把他们的 bottom 改成一下就行了 -->
  195. <!-- <view v-if="isDragging == false" @touchmove="touchmove" @touchend="touchend" @touchstart="touchstart" style="position: absolute; bottom: 0; left: 0;"> -->
  196. <!-- 1.这一步必须加,为了适配低端机型 -->
  197. <!-- <text :style="'width: '+ windowWidth +'px; opacity: 0;'">.</text> -->
  198. <!-- 2.这是未加载的时的右边的灰色部分 -->
  199. <!-- <view :style="'width: '+ windowWidth +'px; height: 4upx; background-color: #C8C7CC; position: absolute; bottom: '+ ProgressBarBottom +'upx; opacity: '+ ProgressBarOpacity +';'"></view> -->
  200. <!-- 3.这里我采用的分离式办法:就是让滑动样式和不滑动的样式分开,这样相互不干扰,可以避免进度条闪动的问题 -->
  201. <!-- 4.注意:isShowProgressBarTime 加入了返回数据中 -->
  202. <!-- <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>
  203. <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>
  204. <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>
  205. <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> -->
  206. <!-- </view> -->
  207. </view>
  208. <!--
  209. 请前往 douyin-scrollview.nvue 文件查看
  210. 已经全部注释
  211. 这里就是引入评论插件
  212. -->
  213. <uni-popup type="bottom" ref="pinglun" @touchmove.stop.prevent="moveHandle">
  214. <view :style="'width: '+ windowWidth +'px; height: '+ (boxStyle.height/heightNum) +'px; background-color: #fff; border-top-left-radius: 10px; border-top-right-radius: 10px;'">
  215. <!--
  216. 注意:
  217. deleteIOSHeight
  218. deleteAndroidHeight
  219. 这两个参数用于控制评论等的高度
  220. -->
  221. <douyin-scrollview
  222. :Width="windowWidth"
  223. :Height="(boxStyle.height/1.18)"
  224. :deleteIOSHeight="36"
  225. :deleteAndroidHeight="15"
  226. @closeScrollview="closeScrollview"
  227. @pinlunFun="pinlunFun"
  228. ></douyin-scrollview>
  229. </view>
  230. </uni-popup>
  231. <uni-popup type="bottom" ref="pinglunGoods" @touchmove.stop.prevent="moveHandle">
  232. <view :style="'width: '+ windowWidth +'px;background-color: #F5F5F5; border-top-left-radius: 10px; border-top-right-radius: 10px;'">
  233. <goodsList
  234. :Width="windowWidth"
  235. :Height="(boxStyle.height/1.18)"
  236. ></goodsList>
  237. </view>
  238. </uni-popup>
  239. </view>
  240. </template>
  241. <script>
  242. // import userList from './data.js'//这个是假数据
  243. const app = getApp();
  244. import {
  245. toLogin
  246. } from '@/libs/login.js';
  247. import {
  248. mapGetters
  249. } from 'vuex';
  250. /*
  251. 引入评论组件
  252. */
  253. import douyinScrollview from '../components/douyin-scrollview/douyin-scrollview.nvue'
  254. import goodsList from '../components/goodsList/index.vue'
  255. import {
  256. videoList,
  257. markeVideo
  258. } from '@/api/short-video.js';
  259. import {
  260. HTTP_REQUEST_URL
  261. } from '@/config/app.js';
  262. export default {
  263. computed: mapGetters(['isLogin','uid']),
  264. data() {
  265. return {
  266. isGoods:false,
  267. //下面打🌟号的是必须要的基础字段
  268. //下面打💗号的是拥有滑动条的必须字段
  269. dataList:[],//用于数据循环的列表🌟💗
  270. wHeight:0,//获取的屏幕高度🌟💗
  271. boxStyle:{//视频,图片封面样式🌟💗
  272. 'height': 0,
  273. 'width': 0,
  274. },
  275. k:0,//默认为0🌟💗
  276. playIngIds:[],//正在播放的视频id列队,列队用于处理滑动过快导致的跳频问题🌟💗
  277. ready:false,//可忽略
  278. isDragging: false,//false代表停止滑动🌟💗
  279. refreshing: true,//用于下拉刷新🌟💗
  280. windowWidth: 0,//获取屏幕宽度🌟💗
  281. windowHeight: 0,
  282. dex: [0,0],//用于判断是上滑还是下滑,第一个存旧值,第二个存新值【目前在1.0.7已经废弃】
  283. currents: 0,//用于左右滑动,0代表视频界面,1代表右滑界面🌟💗
  284. platform: '',//用于获取操作系统:ios、android🌟💗
  285. playIng: false,//用于视频初始化时是否播放,默认不播放🌟💗
  286. videoTime: '',//视频总时长,这个主要用来截取时间数值💗
  287. videoTimes: '',//视频时长,用这个来获取时间值,例如:00:30这个时间值💗
  288. changeTime: '',//显示滑动进度条时变化的时间💗
  289. isShowimage: false,//是否显示封面【1.0.4已废弃,但是意思需要记住】
  290. currenttimes: 0,//当前时间💗
  291. isShowProgressBarTime: false,//是否拖动进度条,如果拖动(true)则显示进度条时间,否则不显示(false)【1.0.4已废弃,但是意思需要记住】
  292. ProgressBarOpacity: 0.7,//进度条不拖动时的默认值,就是透明的💗
  293. dotWidth: 0,//播放的小圆点,默认没有💗
  294. deleteHeight: 0,//测试高度🌟💗
  295. percent: 0,//百分小数💗
  296. currentPosition: 0,//滑块当前位置💗//2.0已弃用,现已用于后端参数
  297. currentPositions: 0,//滑块当前位置的副本💗//2.0已弃用,现已用于后端参数
  298. newTime: 0,//跟手滑动后的最新时间💗
  299. timeNumber: 0,//🌟💗
  300. ProgressBarBottom: 20,//进度条离底部的距离💗
  301. object_fit: 'contain',//视频样式默认包含🌟💗
  302. mode: 'aspectFit',//图片封面样式🌟💗
  303. timeout: "",//🌟用来阻止 setTimeout()方法
  304. voice: "",//🌟用来阻止 setTimeout()方法
  305. oldVideo: "",
  306. isAutoplay: false,//是否开启自动播放(默认不开启)
  307. autoplayText: "开启自动播放",
  308. timers: "",
  309. // 引入评论 - 参数
  310. heightNum: 1.18,
  311. // 双击点赞参数
  312. touchNum: 0,
  313. aixinLeft: 0,
  314. aixinTop: 0,
  315. isShowAixin: false,
  316. Rotate: 0,
  317. currentNav:1,
  318. limit: 6,
  319. page: 1
  320. }
  321. },
  322. components:{
  323. douyinScrollview,
  324. goodsList
  325. },
  326. watch:{
  327. k(k,old_k){//监听 k 值的变化,可以控制视频的播放与暂停
  328. // console.log('的点点滴滴多',this.dataList[k].id);
  329. if(!this.dataList.length) return
  330. this.dataList[old_k].state = 'stop'//如果是被滑走的视频,就停止播放
  331. this.dataList[old_k].playIng = false//如果视频暂停,就加载封面
  332. this.dataList[old_k].isplay = true
  333. uni.createVideoContext(this.dataList[old_k].id,this).seek(0)
  334. uni.createVideoContext(this.dataList[old_k].id,this).play()
  335. clearTimeout(this.oldVideo)
  336. this.oldVideo = setTimeout(()=>{
  337. uni.createVideoContext(this.dataList[old_k].id,this).seek(0)
  338. uni.createVideoContext(this.dataList[old_k].id,this).pause()
  339. console.log('预留第' + (old_k + 1) + '个视频:' + this.dataList[old_k].id)
  340. },500)
  341. uni.createVideoContext(this.dataList[k].id,this).play();
  342. clearTimeout(this.voice)
  343. this.voice = setTimeout(()=>{
  344. this.dataList[k].isplay = false
  345. },300)
  346. setTimeout(()=>{
  347. this.dataList[k].playIng = true
  348. },850)
  349. //【2.0版本更新内容】- start
  350. var p = k
  351. ++p
  352. setTimeout(()=>{
  353. uni.createVideoContext(this.dataList[p].id,this).play()
  354. },20)
  355. clearTimeout(this.timeout)
  356. this.timeout = setTimeout(()=>{
  357. uni.createVideoContext(this.dataList[p].id,this).seek(0)
  358. uni.createVideoContext(this.dataList[p].id,this).pause()
  359. console.log('预加载6第' + (p + 1) + '个视频:' + this.dataList[p].id)
  360. },1500)
  361. //【2.0版本更新内容】- end
  362. }
  363. },
  364. onShow(){
  365. console.log('回到前台');
  366. if(this.dataList.length !== 0){
  367. this.dataList[this.k].state = 'play';
  368. uni.createVideoContext(this.dataList[this.k].id,this).play()
  369. }
  370. },
  371. onHide(){
  372. this.dataList[this.k].state = 'pause';//界面隐藏也要停止播放视频
  373. uni.createVideoContext(this.dataList[this.k].id,this).pause();//暂停以后继续播放
  374. console.log('到后台');
  375. },
  376. onLoad(options){
  377. if (options.pid) app.globalData.spid = options.pid;
  378. console.log('到后台');
  379. this.platform = uni.getSystemInfoSync().platform
  380. var model = uni.getSystemInfoSync().model
  381. if(this.platform == 'ios' && (model !== 'iPhone6' || model !== 'iPhone6s' || model !== 'iPhone7' || model !== 'iPhone8')){
  382. this.deleteHeight = 32//有 tabbar的 修改这里可以改变视频高度
  383. /*
  384. 引入评论参数
  385. */
  386. this.heightNum = 1.27
  387. } else {
  388. this.deleteHeight = 0
  389. /*
  390. 引入评论参数
  391. */
  392. this.heightNum = 1.18
  393. }
  394. this.windowWidth = uni.getSystemInfoSync().screenWidth//获取屏幕宽度
  395. this.boxStyle.width = this.windowWidth + 'px'//给宽度加px
  396. this.wHeight = uni.getSystemInfoSync().screenHeight;//获取屏幕高度
  397. this.boxStyle.height = this.wHeight - this.deleteHeight;//改变视频高度
  398. this.get()//这一步,加载视频数据
  399. },
  400. onReady() {
  401. },
  402. methods: {
  403. pinlunFun(e){
  404. let videoID = uni.getStorageSync("videoID");
  405. this.dataList.forEach(item=>{
  406. if(item.id == videoID){
  407. item.comment_num = e;
  408. }
  409. })
  410. },
  411. // 分享
  412. // #ifdef APP-PLUS
  413. appShare(scene) {
  414. let that = this
  415. uni.showLoading({
  416. title: '加载中',
  417. mask: true
  418. });
  419. let uid = this.uid?this.uid:0;
  420. let data = this.dataList[0];
  421. let routes = getCurrentPages(); // 获取当前打开过的页面路由数组
  422. let curRoute = routes[routes.length - 1].$page.fullPath // 获取当前页面路由,也就是最后一个打开的页面路由
  423. uni.share({
  424. provider: "weixin",
  425. scene: scene,
  426. type: 0,
  427. href: `${HTTP_REQUEST_URL}${curRoute}&pid=${that.uid}`,
  428. title: data.type_name || '',
  429. summary: data.desc || '',
  430. imageUrl: data.image || '',
  431. success: function(res) {
  432. uni.hideLoading();
  433. },
  434. fail: function(err) {
  435. uni.showToast({
  436. title: '分享失败',
  437. icon: 'none',
  438. duration: 2000
  439. })
  440. }
  441. });
  442. },
  443. // #endif
  444. onMyEvent: function() {
  445. this.$set(this, 'isGoods', false);
  446. },
  447. goCart(item){
  448. if (this.isLogin === false) {
  449. return toLogin();
  450. }
  451. uni.showToast({
  452. title: '加载中...',
  453. icon: 'none',
  454. position: 'bottom',
  455. duration: 300
  456. })
  457. uni.setStorageSync("videoID",parseInt(item.id));
  458. this.$refs.pinglunGoods.open('bottom');
  459. },
  460. navTap(n){
  461. this.currentNav = n;
  462. this.oldVideo = "";
  463. this.k = 0;
  464. this.page = 1;
  465. this.dataList = [];
  466. this.get();
  467. },
  468. moreTap(item){
  469. item.isMore = !item.isMore;
  470. },
  471. autoPlay(){
  472. this.isAutoplay = !this.isAutoplay;
  473. if(!this.isAutoplay){
  474. this.autoplayText = "开启自动播放"
  475. uni.showToast({
  476. title: "关闭自动播放",
  477. icon: 'none',
  478. duration: 3000
  479. })
  480. } else {
  481. this.autoplayText = "关闭自动播放"
  482. uni.showToast({
  483. title: "开启自动播放",
  484. icon: 'none',
  485. duration: 3000
  486. })
  487. }
  488. },
  489. getData(){
  490. // 这里就是数据加载完以后再向后端发送数据的地方,
  491. videoList({
  492. page: this.page,
  493. limit: this.limit,
  494. order_type: this.currentNav
  495. }).then(res=>{
  496. this.page = this.page + 1;
  497. var msg = res.data
  498. for (let i = 0; i < msg.length; i++) {
  499. this.dataList.push(msg[i])
  500. }
  501. }).catch(err=>{
  502. return uni.showToast({ title: err, icon: 'none', duration: 2000 });
  503. })
  504. },
  505. touchstart(event){
  506. this.dataList[this.k].isShowimage = true //刚触摸的时候就要显示预览视频图片了
  507. this.dataList[this.k].isShowProgressBarTime = true //显示时间线
  508. this.ProgressBarOpacity = 1 //让滑块显示起来更明显一点
  509. this.dotWidth = 10 //让点显示起来更明显一点
  510. },
  511. touchend(){//当手松开后,跳到最新时间
  512. uni.createVideoContext(this.dataList[this.k].id,this).seek(this.newTime)
  513. if(this.dataList[this.k].state == 'pause'){
  514. this.dataList[this.k].state = 'play'
  515. uni.createVideoContext(this.dataList[this.k].id,this).play()
  516. }
  517. this.dataList[this.k].isShowProgressBarTime = false //触摸结束后,隐藏时间线
  518. this.dataList[this.k].isShowimage = false //触摸结束后,隐藏时间预览
  519. this.ProgressBarOpacity = 0.5 //隐藏起来进度条,不那么明显了
  520. this.dotWidth = 0 //隐藏起来进度条,不那么明显了
  521. },
  522. touchmove(event){//当手移动滑块时,计算位置、百分小数、新的时间
  523. var msg = []
  524. if(this.videoTime !== ''){
  525. msg = this.videoTime.split(':')
  526. }
  527. var timeNumber = Number(msg[0])*60 + Number(msg[1])
  528. this.currentPositions = event.changedTouches[0].screenX
  529. this.percent = this.currentPositions / this.windowWidth
  530. this.newTime = this.percent*timeNumber
  531. this.currenttimes = parseInt(this.newTime)
  532. let theTime = this.newTime
  533. let middle = 0;// 分
  534. if(theTime > 60) {
  535. middle = parseInt(theTime/60);
  536. theTime = parseInt(theTime%60);
  537. }
  538. this.changeTime = `${Math.round(middle)>9?Math.round(middle):'0'+Math.round(middle)}:${Math.round(theTime)>9?Math.round(theTime):'0'+Math.round(theTime)}`
  539. },
  540. timeupdate(event,index){//计算滑块当前位置,计算当前百分小数
  541. // console.log(index)
  542. if(index == this.k){
  543. // console.log(event)
  544. var currenttime = event.detail.currentTime
  545. this.timeNumber = Math.round(event.detail.duration)
  546. this.getTime()
  547. this.percent = currenttime/this.timeNumber
  548. this.currentPosition = this.windowWidth*this.percent
  549. let theTime = currenttime
  550. let middle = 0;// 分
  551. if(theTime > 60) {
  552. middle = parseInt(theTime/60);
  553. theTime = parseInt(theTime%60);
  554. }
  555. this.changeTime = `${Math.round(middle)>9?Math.round(middle):'0'+Math.round(middle)}:${Math.round(theTime)>9?Math.round(theTime):'0'+Math.round(theTime)}`
  556. //自动切换视频
  557. if(this.isAutoplay){//true,代表自动播放
  558. if(Math.round(currenttime) == this.timeNumber - 1){
  559. const dom = uni.requireNativePlugin('dom')
  560. let doms = 'item'+(this.k+1)
  561. setTimeout(()=>{
  562. let el = this.$refs[doms][0]
  563. dom.scrollToElement(el,{
  564. offset: 0,
  565. animated: true
  566. })
  567. },500)
  568. }
  569. }
  570. }
  571. },
  572. getTime(){//得到时间函数
  573. this.videoTime = this.formatSeconds(this.timeNumber);
  574. // console.log(that.videoTime)
  575. var msg = []
  576. if(this.videoTime !== ''){
  577. msg = this.videoTime.split(':')
  578. }
  579. this.videoTimes = `${msg[0]>9?msg[0]:'0'+msg[0]}:${msg[1]>9?msg[1]:'0'+msg[1]}`;
  580. },
  581. formatSeconds(value) {//获取时间函数
  582. let theTime = parseInt(value);// 秒
  583. let middle= 0;// 分
  584. if(theTime > 60) {
  585. middle= parseInt(theTime/60);
  586. theTime = parseInt(theTime%60);
  587. }
  588. return `${middle>9?middle:middle}:${theTime>9?theTime:theTime}`;
  589. },
  590. playIngs(index) {
  591. //
  592. },
  593. moreVideo(index){
  594. },
  595. toVideo(index){
  596. },
  597. erweima(){
  598. },
  599. tozuozhe(){
  600. this.currents = 1//点击头像以后就会切换
  601. },
  602. stop(){
  603. // console.log('stop')
  604. },
  605. scrolls (event) {
  606. this.isDragging = event.isDragging
  607. if (!event.isDragging) {//isDragging:判断用户是不是在滑动,滑动:true,停止滑动:false。我们要用户停止滑动时才给 k 赋值,这样就可以避免很多麻烦
  608. var i = Math.round(Math.abs(event.contentOffset.y) / (this.wHeight - this.deleteHeight + 1))//先用绝对值取出滑动的距离,然后除以屏幕高度,取一个整,就知道你现在滑动到哪一个视频了
  609. if(i !== this.k){//这里加判断是因为这个方法会执行很多次,会造成重复请求,所以这里写一个限制
  610. if(uni.getSystemInfoSync().platform == 'ios'){
  611. this.k = i//判断了用户没有滑动,确认了用户的确是在看这个视频,然后就赋值啦
  612. this.dataList[this.k].state = 'play'
  613. console.log('正在播放 --> 第' + (this.k + 1) + '个视频~')
  614. } else {
  615. clearTimeout(this.timers);
  616. this.timers = setTimeout(()=>{
  617. this.k = i//判断了用户没有滑动,确认了用户的确是在看这个视频,然后就赋值啦
  618. this.dataList[this.k].state = 'play'
  619. console.log('正在播放 --> 第' + (this.k + 1) + '个视频~')
  620. },80)
  621. }
  622. }
  623. }
  624. },
  625. get(){
  626. // 这个方法主要就是用来第一次进入视频播放时用来处理的
  627. videoList({
  628. page: this.page,
  629. limit: this.limit,
  630. order_type: this.currentNav
  631. }).then(res=>{
  632. this.page = this.page + 1;
  633. var msg = res.data;
  634. this.dataList = msg;
  635. this.dataList[0].state = "play";
  636. setTimeout(()=>{
  637. //这里的延迟是为了避免执行时间太快而直接跳过执行的bug
  638. uni.createVideoContext(this.dataList[0].id,this).seek(0)
  639. uni.createVideoContext(this.dataList[0].id,this).play()
  640. },200)
  641. this.dataList[0].isplay = false
  642. setTimeout(()=>{
  643. this.dataList[0].playIng = true
  644. },500)
  645. var p = 0
  646. setTimeout(()=>{
  647. ++p
  648. uni.createVideoContext(this.dataList[p].id,this).play()
  649. setTimeout(()=>{
  650. uni.createVideoContext(this.dataList[p].id,this).seek(0)
  651. uni.createVideoContext(this.dataList[p].id,this).pause()
  652. console.log('预加载第' + (p + 1) + '个视频s:' + this.dataList[p].id)
  653. },2000)
  654. },50)
  655. }).catch(err=>{
  656. return uni.showToast({
  657. title: err,
  658. icon: 'none',
  659. duration: 2000
  660. });
  661. })
  662. },
  663. onpullingdown(){
  664. // console.log('正在下拉刷新,此时手还在触摸没有松开')
  665. this.refreshing = true
  666. },
  667. onrefresh(){
  668. // console.log('下拉刷新完毕,此时手松开了')
  669. setTimeout(()=>{
  670. this.refreshing = false
  671. },1000)
  672. },
  673. // 双击点赞效果
  674. touchstartHover(event){
  675. if(this.touchNum >= 1){
  676. // console.log('双击 -- X坐标:'+ event.touches[0].screenX);
  677. // console.log('双击 -- Y坐标:'+ event.touches[0].screenY);
  678. this.aixinLeft = event.touches[0].screenX - 50;
  679. this.aixinTop = event.touches[0].screenY - 50;
  680. this.isShowAixin = true;
  681. let max = 40; let min = -40;
  682. this.Rotate = Math.floor(Math.random() * (max - min + 1)) + min;
  683. setTimeout(()=>{
  684. this.isShowAixin = false;
  685. },700)
  686. this.onTabItemTaps();
  687. }
  688. },
  689. //点击播放&&暂停
  690. tapVideoHover(state,event){
  691. this.dataList[this.k].isShowimage = false
  692. this.dataList[this.k].isShowProgressBarTime = false
  693. this.ProgressBarOpacity = 0.5
  694. this.dotWidth = 0
  695. console.log('state--',state);
  696. // 1.启用双击点赞 --- start
  697. this.touchNum++;
  698. setTimeout(()=>{
  699. if(this.touchNum == 1){
  700. if(state=='play'||state=='continue'){
  701. this.dataList[this.k].state = 'pause';
  702. }else{
  703. this.dataList[this.k].state = 'continue';
  704. }
  705. if(this.dataList[this.k].state == 'continue'){
  706. uni.createVideoContext(this.dataList[this.k].id,this).play();//暂停以后继续播放
  707. }
  708. if(this.dataList[this.k].state == 'pause'){
  709. uni.createVideoContext(this.dataList[this.k].id,this).pause();//暂停以后继续播放
  710. }
  711. }
  712. if(this.touchNum >= 2){
  713. this.doubleLike();
  714. }
  715. this.touchNum = 0;
  716. },200)
  717. // --------------- ending
  718. // 2. 不启用双击点赞 start
  719. // if(state=='play'||state=='continue'){
  720. // this.dataList[this.k].state = 'pause';
  721. // }else{
  722. // this.dataList[this.k].state = 'continue';
  723. // }
  724. // if(this.dataList[this.k].state == 'continue'){
  725. // uni.createVideoContext(this.dataList[this.k].id,this).play();//暂停以后继续播放
  726. // }
  727. // if(this.dataList[this.k].state == 'pause'){
  728. // uni.createVideoContext(this.dataList[this.k].id,this).pause();//暂停以后继续播放
  729. // }
  730. // --------------- ending
  731. },
  732. doubleLike(){
  733. if(this.dataList[this.k].is_like == false){
  734. this.dataList[this.k].like_num += 1;
  735. this.dataList[this.k].is_like = true;
  736. }
  737. /*
  738. 点赞
  739. */
  740. },
  741. toComment(item){
  742. // 注意点击评论之后会执行这里
  743. /*
  744. (1)先加载缓冲
  745. (2)获取当前视频 ID 信息
  746. (3)🌟🌟🌟🌟重要🌟🌟🌟🌟
  747. - 一定要记得看 index.vue 里面
  748. uni.setStorageSync("user",this.peopleList[i]);
  749. 这个东西,用于存储当前用户信息。在 插件里面会使用到这个东西,
  750. 记得写一下。
  751. (4)打开评论
  752. */
  753. uni.showToast({
  754. title: '加载中...',
  755. icon: 'none',
  756. position: 'bottom',
  757. duration: 300
  758. })
  759. uni.setStorageSync("videoID",parseInt(item.id));
  760. uni.setStorageSync("pinlunNum",item.comment_num);
  761. this.$refs.pinglun.open('bottom')
  762. },
  763. wxh5Video(){
  764. uni.navigateTo({
  765. url: '../wxh5previewVideo/wxh5previewVideo'
  766. })
  767. },
  768. previewVideo(){
  769. uni.navigateTo({
  770. url: '../previewVideo/previewVideo'
  771. })
  772. },
  773. toTwoVideo(){
  774. uni.navigateTo({
  775. url: '../new_index/new_index'
  776. })
  777. },
  778. tolistVideo(){
  779. uni.navigateTo({
  780. url: '../nvueSwiper/nvueSwiper'
  781. })
  782. },
  783. cLike(item){
  784. markeVideo('like',item.id).then(res=>{
  785. this.dataList[this.k].is_like = !this.dataList[this.k].is_like
  786. const video = this.dataList[this.k];
  787. item.is_like?video.like_num += 1:video.like_num -= 1;
  788. }).catch(err=>{
  789. return uni.showToast({
  790. title: err,
  791. icon: 'none',
  792. duration: 2000
  793. });
  794. })
  795. /*
  796. 点赞
  797. */
  798. },
  799. /*
  800. 收藏
  801. */
  802. cCollect(item){
  803. markeVideo('collect',item.id).then(res=>{
  804. this.dataList[this.k].is_collect = !this.dataList[this.k].is_collect
  805. const video = this.dataList[this.k];
  806. item.is_collect?video.collect_num += 1:video.collect_num -= 1;
  807. }).catch(err=>{
  808. return uni.showToast({
  809. title: err,
  810. icon: 'none',
  811. duration: 2000
  812. });
  813. })
  814. },
  815. moveHandle(){},
  816. closeScrollview(){
  817. // 点击评论里面的叉叉,就会关闭评论
  818. this.$refs.pinglun.close();
  819. },
  820. onTabItemTaps() {
  821. // #ifdef APP-PLUS
  822. if (uni.getSystemInfoSync().platform == "ios") {
  823. let UIImpactFeedbackGenerator = plus.ios.importClass('UIImpactFeedbackGenerator');
  824. let impact = new UIImpactFeedbackGenerator();
  825. impact.prepare();
  826. impact.init(1);
  827. impact.impactOccurred();
  828. }
  829. if (uni.getSystemInfoSync().platform == "android") {
  830. uni.vibrateShort({
  831. success: () => {
  832. console.log('点击震动');
  833. }
  834. });
  835. }
  836. // #endif
  837. }
  838. }
  839. }
  840. </script>
  841. <style lang="scss">
  842. .header{
  843. position: fixed;
  844. z-index: 9;
  845. width: 750rpx;
  846. height: 86rpx;
  847. flex-direction:row;
  848. justify-content: center;
  849. top: 80rpx;
  850. .items{
  851. margin: 0 41rpx;
  852. .tName{
  853. color: #FFFFFF;
  854. font-size: 28rpx;
  855. }
  856. .tLine{
  857. width: 30rpx;
  858. height: 4rpx;
  859. background: #FFFFFF;
  860. border-radius: 2rpx;
  861. margin-left: 15rpx;
  862. margin-top: 10rpx;
  863. }
  864. }
  865. }
  866. .container {background-color: #000000;}
  867. .item {
  868. /* width : 750rpx; */
  869. background-color: #000000;
  870. position: relative;
  871. }
  872. .videoHover{
  873. position: absolute;
  874. top: 0;
  875. left: 0;
  876. flex: 1;
  877. background-color: rgba(0,0,0,0.1);
  878. justify-content: center;
  879. align-items: center;
  880. /* border-style: dashed;
  881. border-color: #DD524D;
  882. border-width: 1px; */
  883. }
  884. .playState{
  885. width: 160rpx;
  886. height: 160rpx;
  887. opacity: 0.2;
  888. }
  889. .userInfo{
  890. position: absolute;
  891. bottom:110px;
  892. right: 10px;
  893. flex-direction: column;
  894. }
  895. .userAvatar{
  896. border-radius: 500%;
  897. margin-bottom: 15px;
  898. border-style: solid;
  899. border-width: 2px;
  900. border-color: #ffffff;
  901. }
  902. .userAvatar{
  903. width : 80rpx;
  904. height: 80rpx;
  905. }
  906. .likeIco,.shareIco,.commentIco{
  907. width : 60rpx;
  908. height: 60rpx;
  909. margin-top: 15px;
  910. }
  911. .likeNum,.commentNum,.shareTex{
  912. color: #ffffff;
  913. font-size: 30rpx;
  914. text-align: center;
  915. margin: 5px;
  916. }
  917. .content{
  918. width: 720rpx;
  919. z-index: 99;
  920. position: absolute;
  921. bottom: 30px;
  922. /* justify-content: center; */
  923. padding: 15rpx;
  924. flex-direction: column;
  925. justify-content: flex-start;
  926. color: #ffffff;
  927. .time{
  928. font-size: 24rpx;
  929. color: rgba(255,255,255,0.5);
  930. margin-left: 12rpx;
  931. }
  932. .cart{
  933. background: rgba(0,0,0,0.3);
  934. width: 376rpx;
  935. height: 48rpx;
  936. border-radius: 4rpx;
  937. margin-bottom: 22rpx;
  938. flex-direction:row;
  939. justify-content: center;
  940. align-items: center;
  941. .cartPic{
  942. width: 36rpx;
  943. height: 36rpx;
  944. margin-right: 14rpx;
  945. }
  946. .cartName{
  947. font-size: 24rpx;
  948. color: #fff;
  949. }
  950. .line{
  951. width: 2rpx;
  952. height: 22rpx;
  953. background-color: rgba(255,255,255,0.3);
  954. margin: 0 12rpx;
  955. }
  956. }
  957. }
  958. .timeCon{
  959. flex-direction:row;
  960. align-items: center;
  961. .userName {
  962. font-size: 30rpx;
  963. color: #ffffff;
  964. }
  965. }
  966. .words {
  967. margin-top: 20rpx;
  968. .close{
  969. display: flex;
  970. flex-direction: row;
  971. align-items: center;
  972. justify-content: flex-end;
  973. margin-right: 20rpx;
  974. .imgClose{
  975. width: 18rpx;
  976. height: 10rpx;
  977. margin-left: 10rpx;
  978. }
  979. }
  980. .wordsCon{
  981. position: relative;
  982. .more{
  983. position: absolute;
  984. bottom: 0;
  985. right: 40rpx;
  986. font-size: 26rpx;
  987. }
  988. .img{
  989. width: 18rpx;
  990. height: 10rpx;
  991. margin-left: 4rpx;
  992. position: absolute;
  993. bottom: 7rpx;
  994. right: 20rpx;
  995. }
  996. }
  997. .info{
  998. color: #fff;
  999. font-size: 28rpx;
  1000. }
  1001. .more{
  1002. font-size: 26rpx;
  1003. color: #AAAAAA;
  1004. font-weight: 400;
  1005. }
  1006. }
  1007. .root{
  1008. background-color: #000000;
  1009. }
  1010. </style>