js弹幕

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <title>原生JS实现弹幕效果</title>
  <style>
    #wrapper {
      height: 400px;
      width: 700px;
      position: relative;
      overflow: hidden;
      background: url(http://www.drama-asia.se/wp-content/uploads/2016/06/14375197_1349947520504_800x600.jpg);
      
      color: #ffffff82;
      font-size: 14px;
      text-shadow: 1px 1px #000;
    }
    .right {
      position: absolute;
      visibility: hidden;
      white-space: nowrap;
      /*left: 700px;*/
      transform: translateX(700px);
    }
    .left {
      position: absolute;
      white-space: nowrap;
      user-select: none;
      transition: transform 7s linear; /* 时间相同 越长的弹幕滑动距离越长 所以越快~ */
    }
    input {
      position: absolute;
      bottom: 10px;
      left: 150px;
      width: 300px;
      height: 26px;
    }

    button {
      position: absolute;
      bottom: 8px;
      left: 476px;
      width: 100px;
      height: 38px;
      border-radius: 10px;
      font-size: 16px;
    }
  </style>
</head>
<body>
<div id="wrapper">
  <input type="text">
  <button>发&nbsp;&nbsp;送</button>
</div>
<script>
/**
 * 设置 弹幕DOM池 每一个通道最多六条弹幕
**/

const MAX_DM_COUNT = 6;
const CHANNEL_COUNT = 10;

let domPool = [];
let danmuPool = [
  '前方大量弹幕来袭,请做好准备!', '2333333', '2333333', '2333333', '2333333', '2333333', 
  '浔阳江头夜送客, 枫叶荻花秋瑟瑟',  '2333333', '2333333', '2333333', '2333333', '2333333', '2333333',
  '主人下马客在船, 举酒欲饮无管弦。', '醉不成欢惨将别, 别时茫茫江浸月', '忽闻水上琵琶声, 主人忘归客不发。', 
  '寻声暗问弹者谁? 琵琶声停欲语迟。', '移船相近邀相见, 添酒回灯重开宴。', '千呼万唤始出来, 犹抱琵琶半遮面。',
  '转轴拨弦三两声, 未成曲调先有情。', '弦弦掩抑声声思, 似诉平生不得志。', '低眉信手续续弹, 说尽心中无限事。', 
  '轻拢慢捻抹复挑, 初为霓裳后六幺。', '大弦嘈嘈如急雨, 小弦切切如私语。', '嘈嘈切切错杂弹, 大珠小珠落玉盘。', 
  '间关莺语花底滑, 幽咽泉流冰下难。', '冰泉冷涩弦凝绝, 凝绝不通声暂歇。', '别有幽愁暗恨生, 此时无声胜有声。', 
  '银瓶乍破水浆迸, 铁骑突出刀枪鸣。', '曲终收拨当心画, 四弦一声如裂帛。', '东船西舫悄无言, 唯见江心秋月白。', 
  '沉吟放拨插弦中, 整顿衣裳起敛容。', '自言本是京城女, 家在虾蟆陵下住。', '十三学得琵琶成, 名属教坊第一部。', 
  '曲罢曾教善才服, 妆成每被秋娘妒。', '五陵年少争缠头, 一曲红绡不知数。', '钿头银篦击节碎, 血色罗裙翻酒污。', 
  '今年欢笑复明年, 秋月春风等闲度。', '弟走从军阿姨死, 暮去朝来颜色故。', '门前冷落鞍马稀, 老大嫁作商人妇。', 
  '商人重利轻别离, 前月浮梁买茶去。', '去来江口守空船, 绕船月明江水寒。', '夜深忽梦少年事, 梦啼妆泪红阑干。',
  '我闻琵琶已叹息, 又闻此语重唧唧。', '同是天涯沦落人, 相逢何必曾相识!', '我从去年辞帝京, 谪居卧病浔阳城。',
  '浔阳地僻无音乐, 终岁不闻丝竹声。', '住近湓江地低湿, 黄芦苦竹绕宅生。', '其间旦暮闻何物? 杜鹃啼血猿哀鸣。',
  '春江花朝秋月夜, 往往取酒还独倾。', '岂无山歌与村笛? 呕哑嘲哳难为听。', '今夜闻君琵琶语, 如听仙乐耳暂明。',
  '莫辞更坐弹一曲, 为君翻作《琵琶行》。', '感我此言良久立, 却坐促弦弦转急。', '凄凄不似向前声, 满座重闻皆掩泣。',
  '座中泣下谁最多? 江州司马青衫湿。'
];
let hasPosition = [];

