如何在Kirby CMS单页网站中为每个文章实现自定义URL并自动展开对应内容?
我来帮你搞定这个需求!要在Kirby单页站里实现「URL锚点对应文章+自动展开」的效果,核心就是处理浏览器URL的hash值,结合你现有的展开逻辑来做,分这几步就能实现:
1. 确认锚点URL与文章ID的匹配性
你现在的PHP代码已经做得很好了——每个文章容器的ID是article-<?= $article->slug() ?>,而slug是Kirby自动生成的唯一标识,所以对应的自定义URL就是你的网站域名加上#article-文章slug,比如:https://你的网站.com#article-2024-summer-report
访问这个URL就能定位到对应文章的位置,接下来我们要让页面自动展开它的内容。
2. 重构JS逻辑,复用展开/收起功能
你的现有toggleSibling函数已经实现了点击展开的逻辑,但为了方便自动加载时复用,我们可以把展开、收起的逻辑拆成单独的函数,这样不管是点击触发还是自动加载,都能调用同一套逻辑:
// 封装「展开内容」的独立函数 function openContent(content) { // 先关闭所有其他已展开的内容 const allContent = document.querySelectorAll('.content.active'); allContent.forEach(openItem => { if (openItem !== content) { closeContent(openItem); } }); // 执行展开动画与样式 content.classList.add('active'); content.classList.add('fall'); setTimeout(() => { content.classList.remove('fall'); }, 500); } // 封装「收起内容」的独立函数 function closeContent(content) { content.classList.remove('active'); Array.from(content.children).forEach(child => { child.style.transform = ""; child.style.opacity = ""; child.style.transition = ""; }); } // 原有的点击触发逻辑,现在复用上面的封装函数 function toggleSibling(element) { const content = element.nextElementSibling; if (content.classList.contains('active')) { closeContent(content); } else { openContent(content); } }
3. 实现页面加载时的锚点检测与自动展开
接下来添加页面加载的监听事件,当页面打开时自动检测URL的hash值,找到对应文章并展开:
// 页面加载完成后检测URL锚点 document.addEventListener('DOMContentLoaded', function() { const urlHash = window.location.hash; if (urlHash) { // 去掉hash开头的#,得到文章的ID const targetArticleId = urlHash.slice(1); const targetArticle = document.getElementById(targetArticleId); if (targetArticle) { // 找到该文章对应的content元素(就是点击容器的下一个兄弟节点) const targetContent = targetArticle.querySelector('.container').nextElementSibling; if (targetContent) { // 调用展开函数 openContent(targetContent); // 平滑滚动到该文章的位置(可选,提升用户体验) targetArticle.scrollIntoView({ behavior: 'smooth', block: 'start' }); } } } });
4. 测试验证
现在你可以创建一个文章,比如slug是movie-review-2024,访问https://你的网站.com#article-movie-review-2024,页面加载后会自动:
- 关闭所有其他展开的内容
- 展开目标文章的内容
- 平滑滚动到该文章的顶部
如果想要更简洁的URL(比如去掉article-前缀),只需要把PHP里的容器ID改成id="<?= $article->slug() ?>",对应的URL就变成https://你的网站.com#movie-review-2024,同时把JS里的targetArticleId = urlHash.slice(1)这部分保留即可,其他逻辑不用改。
备注:内容来源于stack exchange,提问作者Balázs Milánik

