Vue.js--标签页组件

效果

在这里插入图片描述

入口页 index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>标签页组件</title>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
    <div id="app" v-cloak>
        <tabs v-model="activeKey">
            <pane label="标签一" name="1">
                标签一的内容
            </pane>
            <pane label="标签二" name="2">
                标签二的内容
            </pane>
            <pane label="标签三" name="3">
                标签三的内容
            </pane>
        </tabs>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="pane.js"></script>
    <script src="tabs.js"></script>
    <script type="text/javascript">
        var app = new Vue({
            el: '#app',
            data: {
                activeKey: '1'
            }
        });
    </script>
</body>
</html>
样式表 style.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 #d7dde4;
    cursor: pointer;
    position: relative;
}
.tabs-tab-active{
    color: #ee99ff;
    border-top: 1px solid #3399ff;
    border-bottom: 1px solid #fff;
}
.tabs-tab-active:befor{
    content: '';
    display: block;
    height: 1px;
    background: #3399ff;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
}
.tabs-content{
    padding: 8px 0;
}
标签页外层的组件tabs tabs.js
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: {
            type: [String, Number]
        }
    },
    data: function () {
        return {
            //用于渲染tabs的标题
            currentValue: this.value,
            navList: []
        }
    },
    methods: {
        tabCls(item){
            return [
                'tabs-tab',
                {
                    'tabs-tab-active': item.name === this.currentValue
                }
            ]
        },
        getTabs(){
            //通过遍历子组件,得到所有的pane组件
            return this.$children.filter(function (item) {
                return item.$options.name === 'pane';
            });
        },
        updateNav(){
            this.navList = [];
            //设置对this的引用,在function回调里,this的指向的并不是Vue实例
            var _this = this;

            this.getTabs().forEach((pane, index) => {
                _this.navList.push({
                    label: pane.label,
                    name: pane.name || index
                });
                //如果没有给pane设置name,默认设置它的索引
                if(!pane.name)
                    pane.name = index;
                //设置当前选中的tab的索引
                if(index === 0){
                    if(!_this.currentValue){
                        _this.currentValue = pane.name || index;
                    }
                }
            });
            this.updateStatus();
        },
        updateStatus(){
            var tabs = this.getTabs();
            var _this = this;
            //显示当前选中的tab对应的pane组件,隐藏没有选中的
            tabs.forEach(tab => {
                return tab.show = tab.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);
        }
    },
    watch: {
        value: val => {
            this.currentValue = val;
        },
        currentValue: function () {
            this.updateStatus();
        }
    }
});
标签页嵌套的组件pane pane.js


Vue.component('pane',{
    name: 'pane',
    template: '\
        <div class="pane" v-show="show">\
            <slot></slot>\
        </div>',
    data: function () {
        return {
            show: true
        }
    },
    props: {
        name: {
            type: String
        },
        label: {
            type: String,
            default: ''
        }
    },
    methods: {
        updateNav: function () {
            this.$parent.updateNav();
        }
    },
    watch: {
        label: function () {
            this.updateNav();
        }
    },
    mounted: function () {
        this.updateNav();
    }
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值