gpt
This commit is contained in:
154
code/public/static/js/modules/lazy.js
Normal file
154
code/public/static/js/modules/lazy.js
Normal file
@@ -0,0 +1,154 @@
|
||||
(function () {
|
||||
if (window.__LAZY_LOADER_READY__) return;
|
||||
|
||||
const hasIO = "IntersectionObserver" in window;
|
||||
|
||||
// 统一拿 fallback(支持:data-fallback > data-placeholder > window.__LAZY_PLACEHOLDER__ > 当前 src)
|
||||
function getFallback(el) {
|
||||
return (
|
||||
el.getAttribute("data-fallback") ||
|
||||
el.getAttribute("data-placeholder") ||
|
||||
window.__LAZY_PLACEHOLDER__ ||
|
||||
el.getAttribute("src") ||
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
// 背景图预加载(可选:避免 background-image 失败无感知)
|
||||
function preloadImage(url, onOk, onFail) {
|
||||
const img = new Image();
|
||||
img.onload = function () { onOk && onOk(); };
|
||||
img.onerror = function () { onFail && onFail(); };
|
||||
img.src = url;
|
||||
}
|
||||
|
||||
function applyBg(el) {
|
||||
const src = el.getAttribute("data-src");
|
||||
if (!src) return;
|
||||
|
||||
// 如果你不需要 bg 失败兜底,可把 preloadImage 这段改成直接 set backgroundImage
|
||||
preloadImage(
|
||||
src,
|
||||
function () {
|
||||
el.style.backgroundImage = `url(${src})`;
|
||||
el.classList.remove("lazyload-bg");
|
||||
el.removeAttribute("data-src");
|
||||
el.classList.add("is-bg-loaded");
|
||||
},
|
||||
function () {
|
||||
// bg 回退:如果你不给 data-fallback / window.__LAZY_PLACEHOLDER__,这里就不处理
|
||||
const fallback = getFallback(el);
|
||||
if (fallback) {
|
||||
el.style.backgroundImage = `url(${fallback})`;
|
||||
el.classList.add("is-bg-fallback");
|
||||
}
|
||||
el.classList.remove("lazyload-bg");
|
||||
el.removeAttribute("data-src");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function applyImg(img) {
|
||||
const src = img.getAttribute("data-src");
|
||||
const srcset = img.getAttribute("data-srcset");
|
||||
const sizes = img.getAttribute("data-sizes");
|
||||
|
||||
if (!src && !srcset) return;
|
||||
|
||||
const fallback = getFallback(img);
|
||||
let done = false;
|
||||
|
||||
// 必须在赋值 src/srcset 之前绑定,才能抓到加载失败
|
||||
img.onerror = function () {
|
||||
if (done) return;
|
||||
done = true;
|
||||
|
||||
// 防止 fallback 也报错导致死循环
|
||||
img.onerror = null;
|
||||
img.onload = null;
|
||||
|
||||
if (fallback) img.setAttribute("src", fallback);
|
||||
img.removeAttribute("srcset");
|
||||
img.removeAttribute("sizes");
|
||||
|
||||
img.classList.add("is-img-fallback");
|
||||
|
||||
// 清理 lazy 属性,避免重复触发
|
||||
img.classList.remove("lazyload-img");
|
||||
img.removeAttribute("data-src");
|
||||
img.removeAttribute("data-srcset");
|
||||
img.removeAttribute("data-sizes");
|
||||
};
|
||||
|
||||
img.onload = function () {
|
||||
if (done) return;
|
||||
done = true;
|
||||
|
||||
img.onerror = null;
|
||||
img.onload = null;
|
||||
|
||||
img.classList.add("is-img-loaded");
|
||||
|
||||
// 清理 lazy 属性
|
||||
img.classList.remove("lazyload-img");
|
||||
img.removeAttribute("data-src");
|
||||
img.removeAttribute("data-srcset");
|
||||
img.removeAttribute("data-sizes");
|
||||
};
|
||||
|
||||
// 先设置响应式属性
|
||||
if (sizes) img.setAttribute("sizes", sizes);
|
||||
if (srcset) img.setAttribute("srcset", srcset);
|
||||
|
||||
// 最后触发真实加载
|
||||
if (src) img.setAttribute("src", src);
|
||||
|
||||
// 注意:这里不立刻 remove lazy class/attrs,等 onload/onerror 决定
|
||||
// 否则失败后你很难判断是否已经处理过
|
||||
}
|
||||
|
||||
function observe(elements, callback, options) {
|
||||
if (!elements || elements.length === 0) return;
|
||||
|
||||
// 兜底:不支持 IO 直接加载
|
||||
if (!hasIO) {
|
||||
elements.forEach(callback);
|
||||
return;
|
||||
}
|
||||
|
||||
const obs = new IntersectionObserver((entries, observer) => {
|
||||
entries.forEach(entry => {
|
||||
if (!entry.isIntersecting) return;
|
||||
callback(entry.target);
|
||||
observer.unobserve(entry.target);
|
||||
});
|
||||
}, options);
|
||||
|
||||
elements.forEach(el => obs.observe(el));
|
||||
}
|
||||
|
||||
function scan(root) {
|
||||
const ctx = root || document;
|
||||
|
||||
observe(
|
||||
ctx.querySelectorAll(".lazyload-bg"),
|
||||
applyBg,
|
||||
{ rootMargin: "50px 0px", threshold: 0 }
|
||||
);
|
||||
|
||||
observe(
|
||||
ctx.querySelectorAll(".lazyload-img"),
|
||||
applyImg,
|
||||
{ rootMargin: "0px 0px", threshold: 0 }
|
||||
);
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
scan(document);
|
||||
});
|
||||
|
||||
// 给“加载更多/分页追加 DOM”使用
|
||||
window.lazyScan = scan;
|
||||
|
||||
window.__LAZY_LOADER_READY__ = true;
|
||||
})();
|
||||
138
code/public/static/js/modules/player/dplayer.init.js
Normal file
138
code/public/static/js/modules/player/dplayer.init.js
Normal file
@@ -0,0 +1,138 @@
|
||||
(function () {
|
||||
/**
|
||||
* =====================================================
|
||||
* DPlayer Initializer (Scoped by dom_prefix)
|
||||
* -----------------------------------------------------
|
||||
* - 不使用全局变量
|
||||
* - 支持一个页面多个播放器
|
||||
* - 只初始化 data-engine="dplayer" 的模块
|
||||
* =====================================================
|
||||
*/
|
||||
|
||||
function initDPlayer(strPlayUrl) {
|
||||
|
||||
let DomDPlayer = document.getElementById('dplayer')
|
||||
// ---- 创建 DPlayer 实例 ----
|
||||
try {
|
||||
videoPlayer = new DPlayer({
|
||||
container: DomDPlayer,
|
||||
autoplay: true,
|
||||
screenshot: false,
|
||||
//logo: dplayerLogo,
|
||||
video: {
|
||||
url: strPlayUrl,
|
||||
type: 'hls',
|
||||
},
|
||||
pluginOptions: {
|
||||
hls: {
|
||||
maxBufferLength: 600,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
videoPlayer.play()
|
||||
|
||||
// ---- 错误处理(兜底)----
|
||||
videoPlayer.on('error', function () {
|
||||
showError(root, '播放失败,请尝试切换线路');
|
||||
});
|
||||
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
showError(root, '播放器初始化失败');
|
||||
}
|
||||
}
|
||||
|
||||
function showError(root, msg) {
|
||||
var err = root.querySelector('.' + root.dataset.prefix + '-player-status');
|
||||
if (!err) {
|
||||
err = document.createElement('div');
|
||||
err.className = root.dataset.prefix + '-player-status is-error';
|
||||
root.appendChild(err);
|
||||
}
|
||||
err.innerText = msg;
|
||||
}
|
||||
|
||||
function boot() {
|
||||
var players = document.querySelectorAll('[data-engine="dplayer"]');
|
||||
if (!players.length) return;
|
||||
|
||||
players.forEach(function (root) {
|
||||
// dom_prefix 注入(防串)
|
||||
if (!root.dataset.prefix) {
|
||||
var cls = root.className || '';
|
||||
var m = cls.match(/([a-z0-9]{4,8})-player/);
|
||||
if (m) {
|
||||
root.dataset.prefix = m[1];
|
||||
}
|
||||
}
|
||||
console.log(root)
|
||||
initDPlayer(root);
|
||||
});
|
||||
}
|
||||
|
||||
// 获取第一个线路 key(带容错)
|
||||
function getDefaultLine() {
|
||||
if (typeof arrPlayUrl === "undefined" || !arrPlayUrl || typeof arrPlayUrl !== "object") {
|
||||
console.warn("arrPlayUrl 无效:");
|
||||
return null;
|
||||
}
|
||||
|
||||
const keys = Object.keys(arrPlayUrl);
|
||||
if (keys.length === 0) {
|
||||
console.warn("没有任何播放线路");
|
||||
return null;
|
||||
}
|
||||
|
||||
return keys[0]; // 后端排序,第一位为默认
|
||||
}
|
||||
|
||||
// 获取某个线路的第一个 url
|
||||
function getFirstPlayUrl(playLine) {
|
||||
if (!arrPlayUrl || !arrPlayUrl[playLine] || !arrPlayUrl[playLine][0]) {
|
||||
console.warn("播放线路不存在:", playLine, arrPlayUrl);
|
||||
return null;
|
||||
}
|
||||
return arrPlayUrl[playLine][0].url || null;
|
||||
}
|
||||
|
||||
// DOM Ready
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
try {
|
||||
if (typeof strVideoId == "undefined") return;
|
||||
|
||||
console.log(strPlayType)
|
||||
console.log(boolIsPlayPage)
|
||||
if (typeof strPlayType !== "undefined" && boolIsPlayPage) {
|
||||
|
||||
// 用户指定线路
|
||||
if (strPlayType !== "default") {
|
||||
const activeUrl = arrPlayUrl[strPlayType][intPlayUrlIndex - 1];
|
||||
strPlayUrl = activeUrl.url;
|
||||
// checkLine(strPlayType);
|
||||
|
||||
// 默认播放第一个线路的第一个 URL
|
||||
} else {
|
||||
const defaultLine = getDefaultLine();
|
||||
strPlayUrl = getFirstPlayUrl(defaultLine);
|
||||
// checkLine(defaultLine);
|
||||
}
|
||||
console.log('strPlayUrlstrPlayUrl')
|
||||
initDPlayer(strPlayUrl);
|
||||
|
||||
} else if (strPlayType == "default" && !boolIsPlayPage) {
|
||||
|
||||
const defaultLine = getDefaultLine();
|
||||
strPlayUrl = getFirstPlayUrl(defaultLine);
|
||||
// checkLine(defaultLine);
|
||||
|
||||
initDPlayer(strPlayUrl);
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
})
|
||||
})();
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user