This commit is contained in:
Ling53666
2025-08-18 09:11:51 +08:00
commit 02554225da
2516 changed files with 133155 additions and 0 deletions

View File

@ -0,0 +1 @@
.ant-tabs{width:100%}.ant-tabs-bar{position:relative;width:100%;display:flex;align-content:stretch;background-color:#fff;box-sizing:border-box}.ant-tabs-bar-underline{border-bottom:1px solid #eee}.ant-tabs-bar-fade{position:absolute;top:0;bottom:0;z-index:9;width:18px;background-color:#fff;pointer-events:none;transition:all .2s}.ant-tabs-bar-fade-left{left:0;background:linear-gradient(90deg,#fff,hsla(0,0%,100%,0))}.ant-tabs-bar-fade-right{right:42px;background:linear-gradient(270deg,#fff,hsla(0,0%,100%,0))}.ant-tabs-bar-plus{display:flex;width:36px;height:36px;color:#000;align-self:center;align-items:center;justify-content:center;overflow:hidden;margin-right:12px;order:1}.ant-tabs-bar-plus:empty{display:none}.ant-tabs-bar-plus:empty~.ant-tabs-bar-fade-right{right:0}.ant-tabs-bar-scroll-view{width:100%;display:flex;flex-direction:row;justify-content:space-between;flex-wrap:nowrap;overflow:hidden;will-change:auto}.ant-tabs-bar-scroll-view::-webkit-scrollbar{display:none}.ant-tabs-bar-wrap{display:flex;flex-shrink:0}.ant-tabs-bar-wrap-capsule{flex:1}.ant-tabs-bar-wrap:nth-of-type(2) .ant-tabs-bar-capsule,.ant-tabs-bar-wrap:nth-of-type(2) .ant-tabs-bar-mixin{margin-left:12px}.ant-tabs-bar-wrap:nth-last-of-type(2) .ant-tabs-bar-capsule,.ant-tabs-bar-wrap:nth-last-of-type(2) .ant-tabs-bar-mixin{margin-right:12px}.ant-tabs-bar-item{display:flex;align-items:center;justify-content:center;flex:1 0 auto;font-size:17px;white-space:nowrap;color:#333}.ant-tabs-bar-item .ant-badge{width:100%}.ant-tabs-bar-basic{position:relative;display:flex;align-items:center;padding:8px 12px;box-sizing:border-box}.ant-tabs-bar-basic.ant-tabs-bar-active{color:#1677ff;position:relative}.ant-tabs-bar-basic.ant-tabs-bar-active:after{content:'';position:absolute;bottom:0;width:calc(100% - 12px * 2);height:2px;overflow:hidden;font-size:0;border-radius:50vh;box-sizing:border-box;background-color:#1677ff}.ant-tabs-bar-capsule{padding:12px 0;margin:0 12px/2;box-sizing:border-box;position:relative}.ant-tabs-bar-capsule-title{flex:1;justify-content:center;margin-right:0;padding:8px 15px;font-size:15px;text-align:center;line-height:1;border-radius:10vh;background-color:#f5f5f5;border-bottom:0 none}.ant-tabs-bar-capsule.ant-tabs-bar-active .ant-tabs-bar-capsule-title{color:#fff;background-color:#1677ff}.ant-tabs-bar-mixin{flex-direction:column;margin:0 8px;padding:12px 0;text-align:center}.ant-tabs-bar-mixin-title{margin:1px 0;position:relative}.ant-tabs-bar-mixin-subtitle{padding:0 8px;font-size:13px;line-height:1.5;color:#999;border-radius:50vh;background-color:#f5f5f5;margin:1px 0}.ant-tabs-bar-mixin.ant-tabs-bar-active .ant-tabs-bar-mixin-title{color:#1677ff}.ant-tabs-bar-mixin.ant-tabs-bar-active .ant-tabs-bar-mixin-subtitle{color:#fff;background-color:#1677ff}.ant-tabs-bar-disabled{opacity:.4;pointer-events:none;cursor:not-allowed}.ant-tabs-content{overflow:hidden;background-color:#fff;color:#333}.ant-vtabs{width:100%;display:flex;flex-direction:row}.ant-vtabs-bar{width:105px;overflow:hidden}.ant-vtabs-bar-scroll-view{display:flex;flex-direction:column;width:100%;height:100%;background-color:#f5f5f5}.ant-vtabs-bar-scroll-view::-webkit-scrollbar{display:none}.ant-vtabs-bar-item{position:relative;width:100%;padding:16px 12px;overflow:hidden;display:flex;align-items:center;font-size:13px;line-height:18.5px;color:#333;background-color:#f5f5f5;box-sizing:border-box;transition:background-color .1s linear,color .3s linear}.ant-vtabs-bar-item-wrap{background-color:#fff}.ant-vtabs-bar-item-active{color:#1677ff;background-color:#fff}.ant-vtabs-bar-item-active::after{position:absolute;content:'';top:16px;bottom:16px;left:0;width:2px;border-radius:2px;background-color:#1677ff}.ant-vtabs-bar-item-disabled{pointer-events:none;cursor:not-allowed}.ant-vtabs-bar-item-disabled .ant-vtabs-bar-item-count,.ant-vtabs-bar-item-disabled .ant-vtabs-bar-item-title{opacity:.4}.ant-vtabs-bar-item-count{color:#ccc;margin-left:4px}.ant-vtabs-bar-item-icon{padding-left:4px;width:14px;height:14px;font-size:13px;overflow:hidden;position:relative;top:-2px;display:flex;justify-content:center;align-items:center}.ant-vtabs-bar-item-icon:empty{display:none}.ant-vtabs-content{overflow:hidden;flex:1;background-color:#fff;color:#333}

View File

@ -0,0 +1,157 @@
<view
a:if="{{direction !== 'vertical'}}"
class="ant-tabs {{className ? className : ''}}"
style="{{style}}"
>
<view class="ant-tabs-bar {{type === 'basic' ? 'ant-tabs-bar-underline' : ''}} {{tabsBarClassName ? tabsBarClassName : ''}}">
<view class="ant-tabs-bar-plus">
<slot name="plus"></slot>
</view>
<view
class="ant-tabs-bar-fade ant-tabs-bar-fade-left"
style="opacity: {{leftFade ? '1' : '0'}}"
></view>
<view
class="ant-tabs-bar-fade ant-tabs-bar-fade-right"
style="opacity: {{rightFade ? '1' : '0'}}"
></view>
<scroll-view
class="ant-tabs-bar-scroll-view"
id="ant-tabs-bar-scroll-view{{$id ? '-' + $id : ''}}"
onScroll="onScroll"
scrollLeft="{{scrollLeft}}"
scrollX="{{true}}"
scrollWithAnimation="{{true}}"
scrollAnimationDuration="{{300}}"
>
<view></view>
<block
a:for="{{items}}"
a:for-index="index"
a:for-item="item"
>
<view
id="ant-tabs-bar-item{{$id ? '-' + $id : ''}}-{{index}}"
class="ant-tabs-bar-wrap ant-tabs-bar-wrap-{{type}} {{tabsBarClassName ? tabsBarClassName : ''}}"
>
<view
a:if="{{type === 'basic'}}"
class="ant-tabs-bar-item ant-tabs-bar-basic {{tabClassName ? tabClassName : ''}} {{mixin.value === index && !item.disabled ? 'ant-tabs-bar-active' : ''}} {{item.disabled ? 'ant-tabs-bar-disabled' : ''}} {{mixin.value === index && !item.disabled && tabActiveClassName ? tabActiveClassName : ''}}"
onTap="onChange"
data-index="{{index}}"
>
<view class="ant-tabs-bar-basic-title">
<slot
name="title"
value="{{item}}"
index="{{index}}"
>
{{item.title}}
</slot>
</view>
</view>
<view
a:elif="{{type === 'capsule'}}"
class="ant-tabs-bar-item ant-tabs-bar-capsule {{tabClassName ? tabClassName : ''}} {{mixin.value === index && !item.disabled ? 'ant-tabs-bar-active' : ''}} {{item.disabled ? 'ant-tabs-bar-disabled' : ''}} {{mixin.value === index && !item.disabled && tabActiveClassName ? tabActiveClassName : ''}}"
onTap="onChange"
data-index="{{index}}"
>
<view class="ant-tabs-bar-capsule-title">
<slot
name="title"
value="{{item}}"
index="{{index}}"
>
{{item.title}}
</slot>
</view>
</view>
<view
a:else
class="ant-tabs-bar-item ant-tabs-bar-mixin {{tabClassName ? tabClassName : ''}} {{mixin.value === index && !item.disabled ? 'ant-tabs-bar-active' : ''}} {{item.disabled ? 'ant-tabs-bar-disabled' : ''}} {{mixin.value === index && !item.disabled && tabActiveClassName ? tabActiveClassName : ''}}"
onTap="onChange"
data-index="{{index}}"
>
<view class="ant-tabs-bar-mixin-title">
<slot
name="title"
value="{{item}}"
index="{{index}}"
>
{{item.title}}
</slot>
</view>
<view class="ant-tabs-bar-mixin-subtitle">
<slot
name="subTitle"
value="{{item}}"
index="{{index}}"
>
{{item.subTitle}}
</slot>
</view>
</view>
</view>
</block>
<view></view>
</scroll-view>
</view>
<view class="ant-tabs-content">
<slot
value="{{items[mixin.value]}}"
index="{{mixin.value}}"
></slot>
</view>
</view>
<view
a:else
class="ant-vtabs {{className ? className : ''}}"
style="{{style}}"
>
<view class="ant-vtabs-bar {{tabsBarClassName ? tabsBarClassName : ''}}">
<scroll-view
class="ant-vtabs-bar-scroll-view"
id="ant-tabs-bar-scroll-view{{$id ? '-' + $id : ''}}"
onScroll="onScroll"
scrollTop="{{scrollTop}}"
scrollY="{{true}}"
scrollWithAnimation="{{true}}"
scrollAnimationDuration="{{300}}"
>
<view class="ant-vtabs-bar-item-wrap">
<block
a:for="{{items}}"
a:for-index="index"
a:for-item="item"
>
<view
id="ant-tabs-bar-item{{$id ? '-' + $id : ''}}-{{index}}"
class="ant-vtabs-bar-item {{tabClassName ? tabClassName : ''}} {{mixin.value === index && !item.disabled ? 'ant-vtabs-bar-item-active' : ''}} {{item.disabled ? 'ant-vtabs-bar-item-disabled' : ''}} {{mixin.value === index && !item.disabled && tabActiveClassName ? tabActiveClassName : ''}}"
style="{{mixin.value + 1 === index ? 'border-radius: 0 16rpx 0 0' : ''}};{{mixin.value - 1 === index ? 'border-radius: 0 0 16rpx 0' : ''}}"
onTap="onChange"
data-index="{{index}}"
>
<!--display: inline-->
<text class="ant-vtabs-bar-item-title">
<slot
name="title"
value="{{item}}"
index="{{index}}"
>
{{item.title}}
</slot>
</text>
</view>
</block>
</view>
</scroll-view>
</view>
<view class="ant-vtabs-content">
<slot
value="{{items[mixin.value]}}"
index="{{mixin.value}}"
>
{{items[mixin.value].content}}
</slot>
</view>
</view>

View File

@ -0,0 +1 @@
export {};

View File

@ -0,0 +1,185 @@
import { __awaiter, __generator } from "tslib";
import { Component, triggerEvent, getValueFromProps } from '../_util/simply';
import { TabsDefaultProps } from './props';
import createValue from '../mixins/value';
import { getInstanceBoundingClientRect } from '../_util/jsapi/get-instance-bounding-client-rect';
Component(TabsDefaultProps, {
getInstance: function () {
if (this.$id) {
return my;
}
return this;
},
get$Id: function () {
return this.$id ? "-".concat(this.$id) : '';
},
getBoundingClientRect: function (query) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, getInstanceBoundingClientRect(this.getInstance(), query)];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
},
updateFade: function () {
return __awaiter(this, void 0, void 0, function () {
var items, _a, view, item;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
this.setData({
leftFade: !!this.scrollLeft,
});
items = getValueFromProps(this, 'items');
return [4 /*yield*/, Promise.all([
this.getBoundingClientRect("#ant-tabs-bar-scroll-view".concat(this.get$Id())),
this.getBoundingClientRect("#ant-tabs-bar-item".concat(this.get$Id(), "-").concat(items.length - 1)),
])];
case 1:
_a = _b.sent(), view = _a[0], item = _a[1];
if (!item || !view) {
return [2 /*return*/];
}
this.setData({
rightFade: item.left + item.width / 2 > view.width,
});
return [2 /*return*/];
}
});
});
},
updateScroll: function () {
return __awaiter(this, void 0, void 0, function () {
var current, _a, view, item, _b, direction, scrollMode, scrollTop, needScroll_1, distance, scrollLeft, needScroll, distance;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
current = this.getValue();
return [4 /*yield*/, Promise.all([
this.getBoundingClientRect("#ant-tabs-bar-scroll-view".concat(this.get$Id())),
this.getBoundingClientRect("#ant-tabs-bar-item".concat(this.get$Id(), "-").concat(current)),
])];
case 1:
_a = _c.sent(), view = _a[0], item = _a[1];
if (!view || !item) {
return [2 /*return*/];
}
_b = getValueFromProps(this, [
'direction',
'scrollMode',
]), direction = _b[0], scrollMode = _b[1];
if (direction === 'vertical') {
scrollTop = this.scrollTop || 0;
needScroll_1 = false;
if (scrollMode === 'center') {
needScroll_1 = true;
scrollTop +=
item.top - view.top - Math.max((view.height - item.height) / 2, 0);
}
else {
distance = item.top - view.top;
if (distance < 0) {
scrollTop += distance;
needScroll_1 = true;
}
else if (distance + item.height > view.height) {
scrollTop += Math.min(distance + item.height - view.height, distance);
needScroll_1 = true;
}
}
if (needScroll_1) {
if (scrollTop === this.data.scrollTop) {
scrollTop += Math.random();
}
this.setData({
scrollTop: scrollTop,
});
}
return [2 /*return*/];
}
scrollLeft = this.scrollLeft || 0;
needScroll = false;
if (scrollMode === 'center') {
needScroll = true;
scrollLeft +=
item.left - view.left - Math.max((view.width - item.width) / 2, 0);
}
else {
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: scrollLeft,
});
this.updateFade();
}
return [2 /*return*/];
}
});
});
},
onScroll: function (e) {
return __awaiter(this, void 0, void 0, function () {
var direction;
return __generator(this, function (_a) {
direction = getValueFromProps(this, 'direction');
if (direction === 'vertical') {
this.scrollTop = e.detail.scrollTop;
return [2 /*return*/];
}
this.scrollLeft = e.detail.scrollLeft;
this.updateFade();
return [2 /*return*/];
});
});
},
onChange: function (e) {
var index = parseInt(e.currentTarget.dataset.index, 10);
var 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);
},
}, {
scrollLeft: 0,
scrollTop: 0,
leftFade: false,
rightFade: false,
}, [
createValue({
valueKey: 'current',
defaultValueKey: 'defaultCurrent',
}),
], {
scrollLeft: 0,
scrollTop: 0,
didMount: function () {
this.updateScroll();
},
didUpdate: function (prevProps, prevData) {
var items = getValueFromProps(this, 'items');
if (prevProps.items !== items || !this.isEqualValue(prevData)) {
this.updateScroll();
}
},
});

