Vue2 个人组件库 —— 标签页

452 阅读1分钟

个人组件库文档地址

Tabs 标签页

基础用法

<vp-tabs v-model="tabsActiveName">
  <vp-tab-pane label="小卡车" name="n1">小卡车</vp-tab-pane>
  <vp-tab-pane label="蜘蛛侠" name="n2">蜘蛛侠</vp-tab-pane>
  <vp-tab-pane label="猪猪侠" name="n3">猪猪侠</vp-tab-pane>
</vp-tabs>

<script>
  export default {
    data() {
      return {
        tabsActiveName: "n2",
      };
    },
  };
</script>

Tabs 组件代码

<template>
  <div class="vp-tabs">
    <div class="vp-tabs_item_container">
      <div
        :class="[
          'vp-tabs_item',
          value === child.name ? 'vp-tabs_item_active' : '',
        ]"
        @click="handleClickTabItem(child.name, $event)"
        v-for="child in $children"
        :key="child.name"
      >
        {{ child.label }}
      </div>
      <div
        class="vp-tabs__active-bar"
        :style="{
          width: clientWidth + 'px',
          transform: `translateX(${scrollleft}px)`,
        }"
      ></div>
    </div>
    <slot></slot>
  </div>
</template>

<script>
export default {
  name: "vpTabs",
  props: {
    value: {
      type: String,
      default: "",
    },
  },
  watch: {
    value: {
      handler(newVal) {
        this.$nextTick(() => {
          let currentIndex = this.$children.findIndex((item) => {
            return item.name === newVal;
          });
          this.currentIndex = currentIndex;
          let itemNodeList = this.$el.children[0].children;
          let scrollleft = 0;
          for (let i = 0; i < itemNodeList.length - 1; i++) {
            if (i !== this.currentIndex) {
              scrollleft += itemNodeList[i].clientWidth;
            } else {
              this.clientWidth = itemNodeList[i].clientWidth;
              break;
            }
          }
          this.scrollleft = scrollleft;
        });
      },
      immediate: true,
      deep: true,
    },
  },
  data() {
    return {
      currentIndex: 0,
      scrollleft: 0,
      clientWidth: 0,
    };
  },
  mounted() {
    let currentIndex = this.$children.findIndex((item) => {
      return item.name === this.value;
    });
    this.currentIndex = currentIndex;
    setTimeout(() => {
      let itemlist = this.$el.querySelectorAll(".vp-tabs_item");
      this.clientWidth = itemlist[this.currentIndex]?.clientWidth;
      let itemNodeList = this.$el.children[0].children;
      let scrollleft = 0;
      for (let i = 0; i < itemNodeList.length - 1; i++) {
        if (i !== this.currentIndex) {
          scrollleft += itemNodeList[i].clientWidth;
        } else {
          this.clientWidth = itemNodeList[i].clientWidth;
          break;
        }
      }
      this.scrollleft = scrollleft;
    }, 500);
  },
  methods: {
    /**
     * 点击tab事件
     */
    handleClickTabItem(name, e) {
      this.$emit("input", name);
    },
  },
};
</script>

<style lang="less" scoped>
.vp-tabs {
  .vp-tabs_item_container {
    display: flex;
    position: relative;
    z-index: 1;
    .vp-tabs__active-bar {
      position: absolute;
      bottom: 0;
      left: 0;
      height: 4px;
      background-color: #409eff;
      z-index: 100;
      transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
      list-style: none;
    }
    .vp-tabs_item {
      padding: 10px 20px;
      cursor: pointer;

      &:hover {
        color: #409eff;
      }
    }
    .vp-tabs_item_active {
      color: #409eff;
    }
    ::after {
      content: "";
      position: absolute;
      width: 100%;
      height: 2px;
      background-color: #e4e7ed;
      z-index: 2;
      left: 0;
      bottom: 0;
    }
  }
}
</style>

Tab-pane 组件代码


<template>
  <div class="vp-tab-pane">
    <transition name="slide-fade">
      <div class="vp-tab-pane_content" v-show="currentTab === name">
        <slot></slot>
      </div>
    </transition>
  </div>
</template>

<script>
export default {
  name: "vpTabPane",
  props: {
    label: {
      type: String,
      default: "",
    },
    name: {
      type: String,
      default: "",
    },
  },
  watch: {
    "$parent.value": {
      handler(newVal) {
        this.currentTab = newVal;
      },
      immediate: true,
    },
  },
  data() {
    return {
      currentTab: "",
    };
  },
  created() {},
  mounted() {},
};
</script>

<style lang="less" scoped>
.vp-tab-pane {
  .vp-tab-pane_content {
    padding: 10px;
  }
}

.slide-fade-enter-active {
  transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1);
}

.slide-fade-enter {
  transform: translateX(10px);
  opacity: 0;
}
</style>

Tabs Attributes

属性名类型属性值描述默认值
v-modelString-第一个选项卡的 name-

Tabs-pane Attributes

属性名类型属性值描述默认值
labelString-标签卡标题-
nameString-与选项卡绑定值 value 对应的标识符,表示选项卡别名-

Tabs Events

事件名描述返回值
tab-click标签页点击vnode, event
.switch-base { padding: 20px; border: 1px solid #95a5a6; border-radius: 5px; display: flex; } .div-row { margin: 10px; }