l-barrage.vue 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. <template>
  2. <view class="l-barrage" :style="[styles, props.lStyle]">
  3. <!-- #ifdef VUE3 -->
  4. <template v-for="item in list" :key="item.id">
  5. <!-- IOS不能动态offset -->
  6. <view
  7. class="l-barrage-item"
  8. v-if="item && item.style.opacity && !item.style['--l-barrage-offset']"
  9. :id="item.id">
  10. <slot :content="item.content" />
  11. </view>
  12. <view
  13. class="l-barrage-item"
  14. v-if="item && item.style.opacity && item.style['--l-barrage-offset']"
  15. :id="item.id"
  16. :count="item.count"
  17. :style="[item.style]"
  18. @animationend="animationend(item)"
  19. @animationstart="animationstart(item)"
  20. @touchcancel="touchend(item)"
  21. @touchstart="touchstart(item)"
  22. @touchend="touchend(item)">
  23. <slot :content="item.content" />
  24. </view>
  25. </template>
  26. <!-- #endif -->
  27. <!-- #ifndef VUE3 -->
  28. <!-- 微信小程序在vue2删除会闪 IOS不能动态offset -->
  29. <block v-for="item in list" :key="item.id">
  30. <view
  31. class="l-barrage-item"
  32. v-if="item && !item.style['--l-barrage-offset']"
  33. :id="item.id">
  34. <slot :content="item.content" />
  35. </view>
  36. <view
  37. class="l-barrage-item"
  38. v-if="item && item.style['--l-barrage-offset']"
  39. :id="item.id"
  40. :count="item.count"
  41. :style="[item.style]"
  42. @animationend="animationend(item)"
  43. @animationstart="animationstart(item)"
  44. @touchcancel="touchend(item)"
  45. @touchstart="touchstart(item)"
  46. @touchend="touchend(item)">
  47. <slot :content="item.content" />
  48. </view>
  49. </block>
  50. <!-- #endif -->
  51. </view>
  52. </template>
  53. <script lang="ts">
  54. // @ts-nocheck
  55. import { defineComponent, onMounted, getCurrentInstance, watch, reactive, onBeforeUnmount, ref } from '@/uni_modules/lime-shared/vue';
  56. import BarrageProps from './props';
  57. import { Barrage } from './barrage';
  58. import { getRect } from '@/uni_modules/lime-shared/getRect';
  59. const PLAY_STATE = '--l-barrage-play-state'
  60. const LOOP_COUNT = '--l-barrage-loop-count'
  61. const ANI_STATE = 'animation-play-state'
  62. // const OFFSET = '--l-barrage-offset'
  63. // const TIME = '--l-barrage-time'
  64. export default defineComponent({
  65. props: BarrageProps,
  66. emits: ['end', 'progress'],
  67. setup(props, {emit}) {
  68. const app = getCurrentInstance()
  69. let barrage = null
  70. const styles = reactive({[PLAY_STATE]:'running', [LOOP_COUNT]: props.loopCount})
  71. const touchend = (item: any) => {
  72. if(props.touchPause) {
  73. item.style[ANI_STATE] = ''
  74. }
  75. }
  76. const touchstart = (item: any) => {
  77. if(props.touchPause) {
  78. item.style[ANI_STATE] = 'paused'
  79. item.style['z-index'] = '1'
  80. }
  81. }
  82. const animationstart = (item: any) => {
  83. if(!item) return
  84. item.time = +new Date()
  85. }
  86. let timer = null
  87. const animationend = (item: any) => {
  88. if(!item) return
  89. const endTime = +new Date() - item.time
  90. if(endTime > 100) {
  91. item.style.opacity = 0;
  92. clearTimeout(timer)
  93. timer = setTimeout(() => {
  94. let count = 0
  95. const flag = list.value.every((item) => {
  96. if(item.style && !item.style.opacity) {
  97. count++
  98. return !0
  99. }
  100. return !1
  101. })
  102. emit('progress', count / props.data.length * 100)
  103. if(flag) {
  104. list.value = []
  105. emit('end')
  106. }
  107. }, 200)
  108. }
  109. }
  110. let stopWatchPause = null
  111. let stopWatchData = null
  112. let stopWatchArea = null
  113. let list = ref([])
  114. const append = (node: any) => {
  115. list.value.push(node)
  116. }
  117. onMounted(() => {
  118. getRect('.l-barrage', { context: app.proxy }).then(container => {
  119. if (container) {
  120. barrage = new Barrage({
  121. config: Object.assign({}, props) as any,
  122. container,
  123. reactive,
  124. getBoundingClientRect: (selector : string):Promise<any> => {
  125. return getRect('#'+selector, { context: app.proxy })
  126. }
  127. }, append)
  128. stopWatchPause = watch(() => props.pause, (v) => {
  129. if (v) {
  130. barrage.pause()
  131. } else {
  132. barrage.start()
  133. }
  134. styles[PLAY_STATE] = barrage.playState
  135. })
  136. let count = 0
  137. let isVue3 = true
  138. //#ifndef VUE3
  139. isVue3 = false
  140. // #endif
  141. stopWatchData = watch(isVue3 ? props.data : () => props.data, (v) => {
  142. if (barrage && v && v.length && v.length > count) {
  143. const bullets = v.slice(count, v.length)
  144. barrage.setBullet(bullets)
  145. count = v.length
  146. }
  147. }, {immediate: true})
  148. stopWatchArea = watch(()=> props.showArea, (v) => {
  149. barrage.showTracks(v)
  150. })
  151. }
  152. })
  153. })
  154. onBeforeUnmount(() => {
  155. stopWatchPause && stopWatchPause()
  156. stopWatchData && stopWatchData()
  157. stopWatchArea && stopWatchArea()
  158. barrage && (barrage = null)
  159. })
  160. return {
  161. styles,
  162. touchend,
  163. touchstart,
  164. animationend,
  165. animationstart,
  166. props,
  167. list
  168. }
  169. }
  170. })
  171. </script>
  172. <style lang="scss">
  173. $playState: var(--l-barrage-play-state);
  174. $time: var(--l-barrage-time);
  175. $offset: var(--l-barrage-offset);
  176. $loopCount: var(--l-barrage-loop-count, 1);
  177. .l-barrage {
  178. width: 100%;
  179. height: 100%;
  180. position: relative;
  181. overflow: hidden;
  182. &-item {
  183. position: absolute;
  184. display: inline-block;
  185. height: 20px;
  186. top: 0;
  187. left: 100%;
  188. white-space: nowrap;
  189. animation-name: barrageMove;
  190. animation-timing-function: linear;
  191. animation-play-state: $playState;
  192. animation-duration: $time;
  193. animation-iteration-count: $loopCount;
  194. display: inline-block;
  195. }
  196. // &.l-is-touch {
  197. // .l-barrage-item:hover {
  198. // cursor: pointer;
  199. // animation-play-state: paused;
  200. // z-index: 1;
  201. // }
  202. // }
  203. }
  204. @keyframes barrageMove {
  205. to {
  206. transform: translateX($offset);
  207. }
  208. }
  209. </style>