La colonne
JavaScript présente aujourd'hui comment implémenter des composants de barrage à l'aide de JavaScript natif.
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 :
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 speed
Le temps nécessaire au barrage pour traverser l'écrangapWidth
La distance entre le prochain barrage et le barrage précédentpushData
Ajouter des métadonnées de barrageaddData
Continuer à rejoindre le barragestart
Commencer à planifier le barragestop
Arrêter le barragerestart
Redémarrer le barrageclearData
Effacer le barrageclose
Fermeropen
Réafficher le barragePS : Il existe certaines fonctions d'outils auto-encapsulées que je ne publierai pas ici. Vous savez probablement ce qu'elles signifient
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'})复制代码
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 = [] }复制代码
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'))) } }复制代码
pour calculer la boîte. l'getComputedStyle
api 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 }复制代码
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.
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('p') p.classList = `barrage-list barrage-list-${i}` p.style.height = `${this.boxSize.height*getpisor(this.mode)/this.rows}px` this.container.appendChild(p) } } }复制代码
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 }复制代码
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() }复制代码
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]) } }复制代码
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('p'), parent = document.querySelector(`${el} .barrage-list-${i}`), width, pastTime p.innerHTML = item.content p.className = 'barrage-item' 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); }复制代码
//用css动画,整体还是比较流畅的this.run = function (item) { item.classList += ' running' item.style.left = "left:100%" item.style.display = '' item.style.animation = `run ${this.speed/1000}s linear` //已完成的打一个标记 setTimeout(() => { item.classList+=' done' }, this.speed); }复制代码
//根据弹幕的宽度和gapWth,算出下一条弹幕应该出现的时间this.computeTime = function (width) { let length = width + this.gapWidth let time = Math.round(length / this.boxSize.width * this.speed/2) return time }复制代码
L'animation CSS est la suivante
@keyframes run { 0% { left: 100%; } 50% { left: 0 } 100% { left: -100%; } }.run { animation-name: run; }复制代码
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 += ' pause' }) }复制代码
Supprimer la classe pause
.pause { animation-play-state: paused !important; }复制代码
Faites simplement une logique afficher-masquer
this.restart = function () { let items = document.querySelectorAll(`${el} .barrage-item`); [...items].forEach(item => { removeClassName(item, 'pause') }) }复制代码
this.close = function () { this.container.style.display = 'none'}this.open = function () { this.container.style.display = ''}复制代码
Enfin, utilisez une minuterie pour nettoyer les barrages expirés :
this.clearData = function () { //清除list this.list = [] //清除dom document.querySelector(`${el}`).innerHTML = '' //清除timeout this.timeoutFuncs.forEach(fun => clearTimeout(fun)) }复制代码
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!