1. 程式人生 > 其它 >Vue 基於 ant-design-vue 封裝 TabBar

Vue 基於 ant-design-vue 封裝 TabBar

技術標籤:vuejs封裝javascripthtml

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 普通樣式