[new feature] IndexBar: add sticky prop (#3402)
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import { use } from '../utils';
|
||||
import { TouchMixin } from '../mixins/touch';
|
||||
import { ParentMixin } from '../mixins/relation';
|
||||
import { on, off } from '../utils/event';
|
||||
import { getScrollTop, getElementTop, getScrollEventTarget } from '../utils/scroll';
|
||||
|
||||
const [sfc, bem] = use('index-bar');
|
||||
|
||||
@@ -8,6 +10,10 @@ export default sfc({
|
||||
mixins: [TouchMixin, ParentMixin('vanIndexBar')],
|
||||
|
||||
props: {
|
||||
sticky: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
zIndex: {
|
||||
type: Number,
|
||||
default: 1
|
||||
@@ -27,13 +33,72 @@ export default sfc({
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.scroller = getScrollEventTarget(this.$el);
|
||||
this.handler(true);
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
this.handler(false);
|
||||
},
|
||||
|
||||
activated() {
|
||||
this.handler(true);
|
||||
},
|
||||
|
||||
deactivated() {
|
||||
this.handler(false);
|
||||
},
|
||||
|
||||
methods: {
|
||||
onClick(event) {
|
||||
this.scrollToElement(event.target);
|
||||
handler(bind) {
|
||||
/* istanbul ignore else */
|
||||
if (this.binded !== bind) {
|
||||
this.binded = bind;
|
||||
(bind ? on : off)(this.scroller, 'scroll', this.onScroll);
|
||||
}
|
||||
},
|
||||
|
||||
onTouchStart(event) {
|
||||
this.touchStart(event);
|
||||
onScroll() {
|
||||
if (!this.sticky) {
|
||||
return;
|
||||
}
|
||||
|
||||
const scrollTop = getScrollTop(this.scroller);
|
||||
const rects = this.children.map(item => ({
|
||||
height: item.height,
|
||||
top: getElementTop(item.$el)
|
||||
}));
|
||||
|
||||
const active = this.getActiveAnchorIndex(scrollTop, rects);
|
||||
|
||||
this.children.forEach((item, index) => {
|
||||
if (index === active) {
|
||||
item.active = true;
|
||||
item.top = Math.max(0, rects[index].top - scrollTop);
|
||||
} else if (index === active - 1) {
|
||||
const activeItemTop = rects[active].top - scrollTop;
|
||||
item.active = activeItemTop > 0;
|
||||
item.top = activeItemTop - rects[active].height;
|
||||
} else {
|
||||
item.active = false;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getActiveAnchorIndex(scrollTop, rects) {
|
||||
for (let i = this.children.length - 1; i >= 0; i--) {
|
||||
const prevHeight = i > 0 ? rects[i - 1].height : 0;
|
||||
|
||||
if (scrollTop + prevHeight >= rects[i].top) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
|
||||
onClick(event) {
|
||||
this.scrollToElement(event.target);
|
||||
},
|
||||
|
||||
onTouchMove(event) {
|
||||
@@ -80,7 +145,7 @@ export default sfc({
|
||||
class={bem('sidebar')}
|
||||
style={{ zIndex: this.zIndex }}
|
||||
onClick={this.onClick}
|
||||
onTouchstart={this.onTouchStart}
|
||||
onTouchstart={this.touchStart}
|
||||
onTouchmove={this.onTouchMove}
|
||||
onTouchend={this.onTouchEnd}
|
||||
onTouchcancel={this.onTouchEnd}
|
||||
|
||||
Reference in New Issue
Block a user