audio-slide.vue 4.6 KB

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