1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
| <div id="bn-dynamic-bookshelf"> <div class="loading-text">正在从云端加载高颜值书架...</div> </div>
<script> document.addEventListener("DOMContentLoaded", function() { // 建议使用加速镜像地址,确保国内秒开 // const jsonUrl = "https://jsd.onmicrosoft.cn/gh/qqhsx/book@main/data.json"; const jsonUrl = "https://raw.githubusercontent.com/qqhsx/book/main/data.json"; const shelfContainer = document.getElementById("bn-dynamic-bookshelf");
fetch(jsonUrl) .then(response => { if (!response.ok) throw new Error("无法获取书籍数据"); return response.json(); }) .then(books => { // 清空加载提示 shelfContainer.innerHTML = "";
// 1. 按分类将书籍归档 const categorizedBooks = {}; books.forEach(book => { let genre = book.genre || "未分类"; // 兼容归一化:把老数据的“经济”合并到“经济理财” if (genre === "经济") genre = "经济理财"; if (!categorizedBooks[genre]) { categorizedBooks[genre] = []; } categorizedBooks[genre].push(book); }); // 2. 动态循环生成每个分类的书架 // 为了让分类有固定顺序,你可以定义一个偏好顺序,不在列表里的自动排在后面 const genreOrder = ["经济理财", "历史", "科学技术", "文学"]; const sortedGenres = Object.keys(categorizedBooks).sort((a, b) => { let indexA = genreOrder.indexOf(a); let indexB = genreOrder.indexOf(b); if (indexA === -1) indexA = 99; if (indexB === -1) indexB = 99; return indexA - indexB; }); sortedGenres.forEach(genre => { // 创建书架大标题和网格 const shelfId = `shelf-${Math.random().toString(36).substr(2, 9)}`; const shelfHtml = ` <div class="bn-genre-section"> <h2 class="shelf-title">${getGenreIcon(genre)} ${genre}</h2> <div class="bn-book-grid" id="${shelfId}"></div> </div> `; shelfContainer.insertAdjacentHTML('beforeend', shelfHtml); const gridContainer = document.getElementById(shelfId); // 渲染该分类下的所有书籍 categorizedBooks[genre].forEach(book => { // 默认先尝试加载 .jpg 格式 const primaryCover = `https://raw.githubusercontent.com/qqhsx/book/main/covers/[${book.genre}]${book.title}-${book.author}.jpg`; // 备用地址换成 .jpeg 格式 const backupCover = `https://raw.githubusercontent.com/qqhsx/book/main/covers/[${book.genre}]${book.title}-${book.author}.jpeg`; const defaultPlaceholder = "https://via.placeholder.com/150x220?text=No+Cover"; const cardHtml = ` <div class="bn-book-card"> <div class="cover-wrapper"> <img src="${primaryCover}" class="bn-book-cover" onerror="handleCoverError(this, '${backupCover}', '${defaultPlaceholder}')"> </div> <div class="bn-book-title" title="${book.title}">${book.title}</div> <div class="bn-book-author" title="${book.author}">${book.author}</div> <a href="${book.file_path}" class="bn-read-btn" target="_blank">立即阅读</a> </div> `; gridContainer.insertAdjacentHTML('beforeend', cardHtml); }); }); }) .catch(error => { shelfContainer.innerHTML = `<div class="error-text">书架加载失败,请刷新重试。错误信息: ${error.message}</div>`; }); });
/** * 核心:封面多格式兼容错误处理函数 */ function handleCoverError(imgElement, backupUrl, placeholderUrl) { // 如果当前尝试的是第一顺位的 .jpg 并且失败了,切换到 .jpeg if (!imgElement.getAttribute('data-tried-backup')) { imgElement.setAttribute('data-tried-backup', 'true'); imgElement.src = backupUrl; } else { // 如果 .jpeg 也失败了,展示兜底图,并断开死循环 imgElement.onerror = null; imgElement.src = placeholderUrl; } }
/** * 辅助:根据分类名自动匹配精美的小图标(可自行在下方增删) */ function getGenreIcon(genre) { const icons = { "经济理财": "🪙", "历史": "⏳", "科学技术": "🔬", "文学": "📚", "未分类": "📖" }; return icons[genre] || "🔖"; // 没匹配到时默认用书签图标 } </script>
<style> .bn-genre-section { margin-bottom: 40px; } .loading-text, .error-text { text-align: center; padding: 40px; color: #767676; font-size: 15px; } .error-text { color: #cc0000; }
.shelf-title { font-size: 20px !important; font-weight: 700; color: #1a1a1a; border-bottom: 2px solid #006644 !important; /* B&N 经典绿下划线 */ padding-bottom: 8px; margin-top: 30px !important; margin-bottom: 20px !important; }
.bn-book-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 25px; padding: 10px 0; }
.bn-book-card { display: flex; flex-direction: column; align-items: center; text-align: center; background: #fff; padding: 10px; border-radius: 6px; transition: all 0.3s ease; } .bn-book-card:hover { transform: translateY(-6px); }
.cover-wrapper { width: 100%; aspect-ratio: 2 / 3; overflow: hidden; border-radius: 4px; box-shadow: 0 8px 16px rgba(0,0,0,0.12), 0 2px 4px rgba(0,0,0,0.06); margin-bottom: 12px; background: #f5f5f5; }
.bn-book-cover { width: 100%; height: 100%; object-fit: cover; transition: transform 0.3s ease; } .bn-book-card:hover .bn-book-cover { transform: scale(1.05); }
.bn-book-title { font-size: 14px; font-weight: 600; color: #2b2b2b; margin: 4px 0; line-height: 1.3; width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bn-book-author { font-size: 12px; color: #767676; margin-bottom: 10px; width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bn-read-btn { display: inline-block; width: 85%; padding: 6px 0; background-color: #006644 !important; color: #ffffff !important; font-size: 12px; font-weight: 500; text-decoration: none !important; border-radius: 20px; transition: background-color 0.2s ease; margin-top: auto; } .bn-read-btn:hover { background-color: #004d33 !important; box-shadow: 0 4px 8px rgba(0,102,68,0.2); } </style>
|