Tab页签切换是常用组件,经常穿梭于各个业务场景中,这篇文章将代理大家实现一个tabs和tab组件

我们先来看一下最终实现的效果图:
在这里插入图片描述

废话不多说,直接上代码,

先来看tabs.vue:

<template>
  <div class="tabs">
    <div class="tabs-bar">
      <div
        v-for="(item,index) in navList"
        :key="item.name"
        :class="tabCls(item)"
        @click="handleChange(index)">
        {{ item.label }}
      </div>
    </div>
    <div class="tabs-content">
      <slot />
    </div>
  </div>
</template>

<script>
export default {
  name: 'Tabs',
  props: {
    value: {
      type: [String, Number],
      default: null
    },
    required: {
      type: Boolean,
      default: true
    }
  },
  data () {
    return {
      currentValue: this.value,
      navList: []
    }
  },
  watch: {
    value: function (val) {
      this.currentValue = val
    },
    currentValue () {
      this.updateStatus()
    }
  },
  methods: {
    tabCls (item) {
      return [
        'tabs-tab',
        {
          'tabs-tab-active': item.name === this.currentValue
        }
      ]
    },
    getTabs () {
      // 获取tab
      return this.$children.filter(function (item) {
        // console.log('===>', item.$options.name)
        return item.$options.name === 'Tab'
      })
    },
    updateNav () {
      // 获取标题,name,并放置到navList数组中
      // console.log('获取标题,name,并放置到navList数组中', this.$children, this.getTabs())
      this.navList = []
      let _this = this
      this.getTabs().forEach(function (tab, index) {
        _this.navList.push({
          label: tab.label,
          name: tab.name || index

        })
        if (!tab.name) tab.name = index
        if (index === 0) {
          if (!_this.currentValue) {
            _this.currentValue = tab.name || index
          }
        }
      })
      this.updateStatus()
    },
    updateStatus () {
      let tabs = this.getTabs()
      let _this = this
      tabs.forEach(function (tab) {
        let b = tab.name === _this.currentValue
        tab.show = b
        return tab.show
      })
    },
    handleChange (index) {
      let nav = this.navList[index]
      let name = nav.name
      this.currentValue = name
      this.$emit('input', name)
      this.$emit('on-click', name)
    }
  }
}
</script>

<style lang="scss" scoped>
[v-cloak] {
  display: none;
}
.tabs {
  font-size: 14px;
  color: #657180;
}
.tabs-bar:after {
  content: "";
  display: block;
  width: 100%;
  height: 1px;
  background: #d7dde4;
  margin-top: -1px;
}
.tabs-tab {
  display: inline-block;
  padding: 4px 16px;
  margin-right: 6px;
  background: #fff;
  border: 1px solid #d7dde4;
  cursor: pointer;
  position: relative;
}
.tabs-tab-active {
  color: #3399ff;
  border-top: 1px solid #3399ff;
  border-bottom: 1px solid #3399ff;
}
.tabs-tab-active:before {
  content: "";
  display: block;
  height: 1px;
  background: #3399ff;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
}
.tabs-content {
  padding: 8px 0;
}
</style>

如下是tab.vue:

<template>
  <div
    v-show="show"
    class="tab">
    <slot />
  </div>
</template>

<script>
export default {
  name: 'Tab',
  props: {
    name: {
      type: String,
      default: ''
    },
    label: {
      type: String,
      default: ''
    }
  },
  data () {
    return {
      show: true
    }
  },
  computed: {
    active () {
      return false
    }
  },
  watch: {
    label () {
      this.updateNav()
    }
  },
  mounted () {
    this.updateNav()
  },
  methods: {
    updateNav () {
      this.$parent.updateNav()
    }
  }
}
</script>

最后我们来看一下如何使用:

<template>
  <div>
    <tabs v-model="value">
      <tab
        label="标签一"
        name="1">
        标签一内容
      </tab>
      <tab
        label="标签二"
        name="2">
        标签二内容
      </tab>
      <tab
        label="标签三"
        name="3">
        标签三内容
      </tab>
    </tabs>
  </div>
</template>
<script>
import tabs from '@/component/tabs'
import tab from '@/component/tab'
export default {
  components: {
    tabs,
    tab
  },
  data () {
    return {
      value: ''
    }
  }
}
</script>

欢迎访问我的个人博客:https://www.gaoyuan.ink,一起共勉学习~

Logo

前往低代码交流专区

更多推荐