antd-mini
Version:
antd-mini 是支付宝小程序 UI 组件库,遵循 Ant Design 规范。
163 lines (156 loc) • 4.49 kB
text/typescript
import createValue from '../mixins/value';
import { getInstanceBoundingClientRect } from '../_util/jsapi/get-instance-bounding-client-rect';
import { Component, getValueFromProps, triggerEvent } from '../_util/simply';
import { TabsDefaultProps } from './props';
Component({
props: TabsDefaultProps,
data: {
scrollLeft: 0,
scrollTop: 0,
leftFade: false,
rightFade: false,
},
scrollLeft: 0,
scrollTop: 0,
methods: {
getInstance() {
if (this.$id) {
return my;
}
return this;
},
get$Id() {
return this.$id ? `-${this.$id}` : '';
},
async getBoundingClientRect(query: string) {
return await getInstanceBoundingClientRect(this.getInstance(), query);
},
async updateFade() {
this.setData({
leftFade: !!this.scrollLeft,
});
const items = getValueFromProps(this, 'items');
const [view, item] = await Promise.all([
this.getBoundingClientRect(`#ant-tabs-bar-scroll-view${this.get$Id()}`),
this.getBoundingClientRect(
`#ant-tabs-bar-item${this.get$Id()}-${items.length - 1}`
),
]);
if (!item || !view) {
return;
}
this.setData({
rightFade: item.left + item.width / 2 > view.width,
});
},
async updateScroll() {
const current = this.getValue();
const [view, item] = await Promise.all([
this.getBoundingClientRect(`#ant-tabs-bar-scroll-view${this.get$Id()}`),
this.getBoundingClientRect(
`#ant-tabs-bar-item${this.get$Id()}-${current}`
),
]);
if (!view || !item) {
return;
}
const [direction, scrollMode] = getValueFromProps(this, [
'direction',
'scrollMode',
]);
if (direction === 'vertical') {
let scrollTop = this.scrollTop || 0;
let needScroll = false;
if (scrollMode === 'center') {
needScroll = true;
scrollTop +=
item.top - view.top - Math.max((view.height - item.height) / 2, 0);
} else {
const distance = item.top - view.top;
if (distance < 0) {
scrollTop += distance;
needScroll = true;
} else if (distance + item.height > view.height) {
scrollTop += Math.min(
distance + item.height - view.height,
distance
);
needScroll = true;
}
}
if (needScroll) {
if (scrollTop === this.data.scrollTop) {
scrollTop += Math.random();
}
this.setData({
scrollTop,
});
}
return;
}
let scrollLeft = this.scrollLeft || 0;
let needScroll = false;
if (scrollMode === 'center') {
needScroll = true;
scrollLeft +=
item.left - view.left - Math.max((view.width - item.width) / 2, 0);
} else {
const distance = item.left - view.left;
if (distance < 0) {
scrollLeft += distance;
needScroll = true;
} else if (distance + item.width > view.width) {
scrollLeft += Math.min(distance + item.width - view.width, distance);
needScroll = true;
}
}
if (needScroll) {
if (scrollLeft === this.data.scrollLeft) {
scrollLeft += Math.random();
}
this.setData({
scrollLeft,
});
this.updateFade();
}
},
async onScroll(e) {
const direction = getValueFromProps(this, 'direction');
if (direction === 'vertical') {
this.scrollTop = e.detail.scrollTop;
return;
}
this.scrollLeft = e.detail.scrollLeft;
this.updateFade();
},
onChange(e) {
const index = parseInt(e.currentTarget.dataset.index, 10);
const items = getValueFromProps(this, 'items');
if (items[index].disabled) {
return;
}
if (this.getValue() === index) {
return;
}
if (!this.isControlled()) {
this.update(index);
}
triggerEvent(this, 'change', index, e);
},
},
mixins: [
createValue({
valueKey: 'current',
defaultValueKey: 'defaultCurrent',
}),
],
didMount() {
this.updateScroll();
},
didUpdate(prevProps, prevData) {
const items = getValueFromProps(this, 'items');
if (prevProps.items !== items || !this.isEqualValue(prevData)) {
this.updateScroll();
}
},
});