first commit
This commit is contained in:
25
uni_modules/tdesign-uniapp/components/tab-bar-item/props.ts
Normal file
25
uni_modules/tdesign-uniapp/components/tab-bar-item/props.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC
|
||||
* */
|
||||
|
||||
export default {
|
||||
/** 图标右上角提示信息 */
|
||||
badgeProps: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
/** 图标名称。传入对象时透传至 Icon 组件 */
|
||||
icon: {
|
||||
type: [String, Object],
|
||||
},
|
||||
/** 二级菜单 */
|
||||
subTabBar: {
|
||||
type: Array,
|
||||
},
|
||||
/** 标识符 */
|
||||
value: {
|
||||
type: [String, Number],
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,117 @@
|
||||
:host {
|
||||
flex: 1;
|
||||
}
|
||||
.t-tab-bar-item {
|
||||
flex: 1;
|
||||
height: var(--td-tab-bar-height, 80rpx);
|
||||
box-sizing: border-box;
|
||||
user-select: none;
|
||||
position: relative;
|
||||
margin: 16rpx 0;
|
||||
padding: 0 24rpx;
|
||||
}
|
||||
.t-tab-bar-item--split + .t-tab-bar-item--split::before {
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
content: ' ';
|
||||
pointer-events: none;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-left: 1px solid var(--td-tab-bar-border-color, var(--td-border-color, var(--td-gray-color-3, #e7e7e7)));
|
||||
transform: scaleX(0.5);
|
||||
top: 16rpx;
|
||||
bottom: 16rpx;
|
||||
}
|
||||
.t-tab-bar-item--crowded {
|
||||
padding: 0 16rpx;
|
||||
}
|
||||
.t-tab-bar-item--round {
|
||||
border-radius: 99px;
|
||||
}
|
||||
.t-tab-bar-item__content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 16rpx;
|
||||
color: var(--td-tab-bar-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
|
||||
}
|
||||
.t-tab-bar-item__content--checked .t-tab-bar-item__text,
|
||||
.t-tab-bar-item__content--checked .t-tab-bar-item__icon {
|
||||
color: var(--td-tab-bar-active-color, var(--td-brand-color, var(--td-primary-color-7, #0052d9)));
|
||||
font-weight: 600;
|
||||
}
|
||||
.t-tab-bar-item__content--tag {
|
||||
border-radius: 99px;
|
||||
}
|
||||
.t-tab-bar-item__content--tag.t-tab-bar-item__content--checked {
|
||||
background-color: var(--td-tab-bar-active-bg, var(--td-brand-color-light, var(--td-primary-color-1, #f2f3ff)));
|
||||
}
|
||||
.t-tab-bar-item__icon {
|
||||
display: contents;
|
||||
}
|
||||
.t-tab-bar-item__icon:empty {
|
||||
display: none;
|
||||
}
|
||||
.t-tab-bar-item__text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font: var(--td-font-body-large, 32rpx / 48rpx var(--td-font-family, PingFang SC, Microsoft YaHei, Arial Regular));
|
||||
}
|
||||
.t-tab-bar-item__text--small {
|
||||
font: var(--td-font-body-extraSmall, 20rpx / 32rpx var(--td-font-family, PingFang SC, Microsoft YaHei, Arial Regular));
|
||||
}
|
||||
.t-tab-bar-item__icon-menu {
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
.t-tab-bar-item__spread {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 7%;
|
||||
width: 86%;
|
||||
background-color: var(--td-tab-bar-bg-color, var(--td-bg-color-container, var(--td-font-white-1, #ffffff)));
|
||||
transform: translate3d(0, calc(-100% - 32rpx), 0);
|
||||
z-index: 1;
|
||||
border-radius: 12rpx;
|
||||
color: var(--td-tab-bar-color, var(--td-text-color-primary, var(--td-font-gray-1, rgba(0, 0, 0, 0.9))));
|
||||
box-shadow: var(--td-tab-bar-spread-shadow, var(--td-shadow-3, 0 6px 30px 5px rgba(0, 0, 0, 0.05), 0 16px 24px 2px rgba(0, 0, 0, 0.04), 0 8px 10px -5px rgba(0, 0, 0, 0.08)));
|
||||
}
|
||||
.t-tab-bar-item__spread::before {
|
||||
display: block;
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 16rpx solid transparent;
|
||||
border-top: 16rpx solid var(--td-tab-bar-bg-color, var(--td-bg-color-container, var(--td-font-white-1, #ffffff)));
|
||||
transform: translate3d(-50%, 32rpx, 0);
|
||||
}
|
||||
.t-tab-bar-item__spread-item {
|
||||
width: 100%;
|
||||
height: 96rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
}
|
||||
.t-tab-bar-item__spread-item--active {
|
||||
background-color: var(--td-tab-bar-hover-bg-color, rgba(0, 0, 0, 0.05));
|
||||
}
|
||||
.t-tab-bar-item__spread-item-split {
|
||||
box-sizing: border-box;
|
||||
content: ' ';
|
||||
pointer-events: none;
|
||||
background-color: var(--td-tab-bar-spread-border-color, var(--td-border-color, var(--td-gray-color-3, #e7e7e7)));
|
||||
width: 80%;
|
||||
height: 1px;
|
||||
transform: translateY(0.5);
|
||||
}
|
||||
.t-tab-bar-item__spread-item-text {
|
||||
padding-top: 24rpx;
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
<template>
|
||||
<view
|
||||
:style="tools._style([customStyle])"
|
||||
:class="tools.cls(classPrefix, [
|
||||
['split', split],
|
||||
['crowded', crowded], shape]
|
||||
) + ' ' + tClass"
|
||||
>
|
||||
<view
|
||||
:class="tools.cls(classPrefix + '__content', [['checked', isChecked], theme])"
|
||||
:hover-class="classPrefix + '__content--active'"
|
||||
:hover-stay-time="200"
|
||||
:aria-selected="(!hasChildren || !isSpread) && isChecked ? true : false"
|
||||
:aria-expanded="hasChildren && isSpread ? true : ''"
|
||||
:aria-role="hasChildren ? 'button' : 'tab'"
|
||||
:aria-label="ariaLabel || (badgeProps.dot || badgeProps.count ? tools.getBadgeAriaLabel({ ...badgeProps }) : '')"
|
||||
@click="toggle"
|
||||
>
|
||||
<view
|
||||
:class="classPrefix + '__icon'"
|
||||
:style="'height: ' + (iconOnly ? 24 : 20) + 'px'"
|
||||
:aria-hidden="badgeProps.dot || badgeProps.count"
|
||||
>
|
||||
<t-badge
|
||||
v-if="badgeProps.dot || badgeProps.count"
|
||||
:count="badgeProps.count || 0"
|
||||
:max-count="badgeProps.maxCount || 99"
|
||||
:dot="badgeProps.dot || false"
|
||||
:content="badgeProps.content || ''"
|
||||
:size="badgeProps.size || 'medium'"
|
||||
:visible="badgeProps.visible"
|
||||
:offset="badgeProps.offset || [0, 0]"
|
||||
:t-class-count="prefix + '-badge-class'"
|
||||
>
|
||||
<block
|
||||
v-if="_icon"
|
||||
name="icon"
|
||||
>
|
||||
<t-icon
|
||||
:custom-style="_icon.style || ''"
|
||||
:t-class="_icon.tClass || ''"
|
||||
:prefix="_icon.prefix"
|
||||
:name="_icon.name"
|
||||
:size="_icon.size || (iconOnly ? 24 : 20)"
|
||||
:color="_icon.color"
|
||||
:aria-hidden="_icon.ariaHidden"
|
||||
:aria-label="_icon.ariaLabel"
|
||||
:aria-role="_icon.ariaRole"
|
||||
@click="_icon.click || ''"
|
||||
/>
|
||||
</block>
|
||||
<!-- 避免被 badge 组件识别为空,t-badge__content:not(:empty) -->
|
||||
<view v-else />
|
||||
</t-badge>
|
||||
<block
|
||||
v-else-if="!!icon"
|
||||
name="icon"
|
||||
>
|
||||
<t-icon
|
||||
:custom-style="_icon.style || ''"
|
||||
:t-class="_icon.tClass || ''"
|
||||
:prefix="_icon.prefix"
|
||||
:name="_icon.name"
|
||||
:size="_icon.size || (iconOnly ? 24 : 20)"
|
||||
:color="_icon.color"
|
||||
:aria-hidden="!iconOnly"
|
||||
:aria-label="_icon.ariaLabel"
|
||||
:aria-role="_icon.ariaRole"
|
||||
@click="_icon.click || ''"
|
||||
/>
|
||||
</block>
|
||||
<slot name="icon" />
|
||||
</view>
|
||||
<view :class="tools.cls(classPrefix + '__text', [['small', !!icon]])">
|
||||
<t-icon
|
||||
v-if="hasChildren"
|
||||
name="view-list"
|
||||
size="32rpx"
|
||||
:t-class="classPrefix + '__icon-menu'"
|
||||
/>
|
||||
<slot />
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
v-if="hasChildren && isSpread"
|
||||
:class="classPrefix + '__spread'"
|
||||
>
|
||||
<view
|
||||
v-for="(child, index) in (subTabBar || [])"
|
||||
:key="index"
|
||||
:class="classPrefix + '__spread-item'"
|
||||
:hover-class="classPrefix + '__spread-item--active'"
|
||||
:hover-stay-time="200"
|
||||
:data-value="child.value || index"
|
||||
aria-role="tab"
|
||||
@click="selectChild"
|
||||
>
|
||||
<view
|
||||
v-if="index !== 0"
|
||||
:class="classPrefix + '__spread-item-split'"
|
||||
/>
|
||||
|
||||
<view
|
||||
:class="classPrefix + '__spread-item-text'"
|
||||
:data-value="child.value || index"
|
||||
>
|
||||
{{ child.label }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import TIcon from '../icon/icon';
|
||||
import TBadge from '../badge/badge';
|
||||
import { uniComponent } from '../common/src/index';
|
||||
import { prefix } from '../common/config';
|
||||
import props from './props';
|
||||
import { getRect, calcIcon } from '../common/utils';
|
||||
import tools from '../common/utils.wxs';
|
||||
import { ChildrenMixin, RELATION_MAP } from '../common/relation';
|
||||
|
||||
const classPrefix = `${prefix}-tab-bar-item`;
|
||||
|
||||
|
||||
export default uniComponent({
|
||||
name: classPrefix,
|
||||
options: {
|
||||
styleIsolation: 'shared',
|
||||
virtualHost: true,
|
||||
},
|
||||
externalClasses: [`${prefix}-class`],
|
||||
mixins: [ChildrenMixin(RELATION_MAP.TabBarItem)],
|
||||
components: {
|
||||
TIcon,
|
||||
TBadge,
|
||||
},
|
||||
props: {
|
||||
...props,
|
||||
},
|
||||
emits: [],
|
||||
watch: {
|
||||
subTabBar: {
|
||||
handler(value) {
|
||||
this.hasChildren = value?.length > 0;
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
icon: {
|
||||
handler(v) {
|
||||
this._icon = calcIcon(v);
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
prefix,
|
||||
classPrefix,
|
||||
isSpread: false,
|
||||
isChecked: false,
|
||||
hasChildren: false,
|
||||
currentName: '',
|
||||
split: true,
|
||||
iconOnly: false,
|
||||
theme: '',
|
||||
crowded: false,
|
||||
shape: 'normal',
|
||||
tools,
|
||||
};
|
||||
},
|
||||
async mounted() {
|
||||
const res = await getRect(this, `.${classPrefix}__text`);
|
||||
|
||||
this.iconOnly = res.height === 0;
|
||||
},
|
||||
methods: {
|
||||
innerAfterLinked() {
|
||||
const parent = this[RELATION_MAP.TabBarItem];
|
||||
const { theme, split, shape } = parent;
|
||||
|
||||
this.theme = theme;
|
||||
this.split = split;
|
||||
this.shape = shape;
|
||||
this.currentName = this.value ? this.value : parent.initName();
|
||||
|
||||
parent.updateChildren();
|
||||
},
|
||||
showSpread() {
|
||||
this.isSpread = true;
|
||||
},
|
||||
toggle() {
|
||||
const { currentName, hasChildren, isSpread } = this;
|
||||
|
||||
if (hasChildren) {
|
||||
this.isSpread = !isSpread;
|
||||
}
|
||||
this[RELATION_MAP.TabBarItem].updateValue(currentName);
|
||||
this[RELATION_MAP.TabBarItem].changeOtherSpread(currentName);
|
||||
},
|
||||
selectChild(event) {
|
||||
const { value } = event.target.dataset;
|
||||
|
||||
this[RELATION_MAP.TabBarItem].updateValue(value);
|
||||
this.isSpread = false;
|
||||
},
|
||||
checkActive(value) {
|
||||
const { currentName, subTabBar = [] } = this;
|
||||
const isChecked = subTabBar?.some(item => item.value === value) || currentName === value;
|
||||
|
||||
this.isChecked = isChecked;
|
||||
},
|
||||
closeSpread() {
|
||||
this.isSpread = false;
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style scoped>
|
||||
@import './tab-bar-item.css';
|
||||
|
||||
</style>
|
||||
32
uni_modules/tdesign-uniapp/components/tab-bar-item/type.ts
Normal file
32
uni_modules/tdesign-uniapp/components/tab-bar-item/type.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC
|
||||
* */
|
||||
|
||||
import type { TdBadgeProps as BadgeProps } from '../badge/type';
|
||||
|
||||
export interface TdTabBarItemProps {
|
||||
/**
|
||||
* 图标右上角提示信息
|
||||
* @default {}
|
||||
*/
|
||||
badgeProps?: BadgeProps;
|
||||
/**
|
||||
* 图标名称。传入对象时透传至 Icon 组件
|
||||
*/
|
||||
icon?: string | object;
|
||||
/**
|
||||
* 二级菜单
|
||||
*/
|
||||
subTabBar?: SubTabBarItem[];
|
||||
/**
|
||||
* 标识符
|
||||
*/
|
||||
value?: string | number;
|
||||
}
|
||||
|
||||
export interface SubTabBarItem {
|
||||
value: string;
|
||||
label: string;
|
||||
}
|
||||
Reference in New Issue
Block a user