Maison > interface Web > js tutoriel > Comment implémenter le composant barrage en JavaScript natif

Comment implémenter le composant barrage en JavaScript natif

coldplay.xixi
Libérer: 2020-10-09 16:32:29
avant
2327 Les gens l'ont consulté

La colonne

JavaScript présente aujourd'hui comment implémenter des composants de barrage à l'aide de JavaScript natif.

Comment implémenter le composant barrage en JavaScript natif

Préface

De nos jours, presque tous les sites Web de vidéos ont une fonction de barrage, nous allons donc aujourd'hui utiliser le JavaScript natif pour encapsuler une classe de barrage. Cette classe espère avoir les attributs et méthodes d'instance suivants :

Attributs

  • el Sélecteur pour le nœud conteneur Le nœud conteneur doit être positionné de manière absolue, ainsi que la largeur et la hauteur. doit être réglé
  • height La hauteur de chaque barrage
  • mode En mode barrage, la moitié correspond à la moitié de la hauteur du conteneur, le haut correspond à un tiers et le plein est plein
  • speedLe temps nécessaire au barrage pour traverser l'écran
  • gapWidthLa distance entre le prochain barrage et le barrage précédent

Méthode

  • pushDataAjouter des métadonnées de barrage
  • addDataContinuer à rejoindre le barrage
  • startCommencer à planifier le barrage
  • stopArrêter le barrage
  • restart Redémarrer le barrage
  • clearDataEffacer le barrage
  • closeFermer
  • openRéafficher le barrage

PS : Il existe certaines fonctions d'outils auto-encapsulées que je ne publierai pas ici. Vous savez probablement ce qu'elles signifient

Initialisation

Après avoir introduit le JavaScript. fichier, nous voulons l’utiliser comme suit. Prenez d’abord la configuration par défaut.

let barrage = new Barrage({    el: '#container'})复制代码
Copier après la connexion

Initialisation des paramètres :

function Barrage(options) {    let {
        el,
        height,
        mode,
        speed,
        gapWidth,
    } = options    this.container = document.querySelector(el)    this.height = height || 30
    this.speed = speed || 15000 //2000ms
    this.gapWidth = gapWidth || 20
    this.list = []    this.mode = mode || 'half'
    this.boxSize = getBoxSize(this.container)    this.perSpeed = Math.round(this.boxSize.width / this.speed)    this.rows = initRows(this.boxSize, this.mode, this.height)    this.timeoutFuncs = []    this.indexs = []    this.idMap = []
}复制代码
Copier après la connexion

accepte d'abord les paramètres puis les initialise. Jetons un coup d'œil à getBoxSize et initRows

function getBoxSize(box) {    let {
        height,
        width
    } = window.getComputedStyle(box)    return {        height: px2num(height),        width: px2num(width)
    }    function px2num(str) {        return Number(str.substring(0, str.indexOf('p')))
    }
}复制代码
Copier après la connexion

pour calculer la boîte. l'getComputedStyleapi Largeur et hauteur, utilisée ici pour calculer la largeur et la hauteur du conteneur, sera également utilisée ultérieurement.

function initRows(box, mode, height) {    let pisor = getpisor(mode)
    rows = Math.ceil(box.height * pisor / height)    return rows
}function getpisor(mode) {    let pisor = .5
    switch (mode) {        case 'half':
            pisor = .5
            break
        case 'top':
            pisor = 1 / 3
            break;        case 'full':
            pisor = 1;            break
        default:            break;
    }    return pisor
}复制代码
Copier après la connexion

Calculez le nombre de lignes que le barrage devrait avoir en fonction de la hauteur. Le nombre de lignes sera utilisé quelque part en dessous.

Insérer des données

Il existe deux façons d'insérer des données, l'une consiste à ajouter des données source et l'autre consiste à en ajouter continuellement. Examinons d'abord la méthode d'ajout de données source :

this.pushData = function (data) {    this.initDom()    if (getType(data) == '[object Object]') {        //插入单条
        this.pushOne(data)
    }    if (getType(data) == '[object Array]') {        //插入多条
        this.pushArr(data)
    }
}this.initDom = function () {    if (!document.querySelector(`${el} .barrage-list`)) {        //注册dom节点
        for (let i = 0; i < this.rows; i++) {            let p = document.createElement(&#39;p&#39;)
            p.classList = `barrage-list barrage-list-${i}`
            p.style.height = `${this.boxSize.height*getpisor(this.mode)/this.rows}px`
            this.container.appendChild(p)
        }
    }
}复制代码
Copier après la connexion
this.pushOne = function (data) {    for (let i = 0; i < this.rows; i++) {        if (!this.list[i]) this.list[i] = []

    }    let leastRow = getLeastRow(this.list) //获取弹幕列表中最少的那一列,弹幕列表是一个二维数组
    this.list[leastRow].push(data)
}this.pushArr = function (data) {    let list = sliceRowList(this.rows, data)
    list.forEach((item, index) => {        if (this.list[index]) {            this.list[index] = this.list[index].concat(...item)
        } else {            this.list[index] = item
        }
    })
}//根据行数把一维的弹幕list切分成rows行的二维数组function sliceRowList(rows, list) {    let sliceList = [],
        perNum = Math.round(list.length / rows)    for (let i = 0; i < rows; i++) {        let arr = []        if (i == rows - 1) {
            arr = list.slice(i * perNum)
        } else {
            i == 0 ? arr = list.slice(0, perNum) : arr = list.slice(i * perNum, (i + 1) * perNum)
        }
        sliceList.push(arr)
    }    return sliceList
}复制代码
Copier après la connexion

