| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 | <template><uni-shadow-root class="vant-index-bar-index"><view class="van-index-bar">  <slot></slot>  <view v-if="showSidebar" class="van-index-bar__sidebar" @click.stop.prevent="onClick" @touchmove.stop.prevent="onTouchMove" @touchend.stop.prevent="onTouchStop" @touchcancel.stop.prevent="onTouchStop">    <view v-for="(item,index) in (indexList)" :key="item.index" class="van-index-bar__index" :style="'z-index: '+(zIndex + 1)+'; color: '+(activeAnchorIndex === index ? highlightColor : '')" :data-index="index">      {{ item }}    </view>  </view></view></uni-shadow-root></template><script>global['__wxRoute'] = 'vant/index-bar/index'import { GREEN } from '../common/color';import { VantComponent } from '../common/component';import { useChildren } from '../common/relation';import { getRect, isDef } from '../common/utils';import { pageScrollMixin } from '../mixins/page-scroll';const indexList = () => {    const indexList = [];    const charCodeOfA = 'A'.charCodeAt(0);    for (let i = 0; i < 26; i++) {        indexList.push(String.fromCharCode(charCodeOfA + i));    }    return indexList;};VantComponent({    relation: useChildren('index-anchor', function () {        this.updateData();    }),    props: {        sticky: {            type: Boolean,            value: true,        },        zIndex: {            type: Number,            value: 1,        },        highlightColor: {            type: String,            value: GREEN,        },        stickyOffsetTop: {            type: Number,            value: 0,        },        indexList: {            type: Array,            value: indexList(),        },    },    mixins: [        pageScrollMixin(function (event) {            this.scrollTop = (event === null || event === void 0 ? void 0 : event.scrollTop) || 0;            this.onScroll();        }),    ],    data: {        activeAnchorIndex: null,        showSidebar: false,    },    created() {        this.scrollTop = 0;    },    methods: {        updateData() {            wx.nextTick(() => {                if (this.timer != null) {                    clearTimeout(this.timer);                }                this.timer = setTimeout(() => {                    this.setData({                        showSidebar: !!this.children.length,                    });                    this.setRect().then(() => {                        this.onScroll();                    });                }, 0);            });        },        setRect() {            return Promise.all([                this.setAnchorsRect(),                this.setListRect(),                this.setSiderbarRect(),            ]);        },        setAnchorsRect() {            return Promise.all(this.children.map((anchor) => getRect(anchor, '.van-index-anchor-wrapper').then((rect) => {                Object.assign(anchor, {                    height: rect.height,                    top: rect.top + this.scrollTop,                });            })));        },        setListRect() {            return getRect(this, '.van-index-bar').then((rect) => {                if (!isDef(rect)) {                    return;                }                Object.assign(this, {                    height: rect.height,                    top: rect.top + this.scrollTop,                });            });        },        setSiderbarRect() {            return getRect(this, '.van-index-bar__sidebar').then((res) => {                if (!isDef(res)) {                    return;                }                this.sidebar = {                    height: res.height,                    top: res.top,                };            });        },        setDiffData({ target, data }) {            const diffData = {};            Object.keys(data).forEach((key) => {                if (target.data[key] !== data[key]) {                    diffData[key] = data[key];                }            });            if (Object.keys(diffData).length) {                target.setData(diffData);            }        },        getAnchorRect(anchor) {            return getRect(anchor, '.van-index-anchor-wrapper').then((rect) => ({                height: rect.height,                top: rect.top,            }));        },        getActiveAnchorIndex() {            const { children, scrollTop } = this;            const { sticky, stickyOffsetTop } = this.data;            for (let i = this.children.length - 1; i >= 0; i--) {                const preAnchorHeight = i > 0 ? children[i - 1].height : 0;                const reachTop = sticky ? preAnchorHeight + stickyOffsetTop : 0;                if (reachTop + scrollTop >= children[i].top) {                    return i;                }            }            return -1;        },        onScroll() {            const { children = [], scrollTop } = this;            if (!children.length) {                return;            }            const { sticky, stickyOffsetTop, zIndex, highlightColor } = this.data;            const active = this.getActiveAnchorIndex();            this.setDiffData({                target: this,                data: {                    activeAnchorIndex: active,                },            });            if (sticky) {                let isActiveAnchorSticky = false;                if (active !== -1) {                    isActiveAnchorSticky =                        children[active].top <= stickyOffsetTop + scrollTop;                }                children.forEach((item, index) => {                    if (index === active) {                        let wrapperStyle = '';                        let anchorStyle = `              color: ${highlightColor};            `;                        if (isActiveAnchorSticky) {                            wrapperStyle = `                height: ${children[index].height}px;              `;                            anchorStyle = `                position: fixed;                top: ${stickyOffsetTop}px;                z-index: ${zIndex};                color: ${highlightColor};              `;                        }                        this.setDiffData({                            target: item,                            data: {                                active: true,                                anchorStyle,                                wrapperStyle,                            },                        });                    }                    else if (index === active - 1) {                        const currentAnchor = children[index];                        const currentOffsetTop = currentAnchor.top;                        const targetOffsetTop = index === children.length - 1                            ? this.top                            : children[index + 1].top;                        const parentOffsetHeight = targetOffsetTop - currentOffsetTop;                        const translateY = parentOffsetHeight - currentAnchor.height;                        const anchorStyle = `              position: relative;              transform: translate3d(0, ${translateY}px, 0);              z-index: ${zIndex};              color: ${highlightColor};            `;                        this.setDiffData({                            target: item,                            data: {                                active: true,                                anchorStyle,                            },                        });                    }                    else {                        this.setDiffData({                            target: item,                            data: {                                active: false,                                anchorStyle: '',                                wrapperStyle: '',                            },                        });                    }                });            }        },        onClick(event) {            this.scrollToAnchor(event.target.dataset.index);        },        onTouchMove(event) {            const sidebarLength = this.children.length;            const touch = event.touches[0];            const itemHeight = this.sidebar.height / sidebarLength;            let index = Math.floor((touch.clientY - this.sidebar.top) / itemHeight);            if (index < 0) {                index = 0;            }            else if (index > sidebarLength - 1) {                index = sidebarLength - 1;            }            this.scrollToAnchor(index);        },        onTouchStop() {            this.scrollToAnchorIndex = null;        },        scrollToAnchor(index) {            if (typeof index !== 'number' || this.scrollToAnchorIndex === index) {                return;            }            this.scrollToAnchorIndex = index;            const anchor = this.children.find((item) => item.data.index === this.data.indexList[index]);            if (anchor) {                anchor.scrollIntoView(this.scrollTop);                this.$emit('select', anchor.data.index);            }        },    },});export default global['__wxComponents']['vant/index-bar/index']</script><style platform="mp-weixin">@import '../common/index.css';.van-index-bar{position:relative}.van-index-bar__sidebar{display:flex;flex-direction:column;position:fixed;right:0;text-align:center;top:50%;transform:translateY(-50%);-webkit-user-select:none;user-select:none}.van-index-bar__index{font-size:var(--index-bar-index-font-size,10px);font-weight:500;line-height:var(--index-bar-index-line-height,14px);padding:0 var(--padding-base,4px) 0 var(--padding-md,16px)}</style>
 |