antd-mini
Version:
antd-mini 是支付宝小程序 UI 组件库,遵循 Ant Design 规范。
157 lines (145 loc) • 4.25 kB
text/typescript
import { IBoundingClientRect } from '../_util/base';
import { getInstanceBoundingClientRect } from '../_util/jsapi/get-instance-bounding-client-rect';
import {
Component,
getValueFromProps,
triggerEventOnly,
} from '../_util/simply';
import { NoticeBarDefaultProps } from './props';
Component({
props: NoticeBarDefaultProps,
data: {
show: true,
marqueeStyle: '',
},
methods: {
getInstance() {
if (this.$id) {
return my;
}
return this;
},
async getBoundingClientRectWithId(prefix: string) {
return await getInstanceBoundingClientRect(
this.getInstance(),
`${prefix}${this.$id ? `-${this.$id}` : ''}`
);
},
onTap() {
const mode = getValueFromProps(this, 'mode');
if (mode === 'link') {
triggerEventOnly(this, 'tap');
}
if (mode === 'closeable') {
if (typeof this.props.onTap !== 'function') {
return;
}
this.setData({
show: false,
});
triggerEventOnly(this, 'tap');
}
},
startMarquee(state) {
const loop = getValueFromProps(this, 'loop');
const leading = 500;
const { duration, overflowWidth, viewWidth } = state;
let marqueeScrollWidth = overflowWidth;
if (loop) {
marqueeScrollWidth = overflowWidth + viewWidth;
}
const newMarqueeStyle = `transform: translate3d(${-marqueeScrollWidth}px, 0, 0); transition: ${duration}s all linear ${
typeof leading === 'number' ? `${leading / 1000}s` : '0s'
};`;
this.setData({
marqueeStyle: newMarqueeStyle,
});
return newMarqueeStyle;
},
measureText(callback) {
const fps = 40;
const loop = getValueFromProps(this, 'loop');
// 计算文本所占据的宽度,计算需要滚动的宽度
setTimeout(async () => {
const marqueeSize: IBoundingClientRect | null =
await this.getBoundingClientRectWithId('.ant-notice-bar-marquee');
const contentSize: IBoundingClientRect | null =
await this.getBoundingClientRectWithId('.ant-notice-bar-content');
const overflowWidth =
(marqueeSize &&
contentSize &&
marqueeSize.width - contentSize.width) ||
0;
const viewWidth = contentSize?.width || 0;
let marqueeScrollWidth = overflowWidth;
if (loop) {
marqueeScrollWidth = overflowWidth + viewWidth;
}
if (overflowWidth > 0) {
callback({
overflowWidth,
viewWidth,
duration: marqueeScrollWidth / fps,
});
}
}, 0);
},
// 文本滚动的计算
resetMarquee(state) {
const loop = getValueFromProps(this, 'loop');
const { viewWidth } = state;
let showMarqueeWidth = '0px';
if (loop) {
showMarqueeWidth = `${viewWidth}px`;
}
const marqueeStyle = `transform: translate3d(${showMarqueeWidth}, 0, 0); transition: 0s all linear;`;
this.setData({
marqueeStyle,
});
},
onTransitionEnd() {
const loop = getValueFromProps(this, 'loop');
const trailing = 200;
if (loop) {
const timer = setTimeout(() => {
this.measureText((state) => {
this.resetMarquee.call(this, state);
});
clearTimeout(timer);
}, trailing);
}
},
},
didMount() {
const { enableMarquee } = this.props;
if (enableMarquee) {
this.measureText((state) => {
this.startMarquee.call(this, state);
});
}
},
didUpdate() {
const { enableMarquee } = this.props;
// 这里更新处理的原因是防止notice内容在动画过程中发生改变。
if (enableMarquee) {
this.measureText((state) => {
this.startMarquee.call(this, state);
});
}
},
pageEvents: {
onShow() {
if (this.props.enableMarquee) {
this.setData({ marqueeStyle: '' });
this.resetMarquee({
overflowWidth: 0,
duration: 0,
viewWidth: 0,
});
this.measureText((state) => {
this.startMarquee.call(this, state);
});
}
},
},
});