La méthode d'ajout continu de données consiste simplement à appeler la méthode d'ajout de données source et de commencer à planifier

this.addData = function (data) {    this.pushData(data)    this.start()
}复制代码
Copier après la connexion

Lancer des barrages

Jetons un coup d'œil à la logique de lancement des barrages

this.start = function () {    //开始调度list
    this.dispatchList(this.list)
}this.dispatchList = function (list) {    for (let i = 0; i < list.length; i++) {        this.dispatchRow(list[i], i)
    }
}this.dispatchRow = function (row, i) {    if (!this.indexs[i] && this.indexs[i] !== 0) {        this.indexs[i] = 0
    }    //真正的调度从这里开始,用一个实例变量存储好当前调度的下标。
    if (row[this.indexs[i]]) {        this.dispatchItem(row[this.indexs[i]], i, this.indexs[i])
    }
}复制代码
Copier après la connexion
this.dispatchItem = function (item, i) {    //调度过一次的某条弹幕下一次在调度就不需要了
    if (!item || this.idMap[item.id]) {        return
    }    let index = this.indexs[i]    this.idMap[item.id] = item.id    let p = document.createElement(&#39;p&#39;),
        parent = document.querySelector(`${el} .barrage-list-${i}`),
        width,
        pastTime
    p.innerHTML = item.content
    p.className = &#39;barrage-item&#39;
    parent.appendChild(p)
    width = getBoxSize(p).width
    p.style = `width:${width}px;display:none`
    pastTime = this.computeTime(width) //计算出下一条弹幕应该出现的时间
    //弹幕飞一会~
    this.run(p)    if (index > this.list[i].length - 1) {        return
    }    let len = this.timeoutFuncs.length    //记录好定时器,后面清空
    this.timeoutFuncs[len] = setTimeout(() => {        this.indexs[i] = index + 1
        //递归调用下一条
        this.dispatchItem(this.list[i][index + 1], i, index + 1)
    }, pastTime);
}复制代码
Copier après la connexion
//用css动画,整体还是比较流畅的this.run = function (item) {
    item.classList += &#39; running&#39;
    item.style.left = "left:100%"
    item.style.display = &#39;&#39;
    item.style.animation = `run ${this.speed/1000}s linear`
    //已完成的打一个标记
    setTimeout(() => {
        item.classList+=&#39; done&#39;
    }, this.speed);
}复制代码
Copier après la connexion
//根据弹幕的宽度和gapWth,算出下一条弹幕应该出现的时间this.computeTime = function (width) {    let length = width + this.gapWidth    let time = Math.round(length / this.boxSize.width * this.speed/2)    return time
}复制代码
Copier après la connexion

L'animation CSS est la suivante

@keyframes run {
    0% {        left: 100%;
    }

    50% {        left: 0
    }

    100% {        left: -100%;
    }
}.run {    animation-name: run;
}复制代码
Copier après la connexion

Autres méthodes

Arrêter

Utiliser la pause attribut de l'animation pour arrêter

this.stop = function () {    let items = document.querySelectorAll(`${el} .barrage-item`);
    [...items].forEach(item => {
        item.className += &#39; pause&#39;
    })
}复制代码
Copier après la connexion
rrree

Recommencer

Supprimer la classe pause

.pause {    animation-play-state: paused !important;
}复制代码
Copier après la connexion

Activer et désactiver

Faites simplement une logique afficher-masquer

this.restart = function () {    let items = document.querySelectorAll(`${el} .barrage-item`);
    [...items].forEach(item => {
        removeClassName(item, &#39;pause&#39;)
    })
}复制代码
Copier après la connexion

Nettoyer les barrages

this.close = function () {    this.container.style.display = &#39;none&#39;}this.open = function () {    this.container.style.display = &#39;&#39;}复制代码
Copier après la connexion

Enfin, utilisez une minuterie pour nettoyer les barrages expirés :

this.clearData = function () {    //清除list
    this.list = []    //清除dom
    document.querySelector(`${el}`).innerHTML = &#39;&#39;
    //清除timeout
    this.timeoutFuncs.forEach(fun => clearTimeout(fun))
}复制代码
Copier après la connexion

Enfin

J'ai l'impression que la mise en œuvre de c'est toujours imparfait. Si vous le conceviez comme ça, comment concevriez-vous une classe ?

Recommandations d'apprentissage gratuites associées : javascript(vidéo)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:juejin.im
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal