audio-slide.vue 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. <template>
  2. <view class="SlideBody" ref="slide">
  3. <div class="Slide-progress">
  4. <div
  5. class="Slide-progress-loaded"
  6. :style="{ width: `${leftWidth}px` }"
  7. />
  8. </div>
  9. <div
  10. class="Slide-control"
  11. :style="{ left:`${leftWidth}px` }"
  12. @touchmove.stop.prevent="controlMove"
  13. @touchstart="controlTouchStart"
  14. @touchend="controlTouchEnd"
  15. >
  16. {{ playTime | mediaTimeFormatter }} / {{ allTime | mediaTimeFormatter }}
  17. </div>
  18. </view>
  19. </template>
  20. <script>
  21. export default {
  22. props: {
  23. ratio: {
  24. type: Number,
  25. default: 1
  26. },
  27. direction: {
  28. type: String,
  29. default: 'clientX'
  30. },
  31. iosDirection: {
  32. type: Number,
  33. default: 1
  34. },
  35. allTime: {
  36. type: Number,
  37. default: 0
  38. },
  39. playTime: {
  40. type: Number,
  41. default: 0
  42. }
  43. },
  44. data() {
  45. return {
  46. oldToucesX: 0,
  47. leftWidth: 0,
  48. oldLeftWidth: 0,
  49. currentWidth: 0,
  50. controlWidth: 0
  51. }
  52. },
  53. mounted() {
  54. this.init()
  55. },
  56. filters: {
  57. mediaTimeFormatter: num => {
  58. if (!num) return "00:00";
  59. num = Math.floor(num);
  60. let hour = Math.floor(num / 3600);
  61. let minutes = Math.floor((num - hour * 3600) / 60);
  62. let second = num - hour * 3600 - minutes * 60;
  63. if (hour > 0) {
  64. return `${hour > 9 ? hour : "0" + hour}:${
  65. minutes > 9 ? minutes : "0" + minutes
  66. }:${second > 9 ? second : "0" + second}`;
  67. } else {
  68. return `${minutes > 9 ? minutes : "0" + minutes}:${
  69. second > 9 ? second : "0" + second
  70. }`;
  71. }
  72. }
  73. },
  74. watch: {
  75. playTime: {
  76. handler(a) {
  77. if(a && this.allTime) {
  78. if(this.currentWidth && this.controlWidth) {
  79. let maxLeftWidth = this.currentWidth - this.controlWidth
  80. this.leftWidth = Math.ceil((a / this.allTime) * maxLeftWidth)
  81. } else {
  82. this.init(() => {
  83. let maxLeftWidth = this.currentWidth - this.controlWidth
  84. this.leftWidth = Math.ceil((a / this.allTime) * maxLeftWidth)
  85. })
  86. }
  87. } else {
  88. this.leftWidth = 0
  89. }
  90. },
  91. immediate: true
  92. },
  93. allTime: {
  94. handler(a) {
  95. if(a && this.playTime) {
  96. if(this.currentWidth && this.controlWidth) {
  97. let maxLeftWidth = this.currentWidth - this.controlWidth
  98. this.leftWidth = Math.ceil((this.playTime / a) * maxLeftWidth)
  99. } else {
  100. this.init(() => {
  101. let maxLeftWidth = this.currentWidth - this.controlWidth
  102. this.leftWidth = Math.ceil((this.playTime / a) * maxLeftWidth)
  103. })
  104. }
  105. } else {
  106. this.leftWidth = 0
  107. }
  108. },
  109. immediate: true
  110. }
  111. },
  112. methods: {
  113. init(cb) {
  114. const query = uni.createSelectorQuery().in(this);
  115. query.select('.SlideBody').boundingClientRect(({ width }) => {
  116. this.currentWidth = width
  117. }).exec();
  118. query.select('.Slide-control').boundingClientRect(({ width }) => {
  119. this.controlWidth = width
  120. }).exec();
  121. setTimeout(() => {
  122. cb && cb()
  123. }, 200)
  124. },
  125. controlTouchStart(e) {
  126. this.oldLeftWidth = this.leftWidth
  127. this.oldToucesX = e.changedTouches[0][this.direction];
  128. this.$emit('touchStart')
  129. },
  130. controlMove(e) {
  131. let newToucesX;
  132. let maxLeftWidth = this.currentWidth - this.controlWidth
  133. newToucesX= e.changedTouches[0][this.direction];
  134. this.leftWidth = this.iosDirection*(newToucesX - this.oldToucesX)+ this.oldLeftWidth
  135. this.leftWidth = this.leftWidth > maxLeftWidth ? maxLeftWidth : this.leftWidth
  136. this.leftWidth = this.leftWidth < 0? 0 : this.leftWidth
  137. },
  138. controlTouchEnd(e) {
  139. let maxLeftWidth = this.currentWidth - this.controlWidth
  140. let current = this.leftWidth / maxLeftWidth
  141. let value = current * this.allTime
  142. this.$emit('update:progress', { value })
  143. }
  144. }
  145. }
  146. </script>
  147. <style lang="scss" scoped>
  148. .SlideBody {
  149. width: 100%;
  150. height: 34rpx;
  151. display: flex;
  152. align-items: center;
  153. justify-content: center;
  154. position: relative;
  155. -webkit-overflow-scrolling : touch;
  156. .Slide {
  157. &-progress {
  158. width: 100%;
  159. height: 8rpx;
  160. border-radius: 8rpx;
  161. background: #EEEEEE;
  162. position: relative;
  163. overflow: hidden;
  164. &-loaded{
  165. position: absolute;
  166. top: 0;
  167. left: 0;
  168. bottom: 0;
  169. right: 0;
  170. width: 0;
  171. height: 100%;
  172. background: linear-gradient(to right, #F97C55, #F44545);
  173. }
  174. }
  175. &-control {
  176. height: 34rpx;
  177. border-radius: 34rpx;
  178. background: linear-gradient(to right, #F97C55, #F44545);
  179. color: #FFFFFF;
  180. font-size: 24rpx;
  181. padding: 0 12rpx;
  182. line-height: 34rpx;
  183. position: absolute;
  184. top: 50%;
  185. left: 0;
  186. transform: translate(0, -50%);
  187. }
  188. }
  189. }
  190. </style>