From 66d2c8d8c97e19fdbd969f97dd3d6a28f27c415f Mon Sep 17 00:00:00 2001 From: quanyawei <401863037@qq.com> Date: Wed, 01 Nov 2023 16:07:03 +0800 Subject: [PATCH] fix:小程序分享功能和秒级数据 --- uni_modules/uview-ui/components/u-tabs/u-tabs.vue | 354 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 354 insertions(+), 0 deletions(-) diff --git a/uni_modules/uview-ui/components/u-tabs/u-tabs.vue b/uni_modules/uview-ui/components/u-tabs/u-tabs.vue new file mode 100644 index 0000000..9c54cc1 --- /dev/null +++ b/uni_modules/uview-ui/components/u-tabs/u-tabs.vue @@ -0,0 +1,354 @@ +<template> + <view class="u-tabs"> + <view class="u-tabs__wrapper"> + <slot name="left" /> + <view class="u-tabs__wrapper__scroll-view-wrapper"> + <scroll-view + :scroll-x="scrollable" + :scroll-left="scrollLeft" + scroll-with-animation + class="u-tabs__wrapper__scroll-view" + :show-scrollbar="false" + ref="u-tabs__wrapper__scroll-view" + > + <view + class="u-tabs__wrapper__nav" + ref="u-tabs__wrapper__nav" + > + <view + class="u-tabs__wrapper__nav__item" + v-for="(item, index) in list" + :key="index" + @tap="clickHandler(item, index)" + :ref="`u-tabs__wrapper__nav__item-${index}`" + :style="[$u.addStyle(itemStyle), {flex: scrollable ? '' : 1}]" + :class="[`u-tabs__wrapper__nav__item-${index}`, item.disabled && 'u-tabs__wrapper__nav__item--disabled']" + > + <text + :class="[item.disabled && 'u-tabs__wrapper__nav__item__text--disabled']" + class="u-tabs__wrapper__nav__item__text" + :style="[textStyle(index)]" + >{{ item[keyName] }}</text> + <u-badge + :show="!!(item.badge && (item.badge.show || item.badge.isDot || item.badge.value))" + :isDot="item.badge && item.badge.isDot || propsBadge.isDot" + :value="item.badge && item.badge.value || propsBadge.value" + :max="item.badge && item.badge.max || propsBadge.max" + :type="item.badge && item.badge.type || propsBadge.type" + :showZero="item.badge && item.badge.showZero || propsBadge.showZero" + :bgColor="item.badge && item.badge.bgColor || propsBadge.bgColor" + :color="item.badge && item.badge.color || propsBadge.color" + :shape="item.badge && item.badge.shape || propsBadge.shape" + :numberType="item.badge && item.badge.numberType || propsBadge.numberType" + :inverted="item.badge && item.badge.inverted || propsBadge.inverted" + customStyle="margin-left: 4px;" + ></u-badge> + </view> + <!-- #ifdef APP-NVUE --> + <view + class="u-tabs__wrapper__nav__line" + ref="u-tabs__wrapper__nav__line" + :style="[{ + width: $u.addUnit(lineWidth), + height: $u.addUnit(lineHeight), + background: lineColor, + backgroundSize: lineBgSize, + }]" + > + <!-- #endif --> + <!-- #ifndef APP-NVUE --> + <view + class="u-tabs__wrapper__nav__line" + ref="u-tabs__wrapper__nav__line" + :style="[{ + width: $u.addUnit(lineWidth), + transform: `translate(${lineOffsetLeft}px)`, + transitionDuration: `${firstTime ? 0 : duration}ms`, + height: $u.addUnit(lineHeight), + background: lineColor, + backgroundSize: lineBgSize, + }]" + > + <!-- #endif --> + </view> + </view> + </scroll-view> + </view> + <slot name="right" /> + </view> + </view> +</template> + +<script> + // #ifdef APP-NVUE + const animation = uni.requireNativePlugin('animation') + const dom = uni.requireNativePlugin('dom') + // #endif + import props from './props.js'; + /** + * Tabs ������ + * @description tabs��������������������������������������������������������������������������������������������������������������� ���������������������������������������������������������������tab������������������������������������������ + * @tutorial https://www.uviewui.com/components/tabs.html + * @property {String | Number} duration ������������������������������������������������������ 200 ��� + * @property {String | Number} swierWidth swiper������������������ '750rpx' ��� + * @property {String} keyName ���`list`��������������������������������������� 'name' ��� + * @event {Function(index)} change ��������������������� index: ������������������tab������������0������ + * @event {Function(index)} click ��������������������� index: ������������������tab������������0������ + * @example <u-tabs :list="list" :is-scroll="false" :current="current" @change="change"></u-tabs> + */ + export default { + name: 'u-tabs', + mixins: [uni.$u.mpMixin, uni.$u.mixin, props], + data() { + return { + firstTime: true, + scrollLeft: 0, + scrollViewWidth: 0, + lineOffsetLeft: 0, + tabsRect: { + left: 0 + }, + innerCurrent: 0, + moving: false, + } + }, + watch: { + current: { + immediate: true, + handler (newValue, oldValue) { + // ������������������������������������������������ + if (newValue !== this.innerCurrent) { + this.innerCurrent = newValue + this.$nextTick(() => { + this.resize() + }) + } + } + }, + // list������������������������list������������ + list() { + this.$nextTick(() => { + this.resize() + }) + } + }, + computed: { + textStyle() { + return index => { + const style = {} + // ������������������������������ + const customeStyle = index === this.innerCurrent ? uni.$u.addStyle(this.activeStyle) : uni.$u + .addStyle( + this.inactiveStyle) + // ���������������������������������������������������������������������������������������nvue���������������style���������������!import��������������������������� + if (this.list[index].disabled) { + style.color = '#c8c9cc' + } + return uni.$u.deepMerge(customeStyle, style) + } + }, + propsBadge() { + return uni.$u.props.badge + } + }, + async mounted() { + this.init() + }, + methods: { + setLineLeft() { + const tabItem = this.list[this.innerCurrent]; + if (!tabItem) { + return; + } + // ������������������������������ + let lineOffsetLeft = this.list + .slice(0, this.innerCurrent) + .reduce((total, curr) => total + curr.rect.width, 0); + // ������������������������px��������� + const lineWidth = uni.$u.getPx(this.lineWidth); + this.lineOffsetLeft = lineOffsetLeft + (tabItem.rect.width - lineWidth) / 2 + // #ifdef APP-NVUE + // ������������������������������������������ + this.animation(this.lineOffsetLeft, this.firstTime ? 0 : parseInt(this.duration)) + // #endif + + // ���������������������������������������������������������������������������������������tab item��������� + // ������������������������������������������nvue���������������������style���������������������������������������������������������������false(������������������������) + if (this.firstTime) { + setTimeout(() => { + this.firstTime = false + }, 10); + } + }, + // nvue������������������������ + animation(x, duration = 0) { + // #ifdef APP-NVUE + const ref = this.$refs['u-tabs__wrapper__nav__line'] + animation.transition(ref, { + styles: { + transform: `translateX(${x}px)` + }, + duration + }) + // #endif + }, + // ��������������������� + clickHandler(item, index) { + // ���������������������disabled���������������click������������������������������change��������������������������������������� + this.$emit('click', { + ...item, + index + }) + // ������disabled��������������� + if (item.disabled) return + this.innerCurrent = index + this.resize() + this.$emit('change', { + ...item, + index + }) + }, + init() { + uni.$u.sleep().then(() => { + this.resize() + }) + }, + setScrollLeft() { + // ������������tab���������������������tab���������width���left(������������������������������������������������)��������� + const tabRect = this.list[this.innerCurrent] + // ������������������item������������������ + const offsetLeft = this.list + .slice(0, this.innerCurrent) + .reduce((total, curr) => { + return total + curr.rect.width + }, 0) + // ��������������������� + const windowWidth = uni.$u.sys().windowWidth + // ������������tabs-item������������������������������������������scroll-view��������� + let scrollLeft = offsetLeft - (this.tabsRect.width - tabRect.rect.width) / 2 - (windowWidth - this.tabsRect + .right) / 2 + this.tabsRect.left / 2 + // ������������������������������scrollLeft���������������������scroll-view������������tabs��������������� + scrollLeft = Math.min(scrollLeft, this.scrollViewWidth - this.tabsRect.width) + this.scrollLeft = Math.max(0, scrollLeft) + }, + // ��������������������������� + resize() { + // ���������������list��������������� + if(this.list.length === 0) { + return + } + Promise.all([this.getTabsRect(), this.getAllItemRect()]).then(([tabsRect, itemRect = []]) => { + this.tabsRect = tabsRect + this.scrollViewWidth = 0 + itemRect.map((item, index) => { + // ������scroll-view������������������ + this.scrollViewWidth += item.width + // ���������������������item������������X��������� + this.list[index].rect = item + }) + // ���������tabs��������������������������������������� + this.setLineLeft() + this.setScrollLeft() + }) + }, + // ��������������������������� + getTabsRect() { + return new Promise(resolve => { + this.queryRect('u-tabs__wrapper__scroll-view').then(size => resolve(size)) + }) + }, + // ��������������������������� + getAllItemRect() { + return new Promise(resolve => { + const promiseAllArr = this.list.map((item, index) => this.queryRect( + `u-tabs__wrapper__nav__item-${index}`, true)) + Promise.all(promiseAllArr).then(sizes => resolve(sizes)) + }) + }, + // ��������������������������� + queryRect(el, item) { + // #ifndef APP-NVUE + // $uGetRect���uView���������������������������������������������������������https://www.uviewui.com/js/getRect.html + // ���������������������this.$uGetRect���������������uni.$u.getRect������������������������������������ + return new Promise(resolve => { + this.$uGetRect(`.${el}`).then(size => { + resolve(size) + }) + }) + // #endif + + // #ifdef APP-NVUE + // nvue������������dom������������������������ + // ������������promise���������������������������������������then������ + return new Promise(resolve => { + dom.getComponentRect(item ? this.$refs[el][0] : this.$refs[el], res => { + resolve(res.size) + }) + }) + // #endif + }, + }, + } +</script> + +<style lang="scss" scoped> + @import "../../libs/css/components.scss"; + + .u-tabs { + + &__wrapper { + @include flex; + align-items: center; + + &__scroll-view-wrapper { + flex: 1; + /* #ifndef APP-NVUE */ + overflow: auto hidden; + /* #endif */ + } + + &__scroll-view { + @include flex; + flex: 1; + } + + &__nav { + @include flex; + position: relative; + + &__item { + padding: 0 11px; + @include flex; + align-items: center; + justify-content: center; + + &--disabled { + /* #ifndef APP-NVUE */ + cursor: not-allowed; + /* #endif */ + } + + &__text { + font-size: 15px; + color: $u-content-color; + + &--disabled { + color: $u-disabled-color !important; + } + } + } + + &__line { + height: 3px; + background: $u-primary; + width: 30px; + position: absolute; + bottom: 2px; + border-radius: 100px; + transition-property: transform; + transition-duration: 300ms; + } + } + } + } +</style> -- Gitblit v1.8.0