chunlei-video.nvue 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. <template>
  2. <view class="video">
  3. <video :src="src" :controls="controls" :show-center-play-btn="controls" :show-play-btn="controls" play-btn-position="center" autoplay="true" :muted="!load||!play"
  4. :style="{ height: height }" :loop="true" @controlstoggle="controlstoggle" @fullscreenchange="screenChange" @play="continuePlay"
  5. :enable-progress-gesture="false" :objectFit="objectFit" @ended="playEnd" :initial-time="startTime"
  6. :id="`video_${src}`" ref="`video_${src}`" class="video" @timeupdate="timeupdate">
  7. </video>
  8. <cover-view class="icon-view" v-if="!play&&!playFirst">
  9. <!-- <text class="icon" style="color:#FFF">&#xe896;</text> -->
  10. </cover-view>
  11. <cover-image class="img" :style="{ height: height }" :src="poster" v-if="poster!=''&&playFirst"></cover-image>
  12. <cover-view class="top"></cover-view>
  13. <!-- <cover-view class="bottom"></cover-view> -->
  14. <!-- #ifdef APP-PLUS -->
  15. <cover-view class="danmu-view">
  16. <chunLei-danmu :danmuList="danmuList" :width="750" :current="time" ref="danmu"></chunLei-danmu>
  17. </cover-view>
  18. <!-- #endif -->
  19. <!-- #ifndef MP-WEIXIN -->
  20. <cover-view class="slider-view">
  21. <chunLei-slider :max="duration" :value="time" :style="{width:`${100}%`}" :screenLeft="120" :width="380" @change="changeCurrent"></chunLei-slider>
  22. </cover-view>
  23. <cover-image :src="rotateImg" class="rotate-img" :style="{transform:`rotate(${time*20}deg)`}"></cover-image>
  24. <!-- #endif -->
  25. <!-- #ifdef MP-WEIXIN -->
  26. <!-- <cover-view class="progressBar" :style="{ width: barWidth }"></cover-view> -->
  27. <!-- #endif -->
  28. </view>
  29. </template>
  30. <script>
  31. import chunLeiSlider from './chunLei-slider/chunLei-slider.nvue';
  32. //#ifdef APP-NVUE
  33. import chunLeiDanmu from './chunLei-danmu/chunLei-danmu.nvue';
  34. //#endif
  35. export default{
  36. components:{
  37. chunLeiSlider,
  38. //#ifdef APP-NVUE
  39. chunLeiDanmu
  40. //#endif
  41. },
  42. props:{
  43. controls:{
  44. type:Boolean,
  45. default:false
  46. },
  47. src:{
  48. type:String,
  49. default:''
  50. },
  51. rotateImg:{
  52. type:String,
  53. default:''
  54. },
  55. play:{
  56. type:Boolean,
  57. default:false
  58. },
  59. height:{
  60. type:String,
  61. default:''
  62. },
  63. width:{
  64. type:String,
  65. default:''
  66. },
  67. initialTime:{
  68. type:Number,
  69. default:0
  70. },
  71. gDuration:{
  72. type:Number,
  73. default:999
  74. }, //大概时长使进度条更准确
  75. objectFit:{
  76. type:String,
  77. default:'contain'
  78. },
  79. poster:{ //视频封面的图片
  80. type:String,
  81. default:''
  82. },
  83. danmuList:{
  84. type:Array,
  85. default:[]
  86. }
  87. },
  88. data(){
  89. return{
  90. time:0,
  91. duration:0,
  92. playFirst:true,
  93. load:false,
  94. timer:null
  95. }
  96. },
  97. beforeCreate() {
  98. // #ifdef APP-NVUE
  99. var domModule = weex.requireModule('dom');
  100. domModule.addRule('fontFace', {
  101. 'fontFamily': "texticons",
  102. 'src': "url('//static/chunlei-video/text-icon.ttf')"
  103. });
  104. // #endif
  105. },
  106. mounted() {
  107. this.videoCtx = uni.createVideoContext(`video_${this.src}`,this)
  108. //#ifndef MP-WEIXIN
  109. setTimeout(()=>{this.videoCtx.play();},200)
  110. // #endif
  111. },
  112. methods:{
  113. continuePlay(){
  114. if(!this.load){
  115. this.load = true
  116. this.videoPlay()
  117. }
  118. },
  119. //拖动滑块
  120. changeCurrent(e){
  121. this.time = e.detail.value
  122. this.videoCtx.seek(this.time)
  123. },
  124. screenChange(e){
  125. //console.log(e.detail.fullScreen);
  126. this.$emit('screenChange',e.detail.fullScreen)
  127. },
  128. controlstoggle(e){
  129. console.log(e.detail.show);
  130. //console.log(99999999);
  131. this.$emit('controlstoggle',e.detail.show)
  132. },
  133. playEnd(){
  134. // console.log(2222222);
  135. this.videoCtx.exitFullScreen()
  136. this.$emit('playEnd')
  137. },
  138. timeupdate(event){
  139. this.duration = event.detail.duration
  140. if(this.time>=event.detail.duration) this.time=0
  141. this.time = event.detail.currentTime
  142. this.$emit('timeupdate',this.time)
  143. },
  144. videoPlay:function(){
  145. if(this.timer) clearTimeout(this.timer)
  146. this.timer = setTimeout(()=>{
  147. console.log(this.play)
  148. if(this.play){
  149. this.videoCtx.play();
  150. this.playFirst = false
  151. }else{
  152. this.videoCtx.pause();
  153. this.$emit('pause',this.time)
  154. }
  155. })
  156. },
  157. },
  158. watch:{
  159. //防抖 防止视频播放暂停太快
  160. play: function (newVal,oldVal){if(this.load) this.videoPlay()},
  161. startTime:{
  162. immediate: true,
  163. handler(newVal,oldVal){
  164. this.time = newVal
  165. }
  166. },
  167. gDuration:{
  168. immediate: true,
  169. handler(newVal,oldVal){
  170. this.duration = newVal
  171. }
  172. }
  173. },
  174. computed:{
  175. barWidth(){
  176. let width = this.time/this.duration*parseInt(this.width)
  177. return `${width}px`
  178. },
  179. startTime(){
  180. return this.initialTime
  181. }
  182. }
  183. }
  184. </script>
  185. <style scoped>
  186. /* #ifndef APP-PLUS-NVUE */
  187. @font-face {
  188. font-family: "texticons";
  189. src: url('~@/static/chunlei-video/text-icon.ttf') format('truetype');
  190. }
  191. /* #endif*/
  192. .video{
  193. /* #ifndef APP-NVUE */
  194. display: flex;
  195. /* #endif */
  196. width: 750rpx;
  197. justify-content: center;
  198. align-items: center;
  199. }
  200. .img{
  201. position: absolute;
  202. width: 750rpx;
  203. }
  204. .icon-view{
  205. position: absolute;
  206. }
  207. .top{
  208. position: absolute;
  209. top:0;
  210. background-image: linear-gradient(to top , rgba(0,0,0,0) , rgba(0,0,0,0.7));
  211. width: 750rpx;
  212. height: 300rpx;
  213. }
  214. .icon{
  215. opacity: 0.6;
  216. font-size: 42px;
  217. color: #fff;
  218. /* #ifndef APP-PLUS-NVUE */
  219. font-family: "texticons";
  220. /* #endif*/
  221. font-family: texticons;
  222. }
  223. .bottom{
  224. position: absolute;
  225. bottom: 0;
  226. background-image: linear-gradient(to top , rgba(0,0,0,0.7) , rgba(0,0,0,0));
  227. width: 750rpx;
  228. height: 300rpx;
  229. }
  230. .slider-view{
  231. position: absolute;
  232. left: 0;
  233. bottom: 0px;
  234. width: 750rpx;
  235. }
  236. .progressBar{
  237. border-radius: 2upx;
  238. height: 4upx;
  239. background-color: #FFFFFF;
  240. z-index: 999999;
  241. position: absolute;
  242. left: 0;
  243. bottom: 30px;
  244. //#ifndef APP-PLUS-NVUE
  245. animation: flicker 4s linear infinite;
  246. animation-direction:alternate;
  247. //#endif
  248. }
  249. //#ifndef APP-PLUS-NVUE
  250. @keyframes flicker {
  251. 0% { box-shadow:0 0 0 #FFFFFF; }
  252. /** 暂停效果 */
  253. 10% { box-shadow:0 0 2upx #FFFFFF; }
  254. 50% { box-shadow:0 0 10upx #FFFFFF; }
  255. 60% { box-shadow:0 0 12upx #FFFFFF; }
  256. 90% { box-shadow:0 0 18upx #FFFFFF; }
  257. 100% { box-shadow:0 0 20upx #FFFFFF; }
  258. }
  259. //#endif
  260. .danmu-view{
  261. position: absolute;
  262. top:0;
  263. height: 160px;
  264. }
  265. .rotate-img{
  266. width: 90rpx;
  267. height: 90rpx;
  268. position: absolute;
  269. bottom: 100rpx;
  270. right: 20rpx;
  271. border-radius: 45rpx;
  272. }
  273. </style>