130 lines
7.6 KiB
JavaScript
130 lines
7.6 KiB
JavaScript
/* 11-02 首页「孕妈广场」效果稿 V3 · 话题弹幕流(只在 ?gcv=3 时加载)
|
||
「此刻最热」小卡(真实照片 + 热)→ 三行缓慢流动的话题弹幕(按住暂停、点进话题)→ 细长投稿入口。分类切换后弹幕换成该分类话题。 */
|
||
(function () {
|
||
var sec = document.getElementById('gcHome');
|
||
var T = window.GC_TOPICS;
|
||
if (!sec || !Array.isArray(T) || !T.length) return;
|
||
|
||
var esc = function (s) { return String(s == null ? '' : s).replace(/[&<>"]/g, function (c) { return { '&': '&', '<': '<', '>': '>', '"': '"' }[c]; }); };
|
||
var kfmt = function (n) { return n >= 10000 ? (n / 10000).toFixed(1).replace(/\.0$/, '') + '万' : n >= 1000 ? (n / 1000).toFixed(1).replace(/\.0$/, '') + 'k' : String(n); };
|
||
var fmtNum = function (n) { return String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ','); };
|
||
var reduce = window.matchMedia && matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||
var POOL = [];
|
||
for (var i = 1; i <= 22; i++) POOL.push('m' + (i < 10 ? '0' : '') + i);
|
||
for (i = 1; i <= 14; i++) POOL.push('p' + (i < 10 ? '0' : '') + i);
|
||
var ava = function (k) { return 'assets/img/mom/' + POOL[k % POOL.length] + '.jpg'; };
|
||
var CAT = { family: ['家庭婚姻', '#E0566F'], work: ['职场', '#3A72B8'], baby: ['经验', '#2E8A7C'] };
|
||
var ORDER = ['family', 'work', 'baby'];
|
||
|
||
function go(id) {
|
||
location.href = 'guangchang/' + (id ? '?t=' + encodeURIComponent(id) : '') + location.hash;
|
||
}
|
||
/* 「全部」三块轮流排,避免一行同色;某一块:热门在前 */
|
||
function pick(cat) {
|
||
if (cat) { var l = T.filter(function (t) { return t.cat === cat; }); return l.filter(function (t) { return t.hot; }).concat(l.filter(function (t) { return !t.hot; })); }
|
||
var by = ORDER.map(function (c) { return T.filter(function (t) { return t.cat === c; }); }), out = [];
|
||
for (var r = 0; r < 20; r++) by.forEach(function (l) { if (l[r]) out.push(l[r]); });
|
||
return out;
|
||
}
|
||
|
||
var talkAll = T.reduce(function (a, t) { return a + (t.talk || 0); }, 0);
|
||
sec.className = 'gc-home gv3';
|
||
sec.innerHTML =
|
||
'<div class="v3-head">' +
|
||
'<h2 class="v3-title"><span>孕妈广场</span></h2>' +
|
||
'<span class="v3-live"><i></i>' + kfmt(talkAll) + ' 妈妈在聊</span>' +
|
||
'<button type="button" class="v3-more" data-go="">去逛逛<i aria-hidden="true">›</i></button>' +
|
||
'</div>' +
|
||
'<div class="v3-cat" role="tablist" aria-label="话题分类">' +
|
||
'<button type="button" class="on" data-cat="">全部</button>' +
|
||
'<button type="button" data-cat="family">家庭婚姻</button>' +
|
||
'<button type="button" data-cat="work">职场</button>' +
|
||
'<button type="button" data-cat="baby">经验</button>' +
|
||
'</div>' +
|
||
'<button type="button" class="v3-hot" id="v3Hot"></button>' +
|
||
'<div class="v3-dm" id="v3Dm" aria-label="正在聊的话题"></div>' +
|
||
'<button type="button" class="v3-post" data-go=""><b><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 20h4L19 9l-4-4L4 16z"/><path d="M13.5 6.5l4 4"/></svg></b><span>发一条你的故事</span><em>被选中 ¥30+500兜豆</em><i aria-hidden="true">›</i></button>' +
|
||
'<span class="v3-tag">效果稿 V3</span>';
|
||
sec.classList.remove('hide');
|
||
|
||
var hotEl = document.getElementById('v3Hot'), dm = document.getElementById('v3Dm');
|
||
var hotList = [], hotIdx = 0, hotTimer = 0;
|
||
|
||
function hotHtml(t) {
|
||
var c = CAT[t.cat] || ['', '#E0566F'], k = t.id.charCodeAt(1) * 3;
|
||
return '<span class="v3-hot-in">' +
|
||
(t.ph ? '<img class="v3-ph" src="' + esc(t.ph) + '" alt="" loading="lazy">' : '<span class="v3-ph v3-g" style="background:linear-gradient(150deg,' + t.c[0] + ',' + t.c[1] + ');color:' + t.ink + '">' + esc(t.g) + '</span>') +
|
||
'<span class="v3-hb">' +
|
||
'<span class="v3-hk"><em>热</em>此刻最热<i style="background:' + c[1] + '"></i>' + c[0] + '</span>' +
|
||
'<span class="v3-hn">' + esc(t.name) + '</span>' +
|
||
'<span class="v3-hm"><span class="v3-avs"><img src="' + ava(k) + '" alt="" loading="lazy"><img src="' + ava(k + 5) + '" alt="" loading="lazy"><img src="' + ava(k + 11) + '" alt="" loading="lazy"></span>' + fmtNum(t.talk) + ' 人在聊</span>' +
|
||
'</span><span class="v3-go" aria-hidden="true">›</span></span>';
|
||
}
|
||
function showHot(fade) {
|
||
var t = hotList[hotIdx % hotList.length];
|
||
if (!t) return;
|
||
hotEl.dataset.t = t.id;
|
||
if (!fade || reduce) { hotEl.innerHTML = hotHtml(t); return; }
|
||
hotEl.classList.add('out');
|
||
setTimeout(function () { hotEl.innerHTML = hotHtml(t); hotEl.classList.remove('out'); }, 320);
|
||
}
|
||
|
||
function chip(t, k) {
|
||
var c = CAT[t.cat] || ['', '#E0566F'];
|
||
return '<button type="button" class="v3-chip" data-t="' + esc(t.id) + '" style="--cc:' + c[1] + ';--c1:' + t.c[0] + '" tabindex="-1">' +
|
||
'<img src="' + ava(k * 7 + 3) + '" alt="" loading="lazy">' +
|
||
'<span>' + esc(t.name) + '</span>' + (t.hot ? '<em>热</em>' : '') + '<i></i></button>';
|
||
}
|
||
/* 三行:方向 左/右/左,速度 px/s 略不同;每行一组内容不够宽就重复,再整体复制一份做无缝循环 */
|
||
var ROWS = [{ dir: 1, v: 13, d: 0 }, { dir: -1, v: 10, d: -9 }, { dir: 1, v: 15.5, d: -4 }];
|
||
function paint(cat) {
|
||
var list = pick(cat);
|
||
hotList = list.filter(function (t) { return t.hot && t.ph; });
|
||
if (!hotList.length) hotList = list.slice(0, 3);
|
||
hotIdx = 0; showHot(false);
|
||
var rows = [[], [], []];
|
||
list.forEach(function (t, j) { rows[j % 3].push(t); });
|
||
dm.innerHTML = rows.map(function (r, ri) {
|
||
var base = r.slice();
|
||
while (base.length < 6) base = base.concat(r);
|
||
var g = base.map(function (t, j) { return chip(t, ri * 13 + j); }).join('');
|
||
return '<div class="v3-row"><div class="v3-track' + (ROWS[ri].dir < 0 ? ' rev' : '') + '"><div class="v3-grp">' + g + '</div><div class="v3-grp" aria-hidden="true">' + g + '</div></div></div>';
|
||
}).join('');
|
||
requestAnimationFrame(function () {
|
||
Array.prototype.forEach.call(dm.querySelectorAll('.v3-track'), function (tr, ri) {
|
||
var w = tr.firstElementChild.offsetWidth || 600, dur = w / ROWS[ri].v;
|
||
tr.style.animationDuration = dur.toFixed(1) + 's';
|
||
tr.style.animationDelay = (ROWS[ri].d - ri * 3) + 's';
|
||
});
|
||
});
|
||
}
|
||
paint('');
|
||
if (!reduce) hotTimer = setInterval(function () {
|
||
if (dm.classList.contains('hold') || document.hidden) return;
|
||
hotIdx++; showHot(true);
|
||
}, 5200);
|
||
|
||
/* 按住暂停(松手 / 纵向滚动被系统接管时恢复) */
|
||
var hold = function (on) { dm.classList.toggle('hold', on); };
|
||
dm.addEventListener('pointerdown', function () { hold(true); });
|
||
['pointerup', 'pointercancel', 'pointerleave'].forEach(function (ev) { dm.addEventListener(ev, function () { hold(false); }); });
|
||
dm.addEventListener('touchstart', function () { hold(true); }, { passive: true });
|
||
dm.addEventListener('touchend', function () { hold(false); }, { passive: true });
|
||
dm.addEventListener('touchcancel', function () { hold(false); }, { passive: true });
|
||
|
||
sec.addEventListener('click', function (e) {
|
||
var cb = e.target.closest('[data-cat]');
|
||
if (cb) {
|
||
if (cb.classList.contains('on')) return;
|
||
Array.prototype.forEach.call(sec.querySelectorAll('.v3-cat button'), function (x) { x.classList.toggle('on', x === cb); });
|
||
if (reduce) { paint(cb.dataset.cat); return; }
|
||
dm.classList.add('swap');
|
||
setTimeout(function () { paint(cb.dataset.cat); dm.classList.remove('swap'); }, 260);
|
||
return;
|
||
}
|
||
var t = e.target.closest('[data-t]');
|
||
if (t && sec.contains(t)) { go(t.dataset.t); return; }
|
||
if (e.target.closest('[data-go]')) go('');
|
||
});
|
||
})();
|