You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

224 lines
5.9 KiB

// 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);
}
}
}
},
scrollToElement: function scrollToElement(element) {
var index = element.dataset.index;
if (!index) {
return;
}
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);
}
},
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')]);
}
});