用Gemini写了一个单页 TVL.COM.CN
用Gemini写了一个单页 TVL.COM.CN,非常不错!
数据获取慢和失败的根本原因是因为我们使用了**“公共代理服务”**(如 allorigins 或 rss2json)来绕过跨域限制。这些公共服务是免费的,全球几万人共用,当然会拥堵、超时。
要实现秒开、稳定、实时,唯一的办法是建立直连。
这需要您配合做一个极小的服务器修改(只需改动一行代码)。只要解除了您博客的“锁”(CORS限制),您的网页就可以直接读取数据,速度就是您打开博客的速度。
第一步:解锁您的博客服务器(必做)
请通过宝塔面板或 FTP,在您博客网站的根目录下找到 rss.php 文件(注意是 rss.php,不是 index.php,这个文件更独立,修改更安全)。
在文件最顶端(<?php 的紧下面)加入这三行代码:
PHP
<?php
// --- 复制这三行开始 ---
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET");
header("Access-Control-Allow-Headers: *");
// --- 复制这三行结束 ---
/**
* RSS输出
* @copyright (c) Emlog All Rights Reserved
*/
// ... 下面是原有的代码,不要动
原理: 这几行代码的作用是告诉浏览器:“我是 hzpm.com,我允许 TV Labs 这个网页直接读取我的 RSS 数据,不要拦截它。”
第二步:使用直连版 HTML 代码
修改完服务器文件并保存后,使用下面这个版本的 HTML。
这个版本移除了所有代理,直连您的服务器,速度最快,且永不封号。
HTML
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>TV Labs | 视觉科学研究所</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@300;400;500&family=Playfair+Display:ital,wght@0,400;0,600;1,400&display=swap" rel="stylesheet">
<style>
:root {
--bg-color: #fcfcfc;
--text-primary: #111111;
--text-secondary: #666666;
--menu-text-active: #0044cc;
}
* { margin: 0; padding: 0; box-sizing: border-box; -webkit-font-smoothing: antialiased; -webkit-tap-highlight-color: transparent; }
body {
background-color: var(--bg-color); color: var(--text-primary); font-family: 'Manrope', sans-serif;
overflow: hidden; width: 100%; height: 100dvh; position: relative;
}
/* --- 1. 氛围质感 --- */
.noise-overlay {
position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 90; opacity: 0.05;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E");
}
.optical-bg { position: fixed; top: 0; left: 0; width: 100vw; height: 100%; z-index: 1; background: #fff; overflow: hidden; }
.orb { position: absolute; border-radius: 50%; filter: blur(80px); opacity: 0.5; animation: float 20s infinite ease-in-out; }
.orb-1 { width: 80vw; height: 80vw; background: linear-gradient(120deg, #e0c3fc 0%, #8ec5fc 100%); top: -30%; left: -20%; }
.orb-2 { width: 70vw; height: 70vw; background: linear-gradient(120deg, #f093fb 0%, #f5576c 100%); bottom: -30%; right: -20%; opacity: 0.3; animation-delay: -10s; }
/* --- 2. 导航与Logo --- */
nav {
position: fixed; top: 0; left: 0; width: 100%; padding: 40px 50px;
display: flex; justify-content: space-between; align-items: center;
z-index: 999; mix-blend-mode: difference; color: #fff;
}
.logo-container { display: flex; align-items: center; gap: 12px; text-decoration: none; color: inherit; }
.logo-mark { width: 24px; height: 24px; position: relative; }
.logo-mark::before, .logo-mark::after {
content: ''; position: absolute; width: 18px; height: 18px; border-radius: 50%; mix-blend-mode: exclusion;
}
.logo-mark::before { background: #fff; left: 0; top: 50%; transform: translateY(-50%); }
.logo-mark::after { background: #fff; right: 0; top: 50%; transform: translateY(-50%); opacity: 0.7; }
.logo-text { display: flex; flex-direction: column; line-height: 1; }
.logo-text .tv { font-family: 'Playfair Display', serif; font-size: 1.4rem; font-weight: 700; font-style: italic; letter-spacing: -0.5px; }
.logo-text .labs { font-family: 'Manrope', sans-serif; font-size: 0.5rem; font-weight: 600; letter-spacing: 3px; text-transform: uppercase; margin-left: 2px; opacity: 0.8; }
.menu-btn { font-family: 'Manrope', sans-serif; font-size: 0.85rem; font-weight: 600; letter-spacing: 2px; text-transform: uppercase; cursor: pointer; color: inherit; position: relative; padding-bottom: 2px; }
.menu-btn::after { content: ''; position: absolute; bottom: 0; left: 0; width: 0; height: 1px; background: currentColor; transition: width 0.3s; }
.menu-btn:hover::after { width: 100%; }
/* --- 3. 菜单遮罩 --- */
.menu-overlay {
position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.75);
backdrop-filter: blur(25px); -webkit-backdrop-filter: blur(25px); z-index: 500;
display: flex; flex-direction: column; justify-content: center; align-items: center;
opacity: 0; visibility: hidden; transition: all 0.5s cubic-bezier(0.16, 1, 0.3, 1);
}
.menu-overlay.active { opacity: 1; visibility: visible; }
.menu-list { list-style: none; text-align: center; padding: 0; }
.menu-list li { margin: 15px 0; overflow: hidden; }
.menu-list a {
display: block; font-family: 'Playfair Display', serif; font-size: 3.5rem; color: #111; text-decoration: none;
transform: translateY(120%); transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1), color 0.3s; line-height: 1.1;
}
.menu-list a span {
display: block; font-family: 'Manrope', sans-serif; font-size: 0.8rem; letter-spacing: 3px;
text-transform: uppercase; color: var(--text-secondary); margin-top: -5px; opacity: 0; transform: translateY(10px); transition: all 0.3s;
}
.menu-list a:hover { color: var(--menu-text-active); font-style: italic; }
.menu-list a:hover span { opacity: 1; transform: translateY(0); }
.menu-overlay.active .menu-list a { transform: translateY(0); }
.menu-overlay.active li:nth-child(1) a { transition-delay: 0.1s; }
.menu-overlay.active li:nth-child(2) a { transition-delay: 0.15s; }
.menu-overlay.active li:nth-child(3) a { transition-delay: 0.2s; }
.menu-overlay.active li:nth-child(4) a { transition-delay: 0.25s; }
/* --- 4. 主视觉 --- */
.hero {
position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 10;
display: flex; flex-direction: column; justify-content: center; align-items: center;
text-align: center; padding: 0 20px; transition: filter 0.5s, transform 0.5s;
}
body.menu-open .hero { filter: blur(8px); transform: scale(0.95); }
.hero-label { font-size: 0.8rem; letter-spacing: 4px; text-transform: uppercase; color: var(--text-secondary); margin-bottom: 3vh; opacity: 0; animation: fadeIn 2s ease 0.5s forwards; }
.hero h1 { font-family: 'Playfair Display', serif; font-size: clamp(3rem, 10vw, 7.5rem); font-weight: 500; line-height: 1.1; margin-bottom: 2vh; color: #111; opacity: 0; animation: fadeInUp 1.5s ease 0.8s forwards; }
.hero h1 i { font-family: 'Playfair Display', serif; font-weight: 400; color: var(--text-secondary); }
.hero p { max-width: 500px; font-size: 1.05rem; line-height: 1.8; color: var(--text-secondary); opacity: 0; animation: fadeInUp 1.5s ease 1.1s forwards; }
/* --- 5. 滚动文字 (光学聚焦) --- */
.marquee {
position: absolute; bottom: 30px; left: 0; width: 100%; overflow: hidden; z-index: 20; padding-bottom: env(safe-area-inset-bottom);
opacity: 0; animation: fadeIn 1s ease 2s forwards; pointer-events: none;
}
.track { display: flex; width: max-content; animation: scroll 40s linear infinite; }
.marquee:hover .track { animation-play-state: paused; }
.content { display: flex; align-items: center; flex-shrink: 0; gap: 0; }
.content a {
display: inline-block; padding: 0 1.5vw;
font-family: 'Manrope', sans-serif; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 2px;
color: #999; white-space: nowrap; text-decoration: none; pointer-events: auto; position: relative;
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
.content a::before {
content: ''; position: absolute; bottom: -2px; left: 0; width: 100%; height: 1px;
background-color: var(--menu-text-active); transform: scaleX(0); transform-origin: center;
transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1); opacity: 0.8;
}
.track:hover .content a { opacity: 0.4; filter: blur(0.8px); }
.track:hover .content a:hover { color: var(--menu-text-active); opacity: 1; filter: blur(0); }
.content a:hover::before { transform: scaleX(1); }
.content a::after { content: "•"; color: #ddd; margin-left: 1.5vw; display: inline-block; text-decoration: none; pointer-events: none; opacity: 0.5; }
@keyframes scroll { 0% { transform: translateX(0); } 100% { transform: translateX(-50%); } }
@keyframes float { 0%, 100% { transform: translate(0, 0); } 50% { transform: translate(5%, 8%); } }
@keyframes fadeInUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@media (max-width: 768px) {
nav { padding: 25px 20px; }
.menu-list a { font-size: 2.2rem; }
.hero { padding-bottom: 60px; }
.hero h1 { margin-bottom: 15px; }
.marquee { bottom: 0; padding: 15px 0 calc(15px + env(safe-area-inset-bottom)) 0; background: linear-gradient(to top, rgba(252,252,252,0.9) 0%, rgba(252,252,252,0) 100%); }
.content a { font-size: 0.7rem; padding: 0 12px; }
.content a::after { margin-left: 12px; }
.logo-text .tv { font-size: 1.2rem; }
.logo-mark { width: 20px; height: 20px; }
.logo-mark::before, .logo-mark::after { width: 15px; height: 15px; }
}
</style>
</head>
<body>
<div class="noise-overlay"></div>
<div class="optical-bg">
<div class="orb orb-1"></div>
<div class="orb orb-2"></div>
</div>
<nav>
<a href="#" class="logo-container">
<div class="logo-mark"></div>
<div class="logo-text">
<span class="tv">TV</span>
<span class="labs">LABS</span>
</div>
</a>
<div class="menu-btn" onclick="toggleMenu()">Menu +</div>
</nav>
<div class="menu-overlay" id="menuOverlay">
<ul class="menu-list">
<li><a href="#">关于我们 <span>About</span></a></li>
<li><a href="#">研究领域 <span>Research</span></a></li>
<li><a href="#">实验室 <span>Labs</span></a></li>
<li><a href="#">联系 <span>Contact</span></a></li>
</ul>
</div>
<section class="hero">
<div class="hero-label">The Institute of Vision Science</div>
<h1>
重塑视觉<br>
<i>Reshaping Reality.</i>
</h1>
<p>
探索光子、神经与数字像素的数学边界。<br>
致力于下一代显示技术的底层物理研究。
</p>
<div class="marquee">
<div class="track" id="marqueeTrack">
<div class="content" id="contentA">
<a href="#">正在同步数据...</a>
</div>
<div class="content" id="contentB">
<a href="#">正在同步数据...</a>
</div>
</div>
</div>
</section>
<script>
function toggleMenu() {
const overlay = document.getElementById('menuOverlay');
const btn = document.querySelector('.menu-btn');
const body = document.body;
overlay.classList.toggle('active');
body.classList.toggle('menu-open');
btn.textContent = overlay.classList.contains('active') ? 'Close -' : 'Menu +';
}
// --- 极速直连模式 ---
// 直接请求您的 RSS 文件,不经过任何中间商
const DIRECT_RSS_URL = 'https://www.hzpm.com/rss.php';
let lastHash = "";
async function fetchBlogTitles() {
try {
// 1. 发起直连请求
// 注意:前提是您已经修改了 rss.php 添加了 Header,否则这里会报错 CORS
const response = await fetch(DIRECT_RSS_URL + '?t=' + new Date().getTime());
if (!response.ok) throw new Error("Connection failed");
const str = await response.text();
// 2. 浏览器直接解析 XML
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(str, "text/xml");
const items = xmlDoc.querySelectorAll("item");
let articles = [];
if (items.length > 0) {
items.forEach((item) => {
const title = item.querySelector("title")?.textContent;
const link = item.querySelector("link")?.textContent;
if (title && link) articles.push({ title, link });
});
} else {
throw new Error("No articles");
}
// 3. 智能比对更新
const currentHash = JSON.stringify(articles);
if (currentHash !== lastHash) {
updateMarquee(articles);
lastHash = currentHash;
console.log("Feed Updated via Direct Connection");
}
} catch (error) {
console.error("Direct Fetch Error:", error);
// 如果直连失败(通常是因为还没改 PHP 文件),显示提示
if (lastHash === "") {
updateMarquee([
{ title: "请修改服务器 rss.php 添加跨域Header", link: "#" },
{ title: "Connection Blocked by CORS", link: "#" }
]);
}
}
}
function updateMarquee(articles) {
const contentA = document.getElementById('contentA');
const contentB = document.getElementById('contentB');
const displayArticles = articles.slice(0, 15);
const htmlString = displayArticles.map(item =>
`<a href="${item.link}" target="_blank">${item.title}</a>`
).join('');
if (contentA.innerHTML !== htmlString) {
contentA.innerHTML = htmlString;
contentB.innerHTML = htmlString;
}
}
document.addEventListener('DOMContentLoaded', fetchBlogTitles);
setInterval(fetchBlogTitles, 30000); // 30秒极速轮询
</script>
</body>
</html>
总结:
-
先做:去服务器修改
rss.php(加入那 3 行 PHP 代码)。 -
后做:使用上面这个新的 HTML。
-
结果:数据将直接从您的服务器飞到用户浏览器,没有任何中间环节,速度最快,且只要您发文章,这里 30 秒内就会自动同步。
扫描二维码,在手机上阅读
发表评论
