Revert "feat: enhance Danmuku plugin with batch processing for top calculations"

This reverts commit 1841f754dc.
This commit is contained in:
Harvey Zhao committed 2026-03-05 13:58:53 +08:00
1 parent e112b33f97
commit 3ae89ab349
4 files changed
+65 -251

No files matched your search

+32 -133
View File
@@ -94,54 +94,7 @@
function localRequire(x) {
var res = localRequire.resolve(x);
if (res === false) {
return {};
}
// Synthesize a module to follow re-exports.
if (Array.isArray(res)) {
var m = {__esModule: true};
res.forEach(function (v) {
var key = v[0];
var id = v[1];
var exp = v[2] || v[0];
var x = newRequire(id);
if (key === '*') {
Object.keys(x).forEach(function (key) {
if (
key === 'default' ||
key === '__esModule' ||
Object.prototype.hasOwnProperty.call(m, key)
) {
return;
}
Object.defineProperty(m, key, {
enumerable: true,
get: function () {
return x[key];
},
});
});
} else if (exp === '*') {
Object.defineProperty(m, key, {
enumerable: true,
value: x,
});
} else {
Object.defineProperty(m, key, {
enumerable: true,
get: function () {
if (exp === 'default') {
return x.__esModule ? x.default : x;
}
return x[exp];
},
});
}
});
return m;
}
return newRequire(res);
return res === false ? {} : newRequire(res);
}
function resolve(x) {
@@ -295,17 +248,6 @@ class Danmuku {
type: 'application/javascript'
});
this.worker = new Worker(URL.createObjectURL(blob));
// Web Worker 回调池,避免频繁覆盖 onmessage 并支持并发请求
this.workerCallbacks = new Map();
this.worker.onmessage = (event)=>{
const { data } = event;
if (!data || !data.id) return;
const callback = this.workerCallbacks.get(data.id);
if (callback) {
this.workerCallbacks.delete(data.id);
callback(data);
}
};
// 绑定公用事件
this.start = this.start.bind(this);
this.stop = this.stop.bind(this);
@@ -631,11 +573,14 @@ class Danmuku {
// 复杂运算交给 Web Worker 处理
postMessage(message = {}) {
return new Promise((resolve)=>{
const id = `${Date.now()}-${Math.random()}`;
message.id = id // 生成唯一标识
message.id = Date.now() // 生成唯一标识
;
this.workerCallbacks.set(id, resolve);
this.worker.postMessage(message);
this.worker.onmessage = (event)=>{
const { data } = event;
// 判断是否是当前的消息
if (data.id === message.id) resolve(data);
};
});
}
// 根据状态获取弹幕
@@ -646,13 +591,8 @@ class Danmuku {
}
// 设置弹幕状态
setState(danmu, state) {
// 从原状态池中删除,使用原地删除避免创建新数组
const prevState = danmu.$state;
if (prevState && this.states[prevState]) {
const list = this.states[prevState];
const index = list.indexOf(danmu);
if (index !== -1) list.splice(index, 1);
}
// 从原状态池中删除
this.states[danmu.$state] = this.states[danmu.$state].filter((item)=>item !== danmu);
// 设置新状态
danmu.$state = state;
// 设置DOM节点状态
@@ -678,52 +618,22 @@ class Danmuku {
const { setStyles } = this.utils;
this.timer = window.requestAnimationFrame(async ()=>{
if (this.art.playing && !this.isHide) {
const now = Date.now();
const { clientWidth, clientHeight } = this.$player;
// 实时计算弹幕的剩余显示时间,并构建当前可见弹幕数据,避免重复 DOM 读写
const visibles = [];
const playerLeft = this.getLeft(this.$player);
// 实时计算弹幕的剩余显示时间
this.filter('emit', (danmu)=>{
const emitTime = (now - danmu.$lastStartTime) / 1000;
const emitTime = (Date.now() - danmu.$lastStartTime) / 1000;
danmu.$restTime -= emitTime;
danmu.$lastStartTime = now;
danmu.$lastStartTime = Date.now();
// 超过时间即重置弹幕
if (danmu.$restTime <= 0) {
this.makeWait(danmu);
return;
}
if (!danmu.$ref) return;
const top = danmu.$ref.offsetTop;
const left = this.getLeft(danmu.$ref) - playerLeft;
const height = danmu.$ref.clientHeight;
const width = danmu.$ref.clientWidth;
const distance = left + width;
const right = clientWidth - distance;
const speed = distance / danmu.$restTime;
visibles.push({
top,
left,
height,
width,
right,
speed,
distance,
time: danmu.$restTime,
mode: danmu.mode
});
if (danmu.$restTime <= 0) this.makeWait(danmu);
});
// 获取准备好发送的弹幕,可能包含ready和wait状态的弹幕
const readys = this.readys;
if (readys.length) {
const topsTargets = [];
const readyDanmus = [];
// 先初始化 DOM、样式及 target 数据,统一批量计算 top
for(let index = 0; index < readys.length; index++){
const danmu = readys[index];
// 弹幕发送前的过滤器(保持顺序执行,避免行为变化)
// eslint-disable-next-line no-await-in-loop
const state = await this.option.beforeVisible(danmu);
if (!state) continue;
for(let index = 0; index < readys.length; index++){
const danmu = readys[index];
// 弹幕发送前的过滤器
const state = await this.option.beforeVisible(danmu);
if (state) {
const { clientWidth, clientHeight } = this.$player;
danmu.$ref = this.$ref // 获取弹幕DOM节点
;
danmu.$ref.textContent = danmu.text // 设置弹幕文本
@@ -739,37 +649,27 @@ class Danmuku {
// 设置单独弹幕样式
setStyles(danmu.$ref, danmu.style);
// 记录弹幕时间戳
danmu.$lastStartTime = now;
danmu.$lastStartTime = Date.now();
// 计算弹幕剩余时间
danmu.$restTime = this.speed;
const height = danmu.$ref.clientHeight;
// 计算弹幕滚动的距离
const distance = clientWidth + danmu.$ref.clientWidth;
const speed = distance / danmu.$restTime;
topsTargets.push({
mode: danmu.mode,
height,
speed
});
readyDanmus.push({
danmu,
distance
});
}
if (topsTargets.length) {
const { result: tops } = await this.postMessage({
type: 'getDanmuTopBatch',
targets: topsTargets,
visibles,
// 计算弹幕的top值
const { result: top } = await this.postMessage({
type: 'getDanmuTop',
target: {
mode: danmu.mode,
height: danmu.$ref.clientHeight,
speed: distance / danmu.$restTime
},
visibles: this.visibles,
antiOverlap: this.option.antiOverlap,
clientWidth,
clientHeight,
marginBottom: this.marginBottom,
marginTop: this.marginTop
});
for(let index = 0; index < readyDanmus.length; index++){
const { danmu, distance } = readyDanmus[index];
const top = Array.isArray(tops) ? tops[index] : undefined;
if (!danmu.$ref) continue;
if (danmu.$ref) {
if (!this.isStop && top !== undefined) {
this.setState(danmu, 'emit') // 转换为emit状态
;
@@ -920,7 +820,6 @@ class Danmuku {
}
destroy() {
this.stop();
if (this.workerCallbacks) this.workerCallbacks.clear();
this.worker.terminate();
this.art.off('video:play', this.start);
this.art.off('video:playing', this.start);
@@ -934,7 +833,7 @@ class Danmuku {
exports.default = Danmuku;
},{"bundle-text:./worker":"2Spvp","./bilibili":"aIvhn","@parcel/transformer-js/src/esmodule-helpers.js":"8oCsH"}],"2Spvp":[function(require,module,exports,__globalThis) {
module.exports = "// modules are defined as an array\n// [ module function, map of requires ]\n//\n// map of requires is short require name -> numeric require\n//\n// anything defined in a previous bundle is accessed via the\n// orig method which is the require for previous bundles\n\n(function (\n modules,\n entry,\n mainEntry,\n parcelRequireName,\n externals,\n distDir,\n publicUrl,\n devServer\n) {\n /* eslint-disable no-undef */\n var globalObject =\n typeof globalThis !== 'undefined'\n ? globalThis\n : typeof self !== 'undefined'\n ? self\n : typeof window !== 'undefined'\n ? window\n : typeof global !== 'undefined'\n ? global\n : {};\n /* eslint-enable no-undef */\n\n // Save the require from previous bundle to this closure if any\n var previousRequire =\n typeof globalObject[parcelRequireName] === 'function' &&\n globalObject[parcelRequireName];\n\n var importMap = previousRequire.i || {};\n var cache = previousRequire.cache || {};\n // Do not use `require` to prevent Webpack from trying to bundle this call\n var nodeRequire =\n typeof module !== 'undefined' &&\n typeof module.require === 'function' &&\n module.require.bind(module);\n\n function newRequire(name, jumped) {\n if (!cache[name]) {\n if (!modules[name]) {\n if (externals[name]) {\n return externals[name];\n }\n // if we cannot find the module within our internal map or\n // cache jump to the current global require ie. the last bundle\n // that was added to the page.\n var currentRequire =\n typeof globalObject[parcelRequireName] === 'function' &&\n globalObject[parcelRequireName];\n if (!jumped && currentRequire) {\n return currentRequire(name, true);\n }\n\n // If there are other bundles on this page the require from the\n // previous one is saved to 'previousRequire'. Repeat this as\n // many times as there are bundles until the module is found or\n // we exhaust the require chain.\n if (previousRequire) {\n return previousRequire(name, true);\n }\n\n // Try the node require function if it exists.\n if (nodeRequire && typeof name === 'string') {\n return nodeRequire(name);\n }\n\n var err = new Error(\"Cannot find module '\" + name + \"'\");\n err.code = 'MODULE_NOT_FOUND';\n throw err;\n }\n\n localRequire.resolve = resolve;\n localRequire.cache = {};\n\n var module = (cache[name] = new newRequire.Module(name));\n\n modules[name][0].call(\n module.exports,\n localRequire,\n module,\n module.exports,\n globalObject\n );\n }\n\n return cache[name].exports;\n\n function localRequire(x) {\n var res = localRequire.resolve(x);\n if (res === false) {\n return {};\n }\n // Synthesize a module to follow re-exports.\n if (Array.isArray(res)) {\n var m = {__esModule: true};\n res.forEach(function (v) {\n var key = v[0];\n var id = v[1];\n var exp = v[2] || v[0];\n var x = newRequire(id);\n if (key === '*') {\n Object.keys(x).forEach(function (key) {\n if (\n key === 'default' ||\n key === '__esModule' ||\n Object.prototype.hasOwnProperty.call(m, key)\n ) {\n return;\n }\n\n Object.defineProperty(m, key, {\n enumerable: true,\n get: function () {\n return x[key];\n },\n });\n });\n } else if (exp === '*') {\n Object.defineProperty(m, key, {\n enumerable: true,\n value: x,\n });\n } else {\n Object.defineProperty(m, key, {\n enumerable: true,\n get: function () {\n if (exp === 'default') {\n return x.__esModule ? x.default : x;\n }\n return x[exp];\n },\n });\n }\n });\n return m;\n }\n return newRequire(res);\n }\n\n function resolve(x) {\n var id = modules[name][1][x];\n return id != null ? id : x;\n }\n }\n\n function Module(moduleName) {\n this.id = moduleName;\n this.bundle = newRequire;\n this.require = nodeRequire;\n this.exports = {};\n }\n\n newRequire.isParcelRequire = true;\n newRequire.Module = Module;\n newRequire.modules = modules;\n newRequire.cache = cache;\n newRequire.parent = previousRequire;\n newRequire.distDir = distDir;\n newRequire.publicUrl = publicUrl;\n newRequire.devServer = devServer;\n newRequire.i = importMap;\n newRequire.register = function (id, exports) {\n modules[id] = [\n function (require, module) {\n Line truncated
module.exports = "// modules are defined as an array\n// [ module function, map of requires ]\n//\n// map of requires is short require name -> numeric require\n//\n// anything defined in a previous bundle is accessed via the\n// orig method which is the require for previous bundles\n\n(function (\n modules,\n entry,\n mainEntry,\n parcelRequireName,\n externals,\n distDir,\n publicUrl,\n devServer\n) {\n /* eslint-disable no-undef */\n var globalObject =\n typeof globalThis !== 'undefined'\n ? globalThis\n : typeof self !== 'undefined'\n ? self\n : typeof window !== 'undefined'\n ? window\n : typeof global !== 'undefined'\n ? global\n : {};\n /* eslint-enable no-undef */\n\n // Save the require from previous bundle to this closure if any\n var previousRequire =\n typeof globalObject[parcelRequireName] === 'function' &&\n globalObject[parcelRequireName];\n\n var importMap = previousRequire.i || {};\n var cache = previousRequire.cache || {};\n // Do not use `require` to prevent Webpack from trying to bundle this call\n var nodeRequire =\n typeof module !== 'undefined' &&\n typeof module.require === 'function' &&\n module.require.bind(module);\n\n function newRequire(name, jumped) {\n if (!cache[name]) {\n if (!modules[name]) {\n if (externals[name]) {\n return externals[name];\n }\n // if we cannot find the module within our internal map or\n // cache jump to the current global require ie. the last bundle\n // that was added to the page.\n var currentRequire =\n typeof globalObject[parcelRequireName] === 'function' &&\n globalObject[parcelRequireName];\n if (!jumped && currentRequire) {\n return currentRequire(name, true);\n }\n\n // If there are other bundles on this page the require from the\n // previous one is saved to 'previousRequire'. Repeat this as\n // many times as there are bundles until the module is found or\n // we exhaust the require chain.\n if (previousRequire) {\n return previousRequire(name, true);\n }\n\n // Try the node require function if it exists.\n if (nodeRequire && typeof name === 'string') {\n return nodeRequire(name);\n }\n\n var err = new Error(\"Cannot find module '\" + name + \"'\");\n err.code = 'MODULE_NOT_FOUND';\n throw err;\n }\n\n localRequire.resolve = resolve;\n localRequire.cache = {};\n\n var module = (cache[name] = new newRequire.Module(name));\n\n modules[name][0].call(\n module.exports,\n localRequire,\n module,\n module.exports,\n globalObject\n );\n }\n\n return cache[name].exports;\n\n function localRequire(x) {\n var res = localRequire.resolve(x);\n return res === false ? {} : newRequire(res);\n }\n\n function resolve(x) {\n var id = modules[name][1][x];\n return id != null ? id : x;\n }\n }\n\n function Module(moduleName) {\n this.id = moduleName;\n this.bundle = newRequire;\n this.require = nodeRequire;\n this.exports = {};\n }\n\n newRequire.isParcelRequire = true;\n newRequire.Module = Module;\n newRequire.modules = modules;\n newRequire.cache = cache;\n newRequire.parent = previousRequire;\n newRequire.distDir = distDir;\n newRequire.publicUrl = publicUrl;\n newRequire.devServer = devServer;\n newRequire.i = importMap;\n newRequire.register = function (id, exports) {\n modules[id] = [\n function (require, module) {\n module.exports = exports;\n },\n {},\n ];\n };\n\n // Only insert newRequire.load when it is actually used.\n // The code in this file is linted against ES5, so dynamic import is not allowed.\n // INSERT_LOAD_HERE\n\n Object.defineProperty(newRequire, 'root', {\n get: function () {\n return globalObject[parcelRequireName];\n },\n });\n\n globalObject[parcelRequireName] = newRequire;\n\n for (var i = 0; i < entry.length; i++) {\n newRequire(entry[i]);\n }\n\n if (mainEntry) {\n // Expose entry point to Node, AMD or browser globals\n // Based on https://github.com/ForbesLindesay/umd/blob/master/template.js\n var mainExports = newRequire(mainEntry);\n\n // CommonJS\n if (typeof exports === 'object' && typeof module !== 'undefined') {\n module.exports = mainExports;\n\n // RequireJS\n } else if (typeof define === 'function' && define.amd) {\n define(function () {\n return mainExports;\n });\n }\n }\n})({\"02up6\":[function(require,module,exports,__globalThis) {\nfunction getDanmuTop({ target, visibles, clientWidth, clientHeight, marginBottom, marginTop, antiOverlap }) {\n // 弹幕最大高度\n const maxTop = clientHeight - marginBottom;\n // 过滤同模式的弹幕,即每种模式各不影响\n const danmus = visibles.filter((item)= Line truncated
},{}],"aIvhn":[function(require,module,exports,__globalThis) {
var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js");
@@ -1 +1 @@
{"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6CAIwB;AAJxB;;AACA;;AACA;;AAEe,SAAS,uBAAuB,MAAM;IACnD,OAAO,CAAC;QACN,MAAM,UAAU,IAAI,CAAA,GAAA,uBAAO,AAAD,EAAE,KAAK;QACjC,MAAM,UAAU,IAAI,CAAA,GAAA,uBAAO,AAAD,EAAE,KAAK;QAEjC,IAAI,QAAQ,MAAM,CAAC,OAAO,EACxB,CAAA,GAAA,uBAAO,AAAD,EAAE,KAAK,SAAS,QAAQ,MAAM,CAAC,OAAO;QAG9C,OAAO;YACL,MAAM;YACN,MAAM,QAAQ,IAAI,CAAC,IAAI,CAAC;YACxB,MAAM,QAAQ,IAAI,CAAC,IAAI,CAAC;YACxB,QAAQ,QAAQ,MAAM,CAAC,IAAI,CAAC;YAC5B,MAAM,QAAQ,IAAI,CAAC,IAAI,CAAC;YACxB,MAAM,QAAQ,IAAI,CAAC,IAAI,CAAC;YACxB,OAAO,QAAQ,KAAK,CAAC,IAAI,CAAC;YAC1B,OAAO,QAAQ,KAAK,CAAC,IAAI,CAAC;YAC1B,IAAI,UAAS;gBACX,OAAO,QAAQ,MAAM;YACvB;YACA,IAAI,UAAS;gBACX,OAAO,QAAQ,MAAM;YACvB;YACA,IAAI,UAAS;gBACX,OAAO,QAAQ,MAAM;YACvB;QACF;IACF;AACF;AAEA,uBAAuB,KAAK,GAAG,CAAA,GAAA,uBAAO,AAAD,EAAE,KAAK;AAE5C,IAAI,OAAO,WAAW,aACpB,OAAO,sBAAsB,GAAG;;;;;ACtClC;;AACA;AAEe,MAAM;IACnB,YAAY,GAAG,EAAE,MAAM,CAAE;QACvB,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,GAAG;QAElC,IAAI,CAAC,KAAK,GAAG,YAAY,KAAK,CAAC,MAAM;;QACrC,IAAI,CAAC,SAAS,GAAG,YAAY,SAAS,CAAC,QAAQ;;QAC/C,IAAI,CAAC,QAAQ,GAAG,SAAS,QAAQ,CAAC,QAAQ;;QAC1C,IAAI,CAAC,OAAO,GAAG,SAAS,OAAO,CAAC,QAAQ;;QAExC,IAAI,CAAC,GAAG,GAAG;QACX,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,SAAS;;QACzB,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,WAAW;;QAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,OAAO;;QAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,OAAO;;QAC3B,IAAI,CAAC,KAAK,GAAG,KAAK,MAAM;;QACxB,IAAI,CAAC,KAAK,GAAG,EAAE,OAAO;;QAEtB,WAAW;QACX,IAAI,CAAC,MAAM,GAAG,QAAQ,MAAM;QAE5B,QAAQ;QACR,IAAI,CAAC,MAAM,GAAG;YAAE,MAAM,EAAE;YAAE,OAAO,EAAE;YAAE,MAAM,EAAE;YAAE,MAAM,EAAE;QAAC;QAExD,QAAQ;QACR,IAAI,CAAC,MAAM,CAAC,QAAQ;QAEpB,+BAA+B;QAC/B,MAAM,cAAc,CAAA,GAAA,sBAAU,AAAD,EAAE,OAAO,CAAC,yBAAyB;QAChE,MAAM,OAAO,IAAI,KAAK;YAAC;SAAY,EAAE;YAAE,MAAM;QAAyB;QACtE,IAAI,CAAC,MAAM,GAAG,IAAI,OAAO,IAAI,eAAe,CAAC;QAE7C,0CAA0C;QAC1C,IAAI,CAAC,eAAe,GAAG,IAAI;QAE3B,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC;YACvB,MAAM,EAAE,IAAI,EAAE,GAAG;YACjB,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,EACnB;YAEF,MAAM,WAAW,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,EAAE;YACjD,IAAI,UAAU;gBACZ,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,EAAE;gBACnC,SAAS;YACX;QACF;QAEA,SAAS;QACT,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI;QACjC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;QAC/B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI;QACjC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI;QACnC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI;QAErC,OAAO;QACP,IAAI,EAAE,CAAC,cAAc,IAAI,CAAC,KAAK;QAC/B,IAAI,EAAE,CAAC,iBAAiB,IAAI,CAAC,KAAK;QAClC,IAAI,EAAE,CAAC,eAAe,IAAI,CAAC,IAAI;QAC/B,IAAI,EAAE,CAAC,iBAAiB,IAAI,CAAC,IAAI;QACjC,IAAI,EAAE,CAAC,WAAW,IAAI,CAAC,OAAO;QAC9B,IAAI,EAAE,CAAC,UAAU,IAAI,CAAC,MAAM;QAE5B,SAAS;QACT,IAAI,CAAC,IAAI;IACX;IAEA,OAAO;IACP,WAAW,SAAS;QAClB,OAAO;YACL,SAAS,EAAE;YACX,OAAO;YACP,QAAQ;gBAAC;gBAAI;aAAM;YACnB,SAAS;YACT,OAAO;YACP,MAAM;YACN,OAAO;gBAAC;gBAAG;gBAAG;aAAE;YAChB,UAAU;YACV,aAAa;YACb,qBAAqB;YACrB,OAAO;YACP,SAAS;YACT,OAAO;YACP,QAAQ,EAAE;YACV,QAAQ,IAAM;YACd,YAAY,IAAM;YAClB,eAAe,IAAM;YACrB,SAAS;YACT,SAAS;YACT,WAAW;YACX,UAAU;YACV,OAAO;YACP,SAAS,CAAC;YACV,WAAW,CAAC;YACZ,QAAQ,CAAC;YACT,OAAO,CAAC;YACR,OAAO,EAAE;QACX;IACF;IAEA,OAAO;IACP,WAAW,SAAS;QAClB,OAAO;YACL,SAAS;YACT,OAAO;YACP,QAAQ;YACR,SAAS;YACT,OAAO;YACP,MAAM;YACN,OAAO;YACP,UAAU;YACV,aAAa;YACb,qBAAqB;YACrB,OAAO;YACP,SAAS;YACT,OAAO;YACP,QAAQ;YACR,QAAQ;YACR,YAAY;YACZ,eAAe;YACf,SAAS;YACT,SAAS;YACT,WAAW;YACX,UAAU;YACV,OAAO;YACP,SAAS;YACT,WAAW;YACX,QAAQ;YACR,OAAO;YACP,OAAO;QACT;IACF;IAEA,SAAS;IACT,WAAW,UAAU;QACnB,OAAO,CAAC;;;;;;;;;;;;;QAaJ,CAAC;IACP;IAEA,gCAAgC;IAChC,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,iBAAiB;IAC5C;IAEA,UAAU;IACV,IAAI,YAAY;QACd,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,KAAK;QAC5B,MAAM,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;QACnC,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC,OAAO;QAErC,IAAI,OAAO,UAAU,UACnB,OAAO,MAAM,OAAO,GAAG;QAGzB,IAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,CAAC,MAAM;YACpD,MAAM,QAAQ,OAAO,UAAU,CAAC,SAAS;YACzC,OAAO,MAAM,eAAe,OAAO,GAAG;QACxC;QAEA,OAAO,QAAQ,MAAM,CAAC,MAAM,CAAC,EAAE;IACjC;IAEA,UAAU;IACV,IAAI,eAAe;QACjB,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,KAAK;QAC5B,MAAM,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE;QACnC,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC,OAAO;QAErC,IAAI,OAAO,UAAU,UACnB,OAAO,MAAM,OAAO,GAAG;QAGzB,IAAI,OAAO,UAAU,YAAY,MAAM,QAAQ,CAAC,MAAM;YACpD,MAAM,QAAQ,OAAO,UAAU,CAAC,SAAS;YACzC,OAAO,MAAM,eAAe,OAAO,GAAG;QACxC;QAEA,OAAO,QAAQ,MAAM,CAAC,MAAM,CAAC,EAAE;IACjC;IAEA,WAAW;IACX,IAAI,WAAW;QACb,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,KAAK;QAC5B,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC,OAAO;QAErC,MAAM,WAAW,IAAI,CAAC,MAAM,CAAC,QAAQ;QAErC,IAAI,OAAO,aAAa,UACtB,OAAO,KAAK,KAAK,CAAC,MAAM,UAAU,IAAI;QAGxC,IAAI,OAAO,aAAa,YAAY,SAAS,QAAQ,CAAC,MAAM;YAC1D,MAAM,QAAQ,OAAO,UAAU,CAAC,YAAY;YAC5C,OAAO,KAAK,KAAK,CAAC,MAAM,eAAe,OAAO,IAAI;QACpD;QAEA,OAAO,QAAQ,MAAM,CAAC,QAAQ;IAChC;IAEA,YAAY;IACZ,IAAI,OAAO;QACT,MAAM,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,MAAM,SAAS,aAAa,CAAC;QACxD,KAAK,KAAK,CAAC,OAAO,GAAG,QAAQ,OAAO;QACpC,KAAK,OAAO,CAAC,IAAI,GAALine truncated
{"mappings":"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 truncated
@@ -32,21 +32,6 @@ export default class Danmuku {
const blob = new Blob([workerText2], { type: 'application/javascript' })
this.worker = new Worker(URL.createObjectURL(blob))
// Web Worker 回调池,避免频繁覆盖 onmessage 并支持并发请求
this.workerCallbacks = new Map()
this.worker.onmessage = (event) => {
const { data } = event
if (!data || !data.id)
return
const callback = this.workerCallbacks.get(data.id)
if (callback) {
this.workerCallbacks.delete(data.id)
callback(data)
}
}
// 绑定公用事件
this.start = this.start.bind(this)
this.stop = this.stop.bind(this)
@@ -452,10 +437,15 @@ export default class Danmuku {
// 复杂运算交给 Web Worker 处理
postMessage(message = {}) {
return new Promise((resolve) => {
const id = `${Date.now()}-${Math.random()}`
message.id = id // 生成唯一标识
this.workerCallbacks.set(id, resolve)
message.id = Date.now() // 生成唯一标识
this.worker.postMessage(message)
this.worker.onmessage = (event) => {
const { data } = event
// 判断是否是当前的消息
if (data.id === message.id) {
resolve(data)
}
}
})
}
@@ -470,14 +460,8 @@ export default class Danmuku {
// 设置弹幕状态
setState(danmu, state) {
// 从原状态池中删除,使用原地删除避免创建新数组
const prevState = danmu.$state
if (prevState && this.states[prevState]) {
const list = this.states[prevState]
const index = list.indexOf(danmu)
if (index !== -1)
list.splice(index, 1)
}
// 从原状态池中删除
this.states[danmu.$state] = this.states[danmu.$state].filter(item => item !== danmu)
// 设置新状态
danmu.$state = state
@@ -511,65 +495,28 @@ export default class Danmuku {
this.timer = window.requestAnimationFrame(async () => {
if (this.art.playing && !this.isHide) {
const now = Date.now()
const { clientWidth, clientHeight } = this.$player
// 实时计算弹幕的剩余显示时间,并构建当前可见弹幕数据,避免重复 DOM 读写
const visibles = []
const playerLeft = this.getLeft(this.$player)
// 实时计算弹幕的剩余显示时间
this.filter('emit', (danmu) => {
const emitTime = (now - danmu.$lastStartTime) / 1000
const emitTime = (Date.now() - danmu.$lastStartTime) / 1000
danmu.$restTime -= emitTime
danmu.$lastStartTime = now
danmu.$lastStartTime = Date.now()
// 超过时间即重置弹幕
if (danmu.$restTime <= 0) {
this.makeWait(danmu)
return
}
if (!danmu.$ref)
return
const top = danmu.$ref.offsetTop
const left = this.getLeft(danmu.$ref) - playerLeft
const height = danmu.$ref.clientHeight
const width = danmu.$ref.clientWidth
const distance = left + width
const right = clientWidth - distance
const speed = distance / danmu.$restTime
visibles.push({
top,
left,
height,
width,
right,
speed,
distance,
time: danmu.$restTime,
mode: danmu.mode,
})
})
// 获取准备好发送的弹幕,可能包含ready和wait状态的弹幕
const readys = this.readys
if (readys.length) {
const topsTargets = []
const readyDanmus = []
for (let index = 0; index < readys.length; index++) {
const danmu = readys[index]
// 先初始化 DOM、样式及 target 数据,统一批量计算 top
for (let index = 0; index < readys.length; index++) {
const danmu = readys[index]
// 弹幕发送前的过滤器(保持顺序执行,避免行为变化)
// eslint-disable-next-line no-await-in-loop
const state = await this.option.beforeVisible(danmu)
if (!state)
continue
// 弹幕发送前的过滤器
const state = await this.option.beforeVisible(danmu)
if (state) {
const { clientWidth, clientHeight } = this.$player
danmu.$ref = this.$ref // 获取弹幕DOM节点
danmu.$ref.textContent = danmu.text // 设置弹幕文本
@@ -587,29 +534,23 @@ export default class Danmuku {
setStyles(danmu.$ref, danmu.style)
// 记录弹幕时间戳
danmu.$lastStartTime = now
danmu.$lastStartTime = Date.now()
// 计算弹幕剩余时间
danmu.$restTime = this.speed
const height = danmu.$ref.clientHeight
// 计算弹幕滚动的距离
const distance = clientWidth + danmu.$ref.clientWidth
const speed = distance / danmu.$restTime
topsTargets.push({
mode: danmu.mode,
height,
speed,
})
readyDanmus.push({ danmu, distance })
}
if (topsTargets.length) {
const { result: tops } = await this.postMessage({
type: 'getDanmuTopBatch',
targets: topsTargets,
visibles,
// 计算弹幕的top值
const { result: top } = await this.postMessage({
type: 'getDanmuTop',
target: {
mode: danmu.mode,
height: danmu.$ref.clientHeight,
speed: distance / danmu.$restTime,
}, // 当前弹幕信息
visibles: this.visibles, // 可见的弹幕的数据
antiOverlap: this.option.antiOverlap,
clientWidth,
clientHeight,
@@ -617,13 +558,7 @@ export default class Danmuku {
marginTop: this.marginTop,
})
for (let index = 0; index < readyDanmus.length; index++) {
const { danmu, distance } = readyDanmus[index]
const top = Array.isArray(tops) ? tops[index] : undefined
if (!danmu.$ref)
continue
if (danmu.$ref) {
if (!this.isStop && top !== undefined) {
this.setState(danmu, 'emit') // 转换为emit状态
danmu.$ref.style.top = `${top}px`
@@ -786,9 +721,6 @@ export default class Danmuku {
destroy() {
this.stop()
if (this.workerCallbacks) {
this.workerCallbacks.clear()
}
this.worker.terminate()
this.art.off('video:play', this.start)
this.art.off('video:playing', this.start)
@@ -135,29 +135,12 @@ function getDanmuTop({ target, visibles, clientWidth, clientHeight, marginBottom
}
}
function getDanmuTopBatch({ targets, visibles, clientWidth, clientHeight, marginBottom, marginTop, antiOverlap }) {
if (!Array.isArray(targets) || targets.length === 0)
return []
return targets.map((target) => {
return getDanmuTop({
target,
visibles,
clientWidth,
clientHeight,
marginBottom,
marginTop,
antiOverlap,
})
})
}
onmessage = (event) => {
const { data } = event
if (!data.id || !data.type)
return
const fns = { getDanmuTop, getDanmuTopBatch }
const fns = { getDanmuTop }
const fn = fns[data.type]
const result = fn(data)