Vue 基于 ant-design-vue 封装 TabBar

Vue 基于 ant-design-vue 封装 TabBar

目录

BaseTabBar目录

BaseTabBarItem

<template>
  <a-badge
    v-if="true"
    :class="[
      isCenter
        ? 'base-tabbar-center-item-badge-wrap'
        : 'base-tabbar-item-badge-wrap',
      'animate__animated',
      isActive ? 'animate__zoomIn' : ''
    ]"
    :style="{
      '--animate-duration': '.35s',
      'animation-fill-mode': 'forwards'
    }"
    :color="badge.color"
    :count="badge.count"
    :overflow-count="badge.overflowCount"
    :dot="badge.dot"
    @click="clickTabBar"
  >
    <div
      :class="[
        isCenter ? 'base-tabbar-center-item-wrap' : 'base-tabbar-item-wrap',
        isActive
          ? 'base-tabbar-item-wrap-active'
          : 'base-tabbar-item-wrap-unactive'
      ]"
    >
      <div
        class="base-tabbar-item-icon"
        :style="
          isCenter
            ? {
                'background-color': activeColor,
                'border-radius':
                  !item.centerShape || item.centerShape == 'circle'
                    ? '50%'
                    : '15%'
              }
            : {}
        "
      >
        <slot name="icon"
          ><icon
            :icon="item.icon"
            :color="isActive && !isCenter ? activeColor : color"
          ></icon
        ></slot>
      </div>
      <div
        :class="[
          'base-tabbar-item-text',
          'animate__animated',
          !isActive && showTextOnActive
            ? 'animate__zoomOut base-tabbar-item-text-unactive'
            : ''
        ]"
      >
        <slot name="text"
          ><span
            v-text="item.text"
            :style="{ color: isActive ? activeColor : color }"
          ></span
        ></slot>
      </div>
    </div>
  </a-badge>
</template>

<script>
function isString(string) {
  return typeof string === "string";
}

function pushRoute(route) {
  // Vue刷新页面的三种方式
  // https://blog.csdn.net/weixin_43885417/article/details/91310674
  if (!route) {
    return;
  }
  let currentRoutePath = router.currentRoute.path;
  if (
    route && router.currentRoute && isString(route)
      ? currentRoutePath == route
      : currentRoutePath == route.path
  ) {
    return;
  }
  router.push(route);
}
	
export default {
  name: "BaseTabBarItem",
  data() {
    return {};
  },
  props: {
    // 中间是否隐藏 是则不是中间的样式
    centerVisible: {
      type: [Boolean],
      default: true,
      required: false
    },
    // 激活时才显示文字
    showTextOnActive: {
      type: [Boolean],
      default: false,
      required: false
    },
    color: {
      type: [String],
      default: "",
      required: false
    },
    activeColor: {
      type: [String],
      default: "",
      required: false
    },
    itemKey: {
      type: [String, Number],
      default: "",
      required: false
    },
    activeItemKey: {
      type: [String, Number],
      default: "",
      required: false
    },
    item: {
      type: [Object],
      default() {
        //   index: 1,
        //   icon: "Antd_home",
        //   text: "首页",
        //   route: { path: "/pvtnote/home" },
        //   badge: JSON.stringify({ count: 0 }),
        //   isCenter: true,
        //   // circle square
        //   centerShape: "circle"
        return {};
      },
      required: false
    }
  },
  computed: {
    badge() {
      let badge = this.item.badge;
      return badge
        ? isString(badge)
          ? JSON.parse(badge)
          : badge
        : { count: 0 };
    },
    isActive() {
      let activeItemKey = this.activeItemKey;
      return activeItemKey && activeItemKey == this.itemKey;
    },
    isCenter() {
      return this.item.isCenter && this.centerVisible;
    }
  },
  methods: {
    pushRoute,
    clickTabBar() {
      this.$emit("click", this.itemKey);
      this.$emit("change", this.itemKey);
      let route = this.item.route;
      if (route) {
        this.pushRoute(this.item.route);
      }
    }
  }
};
</script>

<style>
.base-tabbar-item-badge-wrap {
  cursor: pointer;
  width: 3.3rem;
  padding: 0 0 0.1rem;
}
.base-tabbar-item-badge-wrap sup,
.base-tabbar-center-item-badge-wrap sup {
  animation: none;
  position: absolute;
}

/* ant-design-vue 修改 badge 样式 避免徽章在底部导航栏突出显示 */
.base-tabbar-item-badge-wrap .ant-badge-count,
.base-tabbar-item-badge-wrap .ant-badge-dot,
.base-tabbar-item-badge-wrap .ant-badge .ant-scroll-number-custom-component {
  transform: translate(30%, 10%);
}

.base-tabbar-item-wrap,
.base-tabbar-center-item-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-around;
}

.base-tabbar-center-item-wrap .icon,
.base-tabbar-item-wrap .icon {
  margin: 0.3rem 0;
}

.base-tabbar-center-item-wrap .icon,
.base-tabbar-center-item-wrap .icon svg {
  width: 1.2rem;
  height: 1.2rem;
}

.base-tabbar-item-wrap .icon,
.base-tabbar-item-wrap .icon svg {
  width: 1.1rem;
  height: 1.1rem;
}

