[improvement] Tabs:sticky实现优化,不依赖外层的scrollTop (#1197)

This commit is contained in:
张敏 2019-01-10 17:34:21 +08:00 committed by neverland
parent 96c2a3af76
commit f5306b88c1
4 changed files with 51 additions and 42 deletions

View File

@ -3,8 +3,7 @@ import Page from '../../common/page';
Page({ Page({
data: { data: {
tabs: [1, 2, 3, 4], tabs: [1, 2, 3, 4],
tabsMore: [1, 2, 3, 4, 5, 6, 7, 8], tabsMore: [1, 2, 3, 4, 5, 6, 7, 8]
scrollTop: 0
}, },
onClickDisabled(event) { onClickDisabled(event) {
@ -26,11 +25,5 @@ Page({
title: `点击标签 ${event.detail.index + 1}`, title: `点击标签 ${event.detail.index + 1}`,
icon: 'none' icon: 'none'
}); });
},
onPageScroll(event) {
this.setData({
scrollTop: event.scrollTop
});
} }
}); });

View File

@ -87,7 +87,7 @@
</demo-block> </demo-block>
<demo-block title="粘性布局"> <demo-block title="粘性布局">
<van-tabs sticky scroll-top="{{ scrollTop }}"> <van-tabs sticky>
<van-tab <van-tab
wx:for="1234" wx:for="1234"
wx:key="index" wx:key="index"

View File

@ -179,7 +179,6 @@ Page({
| swipeable | 是否开启手势滑动切换 | `Boolean` | `false` | | swipeable | 是否开启手势滑动切换 | `Boolean` | `false` |
| sticky | 是否使用粘性定位布局 | `Boolean` | `false` | | sticky | 是否使用粘性定位布局 | `Boolean` | `false` |
| offset-top | 粘性定位布局下与顶部的最小距离,单位 px | `Number` | `0` | | offset-top | 粘性定位布局下与顶部的最小距离,单位 px | `Number` | `0` |
| scroll-top | 页面的`scrollTop`,粘性布局下必须要传入,单位 px | `Number` | `0` |
### Tab API ### Tab API

View File

@ -63,11 +63,7 @@ VantComponent({
type: Number, type: Number,
value: 0 value: 0
}, },
swipeable: Boolean, swipeable: Boolean
scrollTop: {
type: Number,
value: 0
}
}, },
data: { data: {
@ -90,7 +86,6 @@ VantComponent({
lineWidth: 'setLine', lineWidth: 'setLine',
active: 'setActiveTab', active: 'setActiveTab',
animated: 'setTrack', animated: 'setTrack',
scrollTop: 'onScroll',
offsetTop: 'setWrapStyle' offsetTop: 'setWrapStyle'
}, },
@ -102,6 +97,12 @@ VantComponent({
this.setLine(); this.setLine();
this.setTrack(); this.setTrack();
this.scrollIntoView(); this.scrollIntoView();
this.observerTabScroll();
this.observerContentScroll();
},
destroyed() {
wx.createIntersectionObserver(this).disconnect();
}, },
methods: { methods: {
@ -310,39 +311,55 @@ VantComponent({
}); });
}, },
// adjust tab position observerTabScroll() {
onScroll(scrollTop) {
if (!this.data.sticky) return; if (!this.data.sticky) return;
const { offsetTop } = this.data; const { offsetTop } = this.data;
wx.createIntersectionObserver(this, {
thresholds: [1]
}).relativeToViewport().observe('.van-tabs', result => {
const { top } = result.boundingClientRect;
let position = '';
this.getRect('.van-tabs').then(rect => { if (offsetTop > top) {
const { top, height } = rect; position = 'top';
}
this.getRect('.van-tabs__wrap').then(rect => { this.$emit('scroll', {
const { height: wrapHeight } = rect; scrollTop: top + offsetTop,
let position = ''; isFixed: position === 'top'
if (offsetTop > top + height - wrapHeight) {
position = 'bottom';
} else if (offsetTop > top) {
position = 'top';
}
this.$emit('scroll', {
scrollTop: scrollTop + offsetTop,
isFixed: position === 'top'
});
if (position !== this.data.position) {
this.set({
position
}, () => {
this.setWrapStyle();
});
}
}); });
this.setPosition(position);
}); });
},
observerContentScroll() {
if (!this.data.sticky) return;
const { offsetTop } = this.data;
wx.createIntersectionObserver(this).relativeToViewport().observe('.van-tabs__content', result => {
const { top } = result.boundingClientRect;
let position = '';
if (result.intersectionRatio <= 0) {
position = 'bottom';
} else if (offsetTop > top) {
position = 'top';
}
this.setPosition(position);
});
},
setPosition(position) {
if (position !== this.data.position) {
this.set({
position
}, () => {
this.setWrapStyle();
});
}
} }
} }
}); });