y-video.vue 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. <template>
  2. <view>
  3. <DomVideoPlayer class="video" :style="{ 'height': height + 'px' }" ref="domVideoPlayer" object-fit='contain'
  4. :controls="controls" :autoplay="autoplay" :loop="loop" :src="item.video" :key="key" :muted="muted"
  5. :playback-rate="playbackRate" @play="onPlay" @pause="onPause" @ended="onEnded" @error="onError"
  6. @timeupdate="onTimeUpdate" @durationchange="onDurationChange" @ratechange="onRateChange"
  7. @fullscreenchange="onFullscreenChange" @tap.stop="change" />
  8. <view class="play-btn" @tap.stop="change" :style="{ left: `${width / 2}px`, top: `${height / 2}px` }"
  9. v-if="showPlayBtn">
  10. <up-icon name="play-right-fill" size="16" color="var(--light)"></up-icon>
  11. </view>
  12. <!-- loading -->
  13. <image class="loading" :style="{ left: `${width / 2}px`, top: `${height / 2}px` }" src="@/static/loading.gif"
  14. v-if="loading">
  15. </image>
  16. <view class="info" @click.stop="$emit('showMulu')">
  17. <text class="text title">@{{ item.user && item.user.realname }}</text>
  18. <text class="text" style="margin-top: 25rpx;font-size: 26rpx;line-height: 40rpx;">{{ item.title }}</text>
  19. <view class="shop_box" @click.stop="toShopDeatils(item)">
  20. <up-image :src="item.extend_data && item.extend_data.pic_url" width="70rpx" height="70rpx" radius="4">
  21. <template #error>
  22. <image class="toux" src="@/static/tx.png"></image>
  23. </template>
  24. </up-image>
  25. <text class="title">{{ item.extend_data && item.extend_data.title }}</text>
  26. </view>
  27. </view>
  28. <view class="btns" :style="{ height: height + 'px' }" @click.stop>
  29. <view class="userimg">
  30. <up-image :src="item.user && item.user.userimg" shape="circle" width="88rpx" height="88rpx">
  31. <template #error>
  32. <image class="toux" src="@/static/tx.png"></image>
  33. </template>
  34. </up-image>
  35. <view class="user_bottom" @click.stop="$emit('follow')" v-if="!item.is_follow">+</view>
  36. </view>
  37. <image class="btn" :src="item.is_goods ? '/static/dianzan_h.png' : '/static/dianzan.png'"
  38. @click.stop="$emit('like')">
  39. </image>
  40. <text class="text">{{ item.goods }}</text>
  41. <image class="btn" src="@/static/pinglun.png" @click.stop="$emit('showPinglun')"></image>
  42. <text class="text">{{ item.comments }}</text>
  43. <image class="btn" :src="item.is_collect ? '/static/shoucang_h.png' : '/static/shoucang.png'"
  44. @click.stop="$emit('collect')">
  45. </image>
  46. <text class="text">{{ item.collects }}</text>
  47. <image class="btn" src="@/static/fenxiang.png"></image>
  48. </view>
  49. <!-- <view class="progress">
  50. <view class="line" :style="{ width: lineWidth + 'px' }"></view>
  51. </view> -->
  52. <view class="_duration" @click.stop>
  53. <view style="flex-direction: row;flex: 1;">
  54. <text class="text">{{ currentTime ? currentTime : '00:00' }}</text>
  55. <text class="text" style="margin: 0 10rpx;">/</text>
  56. <text class="text" style="opacity: .5;">{{ duration ? duration : '00:00' }}</text>
  57. </view>
  58. <image class="shengyin" :src="muted ? '/static/jingyin.png' : '/static/yinliang.png'" @click="muted = !muted">
  59. </image>
  60. <image class="shengyin" style="margin-left:20rpx" src="/static/quanping.png" @click="fullScreen">
  61. </image>
  62. </view>
  63. </view>
  64. </template>
  65. <script>
  66. import DomVideoPlayer from '@/components/DomVideoPlayer'
  67. const systemInfo = uni.getSystemInfoSync();
  68. import { t } from "@/locale"
  69. export default {
  70. components: {
  71. DomVideoPlayer
  72. },
  73. props: {
  74. info: {
  75. type: Object,
  76. default: () => { }
  77. },
  78. item: {
  79. type: Object,
  80. default: () => { }
  81. },
  82. index: {
  83. type: Number,
  84. default: -1
  85. },
  86. current: {
  87. type: Number,
  88. default: 0
  89. }
  90. },
  91. data() {
  92. return {
  93. playing: true,
  94. loop: true,
  95. controls: false,
  96. autoplay: true,
  97. playbackRate: 1,
  98. currentTime: 0,
  99. duration: 0,
  100. showPlayBtn: false,
  101. loading: false,
  102. lineWidth: 0,
  103. muted: false,
  104. isZan: false,
  105. isSc: false,
  106. isFullscreen: false,
  107. width: systemInfo.screenWidth,
  108. height: systemInfo.screenHeight - 1 - 100,
  109. key: new Date().getTime(),
  110. }
  111. },
  112. watch: {
  113. current: {
  114. handler(val) {
  115. val == this.index ? this.play() : this.pause()
  116. }
  117. },
  118. playing: {
  119. handler(val) {
  120. // #ifdef APP-PLUS
  121. uni.setKeepScreenOn({
  122. keepScreenOn: val
  123. });
  124. // // #endif
  125. }
  126. }
  127. },
  128. methods: {
  129. change() {
  130. if (!this.isFullscreen) {
  131. this.playing ? this.pause() : this.play()
  132. }
  133. },
  134. play() {
  135. this.showPlayBtn = false
  136. this.playing = true;
  137. this.$refs.domVideoPlayer.play();
  138. // this.$refs[`domVideoPlayer${this.current}`] && this.$refs[`domVideoPlayer${this.current}`].play();
  139. },
  140. pause() {
  141. this.showPlayBtn = true
  142. this.playing = false
  143. // this.$refs.domVideoPlayer.pause()
  144. this.$refs.domVideoPlayer.pause()
  145. },
  146. onPlay() {
  147. if (this.current != this.index) {
  148. this.$refs.domVideoPlayer.pause()
  149. this.playing = false
  150. } else {
  151. this.playing = true
  152. this.showPlayBtn = false
  153. this.loading = false
  154. this.$emit('play', this.item)
  155. }
  156. },
  157. onPause() {
  158. this.showPlayBtn = true
  159. this.playing = false
  160. },
  161. onEnded() {
  162. this.currentTime = 0
  163. this.playing = false;
  164. setTimeout(() => {
  165. this.key = new Date().getTime()
  166. }, 150)
  167. },
  168. onError() {
  169. console.log("onError");
  170. if (this.current == this.index) {
  171. uni.showToast({
  172. title: '播放失败',
  173. duration: 1000,
  174. icon: 'none'
  175. })
  176. setTimeout(() => {
  177. this.key = new Date().getTime()
  178. this.onEnded()
  179. }, 1000)
  180. }
  181. },
  182. fullScreen() {
  183. this.$refs.domVideoPlayer.fullScreen();
  184. },
  185. onDurationChange(e) {
  186. if (this.loading) this.loading = false;
  187. if (!this.playing) this.playing = true;
  188. if (!this.duration || this.duration == '00:00') this.duration = this.secondToTime(e, 1)
  189. },
  190. onTimeUpdate(e) {
  191. this.currentTime = this.secondToTime(e)
  192. this.lineWidth = e / this.duration * this.width
  193. },
  194. secondToTime(s, n) {
  195. const t = parseInt(s)
  196. const hours = Math.floor(t / (60 * 60));
  197. const seconds = t % (60 * 60)
  198. const minutes = Math.floor(seconds / 60);
  199. const seconds2 = seconds % 60
  200. if (hours > 0) {
  201. return `${hours}:${minutes.toString().padStart(2, '0')}:${seconds2.toString().padStart(2, '0')}`;
  202. } else {
  203. return `${minutes.toString().padStart(2, '0')}:${seconds2.toString().padStart(2, '0')}`;
  204. }
  205. },
  206. onRateChange(e) {
  207. this.playbackRate = e
  208. },
  209. onFullscreenChange(e) {
  210. console.log('onFullScreenChange', e)
  211. },
  212. toShopDeatils(item) {
  213. uni.navigateTo({
  214. url: `/pages/shop/productDetail?channel=${item.channel}&goods_id=${item.extend_data.num_iid}`
  215. })
  216. }
  217. },
  218. onhide() {
  219. this.pause()
  220. }
  221. }
  222. </script>
  223. <style scoped lang="less">
  224. @import url('@/style.less');
  225. .action-box {
  226. margin-top: 30rpx;
  227. padding: 0 60rpx;
  228. }
  229. .action-box button {
  230. margin-top: 10rpx;
  231. }
  232. .video {
  233. width: 750rpx;
  234. background-color: #000000;
  235. }
  236. .text {
  237. color: #fff;
  238. font-size: 28rpx;
  239. }
  240. .info {
  241. position: absolute;
  242. z-index: 100;
  243. left: 0;
  244. bottom: 50px;
  245. width: 750rpx;
  246. padding: 30rpx 140rpx 130rpx 30rpx;
  247. .flex();
  248. flex-direction: column;
  249. .title {
  250. font-size: 36rpx;
  251. max-width: calc(750rpx - 140rpx - 60rpx);
  252. }
  253. .des {
  254. background-color: rgba(255, 255, 255, .1);
  255. border-radius: 10rpx;
  256. padding: 15rpx 20rpx;
  257. .text {
  258. font-size: 24rpx;
  259. }
  260. }
  261. }
  262. .btns {
  263. position: absolute;
  264. z-index: 100;
  265. right: 0;
  266. bottom: 0;
  267. width: 140rpx;
  268. .flex_position(flex-end);
  269. flex-direction: column;
  270. padding-bottom: 340rpx;
  271. .userimg {
  272. position: relative;
  273. margin-bottom: 40rpx;
  274. .user_bottom {
  275. position: absolute;
  276. left: 50%;
  277. top: 71rpx;
  278. margin-left: -17rpx;
  279. // margin-top: -14rpx;
  280. // margin-bottom: 40rpx;
  281. height: 34rpx;
  282. width: 34rpx;
  283. border-radius: 50%;
  284. background: var(--red);
  285. color: var(--bg);
  286. text-align: center;
  287. line-height: 34rpx;
  288. z-index: 9;
  289. }
  290. }
  291. .toux {
  292. height: 88rpx;
  293. width: 88rpx;
  294. border-radius: 50%;
  295. object-fit: cover;
  296. }
  297. .btn {
  298. height: 66rpx;
  299. width: 66rpx;
  300. }
  301. .text {
  302. margin-top: 10rpx;
  303. margin-bottom: 30rpx;
  304. font-size: 26rpx;
  305. }
  306. }
  307. .play-btn {
  308. height: 68rpx;
  309. width: 68rpx;
  310. border-radius: 50%;
  311. background-color: rgba(0, 0, 0, .5);
  312. position: absolute;
  313. margin-left: -34rpx;
  314. margin-top: -34rpx;
  315. .flex_center();
  316. }
  317. .loading {
  318. position: absolute;
  319. height: 60rpx;
  320. width: 60rpx;
  321. margin-left: -30rpx;
  322. margin-top: -30rpx;
  323. }
  324. .progress {
  325. width: 750rpx;
  326. height: 90rpx;
  327. position: absolute;
  328. left: 0;
  329. bottom: 100rpx;
  330. .line {
  331. height: 2rpx;
  332. width: 500rpx;
  333. background-color: rgba(255, 255, 255, .35);
  334. transform: scaleY(.1);
  335. }
  336. }
  337. ._duration {
  338. position: absolute;
  339. height: 88rpx;
  340. .ver();
  341. left: 0;
  342. width: 750rpx;
  343. bottom: 50px;
  344. z-index: 101;
  345. padding-left: 30rpx;
  346. padding-right: 30rpx;
  347. background-color: rgba(255, 255, 255, .05);
  348. }
  349. .shengyin {
  350. height: 38rpx;
  351. width: 38rpx;
  352. }
  353. .shop_box {
  354. .hor;
  355. max-width: 400rpx;
  356. height: 88rpx;
  357. border-radius: 20rpx;
  358. background: #3d3d3d;
  359. padding: 10rpx;
  360. box-sizing: border-box;
  361. .title {
  362. .ellipsis(2);
  363. .size(24rpx);
  364. margin-left: 4rpx;
  365. color: var(--bg);
  366. }
  367. }
  368. </style>