// Utils import { createNamespace, isDef } from '../utils'; import { isHidden } from '../utils/dom/style'; import { preventDefault } from '../utils/dom/event'; import { getScroller, getScrollTop, getRootScrollTop, setRootScrollTop } from '../utils/dom/scroll'; // Mixins import { TouchMixin } from '../mixins/touch'; import { ParentMixin } from '../mixins/relation'; import { BindEventMixin } from '../mixins/bind-event'; function genAlphabet() { var indexList = []; var charCodeOfA = 'A'.charCodeAt(0); for (var i = 0; i < 26; i++) { indexList.push(String.fromCharCode(charCodeOfA + i)); } return indexList; } var _createNamespace = createNamespace('index-bar'), createComponent = _createNamespace[0], bem = _createNamespace[1]; export default createComponent({ mixins: [TouchMixin, ParentMixin('vanIndexBar'), BindEventMixin(function (bind) { if (!this.scroller) { this.scroller = getScroller(this.$el); } bind(this.scroller, 'scroll', this.onScroll); })], props: { zIndex: [Number, String], highlightColor: String, sticky: { type: Boolean, default: true }, stickyOffsetTop: { type: Number, default: 0 }, indexList: { type: Array, default: genAlphabet } }, data: function data() { return { activeAnchorIndex: null }; }, computed: { sidebarStyle: function sidebarStyle() { if (isDef(this.zIndex)) { return { zIndex: this.zIndex + 1 }; } }, highlightStyle: function highlightStyle() { var highlightColor = this.highlightColor; if (highlightColor) { return { color: highlightColor }; } } }, watch: { indexList: function indexList() { this.$nextTick(this.onScroll); }, activeAnchorIndex: function activeAnchorIndex(value) { if (value) { this.$emit('change', value); } } }, methods: { onScroll: function onScroll() { var _this = this; if (isHidden(this.$el)) { return; } var scrollTop = getScrollTop(this.scroller); var scrollerRect = this.getScrollerRect(); var rects = this.children.map(function (item) { return item.getRect(_this.scroller, scrollerRect); }); var active = this.getActiveAnchorIndex(scrollTop, rects); this.activeAnchorIndex = this.indexList[active]; if (this.sticky) { this.children.forEach(function (item, index) { if (index === active || index === active - 1) { var rect = item.$el.getBoundingClientRect(); item.left = rect.left; item.width = rect.width; } else { item.left = null; item.width = null; } if (index === active) { item.active = true; item.top = Math.max(_this.stickyOffsetTop, rects[index].top - scrollTop) + scrollerRect.top; } else if (index === active - 1) { var activeItemTop = rects[active].top - scrollTop; item.active = activeItemTop > 0; item.top = activeItemTop + scrollerRect.top - rects[index].height; } else { item.active = false; } }); } }, getScrollerRect: function getScrollerRect() { if (this.scroller.getBoundingClientRect) { return this.scroller.getBoundingClientRect(); } return { top: 0, left: 0 }; }, getActiveAnchorIndex: function getActiveAnchorIndex(scrollTop, rects) { for (var i = this.children.length - 1; i >= 0; i--) { var prevHeight = i > 0 ? rects[i - 1].height : 0; var reachTop = this.sticky ? prevHeight + this.stickyOffsetTop : 0; if (scrollTop + reachTop >= rects[i].top) { return i; } } return -1; }, onClick: function onClick(event) { this.scrollToElement(event.target); }, onTouchMove: function onTouchMove(event) { this.touchMove(event); if (this.direction === 'vertical') { preventDefault(event); var _event$touches$ = event.touches[0], clientX = _event$touches$.clientX, clientY = _event$touches$.clientY; var target = document.elementFromPoint(clientX, clientY); if (target) { var index = target.dataset.index; /* istanbul ignore else */ if (this.touchActiveIndex !== index) { this.touchActiveIndex = index; this.scrollToElement(target); } } } }, scrollTo: function scrollTo(index) { var match = this.children.filter(function (item) { return String(item.index) === index; }); if (match[0]) { match[0].scrollIntoView(); if (this.sticky && this.stickyOffsetTop) { setRootScrollTop(getRootScrollTop() - this.stickyOffsetTop); } this.$emit('select', match[0].index); } }, scrollToElement: function scrollToElement(element) { var index = element.dataset.index; this.scrollTo(index); }, onTouchEnd: function onTouchEnd() { this.active = null; } }, render: function render() { var _this2 = this; var h = arguments[0]; var Indexes = this.indexList.map(function (index) { var active = index === _this2.activeAnchorIndex; return h("span", { "class": bem('index', { active: active }), "style": active ? _this2.highlightStyle : null, "attrs": { "data-index": index } }, [index]); }); return h("div", { "class": bem() }, [h("div", { "class": bem('sidebar'), "style": this.sidebarStyle, "on": { "click": this.onClick, "touchstart": this.touchStart, "touchmove": this.onTouchMove, "touchend": this.onTouchEnd, "touchcancel": this.onTouchEnd } }, [Indexes]), this.slots('default')]); } });