diff --git a/packages/common/utils.ts b/packages/common/utils.ts index cb53ccfd..9cf3d061 100644 --- a/packages/common/utils.ts +++ b/packages/common/utils.ts @@ -21,7 +21,7 @@ export function nextTick(fn: Function) { }, 1000 / 30); } -let systemInfo: WechatMiniprogram.GetSystemInfoSyncResult = null; +let systemInfo: WechatMiniprogram.GetSystemInfoSyncResult; export function getSystemInfoSync() { if (systemInfo == null) { systemInfo = wx.getSystemInfoSync(); @@ -54,3 +54,29 @@ export function requestAnimationFrame(cb: Function) { cb(); }); } + +export function getRect( + this: WechatMiniprogram.Component.TrivialInstance, + selector: string +): Promise { + return new Promise((resolve) => { + wx.createSelectorQuery() + .in(this) + .select(selector) + .boundingClientRect() + .exec((rect = []) => resolve(rect[0])); + }); +} + +export function getAllRect( + this: WechatMiniprogram.Component.TrivialInstance, + selector: string +): Promise { + return new Promise((resolve) => { + wx.createSelectorQuery() + .in(this) + .selectAll(selector) + .boundingClientRect() + .exec((rect = []) => resolve(rect[0])); + }); +} diff --git a/packages/tabs/index.ts b/packages/tabs/index.ts index 3a885b2f..427840ba 100644 --- a/packages/tabs/index.ts +++ b/packages/tabs/index.ts @@ -1,7 +1,7 @@ import { VantComponent } from '../common/component'; import { touch } from '../mixins/touch'; import { Weapp } from 'definitions/weapp'; -import { isDef, addUnit } from '../common/utils'; +import { getAllRect, getRect, isDef } from '../common/utils'; type TrivialInstance = WechatMiniprogram.Component.TrivialInstance; @@ -35,10 +35,7 @@ VantComponent({ swipeable: Boolean, titleActiveColor: String, titleInactiveColor: String, - color: { - type: String, - observer: 'setLine', - }, + color: String, animated: { type: Boolean, observer() { @@ -55,7 +52,6 @@ VantComponent({ lineHeight: { type: [String, Number], value: -1, - observer: 'setLine', }, active: { type: [String, Number], @@ -102,13 +98,15 @@ VantComponent({ }, data: { - tabs: [], + tabs: [] as Record[], lineStyle: '', scrollLeft: 0, scrollable: false, trackStyle: '', - currentIndex: null, + currentIndex: 0, container: null, + skipTransition: true, + lineOffsetLeft: 0, }, mounted() { @@ -223,54 +221,34 @@ VantComponent({ } }, - setLine(skipTransition?: boolean) { + setLine(skipTransition = false) { if (this.data.type !== 'line') { return; } - const { - color, - duration, - currentIndex, - lineWidth, - lineHeight, - } = this.data; + const { currentIndex } = this.data; - this.getRect('.van-tab', true).then( - (rects: WechatMiniprogram.BoundingClientRectCallbackResult[] = []) => { - const rect = rects[currentIndex]; - if (rect == null) { - return; - } - const height = - lineHeight !== -1 - ? `height: ${addUnit(lineHeight)}; border-radius: ${addUnit( - lineHeight - )};` - : ''; + Promise.all([ + getAllRect.call(this, '.van-tab'), + getRect.call(this, '.van-tabs__line'), + ]).then(([rects = [], lineRect]) => { + const rect = rects[currentIndex]; - let left = rects - .slice(0, currentIndex) - .reduce((prev, curr) => prev + curr.width, 0); - - left += (rect.width - lineWidth) / 2; - - const transition = skipTransition - ? '' - : `transition-duration: ${duration}s; -webkit-transition-duration: ${duration}s;`; - - this.setData({ - lineStyle: ` - ${height} - width: ${addUnit(lineWidth)}; - background-color: ${color}; - -webkit-transform: translateX(${left}px); - transform: translateX(${left}px); - ${transition} - `, - }); + if (rect == null) { + return; } - ); + + let lineOffsetLeft = rects + .slice(0, currentIndex) + .reduce((prev, curr) => prev + curr.width, 0); + + lineOffsetLeft += (rect.width - lineRect.width) / 2; + + this.setData({ + lineOffsetLeft, + skipTransition, + }); + }); }, // scroll active tab into view @@ -282,23 +260,18 @@ VantComponent({ } Promise.all([ - this.getRect('.van-tab', true), - this.getRect('.van-tabs__nav'), - ]).then( - ([tabRects, navRect]: [ - WechatMiniprogram.BoundingClientRectCallbackResult[], - WechatMiniprogram.BoundingClientRectCallbackResult - ]) => { - const tabRect = tabRects[currentIndex]; - const offsetLeft = tabRects - .slice(0, currentIndex) - .reduce((prev, curr) => prev + curr.width, 0); + getAllRect.call(this, '.van-tab'), + getRect.call(this, '.van-tabs__nav'), + ]).then(([tabRects, navRect]) => { + const tabRect = tabRects[currentIndex]; + const offsetLeft = tabRects + .slice(0, currentIndex) + .reduce((prev, curr) => prev + curr.width, 0); - this.setData({ - scrollLeft: offsetLeft - (navRect.width - tabRect.width) / 2, - }); - } - ); + this.setData({ + scrollLeft: offsetLeft - (navRect.width - tabRect.width) / 2, + }); + }); }, onTouchScroll(event: Weapp.TouchEvent) { diff --git a/packages/tabs/index.wxml b/packages/tabs/index.wxml index da4caa6f..dd92ac49 100644 --- a/packages/tabs/index.wxml +++ b/packages/tabs/index.wxml @@ -20,7 +20,7 @@ style="{{ color ? 'border-color: ' + color : '' }}" > - + - \ No newline at end of file + diff --git a/packages/tabs/index.wxs b/packages/tabs/index.wxs index 88bcafd3..87b553f5 100644 --- a/packages/tabs/index.wxs +++ b/packages/tabs/index.wxs @@ -1,4 +1,6 @@ /* eslint-disable */ +var utils = require('../wxs/utils.wxs'); + function tabClass(active, ellipsis) { var classes = ['tab-class']; @@ -68,11 +70,42 @@ function trackStyle(data) { return [ 'transform: translate3d(' + -100 * data.currentIndex + '%, 0, 0)', '-webkit-transition-duration: ' + data.duration + 's', - 'transition-duration: ' + data.duration + 's' + 'transition-duration: ' + data.duration + 's', ].join(';'); } -module.exports.tabClass = tabClass; -module.exports.tabStyle = tabStyle; -module.exports.trackStyle = trackStyle; -module.exports.tabCardTypeBorderStyle = tabCardTypeBorderStyle; +function lineStyle(data) { + var styles = [ + ['width', utils.addUnit(data.lineWidth)], + ['transform', 'translateX(' + data.lineOffsetLeft + 'px)'], + ['-webkit-transform', 'translateX(' + data.lineOffsetLeft + 'px)'], + ]; + + if (data.color) { + styles.push(['background-color', data.color]); + } + + if (data.lineHeight !== -1) { + styles.push(['height', utils.addUnit(data.lineHeight)]); + styles.push(['border-radius', utils.addUnit(data.lineHeight)]); + } + + if (!data.skipTransition) { + styles.push(['transition-duration', data.duration + 's']); + styles.push(['-webkit-transition-duration', data.duration + 's']); + } + + return styles + .map(function (item) { + return item.join(':'); + }) + .join(';'); +} + +module.exports = { + tabClass: tabClass, + tabStyle: tabStyle, + trackStyle: trackStyle, + lineStyle: lineStyle, + tabCardTypeBorderStyle: tabCardTypeBorderStyle, +};