资讯动态

Legado 阅读 3.0 首页模块(homepageModules)配置指南:数据结构、模块类型与数据绑定原理

发布时间:2026/10/5 2:20:54 来源:尧图企业网站定制
移动开发前端应用【免费下载链接】legado-with-MD3使用 Material Design 3 全新设计的阅读 3.0项目地址https://gitcode.com/gh_mirrors/le/legado-with-MD3点击查看免费下载本篇指南以 Legado阅读 3.0Material Design 3 版书源规范中的homepageModules字段为核心讲解如何通过 JSON 数组声明书源在应用首页展示的内容模块包括通用字段定义、8 种模块类型、layoutConfig布局微调、kindTitle自动匹配与url降级的完整数据绑定逻辑并结合仓库源码剖析模块在 HomepageViewModel 中的解析、同步与加载流程。读完本文你将可以独立编写一份可被 Legado 首页正确渲染的书源首页模块配置并理解其底层实现机制。1. 概述什么是首页模块homepageModules是书源BookSource中的一个可选字段位于书源 JSON 中与exploreUrl同级的配置区源码见 BookSource.kt 中的var homepageModules: String? null。它允许书源开发者声明该书源在应用首页展示的内容模块模块通过 JSON 数组定义支持高度自定义的布局与数据来源。与「发现」Explore页的静态分类列表不同首页模块将多个分类/榜单/推荐流组合进一个可排序、可显隐、可自定义标题的动态首页用户可以按自己的阅读习惯重组首页结构。模块的排序、显隐等用户设置会以key为标识持久化保存。从源码结构看HomepageModels.kt首页模块体系由三层模型构成ModuleDef书源 JSON 解析后的模块定义key/type/title/args/layoutConfig/urlModuleItem落库后的模块实例包含customTitle、isEnabled、sortOrder、sourceJsonHash、syncedAt等运行时状态其中displayTitle优先返回用户自定义标题HomepageModuleType模块类型枚举定义了banner、ranking、gridRanking、grid、card、infiniteGrid、buttonGroup、waterfall八种类型fromKey负责把 JSON 字符串转换为枚举未知类型回退为Unknown。2. 数据结构Data StructurehomepageModules是一个包含多个模块定义对象的 JSON 数组每个对象使用下表通用字段字段类型必须说明keyString是模块唯一标识。建议使用[a-z0-9_]字符。用于保存用户的排序/显隐设置。typeEnum是模块类型。定义了渲染方式和交互逻辑。详见第 3 节。titleString是模块默认标题。用户可在本地自定义覆盖。kindTitleString否用于匹配书源「发现」规则中的分类标题。匹配成功后自动继承其 URL 和规则。urlString否显式指定数据接口 URL。优先级高于kindTitle。支持变量替换。argsString否附加参数。在buttonGroup类型中为 JSON 数组字符串。layoutConfigObject否布局配置对象用于调整列数、行数、图标等。详见第 4 节。字段要点与实现细节key 的全局唯一性key只要求在某一个书源内部唯一。落库后系统会通过ModuleDef.globalIdOf(sourceUrl, key, setId)生成形如setId::sourceUrl::key的全局 ID见 HomepageModels.kt 的globalId扩展属性从而让不同书源、不同用户分组之间的同名key互不冲突。建议key使用[a-z0-9_]字符便于作为稳定标识参与排序/显隐设置的持久化。title 与自定义标题title是书源声明时的默认标题用户改名后写入customTitle渲染时displayTitle优先返回customTitle。url 与 kindTitle 的优先级当url与kindTitle同时存在时url优先级更高详见第 5 节数据绑定逻辑。args 的多义性args是通用附加参数字符串。在buttonGroup中它是 JSON 数组字符串如[\武侠\, \仙侠\]在ranking/gridRanking的「排行榜分组」场景中它是带有isHomepageRankingGroup与kindTitles的 JSON 对象见 HomepageViewModel.kt 中的RankingKindsArgs。3. 模块类型Module Types3.1 列表与轮播类类型描述特点banner横滑轮播图适合展示高权重的精品推荐使用大图封面。ranking排行榜列表垂直列表展示带排名序号。card推荐卡片横向滑动的卡片流同时显示封面、标题及简介。3.2 网格类类型描述特点grid标准网格最常用的展示形式。支持自定义行列。gridRanking网格排行榜多行多列的排行展示。横向翻页。infiniteGrid无限网格垂直滚动的网格流。无限加载。waterfall错位瀑布流垂直错位排列的书架流。无限加载。3.3 功能类类型描述特点buttonGroup快捷按钮组渲染为一组圆形/图标按钮支持自动填充宽度与自动分列。通常用于放置常用分类或功能入口。类型在源码中的对应关系上述 8 种类型与 HomepageModels.kt 中的HomepageModuleType枚举一一对应Banner(banner)、Ranking(ranking)、GridRanking(gridRanking)、Grid(grid)、Card(card)、InfiniteGrid(infiniteGrid)、ButtonGroup(buttonGroup)、Waterfall(waterfall)。类型决定了两件事渲染方式由 Compose 首页 UI 层决定与加载逻辑由 HomepageViewModel 决定。从 HomepageViewModel.kt 的loadModule分支可以看到类型对加载逻辑的核心影响ranking/gridRanking走executeForRanking路径且支持「排行榜分组」多个 kindTitle 同时加载、多列并行请求buttonGroup走分类匹配路径加载后渲染为按钮组其余类型走通用execute路径waterfall/infiniteGrid被isInfinite()判定为无限流类型支持loadMoreModule分页追加与去重deduped result.books.filter { it.bookUrl !in existingUrls }。4. 布局配置LayoutConfig通过layoutConfig对象可以精细化控制模块的表现属性类型适用类型默认值说明columnsIntgrid,waterfall,infiniteGrid3每行显示的列数。iconStringbuttonGroup-按钮组的默认统一图标 URL。iconsObjectbuttonGroup-图标映射表。例{排行: http://path/to/icon}。layoutConfig 的解析实现从源码看layoutConfig会被解析为扁平化的 key-value 映射供 UI 层消费。在 HomepageViewModel.kt 的初始化收集器中每个模块的layoutConfigJSON 会被GSON.fromJson(configStr, Map::class.java)解析并统一加上layout_前缀例如columns: 2变成layout_columns 2数值会被归一化为整数形式如2.0转为2。因此layoutConfig是一个可扩展的键值容器——文档明确定义的columns/icon/icons只是其中三个常用键。补充说明原文档示例中的rows: 5见第 6 节hot_rank模块同样会以layout_rows的形式传给 UI 层用于控制排行榜展示行数。这是文档表格之外、由示例隐含支持的布局键实际可用性以对应 UI 组件的消费逻辑为准。5. 数据绑定逻辑Data Binding模块的数据来源按以下优先级解析自动匹配kindTitle如果提供了kindTitle系统会遍历书源exploreKinds()返回的分类列表。如果某个分类的title与之完全一致该模块将自动使用该分类的url。静态指定url如果提供了url系统将直接请求该 URL。降级逻辑若kindTitle未匹配且无url模块将回退至书源的主exploreUrl。底层exploreKinds() 的分类解析kindTitle匹配依赖书源「发现」分类列表。该列表由exploreKinds()生成实现在 BookSourceExtensions.kt缓存 key 为MD5(bookSourceUrl exploreUrl)分类修改后会自动重新计算无需手动刷新若exploreUrl以js或js:开头会先执行 JS 得到分类规则串并缓存若规则串是 JSON 数组则用GSON.fromJsonArrayExploreKind解析否则按或换行拆分每个分类以::分隔标题与 URL分类对象即 ExploreKind.kt 定义的data class ExploreKind(title, url, type, action, chars, default, viewName, style)。首页模块正是利用这一分类列表做kindTitle的精确匹配allKinds.find { it.title title }匹配成功后复用该分类的url与解析规则。实际加载调用链在 HomepageViewModel.kt 的loadModule中非排名类模块调用exploreBooksUseCase.execute(sourceUrl, module.url, module.args)ranking/gridRanking调用exploreBooksUseCase.executeForRanking(...)其上限在 ExploreBooksUseCase.kt 中定义为MAX_RANKING_BOOKS 20、最多翻页MAX_RANKING_PAGES 3无限流模块waterfall/infiniteGrid首次加载后标记hasMore滚动到底部时通过loadMoreModule以page 1继续请求并做 URL 去重每个模块的加载结果还会与书架状态比对标记IN_SHELF/SAME_NAME_AUTHOR/NOT_IN_SHELF供首页展示「已在书架」标识。6. 完整 JSON 示例下面是一份同时覆盖轮播、按钮组、排行榜与瀑布流的homepageModules完整示例与文档示例保持一致并附注释说明[ { key: top_banner, type: banner, title: 精品强推, kindTitle: 首页推荐 }, { key: quick_nav, type: buttonGroup, title: 分类导航, args: [\武侠\, \仙侠\, \都市\, \历史\], layoutConfig: { icon: https://example.com/icons/default.png, icons: { 武侠: https://example.com/icons/wuxia.png } } }, { key: hot_rank, type: ranking, title: 热门榜单, kindTitle: 排行榜, layoutConfig: { rows: 5 } }, { key: explore_waterfall, type: waterfall, title: 发现更多, kindTitle: 全部, layoutConfig: { columns: 2 } } ]各模块的绑定行为解读top_bannerkindTitle 首页推荐精确命中书源发现分类后自动继承该分类 URL 渲染为横滑轮播未命中时降级使用书源exploreUrl。quick_navargs指定 4 个分类标题按钮组会按标题在exploreKinds()中逐个匹配icons映射表提供每个按钮的专属图标icon提供未匹配项的默认图标。hot_rankranking模块按kindTitle匹配「排行榜」分类rows: 5控制展示行数序号由列表顺序决定。explore_waterfallwaterfall瀑布流模块匹配「全部」分类columns: 2强制双列布局属于无限流类型支持无限滚动加载与去重。7. 配置生效、同步与用户自定义机制7.1 模块同步书源导入后首页模块并不会直接使用 JSON 原文而是经过一次「定义 → 实例」的落库同步。在syncModulesFromSource见 HomepageViewModel.kt中用MD5计算homepageModulesJSON 的sourceJsonHash将解析出的ModuleDef逐个 upsert 为ModuleItem并为该书源自动创建一个src_sourceUrl的用户分组CustomSet已存在且非用户自建的模块若 JSON 哈希未变则跳过哈希变化则更新type/title/args/url等字段书源 JSON 中已删除的模块会通过deleteStale清理。这套机制保证了书源作者更新模块配置后用户在首页的排序/显隐设置以 key 为锚点不会被覆盖丢失而用户手动新增或改名的模块isUserCreated true永远不被书源同步覆盖。7.2 模块刷新首页下拉刷新时onRefresh系统会取消所有进行中的加载任务、对每个涉及的书源重新执行syncModulesFromSource然后清空内容状态并等待所有模块重新加载完成源码中通过uiState.map { it.modules }.first { ... }等待加载结束。7.3 用户自定义能力从HomepageViewModel的公开方法可以推断首页模块在客户端具备以下用户自定义能力addCustomModule/joinModule手动添加模块含 buttonGroup 快捷生成addRankingFromKinds从发现分类直接生成单个或分组排行榜模块updateModule/deleteModule编辑标题、类型、URL、args、layoutConfig或删除模块reorderJoinedModules/reorderCustomSets拖拽排序模块与分组setModuleVisible/toggleSourceFilter单模块显隐与整源过滤隐藏记录存于hiddenSourceUrlsJsonassignModuleToCustomSet把模块分配到用户自建分组。需要留意的是无限流模块waterfall/infiniteGrid在同一分组内只允许存在一个重复添加或把无限流模块移动到已有无限流模块的分组时会收到提示homepage_module_duplicate_infinite。8. 编写建议与验证8.1 编写建议key 命名使用语义化小写命名如top_banner、quick_nav避免特殊字符同一书源内不要重复。优先使用 kindTitle 而非 urlkindTitle自动继承分类规则书源作者调整分类 URL 时首页模块无需跟着改只有需要定制化数据接口时才显式写url。合理选型精品推荐用banner/card榜单用ranking/gridRanking常规分类用grid大流量浏览用waterfall/infiniteGrid快捷入口用buttonGroup。args 保持 JSON 字符串格式buttonGroup的args必须是合法的 JSON 数组字符串否则按钮组会退化为「取前 N 个分类」的逻辑源码常量HOMEPAGE_MAX_BUTTON_GROUP_KINDS 5即未提供有效 args 时最多展示前 5 个分类。8.2 如何验证在书源编辑器中编辑homepageModules字段并保存/导入书源首页对应模块区域出现即为解析成功若某模块加载失败首页该模块区域会进入ModuleLoadState.Error并展示错误摘要可通过下拉刷新重试使用「发现」页调试工具对照exploreKinds()返回的分类标题确认kindTitle是否精确匹配分类数据解析逻辑见 BookSourceExtensions.kt。9. 关联资料本指南的规范原文位于 app/src/main/assets/web/help/md/homepageModulesHelp.md同内容的开发者规格版见 docs/spec/homepage-modules.md模块数据模型与类型枚举app/src/main/java/io/legado/app/domain/model/HomepageModels.kt首页模块加载、同步与自定义逻辑app/src/main/java/io/legado/app/ui/main/homepage/HomepageViewModel.kt发现分类解析exploreKindsapp/src/main/java/io/legado/app/help/source/BookSourceExtensions.kt发现分类数据类app/src/main/java/io/legado/app/data/entities/rule/ExploreKind.kt模块数据请求 UseCaseapp/src/main/java/io/legado/app/domain/usecase/ExploreBooksUseCase.kt。赞分享移动开发前端应用【免费下载链接】legado-with-MD3使用 Material Design 3 全新设计的阅读 3.0项目地址https://gitcode.com/gh_mirrors/le/legado-with-MD3点击查看免费下载相关推荐legado 书源首页模块 homepageModules 配置完全指南从字段规范到源码级加载机制legado 书源首页模块 homepageModules 配置完全指南从字段规范到源码级加载机制 homepageModules 是 legado阅读 3移动开发前端应用Skinny Framework社区贡献指南如何参与开源项目Skinny Framework社区贡献指南如何参与开源项目 Skinny Framework是一个以Scala on Rails为理念的全栈Web应用框后端Legado 阅读 3.0 数据层架构全解析Room 数据库、dao 与 entities 设计Legado 阅读 3.0 数据层架构全解析Room 数据库、dao 与 entities 设计 本指南以 app/src/main/java/io/lega移动开发前端应用上一篇SciPy 对数均匀分布scipy.stats.loguniform完全指南数学定义、源码实现与实战用法下一篇800 数学PDF的GitHub库帮你把程序员的数学底子补上创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