JSFiddle - React, Tailwind, and code Playground

by edith_tang

HTML

<div id="app" v-cloak>
        <tabs v-model="activeKey">
          <pane label="Brightness/Contrast" name="1">标签一的内容</pane>
          <pane label="Input Source" name="2">标签二的内容</pane>
          <pane label="Display" name="3">标签三的内容</pane>
          <pane label="Audio" name ="4">标签四的内容</pane>
        </tabs>
    </div>

CSS

[v-clock] {
    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 #d7dded;
    cursor: pointer;
    position: relative;
}

.tabs-tab-active {
    color: #3399ff;
    border-top: 1px solid #3399ff;
    border-bottom: 1px solid #fff;
}

.tabs-tab-active:before {
    content: '';
    display: block;
    height: 1px;
    background: #3399ff;
    top: 0;
    left: 0;
    right: 0;
}

.tabs-content {
    padding: 8px 0;
}

JavaScript

Vue.component('pane', {
    name: 'pane',
    template: '\
    <div class="pane" v-show="show">\
        <slot></slot>\
    </div>',
    data: function() {
        return {
            show: true
        }
    },
    // 赋予唯一要显示的标签内容唯一的Name,从而进行辨识。pane本身并不会知道这些信息,都是由父组件tabs传递过来的,所以用props来接收。
    // 再说到label,随着每次点击,都需要更新相应的标签,所以需要进行update,但是因为这是一个独立组件,不能用vuex或者总线bus.js的方式来管理状态,可以直接通过this.$parent来访问tabs组件的实例来调用它的方法更新标题
    props: {
        name: {
            type: String
        },
        label: {
            type: String,
            default: ''
        }
    },
    methods: {
        updateNav() {
            this.$parent.updateNav();
        }
    },
    watch: {
        label() {
            this.updateNav();
        }
    },
    mounted() {
        this.updateNav();
    }
}) 

Vue.component('tabs', {
    template: '\
    <div class="tabs">\
        <div class="tabs-bar">\
        <!-- 标签页用v-for放在这里 -->\
            <div \
                :class="tabCls(item)" \
                v-for="(item, index) in navList" \
                @click="handleChange(index)"> \
                {{ item.label }} \
            </div>\
        </div>\
        <div class="tabs-content">\
            <!-- 这里的slot就是嵌套的pane -->\
            <slot></slot>\
        </div>\
    </div>',
    props: {
        value: {
//             Add multiple data types for props
            type: [String, Number]
        }
    },
    data: function() {
        return {
            currentValue: this.value,
            navList: []
        }
    },
    methods: {
        tabCls: function (item) {
            return [
                'tabs-tab',
                {
                    'tabs-tab-active': item.name === this.currentValue
                }
            ]
        },
        handleChange: function(index) {
            var nav = this.navList[index];
            var name = nav.name;
            this.currentValue = name;
            this.$emit('input', name);
            this.$emit('on-click', name);
 ...