.base-tabbar-center-item-wrap .base-tabbar-item-text,
.base-tabbar-item-wrap .base-tabbar-item-text {
  font-size: 0.5rem;
  color: black;
}

.base-tabbar-center-item-wrap .base-tabbar-item-text {
  font-size: 0.75rem;
  margin-top: 0.45rem;
}

.base-tabbar-center-item-wrap .base-tabbar-item-text-unactive,
.base-tabbar-item-wrap .base-tabbar-item-text-unactive {
  display: none;
}

/* Center */
.base-tabbar-center-item-badge-wrap {
  cursor: pointer;
  width: 3.5rem;
  position: relative;
  top: -1.3rem;
}

.base-tabbar-center-item-wrap .base-tabbar-item-icon {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 3.7rem;
  height: 3.7rem;
  /* border-radius: 20%; */
  border: 0.5rem solid #ffffff;
  box-shadow: 0 0 0.35rem 0 #e2e1e1;
  box-shadow: 0 0 6px rgba(180, 160, 120, 0.8);
}
</style>

BaseTabBar

<template>
  <div class="base-tabbar-wrap" :style="{ bottom }">
    <slot name="baseTabBarItem">
      <base-tab-bar-item
        v-for="(baseTabBar, index) in baseTabBars"
        :item="baseTabBar"
        :key="index"
        :item-key="index"
        :active-item-key="realActiveItemKey"
        :centerVisible="centerVisible"
        @click="clickTabBar"
        @change="changeTabBar(index)"
        v-bind="$props"
      ></base-tab-bar-item>
    </slot>
  </div>
</template>

<script>
import BaseTabBarItem from "./BaseTabBarItem";

export default {
  name: "BaseTabBar",
  components: { BaseTabBarItem },
  data() {
    return {
      inActiveItemKey: ""
    };
  },
  props: {
    centerVisible: {
      type: [Boolean],
      default: true,
      required: false
    },
    visible: {
      type: [Boolean],
      default: true,
      required: false
    },
    showTextOnActive: {
      type: [Boolean],
      default: false,
      required: false
    },
    color: {
      type: [String],
      default: "",
      required: false
    },
    activeColor: {
      type: [String],
      default: "",
      required: false
    },
    activeItemKey: {
      type: [String, Number],
      default: "",
      required: false
    },
    baseTabBars: {
      type: [Array],
      default: function() {
        return [
          {
            icon: "Antd_home",
            text: "首页",
            route: {},
            badge: JSON.stringify({
              color: "red",
              count: 12,
              overflowCount: 99,
              dot: false
            })
          }
        ];
      },
      required: false
    }
  },
  computed: {
    realActiveItemKey() {
      let activeItemKey = this.activeItemKey;
      let isNotNull = activeItemKey | (activeItemKey == 0);
      return isNotNull ? activeItemKey : this.inActiveItemKey;
    },
    bottom() {
      return this.visible ? 0 : "-7.25%";
    }
  },
  methods: {
    changeTabBar(key) {
      this.inActiveItemKey = key;
      this.$emit("change", key);
    },
    clickTabBar() {
      this.$emit("click");
    }
  },
  mounted() {
    let activeItemKey = this.activeItemKey;
    let isNotNull = activeItemKey | (activeItemKey == 0);
    return isNotNull ? activeItemKey : this.inActiveItemKey;
  }
};
</script>

<style>
.base-tabbar-wrap {
  height: 7.25%;
  max-height: 7.25%;
  display: flex;
  flex-direction: row;
  justify-content: space-around;
  align-items: center;
  background-color: white;
  position: fixed;
  width: 100%;
  bottom: 0;
  transition: bottom 0.25s;
}
</style>

API

BaseTabBarItem

参数说明类型默认值
centerVisible是否中间隐藏 是则不是中间的样式 用于底部工具栏出现时隐藏中间样式Booleanfalse
showTextOnActive是否激活时才显示文字Booleanfalse
color文字颜色String
activeColor激活时文字颜色String
itemKey项键String,Number
activeItemKey激活项键 用于激活时显示String,Number
icon图标组件 - 图标组件需要自己实现Slot
text文字Slot
itemObject
事件
事件名称说明类型默认值
click点击回调function(itemKey){}
change改变回调function(itemKey){}
Item
参数说明类型默认值
icon图标 - 这里是自己实现的图标组件所需参数String
text文字String
route路由Object,String
badge徽章Object,String
isCenter是否中间样式Boolean
centerShape中间形状Stringcircle,square

BaseTabBar

参数说明类型默认值
centerVisible是否中间隐藏 是则不是中间的样式 用于底部工具栏出现时隐藏中间样式Booleantrue
showTextOnActive是否激活时才显示文字Booleanfalse
visible是否隐藏 是则不显示Booleantrue
color文字颜色String
activeColor激活时文字颜色String
activeItemKey激活项键 用于激活时显示String,Number
baseTabBarstab项数组Array
事件
事件名称说明类型默认值
click点击回调function(){}
change改变回调function(itemKey){}

示例

BaseTabBar 中间样式
BaseTabBar 普通样式

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值