barrageContainer.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. <template>
  2. <div class="barrageContainer" ref="barrageContainer">
  3. <slot />
  4. </div>
  5. </template>
  6. <script>
  7. import { CircularLinkedList } from './circularLinkedList.js'
  8. export default {
  9. props: {
  10. // 动画时间
  11. wheelTime: {
  12. type: Number,
  13. default: 3000
  14. },
  15. // 隐藏的过度距离
  16. excessive: {
  17. type: Number,
  18. default: 500
  19. },
  20. // 距离顶部最小高度
  21. mintop: {
  22. type: Number,
  23. default: 100
  24. },
  25. // 距离底部最小高度
  26. minbottom: {
  27. type: Number,
  28. default: 100
  29. },
  30. // 弹幕样式
  31. barrageStyle: {
  32. type: Object,
  33. default: () => ({})
  34. },
  35. // 默认的数据
  36. // 对象中必要参数又id与time
  37. // 默认以text为展示内容,text可以是文本或者是返回文本的函数。没有则展示id
  38. defaultBarrage: {
  39. type: Array,
  40. default: () => []
  41. }
  42. },
  43. data() {
  44. return {
  45. link: new CircularLinkedList(),
  46. containerWidth: 0,
  47. containerHeight: 0
  48. }
  49. },
  50. created() {
  51. this.defaultBarrage.map(item => {
  52. this.push(item)
  53. })
  54. },
  55. methods: {
  56. // 计算容器高度
  57. kg() {
  58. const element = this.$refs.barrageContainer
  59. this.containerWidth = element.offsetWidth
  60. this.containerHeight = element.offsetHeight
  61. },
  62. // 向后追加
  63. push(val) {
  64. this.link.append(val)
  65. },
  66. // 向前追加
  67. unshift(val) {
  68. this.link.prepend(val)
  69. },
  70. // 执行开始
  71. execute() {
  72. if (this.link.getLength() > 0) {
  73. this.currentData = this.link.head
  74. this.kg()
  75. this.dongtai()
  76. this.$nextTick(() => {
  77. this.start()
  78. })
  79. }
  80. },
  81. // 关闭
  82. close() {
  83. if (this.timeId) {
  84. clearTimeout(this.timeId)
  85. }
  86. // 删除样式
  87. const style = document.getElementById('dynamic-animation-style')
  88. if (style) {
  89. style.parentNode.removeChild(style)
  90. }
  91. // 删除元素
  92. document.querySelectorAll('.newBarrageChild').forEach(element => {
  93. element.remove()
  94. })
  95. },
  96. // 开始
  97. start() {
  98. if (this.timeId) {
  99. clearTimeout(this.timeId)
  100. }
  101. // 上一个距离下一个的时间
  102. var timeNum2 = Math.abs(
  103. new Date(this.currentData?.next?.value?.time).getTime() - new Date(this.currentData?.value?.time).getTime()
  104. )
  105. // 获取间隔时间
  106. var timenum =
  107. this?.currentData?.next === this.link?.head
  108. ? this.wheelTime
  109. : timeNum2 > this.wheelTime
  110. ? this.wheelTime
  111. : timeNum2
  112. // 删除之前的
  113. var node = document.getElementById(this.currentData?.value?.id)
  114. if (node) {
  115. node.parentNode.removeChild(node)
  116. }
  117. // 追加新的元素
  118. var parent = this.$refs.barrageContainer
  119. var newChild = document.createElement('div')
  120. newChild.id = this.currentData?.value?.id
  121. newChild.className = 'barrage newBarrageChild'
  122. newChild.style.top = `${this.getRandomIntInRange(
  123. this.mintop,
  124. this.containerHeight > this.minbottom ? this.containerHeight - this.minbottom : this.minbottom
  125. )}px`
  126. for (var key in this.barrageStyle) {
  127. newChild.style[key] = this.barrageStyle[key]
  128. }
  129. newChild.style.animation = `moveRight ${this.wheelTime / 1000}s linear infinite`
  130. newChild.innerText =
  131. typeof this.currentData?.value?.text === 'function'
  132. ? this.currentData?.value?.text?.()
  133. : typeof this.currentData?.value?.text === 'string'
  134. ? this.currentData?.value?.text
  135. : this.currentData?.value?.id
  136. parent.appendChild(newChild)
  137. // 赋值下一个数据为当前数据
  138. this.currentData = this.currentData.next
  139. // 定时器下一次执行追加
  140. this.timeId = setTimeout(() => {
  141. this.start()
  142. }, timenum)
  143. },
  144. // 获取随机高度
  145. getRandomIntInRange(min, max) {
  146. return Math.floor(Math.random() * (max - min + 1)) + min
  147. },
  148. // 生成uid
  149. uid() {
  150. let d = new Date().getTime()
  151. let d2 = (performance && performance.now && performance.now() * 1000) || 0
  152. return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
  153. let r = Math.random() * 16
  154. if (d > 0) {
  155. r = (d + r) % 16 | 0
  156. d = Math.floor(d / 16)
  157. } else {
  158. r = (d2 + r) % 16 | 0
  159. d2 = Math.floor(d2 / 16)
  160. }
  161. return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16)
  162. })
  163. },
  164. dongtai() {
  165. // 创建一个 <style> 标签
  166. const style = document.createElement('style')
  167. style.id = 'dynamic-animation-style'
  168. style.type = 'text/css'
  169. style.innerHTML = `
  170. @keyframes moveRight {
  171. from {
  172. right: 0;
  173. }
  174. to {
  175. right: ${this.containerWidth + this.excessive}px;
  176. }
  177. }
  178. `
  179. document.getElementsByTagName('head')[0].appendChild(style)
  180. }
  181. }
  182. }
  183. </script>
  184. <style lang="scss">
  185. .barrageContainer {
  186. width: 100%;
  187. height: 100%;
  188. position: relative;
  189. overflow: hidden;
  190. .barrage {
  191. position: absolute;
  192. z-index: 9999999;
  193. transform: translateX(100%);
  194. }
  195. }
  196. </style>