周末闲来无事,我注意到"每日一言"这类简约网站越来越受欢迎,而作为一个有着基督教背景的开发者,突然想到:为什么不做一个每日圣经金句的版本呢?
说干就干!这个项目的目标很明确:创建一个简洁优雅的网站,每次访问都能展示一段随机的圣经经文,配上精美背景,让人在匆忙的生活中能有片刻安静思考。从构思到上线,我给自己设定了24小时的挑战期限。
技术选型与API调研
首先需要找到一个可靠的圣经API。经过一番调研,选定了bible-api.com:
- 提供JSON格式的圣经经文
- 支持多种语言翻译版本
- 有专门的随机经文接口
- 支持CORS跨域请求
- 使用简单,文档清晰
这个API提供两种调用方式:
- 用户输入API - 直接通过URL指定书卷章节(如bible-api.com/john 3:16)
- 参数化API - 通过结构化路径获取(如/data/web/JHN/3)
最重要的是它有一个/data/[translation]/random接口,完美符合"每日一节经文"的需求
设计理念:简约而不简单
设计上我决定遵循极简主义:
- 深色半透明遮罩 + 全屏背景图
- 经文居中展示,使用优雅的衬线字体
- 简洁交互,不干扰阅读体验
- 响应式设计,在任何设备上都能完美展示
核心功能开发
随机经文获取
首先实现了基本的API调用功能:async function fetchRandomVerse() { try { const apiUrl = `https://bible-api.com/data/${currentTranslation}/random`; const response = await fetch(apiUrl); if (!response.ok) { throw new Error(`API request failed with status: ${response.status}`); } const data = await response.json(); if (data && data.random_verse) { const verse = data.random_verse; const text = verse.text; const reference = `${verse.book} ${verse.chapter}:${verse.verse}`; displayVerse(text.trim(), reference); return; } // 处理其他可能的响应格式... } catch (error) { console.error('Error fetching bible verse:', error); useFallbackVerse(); } }
有趣的挑战之一是API响应格式可能因不同翻译版本而异,所以代码中包含了多种格式的解析逻辑。
另外,为了避免API故障时网站无法使用,我添加了本地备用经文集:const fallbackVerses = [ { text: 'For God so loved the world...', reference: 'John 3:16' }, // 更多备用经文... ]; function useFallbackVerse() { const randomFallback = fallbackVerses[Math.floor(Math.random() * fallbackVerses.length)]; displayVerse(randomFallback.text, randomFallback.reference); }
2. 背景图片功能
设计了两种背景模式:
- 默认的耶稣图片背景
来自Bing的随机自然风景图
切换背景时添加了平滑过渡效果:function setBackground(url) { const img = new Image(); img.onload = () => { document.body.classList.add('transitioning'); setTimeout(() => { document.body.style.backgroundImage = `url(${url})`; setTimeout(() => { document.body.classList.remove('transitioning'); }, 1000); }, 200); }; img.src = url; }
加载Bing图片时,添加了加载状态提示,避免用户困惑:
function handleNatureBgClick() { if (!natureBgButton.classList.contains('active')) { wallpaperLoadingModal.classList.add('show'); fetchNatureBackground(); setActiveButton(natureBgButton); } }
3. 多语言翻译支持
实现了16种圣经翻译版本切换功能,包括英文、中文、拉丁文等:
const translations = [ { id: 'web', name: 'World English Bible', language: 'English' }, { id: 'kjv', name: 'King James Version', language: 'English' }, // 更多翻译版本... { id: 'cuv', name: 'Chinese Union Version', language: 'Chinese' }, ];
使用localStorage保存用户偏好设置:
function confirmTranslation() { if (selectedTranslation !== currentTranslation) { currentTranslation = selectedTranslation; localStorage.setItem('bibleTranslation', currentTranslation); updateTranslationButton(); fetchBibleVerse(); } closeTranslationModal(); }
创意加分项:背景音乐播放器
为了增强用户体验,添加了一个优雅的圆形音乐播放器,播放赞美诗:
function setupAudioPlayer() { const audioPlayer = document.getElementById('audio-player'); const playPauseBtn = document.getElementById('play-pause-btn'); const playerContainer = document.querySelector('.audio-player-container'); let isPlaying = true; function updatePlayState() { playPauseBtn.innerHTML = isPlaying ? '<svg>...</svg>' : // 暂停图标 '<svg>...</svg>'; // 播放图标 if (isPlaying) { playerContainer.classList.add('playing'); } else { playerContainer.classList.remove('playing'); } } // 播放器交互逻辑... }
播放器设计成能旋转的圆盘样式,音乐播放时会缓慢旋转,增添视觉趣味性。
遇到的挑战与解决方案1. API响应格式不一致
不同翻译版本的API返回格式略有不同,这需要编写更灵活的解析逻辑:
// 尝试解析多种可能的响应格式 if (data && data.random_verse) { // 格式1 } else if (data && data.verse && typeof data.verse === 'object') { // 格式2 } else if (data && data.verses && Array.isArray(data.verses)) { // 格式3 } else if (data && data.text && data.reference) { // 格式4 }
2. 音频自动播放限制
现代浏览器限制自动播放音频,解决方案是添加用户交互解锁:
document.addEventListener('click', function() { if (audioPlayer.paused) { audioPlayer.play().catch(console.error); isPlaying = true; updatePlayState(); } }, { once: true });
3. 移动端适配
需要确保在各种设备上都有良好体验,使用了媒体查询:
@media (max-width: 768px) { #verse-container { padding: 30px; } h1 { font-size: 28px; } #verse-text { font-size: 20px; } /* 更多适配样式... */ } @media (max-width: 480px) { /* 手机屏幕样式... */ }
细节处理与优化
加载动画
为提升用户体验,添加了优雅的加载过渡:@keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
2. 分享功能
添加了一键分享功能,方便用户将经文复制到剪贴板:
function copyVerseToClipboard() { const verseText = verseTextElement.textContent; const verseReference = verseReferenceElement.textContent; const websiteLink = "bible.drinsper.com"; const textToCopy = `"${verseText}" - ${verseReference}\n\nRead more at: ${websiteLink}`; navigator.clipboard.writeText(textToCopy) .then(() => { copyConfirmation.classList.add('show'); setTimeout(() => { copyConfirmation.classList.remove('show'); }, 3000); }) .catch(err => { console.error('Could not copy text: ', err); alert('Failed to copy verse to clipboard. Please try again.'); }); }
部署上线
最后一步是将网站部署到线上。使用了简单的静态网站托管服务,域名选择了bible.drinsper.com,将整个项目打包上传后,网站立即可用!
短时间内从零到成品,最大的体会是:
- 明确目标很重要:从一开始就清楚要做什么,避免了开发中的迷茫
- 优先核心功能:先实现核心API调用,再逐步添加其他功能,而不是同时处理所有事情
- 用户体验至上:即使是小项目,良好的加载体验、响应式设计和适当动效都能极大提升用户感受
优雅降级处理:API可能失败、图片可能加载错误,提前设计好容错方案很重要
这个项目虽小,但涵盖了现代前端开发的多个方面,从API集成到响应式设计,从本地存储到优雅动效。有时候,简单的项目反而能给人带来意想不到的满足感。下一步计划添加更多功能,如夜间模式、更多背景选项、经文收藏功能等。