ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

cube-ui IndexList 索引列表组件完全指南:基于 better-scroll 的字母索引、自定义插槽与上拉下拉刷新

cube-ui IndexList 索引列表组件完全指南:基于 better-scroll 的字母索引、自定义插槽与上拉下拉刷新 前端UI组件移动开发【免费下载链接】cube-ui:large_orange_diamond: A fantastic mobile ui lib implement by Vue项目地址https://gitcode.com/gh_mirrors/cu/cube-ui点击查看免费下载导读IndexList是 cube-ui 中用于移动端长列表快速检索的核心组件它基于better-scroll二次封装在普通滚动列表之上叠加了「分组索引 右侧导航栏 吸顶分组标题」的能力是城市选择、歌手列表、通讯录等场景的标准解决方案。本文将围绕 cube-ui 官方文档 document/components/docs/zh-CN/index-list.md 展开结合仓库源码与单元测试系统讲解 IndexList 的数据模型、基本用法、自定义插槽、上拉加载与下拉刷新并深入剖析导航栏滚动、吸顶标题等内部实现原理帮助你完全掌握这一组件的配置与二次开发。组件定位与整体架构IndexList 组件在文档中被定义为「索引列表提供了列表索引的功能也是一个基于 better-scroll 进行封装的组件」。从源码结构看它由三部分协作组成外层容器 src/components/index-list/index-list.vue负责整体布局、右侧导航栏navbar、吸顶标题、滚动事件转发并内嵌cube-scroll分组组件 src/components/index-list/index-list-group.vue渲染一个分组li classcube-index-list-group内部通过插槽承载数据项列表项组件 src/components/index-list/index-list-item.vue渲染单个可点击数据项默认显示item.name点击后派发select事件。三个组件分别通过cube-index-list、cube-index-list-group、cube-index-list-item三个标签暴露给使用者。其中外层组件通过import CubeScroll from ../scroll/scroll.vue直接复用了 src/components/scroll/scroll.vue 的滚动能力因此 IndexList 天然继承了 Scroll 组件的下拉刷新、上拉加载等全部特性这解释了文档中「配置同 Scroll 组件」的表述。数据模型理解 data 的分组结构使用 IndexList 的第一步是构造符合要求的数据。文档明确指出data是一个数组代表多组数据每组包含两个字段| 参数 | 说明 | 类型 | | - | - | - | | name | 组名会作为分组标题与右侧导航索引显示 | String | | items | 当前组下的数据项 | Array |而items数组中的每一项必须是对象且必须包含name属性用于显示内容例如items: [{name: xx, ...}, ...]。文档中的cityData就是标准示例const cityData [ { name: ★Hot City, items: [ { name: BEIJING, value: 1 }, { name: SHANGHAI, value: 2 } ] }, { name: A, items: [ { name: ANSHAN, value: 3 }, { name: ANQING, value: 4 } ] } ]仓库中的真实示例数据 example/data/index-list.json 还展示了一个容易被忽略的字段shortcut分组可以额外提供shortcut用于覆盖右侧导航栏的默认索引字符。结合 index-list.vue 的shortcutList计算属性可以确认其规则shortcutList() { return this.data.map((group) { return group ? group.shortcut || group.name.substr(0, 1) : }) }即导航栏索引优先取group.shortcut未配置时取group.name的首个字符——这正是示例数据中★ Hot City配合shortcut: ★的实现方式。此外单元测试 验证了组件对异常数据的健壮性当data中出现undefined分组、items中出现undefined项时组件仍能正常运行而不抛错说明数据字段是可容错的。基本使用一个可运行的最小示例将上述cityData传入cube-index-list的data属性即可获得带索引导航的列表。文档给出的最小用法如下cube-index-list :datacityData :titletitle selectselectItem title-clickclickTitle/cube-index-listexport default { data() { return { title: Current City: BEIJING, cityData: cityData } }, methods: { selectItem(item) { console.log(item.name) }, clickTitle(title) { console.log(title) } } }对应的完整可运行页面位于 example/pages/index-list/default.vue页面容器需要给 IndexList 一个确定高度示例中通过position: fixedheight: 98%overflow: hidden实现因为基于 better-scroll 的组件必须在有限高度的容器内才能滚动。关于两个事件select点击列表任意一项后触发参数为该选项的完整数据对象如{name: BEIJING, value: 1}title-click点击顶部 title 后触发参数为title属性值且只有设置了title属性后该事件才有效源码中titleClick()直接$emit(EVENT_TITLE_CLICK, this.title)未设置 title 时列表顶部不会渲染标题元素。单元测试 test/unit/specs/index-list.spec.js#L62-L85 通过dispatchTap模拟点击验证了select与title-click两个事件各触发且仅触发一次。自定义插槽定制每一项的内容与导航项当默认的纯文本列表项无法满足业务需求时如歌手列表需要展示头像可以通过插槽自定义。文档强调除非你真的知道自己在做什么否则不要修改cube-index-list-group和cube-index-list-item的用法——即v-for遍历结构必须保持只是可以向cube-index-list-item内填充自定义内容。cube-index-list :datacityData cube-index-list-group v-for(group, index) in cityData :keyindex :groupgroup cube-index-list-item v-for(item, index) in group.items :keyindex :itemitem selectselectItem div classcustom-item我是自定义 {{item.name}}/div /cube-index-list-item /cube-index-list-group /cube-index-list仓库中的真实自定义示例 example/pages/index-list/custom.vue 更进一步它基于singer.json数据渲染歌手头像列表并额外使用nav-item插槽slotnav-item slot-scopeprops自定义了右侧导航索引的展示样式。自定义时通常还要覆写内置样式文档给出的 stylus 方案覆盖了四类关键选择器// 自定义项的样式 .custom-item position: relative height: 70px line-height: 70px padding: 0 16px font-size: $fontsize-medium // 用自定义样式覆写内置的默认样式 .cube-index-list-content background-color: #222 color: #909090 .cube-index-list-anchor background-color: #333 height: 30px line-height: 30px padding: 0 0 0 20px .cube-index-list-nav padding: 20px 0 border-radius: 10px background: rgba(0,0,0,.3) ul li padding: 3px font-size: 12px color: #909090 .active color: #ffcd32这些类名与源码模板中的结构一一对应.cube-index-list-content、.cube-index-list-anchor、.cube-index-list-nav默认背景色、文字颜色均来自 src/common/stylus/variable.styl 中的$index-list-*系列变量可以通过修改主题变量统一调整。上拉加载pulling-up 事件与 forceUpdateIndexList 支持上拉加载更多。文档说明可通过pullUpLoad属性开启配置与 Scroll 组件的options.pullUpLoad一致。核心用法cube-index-list refindexList :datadata :titletitle :pullUpLoadtrue selectselectItem title-clickclickTitle pulling-uponPullingUp /cube-index-listexport default { data() { return { title: Current City: BEIJING, data: cityData.slice(0, 4) } }, methods: { onPullingUp() { // Mock async load. setTimeout(() { const length this.data.length if (length cityData.length) { // Update data. this.data.push(cityData[length]) } // Call forceUpdate after finishing data load. this.$refs.indexList.forceUpdate() }, 1000) } } }这里有两个关键点异步加载完成后必须调用forceUpdate()。因为 IndexList 基于 better-scroll数据更新后需要重新计算滚动高度。从 index-list.vue 的源码可见forceUpdate(dirty false, nomore false) { this.$refs.scroll.forceUpdate(dirty, nomore) dirty this.$nextTick(() { this._calculateHeight() }) }forceUpdate会将请求转发给内嵌的cube-scroll同时可选择性地在$nextTick后重新计算分组高度_calculateHeight确保索引导航与吸顶标题的定位仍然准确。pulling-up事件在「上拉超过阈值」时触发。单元测试 test/unit/specs/index-list.spec.js#L87-L124 通过dispatchSwipe从底部向上模拟上拉手势断言pulling-up处理器被调用一次验证了该事件的触发链路。完整的上拉加载示例页面见 example/pages/index-list/pull-up-load.vue注意它采用的是新版推荐写法——将pullUpLoad配置放进options属性options: { pullUpLoad: true }。下拉刷新pulling-down 事件与配置细节与上拉加载对称IndexList 也支持下拉刷新通过pullDownRefresh属性开启配置同 Scroll 组件的options.pullDownRefreshcube-index-list refindexList :datadata :titletitle :pullDownRefreshpullDownRefresh selectselectItem title-clickclickTitle pulling-downonPullingDown /cube-index-listexport default { data() { return { title: Current City: BEIJING, data: cityData, pullDownRefresh: { stop: 55 } } }, methods: { onPullingDown() { // Mock async load. setTimeout(() { // Update data. this.data[1].items.push(...cityData[1].items) // Call forceUpdate after finishing data load. this.$refs.indexList.forceUpdate(true) }, 1000) } } }与上拉加载的差异点pullDownRefresh支持传入对象示例中的stop: 55表示下拉回弹停止位置px刷新完成后调用forceUpdate(true)传入true会让组件在重新计算高度的同时刷新滚动状态dirty this.$nextTick(...)分支使新增数据可以立即滚动访问pulling-down事件在下拉超过阈值时触发同样有对应测试覆盖test/unit/specs/index-list.spec.js#L126-L162。完整示例页面见 example/pages/index-list/pull-down-refresh.vue同样使用options: { pullDownRefresh: { stop: 55 } }的新写法。另外下拉刷新区域还支持通过pulldown插槽自定义展示详见下文插槽章节。Props 完整配置说明文档给出的全部 Props 配置如下表| 参数 | 说明 | 类型 | 默认值 | | - | - | - | - | | title | 标题 | String | - | | data | 需要展示的数据 | Array | [] | | navbar | 是否需要导航栏 | Boolean | true | | speed | 点击导航栏索引时滚动到相应位置的动画时间单位ms | number | 0 | | options1.9.8 | better-scroll 配置项具体请参考 BS 官方文档 | Object | { observeDOM: true, click: true, probeType: 1, scrollbar: false, pullDownRefresh: false, pullUpLoad: false } | | pullUpLoad1.8.0 | 上拉加载具体配置参考 scroll 组件的options.pullUpLoad。即将废弃推荐使用options属性 | Boolean/Object | false | | pullDownRefresh1.8.0 | 下拉刷新具体配置参考 scroll 组件的options.pullDownRefresh。即将废弃推荐使用options属性 | Boolean/Object | false |几个值得深入的点options的合并逻辑。从 index-list.vue 的scrollOptions计算属性可见组件内部将pullDownRefresh、pullUpLoad两个旧属性与options合并后统一传给cube-scrollscrollOptions() { return Object.assign({}, { pullDownRefresh: this.pullDownRefresh, pullUpLoad: this.pullUpLoad }, this.options) }options作为兜底配置拥有最高优先级这也解释了文档「推荐使用options属性」的原因。options属性本身来自 src/common/mixins/scroll.js 的scrollMixin是所有滚动类组件共享的入口。废弃属性有运行时提示。pullUpLoad与pullDownRefresh在 props 定义时都带上了deprecated: { replacedBy: options }见 index-list.vue配合deprecatedMixin会在控制台输出废弃警告引导开发者迁移到options。iOS 13.4 的兼容性注意点。文档特别注明从1.12.38版本开始为修复 better-scroll 在 iOS 13.4 上的滚动问题对应 issue #978useTransition在 iOS 版本 13.4 时默认置为false如遇 iOS 滚动异常可关注该配置。navbar与speed的行为。navbar: false会隐藏右侧索引导航栏对应模板v-ifnavbar单元测试 test/unit/specs/index-list.spec.js#L217-L224 断言此时.cube-index-list-nav元素不存在speed则控制点击导航索引后scrollToElement的过渡时长毫秒默认为 0 即瞬间定位。插槽一览| 名字 | 说明 | 作用域参数 | | - | - | - | | title1.12.25 | 标题插槽 | - | | pulldown1.9.4 | 位于列表上方会在下拉刷新时显示与 scroll 组件相同 | 具体参考 scroll 组件的 pulldown 插槽作用域参数介绍 | | pullup1.9.4 | 位于列表下方会在上拉加载时显示与 scroll 组件相同 | 具体参考 scroll 组件的 pullup 插槽作用域参数介绍 |从 index-list.vue 的模板可以看到pulldown与pullup插槽并非 IndexList 自己实现的而是通过slotpulldown/slotpullup透传给了内嵌的cube-scroll并转发了完整的作用域参数pulldown提供pullDownRefresh、pullDownStyle、beforePullDown、isPullingDown、bubbleY可用于自定义下拉气泡动画pullup提供pullUpLoad、isPullUpLoad。另外虽然官方文档插槽表未列出但从源码与真实示例可知组件还支持两个实用插槽默认插槽覆盖整个分组结构即上文「自定义插槽」章节的用法nav-item插槽自定义右侧导航栏每个索引项的展示作用域参数为当前索引字符item见 example/pages/index-list/custom.vue 中的slot-scopeprops用法。事件一览| 事件名 | 说明 | 参数 | | - | - | - | | select | 点击 IndexList 的某一项后触发 | 该选项的数据 | | title-click | 点击 title 后触发title 必须设置后才有效 | title 属性值 | | pulling-up1.8.0 | 当 pullUpLoad 属性为 true 时在上拉超过阈值时触发 | - | | pulling-down1.8.0 | 当 pullDownRefresh 属性为 true 时在下拉超过阈值时触发 | - |事件从源码到使用者之间的转发链路非常清晰index-list-item.vue的selectItem()将select事件逐级$emit到index-list-group.vue再到index-list.vuepulling-up/pulling-down则由内嵌cube-scroll触发后由外层组件监听并再次转发见 index-list.vue 的onPullingUp/onPullingDown。源码深入导航栏索引与吸顶标题的实现原理除了文档层面的用法IndexList 还有两个高频被问及的内部机制这里结合源码给出实现级说明。右侧导航栏的滑动定位导航栏支持两种交互点按单个索引或按住后在导航栏上滑动连续切换。核心实现在 index-list.vueonShortcutTouchStart(e) { const target getMatchedTarget(e, cube-index-list-nav-item) if (!target) return let anchorIndex getData(target, index) let firstTouch e.touches[0] this.touch.y1 firstTouch.pageY this.touch.anchorIndex anchorIndex this._scrollTo(anchorIndex) }, onShortcutTouchMove(e) { let firstTouch e.touches[0] this.touch.y2 firstTouch.pageY let delta (this.touch.y2 - this.touch.y1) / ANCHOR_HEIGHT | 0 let anchorIndex parseInt(this.touch.anchorIndex) delta this._scrollTo(anchorIndex) }滑动时通过「滑动的像素距离 / 每个索引项高度ANCHOR_HEIGHT小屏为 17、常规屏为 18」换算成索引增量实现连续滑动切换。最终_scrollTo(index)会调用内嵌 scroll 的scrollToElement(this.groupList[index], this.speed)将对应分组滚动到可视区并对越界索引做了钳制index 0归 0超出归为最后一个分组。吸顶标题fixedTitle当列表滚动时顶部分组标题会「吸顶」展示当前分组名并随下一分组到来被平滑顶出。其实现分为两部分当前分组计算scrollY的 watcherindex-list.vue根据预计算的分组高度数组listHeight通过区间判断-newY height1 -newY height2得出当前索引currentIndex并计算出diff当前分组底部与视口顶部的距离差吸顶位移diff的 watcher 通过translate3d(0, ${fixedTop}px, 0)驱动固定的.cube-index-list-fixed元素index-list.vue当diff介于 0 与分组标题高度之间时产生「推出」动画效果。_calculateHeight()index-list.vue会在mounted、data变化、forceUpdate(true)时被调用逐一累加每个分组的clientHeight构建listHeight数组这是吸顶与导航定位能够准确的基石。单元测试 test/unit/specs/index-list.spec.js#L164-L215 通过模拟点击导航项B后断言固定标题内容依次变为B、C完整验证了该机制。小结IndexList 是 cube-ui 中对 better-scroll 能力复用最充分的组件之一一张分组数据驱动索引导航、吸顶标题与滚动定位一套options配置打通下拉刷新与上拉加载三个子组件加若干插槽覆盖从纯文本到富媒体列表的全部定制需求。建议新项目统一使用options属性承载 better-scroll 配置并在异步数据更新后及时调用forceUpdate即可稳定复现文档与 example/pages/index-list 下四个示例页面的完整效果。赞分享前端UI组件移动开发【免费下载链接】cube-ui:large_orange_diamond: A fantastic mobile ui lib implement by Vue项目地址https://gitcode.com/gh_mirrors/cu/cube-ui点击查看免费下载相关推荐cube-ui IndexList 组件完全指南基于 better-scroll 的索引列表实战与源码解析cube ui IndexList 组件完全指南基于 better scroll 的索引列表实战与源码解析 IndexList 是 cube ui 中用于实现前端UI组件移动开发3分钟构建高性能静态文件服务器解决本地开发与临时共享的5大痛点3分钟构建高性能静态文件服务器解决本地开发与临时共享的5大痛点 Simple HTTP Server 是一款基于 Rust 构建的轻量级静态文件服务器专为开前端UI组件移动开发better-scroll/pull-down 插件全解为 BetterScroll 注入下拉刷新能力better scroll/pull down 插件全解为 BetterScroll 注入下拉刷新能力 better scroll/pull down 是前端UI组件上一篇如何快速获取B站直播推流码新手友好的完整指南下一篇RustDesk Server一键安装终极指南3分钟搭建私有远程桌面服务器创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表