# IndexBar 索引栏

用于列表的索引分类显示和快速定位。

# 引入

import PressIndexBar from 'press-ui/press-index-bar/press-index-bar';
import PressIndexAnchor from 'press-ui/press-index-anchor/press-index-anchor';

export default {
  components: {
    PressIndexBar,
    PressIndexAnchor,
  }
}

# 代码演示

# 基础用法

点击索引栏时,会自动跳转到对应的IndexAnchor锚点位置。

<press-index-bar>
  <div>
    <press-index-anchor index="A" />
    <press-cell title="文本" />
    <press-cell title="文本" />
    <press-cell title="文本" />
  </div>

  <div>
    <press-index-anchor index="B" />
    <press-cell title="文本" />
    <press-cell title="文本" />
    <press-cell title="文本" />
  </div>

  ...
</press-index-bar>

# 自定义索引列表

可以通过index-list属性自定义展示的索引字符列表。

<press-index-bar :index-list="indexList">
  <div>
    <press-index-anchor index="1">标题1</press-index-anchor>
    <press-cell title="文本" />
    <press-cell title="文本" />
    <press-cell title="文本" />
  </div>

  <div>
    <press-index-anchor index="2">标题2</press-index-anchor>
    <press-cell title="文本" />
    <press-cell title="文本" />
    <press-cell title="文本" />
  </div>

  ...
</press-index-bar>
export default {
  data() {
    return {
      indexList: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    }
  },
};

# API

# IndexBar Props

参数 说明 类型 默认值 版本
index-list 索引字符列表 string[] | number[] A-Z -
z-index z-index 层级 number 1 -
sticky 是否开启锚点自动吸顶 boolean true -
sticky-offset-top 锚点自动吸顶时与顶部的距离 number 0 -
highlight-color 索引字符高亮颜色 string #07c160 -

# IndexAnchor Props

参数 说明 类型 默认值 版本
use-slot 是否使用自定义内容的插槽 boolean false -
index 索引字符 string | number - -

# IndexBar Events

事件名 说明 回调参数
select 选中字符时触发 index: 索引字符

# IndexAnchor Slots

名称 说明
- 锚点位置显示内容,默认为索引字符

# 在线调试

# 组件理解

# 结构分析

一看到 bar,就知道是边栏,index-bar 就是索引栏,所以这个组件的核心就是可点击的那一小列,并不是指的整个页面,默认放到右侧,就跟微信里的一样。

那么主体放哪里呢,组件需要监听主体的滚动,所以用 scroll-view 套住,并放在 index-barslot 内。这里的核心就是要把主体放到 index-barslot 内,因为用户可以自定义主体内容,组件只需要关心其滚动行为。

到这里基本的组件结构就呼之欲出了,伪代码如下。

<div>
  <scroll-view>
   <slot/>
  </scroll-view>
  <div 
    v-for="(item, index) of indexList" 
    :key="item"
  >
  </div>
</div>

光有这个还不够,还需要提供一个 index-anchor,也就是锚点。主体滚动时,顶部会固定不同的内容,也就是 fixed,同时右侧 index-bar 的激活内容也跟着变。

使用时,用户可以将 index-anchor 穿插在主体内容中,并用 index-bar 包裹:

<press-index-bar>
  <div>
    <press-index-anchor index="A" />
    <press-cell title="文本" />
    <press-cell title="文本" />
    <press-cell title="文本" />
  </div>

  <div>
    <press-index-anchor index="B" />
    <press-cell title="文本" />
    <press-cell title="文本" />
    <press-cell title="文本" />
  </div>

  ...
</press-index-bar>

# 两个动作

index-bar 有两个主要动作,scroll-view 的滚动(onScroll)和 sidebar 的滑动(onTouchMove)。

第一种情况,scroll-view 滚动时,会判断 active 索引。核心逻辑是,从后往前数,激活态就是第一个满足下面这个条件的,scrollTop + preAnchorHeight >= child[i].top,即第一个加32px(index 为0时不需要加)就可以"漏头"的。

第二种情况,会先计算当前激活的 index,计算方式为 Math.floor((touch.clientY - this.sidebar.top) / itemHeight),然后让 scroll-view 滚动到指定位置,注意滚动的时候会被动触发上面的 onScroll 事件。

# anchor

activeanchorsticky 的条件是:

const isActiveAnchorSticky = children[active].top <= scrollTop;

activeanchorsticky 的原理是,给 anchor-wrapper 一个固定的高度(32px),然后将 anchor 设置为

position: fixed; top: ${stickyOffsetTop}px

这样就固定住了,同时高度没塌陷。

滑动中,激活态的前一个,即 index === active - 1,它的样式是:

position: relative;transform: translate3d(0, ${translateY}px, 0);

就是让前一个激活过的标题,偏移到新的激活标题一起“排排坐”,滑动的时候用户体验好。active 不变的情况下,translateY 是固定的,为:

children[active].top - children[active - 1].top - children[active - 1].height
横屏