View File

@ -0,0 +1,3 @@
{
"component": true
}

View File

@ -0,0 +1,50 @@
import { IBaseProps } from '../_util/base';
export interface ITabsProps extends IBaseProps {
/**
* @description 类型basic(基础)capsule(胶囊)mixin(混合)
* @default "basic"
*/
type: 'basic' | 'capsule' | 'mixin';
/**
* @description tabs方向
*/
direction: 'horizontal' | 'vertical';
/**
* @description tab 切换时的回调
*/
onChange: (index: number, e: Record<string, any>) => void;
/**
* @description 选项
*/
current: number;
/**
* @description 列表
*/
items: {
title: string;
content: string;
disabled?: boolean;
subTitle?: string;
}[];
/**
* 选项初始值
*/
defaultCurrent: number;
/**
* 滚动方式direction为horizontal生效
*/
scrollMode: 'edge' | 'center';
/**
* @description tabs bar类名
*/
tabsBarClassName?: string;
/**
* @description tab类名
*/
tabClassName?: string;
/**
*@description tab active类名
*/
tabActiveClassName?: string;
}
export declare const TabsDefaultProps: Partial<ITabsProps>;

View File

@ -0,0 +1,11 @@
export var TabsDefaultProps = {
type: 'basic',
direction: 'horizontal',
current: null,
defaultCurrent: 0,
items: [],
scrollMode: 'edge',
tabsBarClassName: '',
tabActiveClassName: '',
tabClassName: '',
};