| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- <template>
- <Touchable
- center
- direction="column"
- :innerStyle="{
- ...innerStyle,
- flexBasis: size,
- }"
- :touchable="true"
- @click="handleClick"
- >
- <slot>
- <view v-if="props.hump">
- <Icon v-bind="iconProps" icon=""/>
- </view>
- <Badge
- :containerStyle="{
- ...(props.hump ? {
- position: 'absolute',
- height: theme.resolveSize(iconProps.size),
- bottom: theme.resolveSize(active ? humpHeight[0] : humpHeight[1]),
- left: '50%',
- transform: 'translateX(-50%)',
- } : {}),
- }"
- :content="props.badge === -1 ? '' : ((typeof props.badge === 'undefined' || props.badge === 0) ? 0 : props.badge)"
- :offset="{ x: 3, y: 0 }"
- v-bind="props.badgeProps"
- >
- <slot name="icon" :selected="active" :iconProps="iconProps">
- <Icon v-bind="iconProps" />
- </slot>
- </Badge>
- <Text
- v-if="text"
- :innerStyle="{
- ...themeStyles.tabText.value,
- ...props.textStyle
- }"
- :text="props.text"
- :color="color"
- />
- </slot>
- </Touchable>
- </template>
- <script setup lang="ts">
- import type { IconProps } from '@/components/basic/Icon.vue';
- import { useTheme, type TextStyle } from '@/components/theme/ThemeDefine';
- import { computed, inject, onMounted, onUpdated, ref } from 'vue';
- import { DynamicSize } from '../theme/ThemeTools';
- import Text from '@/components/basic/Text.vue';
- import Icon from '@/components/basic/Icon.vue';
- import Badge, { type BadgeProps } from '../display/Badge.vue';
- import Touchable from '../feedback/Touchable.vue';
- export interface TabBarItemProps {
- /**
- * 标签图标
- */
- icon?: string;
- /**
- * 图标透传样式
- */
- iconProps?: IconProps;
- /**
- * 标签图标大小
- * @default 23
- */
- iconSize?: number;
- /**
- * 标签文字
- */
- text?: string;
- /**
- * 标签文字样式
- */
- textStyle?: TextStyle;
- /**
- * 标签标记。为 0 或者 未定义时不显示,为 -1时显示圆点,为大于0的数时显示数字标记
- */
- badge?: number;
- /**
- * 指定当前标签是否凸起。凸起状态下可以使用 renderIcon 回调渲染自定义图片,图片不会把Tabbar撑开而是会溢出,可以实现凸起按钮的效果。
- * @default false
- */
- hump?: boolean;
- /**
- * 指定当前标签凸起的高度,数组第0位是选中时的凸起高度,第1位是未选中时的凸起高度。
- */
- humpHeight?: number[];
- /**
- * 自定义徽标的属性,传入的对象会被透传给 Badge 组件的 props
- */
- badgeProps?: BadgeProps;
- /**
- * 是否懒加载当前标签,仅在标签模式中有效
- * @default false
- */
- lazy?: boolean;
- /**
- * 自定义样式
- */
- innerStyle?: object,
- }
- defineOptions({
- options: {
- virtualHost: true
- }
- })
- const emit = defineEmits([ 'click' ]);
- const theme = useTheme();
- const props = withDefaults(defineProps<TabBarItemProps>(), {
- activeColor: 'primary',
- inactiveColor: 'text.second',
- active: false,
- iconSize: 50,
- humpHeight: () => ([ 50, 50 ])
- })
- const {
- topProps,
- selectTab,
- getPosition,
- getCount,
- } = inject('TabBarContext', {}) as any;
- const position = computed(() => getPosition());
- const active = computed(() => topProps.selectedTabIndex.value === position.value);
- const color = computed(() => theme.resolveThemeColor(
- active.value ? topProps.activeColor.value : topProps.inactiveColor.value
- ));
- const iconProps = computed(() => ({
- ...props.iconProps,
- icon: props.icon ?? '',
- size: props.iconSize,
- color: color.value,
- }));
- const themeStyles = theme.useThemeStyles({
- tabItem: {
- flexDirection: 'column',
- alignItems: 'center',
- justifyContent: 'center',
- },
- tabText: {
- fontSize: DynamicSize('TabBarItemTextFontSize', 22),
- marginTop: DynamicSize('TabBarItemTextMarginTop', 0),
- },
- });
- function handleClick() {
- selectTab(position.value);
- emit('click');
- }
- const size = ref('');
- onUpdated(() => {
- size.value = `${100 / getCount()}%`
- });
- onMounted(() => {
- size.value = `${100 / getCount()}%`
- });
- </script>
|