
/**
* notice-bar.js
*
* 功能:
* 1. 在页面顶部显示轮播提示条,用于展示网站公告或注意事项
* 2. 可选启用播放记录恢复功能:当用户再次打开相同视频时,会弹窗询问是否从上次进度继续播放
* 3. 统一顶部提示条和恢复提示浮窗的高度、样式、按钮风格
*/
(function () {
// =========== 配置项 ===========
const enablePlaybackResume = true; // 是否启用“播放记录恢复”功能
const noticeList = [ // 顶部提示条要轮播展示的文案列表
"📢 如果播放卡顿,请切换线路或刷新页面重试!",
"📌 视频广告与本站无关,请注意甄别勿上当受骗!"
];
const switchInterval = 8000; // 轮播切换间隔(毫秒)
const autoHideDelay = 30000; // 提示条自动隐藏时间(毫秒),0 表示不自动隐藏
const fixedHeight = 35; // 顶部提示条和恢复提示浮窗统一高度(像素)
// =========== 动态注入全局样式 ===========
const style = document.createElement('style');
style.textContent = `
/* 整个提示条的外层容器 */
#notice-bar {
width: 100%;
position: fixed;
top: 10px;
left: 0;
text-align: center;
z-index: 9999;
background: transparent;
font-size: 14px;
}
/* 顶部提示条 和 播放恢复提示 统一样式 */
#notice-bar .notice-container,
.dplayer-resume-tip {
display: inline-flex; /* 水平并排布局 */
align-items: center; /* 垂直居中 */
gap: 8px; /* 子元素之间间距 */
background: rgba(236, 236, 236, 0.95); /* 半透明浅灰背景 */
color: #666; /* 文字颜色 */
height: ${fixedHeight}px; /* 固定高度 */
line-height: ${fixedHeight}px; /* 行高与高度一致,使文字垂直居中 */
padding: 0 16px; /* 左右内边距 */
border-radius: 8px; /* 圆角 */
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08); /* 轻微阴影 */
font-size: 14px; /* 字体大小 */
white-space: nowrap; /* 禁止换行 */
max-width: 90%; /* 最大宽度,防止超出屏幕 */
}
/* 顶部提示条中的关闭按钮 */
#notice-bar .close-btn {
cursor: pointer;
font-size: 14px;
color: #999;
}
/* 播放恢复提示浮窗的位置 */
.dplayer-resume-tip {
position: absolute;
left: 12px; /* 与播放器左边保持一致的小边距 */
bottom: 60px; /* 位于进度条上方约 60px 处 */
z-index: 9998;
}
/* 恢复提示中加粗显示的时间 */
.dplayer-resume-tip b {
font-weight: bold;
color: #333;
}
/* 所有按钮统一风格(顶部提示条、恢复提示浮窗共用) */
.dplayer-resume-tip button,
#notice-bar .notice-container button {
background: #e0e0e0;
border: none;
padding: 0 10px; /* 左右内边距 */
height: 24px; /* 按钮高度 */
line-height: 24px; /* 行高与高度一致 */
font-size: 13px;
border-radius: 4px;
cursor: pointer;
color: #333;
}
.dplayer-resume-tip button:hover,
#notice-bar .notice-container button:hover {
background: #d0d0d0;
}
/* 移动端适配:略微缩小字体和尺寸 */
@media (max-width: 600px) {
#notice-bar,
.dplayer-resume-tip {
font-size: 13px;
}
#notice-bar .notice-container,
.dplayer-resume-tip {
padding: 0 12px;
height: ${fixedHeight - 4}px;
line-height: ${fixedHeight - 4}px;
}
.dplayer-resume-tip button,
#notice-bar .notice-container button {
font-size: 12px;
padding: 0 8px;
height: 20px;
line-height: 20px;
}
}
`;
document.head.appendChild(style);
// =========== 创建并插入 顶部提示条 ===========
const bar = document.createElement('div');
bar.id = 'notice-bar';
bar.innerHTML = `
<div class="notice-container">
<span class="notice-text" id="notice-text">${noticeList[0]}</span>
<span class="close-btn" title="关闭">✖</span>
</div>
`;
document.body.appendChild(bar);
// =========== 轮播逻辑 ===========
let currentIndex = 0;
const textEl = document.getElementById('notice-text');
const switchTimer = setInterval(() => {
// 切换到下一条文案
currentIndex = (currentIndex + 1) % noticeList.length;
textEl.textContent = noticeList[currentIndex];
}, switchInterval);
// =========== 关闭按钮事件 ===========
bar.querySelector('.close-btn').addEventListener('click', () => {
bar.style.display = 'none';
clearInterval(switchTimer);
});
// =========== 自动隐藏 ===========
if (autoHideDelay > 0) {
setTimeout(() => {
bar.style.display = 'none';
clearInterval(switchTimer);
}, autoHideDelay);
}
// =========== 播放记录恢复功能(可选) ===========
if (enablePlaybackResume) {
// 等待视频元数据加载完再执行恢复逻辑
dp.video.addEventListener('loadedmetadata', () => {
const key = 'dplayer_progress_' + dp.options.video.url; // 存储 Key
const lastTime = parseFloat(localStorage.getItem(key) || '0'); // 上次进度(秒)
// 确保 video.duration 可用后再弹窗
(function checkDuration() {
if (!dp.video.duration || isNaN(dp.video.duration)) {
setTimeout(checkDuration, 100);
} else if (lastTime > 30 && lastTime < dp.video.duration - 15) {
showResumePrompt(lastTime);
}
})();
// 每隔 5 秒保存一次当前播放进度
setInterval(() => {
if (!isNaN(dp.video.currentTime)) {
localStorage.setItem(key, dp.video.currentTime.toFixed(1));
}
}, 5000);
});
/**
* 弹出“是否继续播放”提示浮窗
* @param {number} time — 上次播放的时间(秒)
*/
function showResumePrompt(time) {
const prompt = document.createElement('div');
prompt.className = 'dplayer-resume-tip';
prompt.innerHTML = `
<span>上次播放至 <b>${formatTime(time)}</b>,是否继续?</span>
<button id="resume-yes">继续</button>
<button id="resume-no">重头</button>
<span id="resume-timer">10s</span>
`;
// 插入播放器容器内部
dp.container.appendChild(prompt);
// 10 秒倒计时,默认“重头播放”
let countdown = 10;
const timerEl = prompt.querySelector('#resume-timer');
const timer = setInterval(() => {
countdown--;
timerEl.textContent = `${countdown}s`;
if (countdown <= 0) cleanup(false);
}, 1000);
/**
* 清理浮窗并跳转播放进度
* @param {boolean} resume — 是否从上次时间继续
*/
function cleanup(resume) {
clearInterval(timer);
prompt.remove();
if (resume) {
dp.seek(time);
dp.play();
} else {
dp.seek(0);
dp.play();
}
}
// 按钮点击事件
prompt.querySelector('#resume-yes').onclick = () => cleanup(true);
prompt.querySelector('#resume-no').onclick = () => cleanup(false);
}
/**
* 把秒数格式化为 “hh:mm:ss” 或 “mm:ss”
* @param {number} sec — 秒数
* @returns {string}
*/
function formatTime(sec) {
const h = Math.floor(sec / 3600);
const m = Math.floor((sec % 3600) / 60);
const s = Math.floor(sec % 60);
return (h > 0 ? `${h}:` : '') +
`${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;
}
}
})();
把notice-bar.js文件放到 static/player/dplayer
在播放器文件,比如dplayer.html中引入js文件,在</body>上方加入
<script src="/static/player/dplayer/notice-bar.js"></script>