{"id":19019055,"url":"https://github.com/zcfan/hippy-recycle-listview","last_synced_at":"2025-07-23T01:34:35.966Z","repository":{"id":230861719,"uuid":"780307314","full_name":"zcfan/hippy-recycle-listview","owner":"zcfan","description":"纯 javascript 实现的高性能 Hippy 长列表组件 high performance listview component for hippy.js written purely in javascript.","archived":false,"fork":false,"pushed_at":"2024-04-01T11:31:07.000Z","size":9842,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-06T02:50:05.864Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zcfan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-04-01T07:30:10.000Z","updated_at":"2024-04-01T08:05:40.000Z","dependencies_parsed_at":"2024-04-01T08:32:03.016Z","dependency_job_id":"81fa448a-5f22-4210-9d76-6d0e39a9415c","html_url":"https://github.com/zcfan/hippy-recycle-listview","commit_stats":{"total_commits":10,"total_committers":1,"mean_commits":10.0,"dds":0.0,"last_synced_commit":"eb6995c19d21aa0b8f60f5f8336815f4f99ca370"},"previous_names":["zcfan/hippy-recycle-listview"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/zcfan/hippy-recycle-listview","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zcfan%2Fhippy-recycle-listview","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zcfan%2Fhippy-recycle-listview/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zcfan%2Fhippy-recycle-listview/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zcfan%2Fhippy-recycle-listview/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zcfan","download_url":"https://codeload.github.com/zcfan/hippy-recycle-listview/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zcfan%2Fhippy-recycle-listview/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266602820,"owners_count":23954696,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T20:10:38.789Z","updated_at":"2025-07-23T01:34:35.943Z","avatar_url":"https://github.com/zcfan.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"HippyRecycleListView\n----\n\nHippyRecycleListView 是一个纯前端实现的 Hippy ListView 在特殊场景下的替代品，提供了更灵活的布局能力，以及良好的性能表现。\n\n它是为满足较特殊的设计需求而开发的组件，目前没有和 Hippy ListView 做过严谨的性能对比，各种能力不全面，也无意对标原生实现。\n\n**在两者都能满足需求的情况下，应尽量选择 Hippy Listview**。\n\n## 0. 快速开始\n\n```\nnpm install hippy-recycle-listview\n```\n\n范例参考 `demo`\n\n## 1. 解决什么问题\n\nAndroid 上的 Hippy ListView，如果某一行的内容高度超出行高本身会被裁剪，就像下面展示的这样：\n\n![listview 行被裁剪](./assets/1.png)\n\n目前为止我还没找到什么办法禁用这种裁剪行为，所以当出现这种设计，原生的 ListView 就无法满足需求了。本组件就是为了实现上图这种列表设计而开发。\n\n## 2. 实现思路\n\n要实现这个设计，最简单的方案是换用 ScrollView + 绝对定位，然后不指定固定的行高。\n\n因为每一行没有固定行高，所以内容不会被裁剪，而是行容器根据内容自动扩大。而行的 y 坐标是绝对定位指定的，所以行容器变高不会影响行高。就实现了不会裁剪内容的 ListView。\n\n接下来只需要将所有的 row 都绘制到 ScrollView 中对应的位置即可：\n\n![](./assets/3.png)\n\n显然这种方式在数据量大的时候存在严重的性能问题，所以可以这样进行一个初步的优化：\n\n![](./assets/4.png)\n\n\n从渲染所有 row，改为仅渲染可视范围内的 row。如上图中 ROW 1/6 不可见，所以可以不用渲染。\n\n但这样优化还有问题，那就是滑动时不可避免会频繁发生 ROW 的创建和销毁。比如当我们向上滑动导致 ROW 1 离开屏幕，ROW 6 进入屏幕时：\n\n![](./assets/5.png)\n\n如果 row 较为复杂，或用户滑动速度很快时，这个问题导致的卡顿就会很明显。我们可以通过行复用来解决这个问题：\n\n![](./assets/6.png)\n\n当 ROW 1 离开屏幕时，它不会被销毁而是被保留。后续当 ROW 6 要进入屏幕时，原本的 ROW 1 被重新复用。数据被更新为 ROW 6，并挪动到 ROW 6 应在的位置。\n\n其中的关键在与，我们给每个视图都分配了另外一个固定的 key。新 key 和数据无关，只要改变传入的 props，`key 1` 的内容就可以从 `ROW 1` 变成` ROW 6`：\n\n![](./assets/7.png)\n\n在上文的简单例子中，react 从头到尾只渲染了 5 个不同的组件（Key 1~5），只是它们的 props 在不断变化（ROW 1~N）。\n\n## 3. 优化效果\n\n对比“仅渲染可见范围”的初步优化，我们的行复用方案有明显优势：\n\n![性能对比](./assets/compare.mp4)\n\n从屏幕下方的图表中可以看出，右侧行复用方案的渲染耗时更稳定，卡顿更少。\n\n## 4. 现存问题\n\n缺失许多 ListView 的常用功能，比如不支持不同的行高、横向滑动、下拉刷新、滑动到底部回调等等。\n\n行（key）复用的逻辑也缺少失效机制，池中的行数只会新增，很久没有被复用/相同类型过多的行不会被删除。\n\n这里是战术性功能不全🐶，不是业务需要，不建议同事们填坑。\n\n因为本组件解决的唯一痛点就是 Hippy ListView 行内容出界的裁剪问题，是为了特定业务需求做的基本实现。\n\n而这一个痛点已经跟 Hippy 同事反馈过了，过阵子如果建议接受了这个组件也就没有存在的必要了。所以不需要浪费更多精力在功能补全，更多是分享优化方案探讨思路。\n\n## 5. 更新\n\n万一 hippy 不方便调整的话，这个项目可能会有后续更新。所以也记录一下：\n\n本地仓库新增工蜂 origin：\n\n```\ngit remote add tc git@git.woa.com:wesing-web/hippy-recycle-listview.git\n```\n\n修改同步工蜂仓库：\n\n```\ngit push tc main:master\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzcfan%2Fhippy-recycle-listview","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzcfan%2Fhippy-recycle-listview","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzcfan%2Fhippy-recycle-listview/lists"}