/**
 * 做一下初始化工作
 */
function init() {
  let wrapper = document.getElementById('wrapper')
  // 先new一些span 重复利用这些DOM
  for (let j = 0; j < CHANNEL_COUNT; j++) {
    let doms = [];
    for (let i = 0; i < MAX_DM_COUNT; i++) {
      // 要全部放进wrapper
      let dom = document.createElement('span');
      wrapper.appendChild(dom);
      // 初始化dom的位置 通过设置className
      dom.className = 'right';
      // DOM的通道是固定的 所以设置好top就不需要再改变了
      dom.style.top = j * 20 + 'px';
      // 放入改通道的DOM池
      doms.push(dom);
      // 每次到transition结束的时候 就是弹幕划出屏幕了 将DOM位置重置 再放回DOM池
      dom.addEventListener('transitionend', () => {
        dom.className = 'right';
        // dom.style.transition = null;
        // dom.style.left = null;
        dom.style.transform = null;

        domPool[j].push(dom);
      });
    }
    domPool.push(doms);
  }
  // hasPosition 标记每个通道目前是否有位置
  for (let i = 0; i < CHANNEL_COUNT; i++) {
    hasPosition[i] = true;
  }
}

/**
 * 获取一个可以发射弹幕的通道 没有则返回-1
 */
function getChannel() {
  for (let i = 0; i < CHANNEL_COUNT; i++) {
    if (hasPosition[i] && domPool[i].length) return i;
  }
  return -1;
}

/**
 * 根据DOM和弹幕信息 发射弹幕
 */
function shootDanmu(dom, text, channel) {
  console.log('biu~ [' + text + ']');
  dom.innerText = text;
  // 如果为每个弹幕设置 transition 可以保证每个弹幕的速度相同 这里没有保证速度相同
  // dom.style.transition = `transform ${7 + dom.clientWidth / 100}s linear`;

  // dom.style.left = '-' + dom.clientWidth + 'px';
  // 设置弹幕的位置信息 性能优化 left -> transform
  dom.style.transform = `translateX(${-dom.clientWidth}px)`;
  dom.className = 'left';
  
  hasPosition[channel] = false;
  // 弹幕全部显示之后 才能开始下一条弹幕
  // 大概 dom.clientWidth * 10 的时间 该条弹幕就从右边全部划出到可见区域 再加1秒保证弹幕之间距离
  setTimeout(() => {
    hasPosition[channel] = true;
  }, dom.clientWidth * 10 + 1000);
}

window.onload = function() {

  init();

  // 为input和button添加事件监听
  let btn = document.getElementsByTagName('button')[0];
  let input = document.getElementsByTagName('input')[0];
  btn.addEventListener('click', () => {
    input.value = input.value.trim();
    if (input.value) danmuPool.push(input.value);
  })
  input.addEventListener('keyup', (e) => {
    if (e.key === 'Enter' && (input.value = input.value.trim())) {
      danmuPool.push(input.value);
    }
  })
  // 每隔1ms从弹幕池里获取弹幕(如果有的话)并发射
  setInterval(() => {
    let channel;
    if (danmuPool.length && (channel = getChannel()) != -1) {
      let dom = domPool[channel].shift();
      let danmu = danmuPool.shift();
      shootDanmu(dom, danmu, channel);
    }
  }, 1);

}
 
</script>
</body>
</html>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容