// ==UserScript==
// @name Bilibili 评论区右置无感预载版
// @namespace http://tampermonkey.net/
// @version 2.0
// @description 将B站视频评论区常驻右侧(默认完全透明且不挡交互),实现后台静默预载。点击悬浮球极速淡入,消除加载闪烁与拖沓的滑出动画。
// @author bili_user_helper
// @match *://www.bilibili.com/video/*
// @match *://www.bilibili.com/bangumi/play/*
// @match *://www.bilibili.com/list/*
// @icon https://www.bilibili.com/favicon.ico
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
// 预定义样式,确保在DOM解析第一阶段生效,防止任何首屏底部闪烁
const css = `
/* 核心预载逻辑:常驻屏幕可视区,让B站以为其已曝光从而在后台静默加载评论,同时默认透明且不遮挡任何底层交互 */
#comment, #comment-module, .comment-container, .bili-comment-container, #commentapp, .bili-comment-sidebar {
position: fixed !important;
top: 0 !important;
right: 0 !important;
width: 460px !important;
height: 100vh !important;
z-index: 99999 !important;
background-color: var(--bg1, #ffffff) !important;
box-shadow: -5px 0 25px rgba(0,0,0,0.12) !important;
box-sizing: border-box !important;
padding: 15px 20px 20px 20px !important;
overflow-y: auto !important;
border-left: 1px solid var(--line_regular, #e3e8ec) !important;
/* 默认完全透明,不阻挡鼠标点击底层推荐栏 */
opacity: 0 !important;
pointer-events: none !important;
/* 极速淡入淡出,消除拖沓的位移动画感 */
transition: opacity 0.15s ease-in-out !important;
}
/* 展开状态 */
#comment.expanded, #comment-module.expanded, .comment-container.expanded, .bili-comment-container.expanded, #commentapp.expanded, .bili-comment-sidebar.expanded {
opacity: 1 !important;
pointer-events: auto !important;
}
/* 侧边栏内部元素自适应调节 */
.bili-comment-sidebar .reply-navigation,
.bili-comment-sidebar .reply-send,
.bili-comment-sidebar .comment-container,
.bili-comment-sidebar .comment-send,
.bili-comment-sidebar .reply-list,
.bili-comment-sidebar .reply-item,
.bili-comment-sidebar bili-comments {
width: 100% !important;
max-width: 100% !important;
box-sizing: border-box !important;
}
/* 隐藏B站自带的顶部多余外边距 */
.bili-comment-sidebar .reply-header {
border-top: none !important;
margin-top: 0 !important;
}
/* 自定义粘性控制头部 */
.bili-comment-sidebar-header {
display: flex !important;
align-items: center !important;
justify-content: space-between !important;
padding-bottom: 12px !important;
margin-bottom: 12px !important;
border-bottom: 1px solid var(--line_regular, #e3e8ec) !important;
background-color: var(--bg1, #ffffff) !important;
position: sticky !important;
top: 0 !important;
z-index: 100000 !important;
}
.bili-comment-sidebar-title {
font-size: 16px !important;
font-weight: bold !important;
color: var(--text1, #18191c) !important;
display: flex !important;
align-items: center !important;
gap: 8px !important;
}
.bili-comment-sidebar-close {
background: none !important;
border: none !important;
cursor: pointer !important;
color: var(--text2, #9499a0) !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
padding: 4px !important;
border-radius: 4px !important;
transition: background-color 0.2s, color 0.2s !important;
}
.bili-comment-sidebar-close:hover {
background-color: var(--bg2, #f1f2f3) !important;
color: var(--text1, #18191c) !important;
}
/* 滚动条美化 */
.bili-comment-sidebar::-webkit-scrollbar {
width: 6px !important;
}
.bili-comment-sidebar::-webkit-scrollbar-thumb {
background-color: var(--text3, #c9ccd0) !important;
border-radius: 3px !important;
}
.bili-comment-sidebar::-webkit-scrollbar-track {
background: transparent !important;
}
/* 悬浮球样式 */
#bili-comment-ball {
position: fixed !important;
right: 24px !important;
bottom: 140px !important;
width: 48px !important;
height: 48px !important;
border-radius: 50% !important;
background-color: #fb7299 !important;
color: #ffffff !important;
box-shadow: 0 4px 12px rgba(251, 114, 153, 0.4) !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
cursor: pointer !important;
z-index: 100001 !important;
transition: right 0.2s cubic-bezier(0.25, 0.8, 0.25, 1), transform 0.2s ease, background-color 0.2s ease !important;
user-select: none !important;
}
#bili-comment-ball:hover {
transform: scale(1.08) !important;
background-color: #fc8bab !important;
}
/* 侧边栏激活时悬浮球随之左移 */
.bili-comment-sidebar-active #bili-comment-ball {
right: 484px !important; /* 460px sidebar + 24px spacing */
background-color: #fb7299 !important;
box-shadow: -4px 4px 12px rgba(0,0,0,0.15) !important;
}
@media (max-width: 768px) {
.bili-comment-sidebar {
width: 100% !important;
}
.bili-comment-sidebar-active #bili-comment-ball {
right: calc(100% - 60px) !important;
}
}
`;
// 尽早注入 CSS 规则
const injectStyle = () => {
const style = document.createElement('style');
style.textContent = css;
if (document.documentElement) {
document.documentElement.appendChild(style);
} else {
const observer = new MutationObserver(() => {
if (document.documentElement) {
document.documentElement.appendChild(style);
observer.disconnect();
}
});
observer.observe(document, { childList: true, subtree: true });
}
};
injectStyle();
const selectors = [
'#comment',
'#comment-module',
'.comment-container',
'.bili-comment-container',
'#commentapp'
];
let isExpanded = false;
function getCommentElement() {
for (const selector of selectors) {
const el = document.querySelector(selector);
if (el) return el;
}
return null;
}
// 初始化评论区容器
function initCommentSidebar(el) {
if (el.classList.contains('bili-comment-sidebar')) return;
el.classList.add('bili-comment-sidebar');
// 注入头部控制栏
if (!el.querySelector('.bili-comment-sidebar-header')) {
const header = document.createElement('div');
header.className = 'bili-comment-sidebar-header';
header.innerHTML = `
`;
header.querySelector('.bili-comment-sidebar-close').addEventListener('click', (e) => {
e.stopPropagation();
collapseSidebar();
});
el.insertBefore(header, el.firstChild);
}
// 滚动事件转发
el.addEventListener('scroll', () => {
window.dispatchEvent(new Event('scroll'));
});
}
function toggleSidebar() {
isExpanded = !isExpanded;
updateSidebarState();
if (isExpanded) {
// 补偿触发一次全局滚动,确保最新数据获取
setTimeout(() => {
window.dispatchEvent(new Event('scroll'));
}, 50);
}
}
function collapseSidebar() {
isExpanded = false;
updateSidebarState();
}
function updateSidebarState() {
const commentEl = getCommentElement();
if (isExpanded) {
document.body.classList.add('bili-comment-sidebar-active');
if (commentEl) {
commentEl.classList.add('expanded');
}
} else {
document.body.classList.remove('bili-comment-sidebar-active');
if (commentEl) {
commentEl.classList.remove('expanded');
}
}
}
// 拖拽与交互设置
function setupBallInteractions(ball) {
let isDragging = false;
let startY = 0;
let initialTop = 0;
const handleMove = (clientY) => {
let newTop = initialTop + (clientY - startY);
const margin = 10;
const ballHeight = ball.offsetHeight || 48;
if (newTop < margin) newTop = margin;
if (newTop > window.innerHeight - ballHeight - margin) {
newTop = window.innerHeight - ballHeight - margin;
}
ball.style.top = newTop + 'px';
ball.style.bottom = 'auto';
};
ball.addEventListener('mousedown', (e) => {
if (e.button !== 0) return;
isDragging = false;
startY = e.clientY;
initialTop = ball.getBoundingClientRect().top;
const onMouseMove = (moveEvent) => {
const deltaY = moveEvent.clientY - startY;
if (Math.abs(deltaY) > 5) {
isDragging = true;
}
if (isDragging) {
handleMove(moveEvent.clientY);
}
};
const onMouseUp = () => {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
};
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
});
ball.addEventListener('touchstart', (e) => {
isDragging = false;
startY = e.touches[0].clientY;
initialTop = ball.getBoundingClientRect().top;
const onTouchMove = (moveEvent) => {
const deltaY = moveEvent.touches[0].clientY - startY;
if (Math.abs(deltaY) > 5) {
isDragging = true;
}
if (isDragging) {
handleMove(moveEvent.touches[0].clientY);
}
};
const onTouchEnd = () => {
document.removeEventListener('touchmove', onTouchMove);
document.removeEventListener('touchend', onTouchEnd);
};
document.addEventListener('touchmove', onTouchMove);
document.addEventListener('touchend', onTouchEnd);
});
ball.addEventListener('click', (e) => {
if (isDragging) {
e.preventDefault();
e.stopPropagation();
return;
}
toggleSidebar();
});
}
function createFloatingBall() {
if (document.getElementById('bili-comment-ball')) return;
const ball = document.createElement('div');
ball.id = 'bili-comment-ball';
ball.title = '展开/折叠评论区';
ball.innerHTML = `
`;
document.body.appendChild(ball);
setupBallInteractions(ball);
}
// 页面加载完成后,触发一次模拟滚动以激活静默预载
window.addEventListener('DOMContentLoaded', () => {
createFloatingBall();
setTimeout(() => {
window.dispatchEvent(new Event('scroll'));
}, 300);
});
// 循环监听支持 B站 SPA
setInterval(() => {
createFloatingBall();
const commentEl = getCommentElement();
if (commentEl) {
initCommentSidebar(commentEl);
if (isExpanded) {
commentEl.classList.add('expanded');
document.body.classList.add('bili-comment-sidebar-active');
} else {
commentEl.classList.remove('expanded');
document.body.classList.remove('bili-comment-sidebar-active');
}
}
}, 500);
})();