mirror of
https://gitee.com/vant-contrib/vant-weapp.git
synced 2025-04-05 19:41:45 +08:00
refactor(Tab): refactor component with Sticky (#2285)
fix #2253 #2122 Tab support css variables
This commit is contained in:
parent
13b05cfa9c
commit
66fbfacf19
@ -57,7 +57,7 @@
|
||||
</demo-block>
|
||||
|
||||
<demo-block title="样式风格">
|
||||
<van-tabs type="card" tab-class="tab-class" tab-active-class="tab-active-class">
|
||||
<van-tabs type="card" tab-class="tab-class">
|
||||
<van-tab
|
||||
wx:for="123"
|
||||
wx:key="index"
|
||||
|
@ -14,6 +14,7 @@ page {
|
||||
.right-nav {
|
||||
padding: 0 10px;
|
||||
line-height: 44px !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.tab-class {
|
||||
|
@ -442,6 +442,20 @@
|
||||
@tabbar-item-icon-size: 18px;
|
||||
@tabbar-item-margin-bottom: 5px;
|
||||
|
||||
// Tab
|
||||
@tab-text-color: @gray-darker;
|
||||
@tab-active-text-color: @text-color;
|
||||
@tab-disabled-text-color: @gray;
|
||||
@tab-font-size: @font-size-md;
|
||||
|
||||
// Tabs
|
||||
@tabs-default-color: @red;
|
||||
@tabs-line-height: 44px;
|
||||
@tabs-card-height: 30px;
|
||||
@tabs-nav-background-color: @white;
|
||||
@tabs-bottom-bar-height: 3px;
|
||||
@tabs-bottom-bar-color: @tabs-default-color;
|
||||
|
||||
// Tag
|
||||
@tag-padding: .2em .5em;
|
||||
@tag-font-size: @font-size-xs;
|
||||
|
@ -1,3 +1,11 @@
|
||||
.van-sticky {
|
||||
position: relative;
|
||||
|
||||
&-wrap {
|
||||
&--fixed {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,4 @@
|
||||
import { VantComponent } from '../common/component';
|
||||
import { nextTick } from '../common/utils';
|
||||
|
||||
type Position = 'top' | 'bottom' | '';
|
||||
|
||||
VantComponent({
|
||||
props: {
|
||||
@ -12,131 +9,69 @@ VantComponent({
|
||||
offsetTop: {
|
||||
type: Number,
|
||||
value: 0
|
||||
}
|
||||
},
|
||||
disabled: Boolean
|
||||
},
|
||||
|
||||
data: {
|
||||
position: '', // 当前定位
|
||||
height: 0,
|
||||
wrapStyle: '',
|
||||
containerStyle: ''
|
||||
},
|
||||
|
||||
methods: {
|
||||
setWrapStyle() {
|
||||
const { offsetTop, position } = this.data;
|
||||
let wrapStyle: string;
|
||||
let containerStyle: string;
|
||||
setStyle() {
|
||||
const { offsetTop, height, fixed, zIndex } = this.data;
|
||||
|
||||
switch (position) {
|
||||
case 'top':
|
||||
wrapStyle = `
|
||||
top: ${offsetTop}px;
|
||||
position: fixed;
|
||||
`;
|
||||
containerStyle = `height: ${this.itemHeight}px;`;
|
||||
break;
|
||||
case 'bottom':
|
||||
wrapStyle = `
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
`;
|
||||
containerStyle = '';
|
||||
break;
|
||||
default:
|
||||
wrapStyle = '';
|
||||
containerStyle = '';
|
||||
}
|
||||
|
||||
const data: Record<string, string> = {};
|
||||
|
||||
if (wrapStyle !== this.data.wrapStyle) {
|
||||
data.wrapStyle = wrapStyle;
|
||||
}
|
||||
|
||||
if (containerStyle !== this.data.containerStyle) {
|
||||
data.containerStyle = containerStyle;
|
||||
}
|
||||
|
||||
if (JSON.stringify(data) !== '{}') {
|
||||
this.setData(data);
|
||||
}
|
||||
},
|
||||
|
||||
setPosition(position: Position) {
|
||||
if (position !== this.data.position) {
|
||||
this.setData({ position });
|
||||
nextTick(() => {
|
||||
this.setWrapStyle();
|
||||
if (fixed) {
|
||||
this.setData({
|
||||
wrapStyle: `top: ${offsetTop}px;`,
|
||||
containerStyle: `height: ${height}px; z-index: ${zIndex};`
|
||||
});
|
||||
} else {
|
||||
this.setData({
|
||||
wrapStyle: '',
|
||||
containerStyle: ''
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
observerContentScroll() {
|
||||
const { offsetTop = 0 } = this.data;
|
||||
const { windowHeight } = wx.getSystemInfoSync();
|
||||
|
||||
this.createIntersectionObserver({}).disconnect();
|
||||
|
||||
// @ts-ignore
|
||||
this.createIntersectionObserver()
|
||||
.relativeToViewport({ top: -(this.itemHeight + offsetTop) })
|
||||
.observe(
|
||||
const { offsetTop } = this.data;
|
||||
const intersectionObserver = this.createIntersectionObserver({
|
||||
thresholds: [0, 1]
|
||||
});
|
||||
this.intersectionObserver = intersectionObserver;
|
||||
intersectionObserver.relativeToViewport({ top: -offsetTop });
|
||||
intersectionObserver.observe(
|
||||
'.van-sticky',
|
||||
(res: WechatMiniprogram.ObserveCallbackResult) => {
|
||||
const { top } = res.boundingClientRect;
|
||||
|
||||
if (top > offsetTop) {
|
||||
(res) => {
|
||||
if (this.data.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const position: Position = 'top';
|
||||
|
||||
this.$emit('scroll', {
|
||||
scrollTop: top + offsetTop,
|
||||
isFixed: true
|
||||
});
|
||||
|
||||
this.setPosition(position);
|
||||
}
|
||||
);
|
||||
|
||||
// @ts-ignore
|
||||
this.createIntersectionObserver()
|
||||
.relativeToViewport({ bottom: -(windowHeight - 1 - offsetTop) })
|
||||
.observe(
|
||||
'.van-sticky',
|
||||
(res: WechatMiniprogram.ObserveCallbackResult) => {
|
||||
const { top, bottom } = res.boundingClientRect;
|
||||
|
||||
if (bottom <= this.itemHeight - 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const position: Position = res.intersectionRatio > 0 ? 'top' : '';
|
||||
const { top, height } = res.boundingClientRect;
|
||||
const fixed = top <= offsetTop;
|
||||
|
||||
this.$emit('scroll', {
|
||||
scrollTop: top + offsetTop,
|
||||
isFixed: position === 'top'
|
||||
scrollTop: top,
|
||||
isFixed: fixed
|
||||
});
|
||||
|
||||
this.setPosition(position);
|
||||
this.setData({ fixed, height });
|
||||
|
||||
wx.nextTick(() => {
|
||||
this.setStyle();
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.getRect('.van-sticky').then(
|
||||
(rect: WechatMiniprogram.BoundingClientRectCallbackResult) => {
|
||||
this.itemHeight = rect.height;
|
||||
this.itemTop = rect.top;
|
||||
this.observerContentScroll();
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
this.createIntersectionObserver({}).disconnect();
|
||||
this.intersectionObserver.disconnect();
|
||||
}
|
||||
});
|
||||
|
@ -1,5 +1,7 @@
|
||||
<view class="custom-class van-sticky" style="z-index: {{ zIndex }}; {{ containerStyle }}">
|
||||
<view class="van-sticky-wrap" style="{{ wrapStyle }}">
|
||||
<wxs src="../wxs/utils.wxs" module="utils" />
|
||||
|
||||
<view class="custom-class van-sticky }}" style="{{ containerStyle }}">
|
||||
<view class="{{ utils.bem('sticky-wrap', { fixed }) }}" style="{{ wrapStyle }}">
|
||||
<slot />
|
||||
</view>
|
||||
</view>
|
||||
|
@ -3,7 +3,13 @@ import { VantComponent } from '../common/component';
|
||||
VantComponent({
|
||||
relation: {
|
||||
name: 'tabs',
|
||||
type: 'ancestor'
|
||||
type: 'ancestor',
|
||||
linked(target) {
|
||||
this.parent = target;
|
||||
},
|
||||
unlinked() {
|
||||
this.parent = null;
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
@ -15,7 +21,6 @@ VantComponent({
|
||||
name: {
|
||||
type: [Number, String],
|
||||
value: '',
|
||||
observer: 'setComputedName'
|
||||
}
|
||||
},
|
||||
|
||||
@ -39,10 +44,16 @@ VantComponent({
|
||||
this.computedName = this.data.name || this.index;
|
||||
},
|
||||
|
||||
getComputedName() {
|
||||
if (this.data.name !== '') {
|
||||
return this.data.name;
|
||||
}
|
||||
return this.index;
|
||||
},
|
||||
|
||||
update() {
|
||||
const parent = this.getRelationNodes('../tabs/index')[0];
|
||||
if (parent) {
|
||||
parent.updateTabs();
|
||||
if (this.parent) {
|
||||
this.parent.updateTabs();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"van-info": "../info/index"
|
||||
"van-info": "../info/index",
|
||||
"van-sticky": "../sticky/index"
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +1,13 @@
|
||||
@import '../common/style/var.less';
|
||||
@import '../common/style/theme.less';
|
||||
|
||||
@tabs-line-height: 44px;
|
||||
@tabs-card-height: 30px;
|
||||
|
||||
.van-tabs {
|
||||
position: relative;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
|
||||
&__wrap {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
.theme(background-color, '@white');
|
||||
|
||||
&--page-top {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
&--content-bottom {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
}
|
||||
overflow: hidden;
|
||||
|
||||
&--scrollable {
|
||||
.van-tab {
|
||||
@ -32,9 +16,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
&__scroll--card {
|
||||
border-radius: 2px;
|
||||
.theme(border, '1px solid @red');
|
||||
&__scroll {
|
||||
.theme(background-color, '@tabs-nav-background-color');
|
||||
|
||||
&--line {
|
||||
box-sizing: content-box;
|
||||
height: calc(100% + 15px); /* 15px padding to hide scrollbar in mobile safari */
|
||||
}
|
||||
|
||||
&--card {
|
||||
.theme(margin, '0 @padding-md');
|
||||
}
|
||||
}
|
||||
|
||||
&__nav {
|
||||
@ -42,17 +34,16 @@
|
||||
display: flex;
|
||||
user-select: none;
|
||||
|
||||
&--line {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&--card {
|
||||
box-sizing: border-box;
|
||||
.theme(height, '@tabs-card-height');
|
||||
.theme(border, '@border-width-base solid @tabs-default-color');
|
||||
.theme(border-radius, '@border-radius-sm');
|
||||
|
||||
.van-tab {
|
||||
.theme(color, '@red');
|
||||
.theme(line-height, '@tabs-card-height');
|
||||
.theme(border-right, '1px solid @red');
|
||||
.theme(color, '@tabs-default-color');
|
||||
.theme(line-height, 'calc(@tabs-card-height - 2 * @border-width-base)');
|
||||
.theme(border-right, '@border-width-base solid @tabs-default-color');
|
||||
|
||||
&:last-child {
|
||||
border-right: none;
|
||||
@ -60,7 +51,11 @@
|
||||
|
||||
&.van-tab--active {
|
||||
.theme(color, '@white');
|
||||
.theme(background-color, '@red');
|
||||
.theme(background-color, '@tabs-default-color');
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
.theme(color, '@tab-disabled-text-color');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -71,34 +66,29 @@
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
height: 3px;
|
||||
border-radius: 3px;
|
||||
.theme(background-color, '@red');
|
||||
.theme(height, '@tabs-bottom-bar-height');
|
||||
.theme(border-radius, '@tabs-bottom-bar-height');
|
||||
.theme(background-color, '@tabs-bottom-bar-color');
|
||||
}
|
||||
|
||||
&--line {
|
||||
.theme(padding-top, '@tabs-line-height');
|
||||
|
||||
.van-tabs__wrap {
|
||||
.theme(height, '@tabs-line-height');
|
||||
}
|
||||
}
|
||||
|
||||
&--card {
|
||||
margin: 0 15px;
|
||||
.theme(padding-top, '@tabs-card-height');
|
||||
|
||||
.van-tabs__wrap {
|
||||
.theme(height, '@tabs-card-height');
|
||||
}
|
||||
&__track {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&__content {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&__track {
|
||||
position: relative;
|
||||
&--line {
|
||||
.van-tabs__wrap {
|
||||
.theme(height, '@tabs-line-height');
|
||||
}
|
||||
}
|
||||
|
||||
&--card {
|
||||
.van-tabs__wrap {
|
||||
.theme(height, '@tabs-card-height');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,19 +98,19 @@
|
||||
box-sizing: border-box;
|
||||
min-width: 0; /* hack for flex ellipsis */
|
||||
padding: 0 5px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
.theme(color, '@gray-darker');
|
||||
.theme(color, '@tab-text-color');
|
||||
.theme(font-size, '@tab-font-size');
|
||||
.theme(line-height, '@tabs-line-height');
|
||||
|
||||
&--active {
|
||||
font-weight: 500;
|
||||
.theme(color, '@text-color');
|
||||
.theme(font-weight, '@font-weight-bold');
|
||||
.theme(color, '@tab-active-text-color');
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
.theme(color, '@gray');
|
||||
.theme(color, '@tab-disabled-text-color');
|
||||
}
|
||||
|
||||
&__title {
|
||||
|
@ -4,15 +4,13 @@ import { Weapp } from 'definitions/weapp';
|
||||
import { nextTick, isDef, addUnit } from '../common/utils';
|
||||
|
||||
type TabItemData = {
|
||||
width?: number
|
||||
active: boolean
|
||||
inited?: boolean
|
||||
animated?: boolean
|
||||
name?: string | number
|
||||
width?: number;
|
||||
active: boolean;
|
||||
inited?: boolean;
|
||||
animated?: boolean;
|
||||
name?: string | number;
|
||||
};
|
||||
|
||||
type Position = 'top' | 'bottom' | '';
|
||||
|
||||
VantComponent({
|
||||
mixins: [touch],
|
||||
|
||||
@ -23,7 +21,6 @@ VantComponent({
|
||||
type: 'descendant',
|
||||
linked(child) {
|
||||
child.index = this.children.length;
|
||||
child.setComputedName();
|
||||
this.children.push(child);
|
||||
this.updateTabs(this.data.tabs.concat(child.data));
|
||||
},
|
||||
@ -37,7 +34,6 @@ VantComponent({
|
||||
while (i >= 0 && i < this.children.length) {
|
||||
const currentChild = this.children[i];
|
||||
currentChild.index--;
|
||||
currentChild.setComputedName();
|
||||
i++;
|
||||
}
|
||||
|
||||
@ -46,21 +42,33 @@ VantComponent({
|
||||
},
|
||||
|
||||
props: {
|
||||
color: String,
|
||||
color: {
|
||||
type: String,
|
||||
observer: 'setLine'
|
||||
},
|
||||
sticky: Boolean,
|
||||
animated: Boolean,
|
||||
animated: {
|
||||
type: Boolean,
|
||||
observer: 'setTrack'
|
||||
},
|
||||
swipeable: Boolean,
|
||||
lineWidth: {
|
||||
type: [String, Number],
|
||||
value: -1
|
||||
value: -1,
|
||||
observer: 'setLine'
|
||||
},
|
||||
lineHeight: {
|
||||
type: [String, Number],
|
||||
value: -1
|
||||
value: -1,
|
||||
observer: 'setLine'
|
||||
},
|
||||
active: {
|
||||
type: [String, Number],
|
||||
value: 0,
|
||||
observer(value) {
|
||||
this.currentName = value;
|
||||
this.setActiveTab();
|
||||
}
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
@ -80,7 +88,12 @@ VantComponent({
|
||||
},
|
||||
swipeThreshold: {
|
||||
type: Number,
|
||||
value: 4
|
||||
value: 4,
|
||||
observer() {
|
||||
this.setData({
|
||||
scrollable: this.children.length > this.data.swipeThreshold
|
||||
});
|
||||
}
|
||||
},
|
||||
offsetTop: {
|
||||
type: Number,
|
||||
@ -96,21 +109,7 @@ VantComponent({
|
||||
trackStyle: '',
|
||||
wrapStyle: '',
|
||||
position: '',
|
||||
currentIndex: 0,
|
||||
},
|
||||
|
||||
watch: {
|
||||
swipeThreshold() {
|
||||
this.setData({
|
||||
scrollable: this.children.length > this.data.swipeThreshold
|
||||
});
|
||||
},
|
||||
color: 'setLine',
|
||||
lineWidth: 'setLine',
|
||||
lineHeight: 'setLine',
|
||||
active: 'setActiveTab',
|
||||
animated: 'setTrack',
|
||||
offsetTop: 'setWrapStyle'
|
||||
currentIndex: 0
|
||||
},
|
||||
|
||||
beforeCreate() {
|
||||
@ -121,17 +120,6 @@ VantComponent({
|
||||
this.setLine(true);
|
||||
this.setTrack();
|
||||
this.scrollIntoView();
|
||||
this.getRect('.van-tabs__wrap').then(
|
||||
(rect: WechatMiniprogram.BoundingClientRectCallbackResult) => {
|
||||
this.navHeight = rect.height;
|
||||
this.observerContentScroll();
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
// @ts-ignore
|
||||
this.createIntersectionObserver().disconnect();
|
||||
},
|
||||
|
||||
methods: {
|
||||
@ -156,18 +144,20 @@ VantComponent({
|
||||
onTap(event: Weapp.Event) {
|
||||
const { index } = event.currentTarget.dataset;
|
||||
const child = this.children[index];
|
||||
const computedName = child.getComputedName();
|
||||
|
||||
if (this.data.tabs[index].disabled) {
|
||||
this.trigger('disabled', child.computedName);
|
||||
this.trigger('disabled', computedName);
|
||||
} else {
|
||||
this.trigger('click', child.computedName);
|
||||
this.setActive(child.computedName);
|
||||
this.trigger('click', computedName);
|
||||
this.setActive(computedName);
|
||||
}
|
||||
},
|
||||
|
||||
setActive(computedName) {
|
||||
if (computedName !== this.currentName) {
|
||||
this.currentName = computedName;
|
||||
this.trigger('change', computedName);
|
||||
setActive(name) {
|
||||
if (name !== this.currentName) {
|
||||
this.currentName = name;
|
||||
this.trigger('change', name);
|
||||
this.setActiveTab();
|
||||
}
|
||||
},
|
||||
@ -177,13 +167,22 @@ VantComponent({
|
||||
return;
|
||||
}
|
||||
|
||||
const { color, duration, currentIndex, lineWidth, lineHeight } = this.data;
|
||||
const {
|
||||
color,
|
||||
duration,
|
||||
currentIndex,
|
||||
lineWidth,
|
||||
lineHeight
|
||||
} = this.data;
|
||||
|
||||
this.getRect('.van-tab', true).then(
|
||||
(rects: WechatMiniprogram.BoundingClientRectCallbackResult[]) => {
|
||||
const rect = rects[currentIndex];
|
||||
const width = lineWidth !== -1 ? lineWidth : rect.width / 2;
|
||||
const height = lineHeight !== -1 ? `height: ${addUnit(lineHeight)}; border-radius: ${addUnit(lineHeight)};` : '';
|
||||
const height =
|
||||
lineHeight !== -1
|
||||
? `height: ${addUnit(lineHeight)}; border-radius: ${addUnit(lineHeight)};`
|
||||
: '';
|
||||
|
||||
let left = rects
|
||||
.slice(0, currentIndex)
|
||||
@ -230,34 +229,42 @@ VantComponent({
|
||||
|
||||
const data = { width, animated };
|
||||
|
||||
this.children.forEach((item: WechatMiniprogram.Component.TrivialInstance) => {
|
||||
this.children.forEach(
|
||||
(item: WechatMiniprogram.Component.TrivialInstance) => {
|
||||
item.setData(data);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
setActiveTab() {
|
||||
if (!isDef(this.currentName)) {
|
||||
this.currentName = this.data.active || (this.children[0] || {}).computedName;
|
||||
const { active } = this.data;
|
||||
const { children = [] } = this;
|
||||
|
||||
this.currentName =
|
||||
active === '' && children.length
|
||||
? children[0].getComputedName()
|
||||
: active;
|
||||
}
|
||||
|
||||
this.children.forEach((item: WechatMiniprogram.Component.TrivialInstance, index: number) => {
|
||||
this.children.forEach(
|
||||
(item: WechatMiniprogram.Component.TrivialInstance, index: number) => {
|
||||
const data: TabItemData = {
|
||||
active: item.computedName === this.currentName
|
||||
active: item.getComputedName() === this.currentName
|
||||
};
|
||||
|
||||
if (data.active) {
|
||||
this.setData({
|
||||
currentIndex: index
|
||||
});
|
||||
this.setData({ currentIndex: index });
|
||||
data.inited = true;
|
||||
}
|
||||
|
||||
if (data.active !== item.data.active) {
|
||||
item.setData(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
nextTick(() => {
|
||||
this.setLine();
|
||||
@ -317,101 +324,13 @@ VantComponent({
|
||||
|
||||
if (direction === 'horizontal' && offsetX >= minSwipeDistance) {
|
||||
if (deltaX > 0 && currentIndex !== 0) {
|
||||
this.setActive(this.children[currentIndex - 1].computedName);
|
||||
const child = this.children[currentIndex - 1];
|
||||
this.setActive(child.getComputedName());
|
||||
} else if (deltaX < 0 && currentIndex !== tabs.length - 1) {
|
||||
this.setActive(this.children[currentIndex + 1].computedName);
|
||||
const child = this.children[currentIndex - 1];
|
||||
this.setActive(child.getComputedName());
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
setWrapStyle() {
|
||||
const { offsetTop, position } = this.data as {
|
||||
offsetTop: number
|
||||
position: Position
|
||||
};
|
||||
let wrapStyle: string;
|
||||
|
||||
switch (position) {
|
||||
case 'top':
|
||||
wrapStyle = `
|
||||
top: ${offsetTop}px;
|
||||
position: fixed;
|
||||
`;
|
||||
break;
|
||||
case 'bottom':
|
||||
wrapStyle = `
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
`;
|
||||
break;
|
||||
default:
|
||||
wrapStyle = '';
|
||||
}
|
||||
|
||||
if (wrapStyle !== this.data.wrapStyle) {
|
||||
this.setData({ wrapStyle });
|
||||
}
|
||||
},
|
||||
|
||||
observerContentScroll() {
|
||||
if (!this.data.sticky) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { offsetTop } = this.data;
|
||||
const { windowHeight } = wx.getSystemInfoSync();
|
||||
|
||||
// @ts-ignore
|
||||
this.createIntersectionObserver().disconnect();
|
||||
|
||||
// @ts-ignore
|
||||
this.createIntersectionObserver()
|
||||
.relativeToViewport({ top: -(this.navHeight + offsetTop) })
|
||||
.observe('.van-tabs', (res: WechatMiniprogram.ObserveCallbackResult) => {
|
||||
const { top } = res.boundingClientRect;
|
||||
|
||||
if (top > offsetTop) {
|
||||
return;
|
||||
}
|
||||
|
||||
const position: Position =
|
||||
res.intersectionRatio > 0 ? 'top' : 'bottom';
|
||||
|
||||
this.$emit('scroll', {
|
||||
scrollTop: top + offsetTop,
|
||||
isFixed: position === 'top'
|
||||
});
|
||||
|
||||
this.setPosition(position);
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
this.createIntersectionObserver()
|
||||
.relativeToViewport({ bottom: -(windowHeight - 1 - offsetTop) })
|
||||
.observe('.van-tabs', (res: WechatMiniprogram.ObserveCallbackResult) => {
|
||||
const { top, bottom } = res.boundingClientRect;
|
||||
|
||||
if (bottom < this.navHeight) {
|
||||
return;
|
||||
}
|
||||
|
||||
const position: Position = res.intersectionRatio > 0 ? 'top' : '';
|
||||
|
||||
this.$emit('scroll', {
|
||||
scrollTop: top + offsetTop,
|
||||
isFixed: position === 'top'
|
||||
});
|
||||
|
||||
this.setPosition(position);
|
||||
});
|
||||
},
|
||||
|
||||
setPosition(position: Position) {
|
||||
if (position !== this.data.position) {
|
||||
this.set({ position }).then(() => {
|
||||
this.setWrapStyle();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,14 +1,15 @@
|
||||
<wxs src="../wxs/utils.wxs" module="utils" />
|
||||
|
||||
<view class="custom-class {{ utils.bem('tabs', [type]) }}">
|
||||
<view style="z-index: {{ zIndex }}; {{ wrapStyle }}" class="{{ utils.bem('tabs__wrap', { scrollable }) }} {{ type === 'line' && border ? 'van-hairline--top-bottom' : '' }}">
|
||||
<van-sticky disabled="{{ !sticky }}" z-index="{{ zIndex }}" offset-top="{{ offsetTop }}">
|
||||
<view class="{{ utils.bem('tabs__wrap', { scrollable }) }} {{ type === 'line' && border ? 'van-hairline--top-bottom' : '' }}">
|
||||
<slot name="nav-left" />
|
||||
|
||||
<scroll-view
|
||||
scroll-x="{{ scrollable }}"
|
||||
scroll-with-animation
|
||||
scroll-left="{{ scrollLeft }}"
|
||||
class="van-tabs__scroll--{{ type }}"
|
||||
class="{{ utils.bem('tabs__scroll', [type]) }}"
|
||||
style="{{ color ? 'border-color: ' + color : '' }}"
|
||||
>
|
||||
<view class="{{ utils.bem('tabs__nav', [type]) }} nav-class">
|
||||
@ -36,6 +37,8 @@
|
||||
|
||||
<slot name="nav-right" />
|
||||
</view>
|
||||
</van-sticky>
|
||||
|
||||
<view
|
||||
class="van-tabs__content"
|
||||
bind:touchstart="onTouchStart"
|
||||
|
Loading…
x
Reference in New Issue
Block a user