jabbany / CommentCoreLibrary

Javascript Live Comment (Danmaku) Engine Implementation. JS弹幕模块核心,提供从基本骨架到高级弹幕的支持。
http://jabbany.github.io/CommentCoreLibrary/demo
MIT License
1.9k stars 304 forks source link

我使用cm.insert()时监听到CommentManager.prototype.dispatchEvent派生方法条数不够 #125

Closed wzjiscode closed 3 years ago

wzjiscode commented 3 years ago
  1. 使用cm.insert(data) // data为数据
  2. `CommentManager.prototype.dispatchEvent = function (event, data) {
  3. console.log(event) // 在源码CommentManager.prototype.dispatchEvent(event, data)中打印event, 发现触发次数远远小于data.length if (typeof this._listeners[event] !== "undefined") { for (var i = 0; i < this._listeners[event].length; i++) { try { this._listeners[event]i; } catch (e) { console.error(e.stack); } } } };`
  4. 最终出现在窗口中的弹幕条数和派发的send事件条数一样。
  5. 请问为什么派生的数据少了呢?
  6. list.map(item => { comment = { "mode": [1, 2][randomIndex(2)], "text": item.text, "stime": item.videoCurrentDuration * 1000 - 1, // 比现在时间稍微慢一ms "size": 25, "color": color, } if (item.videoCurrentDuration) { CM.insert(comment); // 调用insert } })
wzjiscode commented 3 years ago
使用cm.insert(data) // data为数据
`CommentManager.prototype.dispatchEvent = function (event, data) {
console.log(event) // 在源码CommentManager.prototype.dispatchEvent(event, data)中打印event, 发现触发次数远远小于data.length
if (typeof this._listeners[event] !== "undefined") {
for (var i = 0; i < this._listeners[event].length; i++) {
try {
this._listeners[event]i;
} catch (e) {
console.error(e.stack);
}
}
}
};`
最终出现在窗口中的弹幕条数和派发的send事件条数一样。
请问为什么派生的数据少了呢?
list.map(item => { comment = { "mode": [1, 2][randomIndex(2)], "text": item.text, "stime": item.videoCurrentDuration * 1000 - 1, // 比现在时间稍微慢一ms "size": 25, "color": color, } if (item.videoCurrentDuration) { CM.insert(comment); // 调用insert } })
jabbany commented 3 years ago

不太确认这个问题的具体原因,但是你可以检查一下以下的几个点:

^1: 具体有关如何动态插入 即时 弹幕可以参考 这里 的文档。 样例里面的逻辑是:首先把弹幕插在目前播放时间前然后更新CCL的播放时间到现在的播时间。这么做就可以保证insert到时间轴时,这条新的弹幕不会因为播放时间更新触发send;之后立刻手动强行触发 send 来保证弹幕被显示。

如果还是有弹幕缺失问题的话,方便的话可以给一个最小再现样本,因为我这边目前没法复现。

wzjiscode commented 3 years ago

image image 我在这个视频开始之前加载接口中的数据,可以看到派发了三次 (insert) 这个event但是从开始直到视频播放完只出现了text为“2”的展示

wzjiscode commented 3 years ago

追加我打印的位置图像 image

wzjiscode commented 3 years ago

// 实现的代码 function requestBarrage(param) { var type = 'get' var url = 'xxxxxxxx' ajax(type, url, param, function (res) { if (res.code == 1) { var color = 0xffffff var colorObj = { '#FFFFFF': 0xFFFFFF, '#ffffff': 0xFFFFFF, '#E01818': 0xE01818, '#e01818': 0xE01818, '#E06B18': 0xE06B18, '#e06B18': 0xE06B18, '#FDFF21': 0xFDFF21, '#fdff21': 0xFDFF21, '#17D62E': 0x17D62E, '#17d62e': 0x17D62E, '#17B4D6': 0x17B4D6, '#17b4d6': 0x17B4D6, '#1742D6': 0x1742D6, '#1742d6': 0x1742D6, } var comment // 弹幕速度 CM.options.global.scale = 1 CM.options.scroll.scale = 2 CM.timeline = [] if (!res.list.length) { CM.timeline = [] return; } res.list.map((item, index) => { if (colorObj[item.color]) { color = colorObj[item.color] } // console.log(item.text, index) comment = { "mode": [1, 2, 9][randomIndex(3)], "text": item.text, "stime": item.videoCurrentDuration * 1000 - 1, // 比现在时间稍微慢一ms "size": 25, "color": color, } if (item.videoCurrentDuration) { // 这里触发insert事件 CM.insert([comment]); } }) } }) }

jabbany commented 3 years ago

看着没有问题啊,三条弹幕触发了三次insert事件?

如果你是指enterComment不够多的话,你需要检查一下你的播放器在怎么推 cm.time()。insert只负责把弹幕放到时间轴上,如果没有正确更新播放位置的话,不会触发渲染的。

建议参考这里的示意图 来理解 CommentManager 的运作概要

wzjiscode commented 3 years ago

很奇怪三条数据 有时候会enterComment三次,有时候会一次。造成显示不全

jabbany commented 3 years ago

这都得看你怎么调用的time。。。你这里提供的码看不出来怎么调用的 time 所以完全有可能一边插入一边播放会播过插进去的位置。如果你想保证插进去的弹幕被播,要么保证插在当前播放位置前(肯定不显示)然后手动send,要么在插入前调用time来更新播放头到弹幕时间之前,然后插入后再调用time更新播放头到弹幕之后,就会保证期间的弹幕触发send。

不是这两种情况完全依赖播放器或者定时器更新time的话就完全没有保证到底是先播到位置还是先插入弹幕,也就不能确定实际会渲染哪些。

jabbany commented 3 years ago

你现在代码是把弹幕的播放时间设定成视频目前的播放时间,理论上这个是模式(1),也就是这么插入的弹幕应该从来不显示。但是这个实现不work,因为插入时候的播放时间是基于ajax返回结果的时间,然而这时 cm 里面的播放时间未必已经更新到了这个时间,所插进去的弹幕虽然在 视频 播放位置前,但是不一定在 cm知道的 播放位置前。解决办法是在insert前先调用 cm.time(...) 强行同步cm里面的播放位置和实际位置。这样插进去的弹幕应该会产生0个enterComment。然后为了保证显示,在插入后,再把所有插进去的弹幕 send 一下渲染就是了。

jabbany commented 3 years ago

建议更仔细的参考之前链的那个实现的代码。那个实现里面每行都很重要。

wzjiscode commented 3 years ago

好的谢谢你,我使用的阿里包装的你的插件。我再去看看代码吧!按照你的方式去做了 还是没用。我去看下阿里的代码

wzjiscode commented 3 years ago

image 阿里的CM.time()更新

wzjiscode commented 3 years ago

我这个是录播弹幕呀不可能直接一把嗦CM.send()

jabbany commented 3 years ago

这个没有问题,建议你仔细看 这里 的文档,就是你想做的事情。建议这里每一行都仔细看一下应该就能解决问题。现在你的实现里面有问题因为缺了这里面的time和send操作,没有time会导致不能判断哪些弹幕会渲染,没有send会导致不能保证有渲染的弹幕。

wzjiscode commented 3 years ago

那我需要实时获取到video元素的播放时间,还要进行数据过滤后才可以send吧我不是第一时间就发送的,要根据video元素的currentTime来判断是否send,这样的方案我操作了,容易造成页面卡顿现象

jabbany commented 3 years ago

那就得看播放器怎么封装的了,如果想具体研究的话可以参考 https://github.com/jabbany/ABPlayerHTML5 这个用 CCL实现的播放器样例。

wzjiscode commented 3 years ago

dispatchEvent(‘insert’)那里走的数据条数是正确的。就是播放出来的不对,所以我又看了我的CM.time()我发现每次少的数据是不同的。所以也排除我传的时间不对,或者其他地方CM.time()设置问题!

wzjiscode commented 3 years ago

image

wzjiscode commented 3 years ago

image

wzjiscode commented 3 years ago

删掉之后数据正常了,请问我可以把这段代码删掉吗

jabbany commented 3 years ago

看你自己需求,这里删掉的bug就是不一定能正确处理用户向前或者向后拖动时间轴,以及不能限制同屏弹幕数和弹幕过滤。如果是这里的问题的话你可以检查一下 (1) cm.options.limit (同屏弹幕数)是 0 或者大于你需要的设定,另外 (1) 检查 cm.filter.allowTypes 里面对应弹幕 mode 的类型是 true。

wzjiscode commented 3 years ago

limit的值是0我感觉就是这里的问题了,是不是需要我手动设置最大数值呢

jabbany commented 3 years ago

不需要,0 是没有限制

wzjiscode commented 3 years ago

嗯嗯 好的目前通过暴力删除,暂时性解决了数据问题。很感谢大佬的帮助。