easy-barrage

Simple implementation of a barrage library

background

The text content is displayed on the page in the form of bullet curtain wall, which requires infinite loop scrolling. After searching on the Internet, I couldn't find a library that met my needs, so I implemented it myself. Tips: The implementation of this library is relatively simple, for specific needs, need to expand on this basis, or issue, learn together, common progress.Copy the code

Basic Implementation Principles

1. Calculate the number of lines of the barrage according to the height of each barrage and the height of the barrage display area (called runway) laneCount 2. Define the state map of a runway, laneStatus, to indicate the current state of the runway in idle (true) or occupied (false) 3 Storage of barrage data; ItemStatusMap is used to indicate that the current state of the barrage is in display (true) or not in display (false). 4. Cycle the runway (laneStatus) every one second. If you have idle runway again from barrage array (data) to retrieve a data begin to render, from the barrage display area into 5 to the right, in the barrage began to enter barrage display area, the runway status set to false, after completely into the barrage display area, the runway status set to true 6, roll out completely in the barrage barrage display area, Delete the DOM node of the barrage and set the state of the barrage to falseCopy the code

Attach a effect

Method of use

Copy the barrage. Js file from the SRC directory (the barrage. Js file from the dist directory is packaged) and import it as import.

  import Barrage from '.. /src/barrage'
  import { barrageData } from './data'

  const el = document.getElementsByClassName('container')[0] Const barrage = new Barrage({barrage: el, // 26, // Mandatory height unit px speed: 3, // The speed parameter ranges from 1 to 5. The higher the speed, the faster the speed. The default value is 3.trueInfinite is not displayed by default:true}) barrage.init()Copy the code

Attached main source code

class Barrage {
  constructor (options) {
      const data = Object.assign({}, {
            data: [],
            barrageHeight: 26,
            speed: 3,
            showAvatar: false,
            infinite: false}, Container this.data = data.data // Projectile state mapping this.itemStatusMap = new Array(this.data.length).fill(true)
      this.itemHeight = data.barrageHeight
      this.speed = data.speed * 0.0293
      this.showAvatar = data.showAvatar
      this.infinite = data.infinite
  }

  init() {// Initialize barrage runway this.initlane () // Initialize barrage runway this.inittimer ()}initTimer () {
    if (this.data.length > 0) {
      this.timer = setInterval(() => {
        for (leti = 0; i < this.laneCount; I++) {const lane = this.getlane () const pointer = this.getonebarrage (if(pointer === -1 && ! this.infinite) { clearInterval(this.timer)return
          }
      
          if (lane > -1 && pointer > -1) {
            this.laneStatus[lane] = false
            this.initItemDom(pointer, lane)
            this.itemStatusMap[pointer] = false
          }
        }
      }, 1000)
    }
  }

  initItemDom (pointer, lane) {
    const data = this.data[pointer]
    const el = document.createElement('div')
    el.classList.add('barrage')
    const startLeft = this.containerWidth + Math.floor(Math.random() * 50)
    const top = lane * this.itemHeight + lane * this.gap
    el.style = `top: ${top}px; left: ${ startLeft }px; height: ${this.itemHeight}px; border-radius:${this.itemHeight / 2}px`
    el.innerHTML = `${this.showAvatar ? '<img class="avatar" src="' + data.avatar + '"/>' : ''}
      <p class="content">${data.text}</p>`
    this.container.appendChild(el)
    const width = el.offsetWidth
    const animateTime = Math.ceil((width + startLeft) / this.speed)
    
    this.animate(el, startLeft, -width, animateTime, () => {
      if (this.infinite) {
        this.itemStatusMap[pointer] = true
      }
      el.remove()
    })
    
    const inScreenTime = animateTime / (width + this.containerWidth) * width
    setTimeout(() => {
      this.laneStatus[lane] = true
    }, inScreenTime)
  }

  initLane () {
    this.containerWidth = this.container.clientWidth
    this.containerHeight = this.container.clientHeight
    this.laneCount = Math.floor(this.containerHeight / this.itemHeight)
    this.laneStatus = new Array(this.laneCount).fill(trueThis.gap = math.floor (this.containerheight % this.itemheight/(this.lanecount-1))}getLane () {
    let lane = Math.floor(Math.random() * this.laneCount)
    let times = 1
    while (times < this.laneCount) {
      if (this.laneStatus[lane]) {
        return lane
      } else {
        lane === this.laneCount - 1 ? lane = 0 : lane++
        times+ +}}return1}getOneBarrage () {
    returnthis.itemStatusMap.findIndex(item => item) } animate (el, start, des, duration, Const createTime = () => +new Date() const startTime = createTime()function tick() { const remaining = Math.max(0, StartTime + duration - createTime ()) const temp = remaining/duration | | 0 const percent = 1 - temp / / in the end each moving distance of the left const leftPos = (des - start) * percent + startif (1 === percent) {
        window.cancelAnimationFrame(frameId)
        el.style.left = des + 'px'
        callback()
      } else {
        el.style.left = leftPos + 'px'Window. RequestAnimationFrame (tick)}} / / start animation const frameId = window. RequestAnimationFrame (tick)} _isDom (el) {return el && typeof el === 'object' && el.nodeType === 1 && typeof el.nodeName === 'string'
  }
      
  _checkSpeed (speed) {
    return speed % 1 === 0 && speed >=1 && speed <= 5
  }
}

export default Barrage
Copy the code

Making portal