Files
YschcmsService/src/main/resources/templates/themes/academic-navy/assets/js/main.js
T
chenxing d2df12b91e
build / build-push (push) Successful in 51s
feat(theme)!: 下线粉/紫两包,改以学院蓝为基座交付 academic-navy/campus-azure 两套高校官网风皮肤
线上 10027 首页配了 home_layout 后走 themes/common 通用骨架,派生皮肤只换了页头页脚,
正文仍是骨架内置蓝灰卡(外加 cherry-bloom 的粉紫配色),用户判定"完全不能用"。

- 新增 academic-navy(学府藏蓝,an-)/campus-azure(青蓝校园,cz-):以 scholar-blue 为基座,
  各自自带 fragments/home-blocks.html 与 home.html 分发,news_grid/media_focus/compact/
  image_wall/card/ticker/gallery/links 八种区块形态全部由皮肤渲染,未知类型才回落通用骨架
- 两套皮肤 :root 把私有变量别名到 --primary/--text/--card-bg/--border/--radius 契约变量;
  中文行锁 nowrap+min-width:0+ellipsis,grid 轨道用 minmax(0,1fr) 防窄视口压塌
- 新闻背景带 .an-sec-bg/.cz-sec-bg 压 z-index:0、卡片抬到 1:绝对定位层默认画在普通流之上,
  不抬起会整张卡片泛成底图色(无头截图实测)
- common 骨架空态守卫改包 th:block(th:replace 优先级 100 先于 th:if 300)
- 删除 cherry-bloom/violet-iris;sql/upgrade_theme_academic_skins.sql 幂等改指存量站点
  (站点缓存 CacheNames.SITE TTL 30 分钟,改库后需重启或在管理端重存站点)
- 测试:AcademicSkinContractTest(区块自带/分发/CJK 行/变量别名/主色必须学术蓝/背景带层级/
  预览图不得沿用基座)、HomeBlocksCssContractTest、PortalHomeLayoutIT 端到端断言零 plb- 输出;
  全量 383 项通过
2026-09-19 20:21:30 +08:00

191 lines
5.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* academic-navy 主题脚本:顶栏日期 + 轮播(圆点/箭头/触摸) + 导航吸顶反蓝 + 移动端抽屉与二级手风琴。
与 default 同源逻辑,无任何外部依赖。 */
(function () {
'use strict';
/* ---------- 顶栏日期(本地时间,YYYY年M月D日 星期X) ---------- */
var dateEl = document.getElementById('siteDate');
if (dateEl) {
var now = new Date();
var week = ['日', '一', '二', '三', '四', '五', '六'][now.getDay()];
dateEl.textContent = now.getFullYear() + '年' + (now.getMonth() + 1) + '月'
+ now.getDate() + '日 星期' + week;
}
/* ---------- 导航吸顶反蓝(桌面端;≤768 不吸顶) ---------- */
var nav = document.getElementById('anNav');
var DESKTOP_MIN = 769;
var navBaseTop = 0;
var holder = null;
function measureNavTop() {
unlockNav();
navBaseTop = nav.getBoundingClientRect().top + window.pageYOffset;
}
function lockNav() {
if (!nav.classList.contains('an-nav--fixed')) {
holder = document.createElement('div');
holder.className = 'an-nav-holder';
holder.style.height = nav.offsetHeight + 'px';
nav.parentNode.insertBefore(holder, nav);
nav.classList.add('an-nav--fixed');
} else if (holder) {
holder.style.height = nav.offsetHeight + 'px';
}
}
function unlockNav() {
nav.classList.remove('an-nav--fixed');
if (holder && holder.parentNode) {
holder.parentNode.removeChild(holder);
}
holder = null;
}
function onScrollNav() {
if (window.innerWidth < DESKTOP_MIN) {
unlockNav();
return;
}
if (window.pageYOffset > navBaseTop) {
lockNav();
} else {
unlockNav();
}
}
if (nav) {
measureNavTop();
window.addEventListener('scroll', onScrollNav, { passive: true });
var resizeTimer = null;
window.addEventListener('resize', function () {
if (resizeTimer) { window.clearTimeout(resizeTimer); }
resizeTimer = window.setTimeout(function () {
measureNavTop();
onScrollNav();
}, 150);
});
}
/* ---------- 移动端抽屉 + 二级手风琴 ---------- */
var navToggle = document.querySelector('.an-nav-toggle');
var navList = document.querySelector('.an-nav-list');
if (navToggle && navList) {
navToggle.addEventListener('click', function () {
var open = navList.classList.toggle('an-open');
navToggle.setAttribute('aria-expanded', open ? 'true' : 'false');
});
}
/* 窄屏下:点击带二级的项先展开面板,再点才跳转;宽屏交还给 CSS hover */
if (navList) {
navList.addEventListener('click', function (e) {
if (window.innerWidth >= DESKTOP_MIN) { return; }
var link = e.target.closest ? e.target.closest('a') : null;
if (!link) { return; }
var li = link.parentElement;
if (!li || !li.classList.contains('has-sub')) { return; }
var sub = li.querySelector('.an-sub');
if (!sub) { return; }
if (!li.classList.contains('an-sub-open')) {
e.preventDefault();
li.classList.add('an-sub-open');
}
});
}
/* ---------- 首页轮播 ---------- */
var root = document.querySelector('.an-banner');
var slides = document.querySelectorAll('.an-banner-slide');
var dots = document.querySelectorAll('.an-banner-dots button');
var prevBtn = document.querySelector('.an-banner-arrow.prev');
var nextBtn = document.querySelector('.an-banner-arrow.next');
if (!slides.length || !root) {
return;
}
var current = 0;
var timer = null;
var INTERVAL = 5000;
function show(index) {
slides[current].classList.remove('active');
if (dots[current]) {
dots[current].classList.remove('active');
}
current = (index + slides.length) % slides.length;
slides[current].classList.add('active');
if (dots[current]) {
dots[current].classList.add('active');
}
}
function start() {
stop();
if (slides.length > 1) {
timer = window.setInterval(function () {
show(current + 1);
}, INTERVAL);
}
}
function stop() {
if (timer) {
window.clearInterval(timer);
timer = null;
}
}
dots.forEach(function (dot, index) {
dot.addEventListener('click', function () {
show(index);
start();
});
});
if (prevBtn) {
prevBtn.addEventListener('click', function () {
show(current - 1);
start();
});
}
if (nextBtn) {
nextBtn.addEventListener('click', function () {
show(current + 1);
start();
});
}
root.addEventListener('mouseenter', stop);
root.addEventListener('mouseleave', start);
root.addEventListener('focusin', stop);
root.addEventListener('focusout', start);
root.setAttribute('tabindex', '-1');
root.addEventListener('keydown', function (e) {
if (e.key === 'ArrowLeft') {
show(current - 1);
start();
} else if (e.key === 'ArrowRight') {
show(current + 1);
start();
}
});
/* 触摸滑动切页 */
var touchX = null;
root.addEventListener('touchstart', function (e) {
touchX = e.changedTouches[0].clientX;
stop();
}, { passive: true });
root.addEventListener('touchend', function (e) {
if (touchX === null) { return; }
var dx = e.changedTouches[0].clientX - touchX;
if (Math.abs(dx) > 40) {
show(dx < 0 ? current + 1 : current - 1);
}
touchX = null;
start();
}, { passive: true });
start();
})();