Vue.js 的组件选项卡功能 试手

<!DOCTYPE html>
<html>
<head>
<meta  charset ="utf-8" >
    <title>标签页组件</title>
    <style>
        .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 #fff;
        }
            .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>
</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="../lib/vue.min.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>

pane.js内容

Vue.component('pane', {
    name: 'pane',
    template: '\<div class="pane" v-show="show">\
                <slot></slot>\
                </div>',
    props: {
        //前台设置的选项卡的编号和值
        name: {
            type: String
        },
        label: {
            type: String,
            default: ''
        }
    },
    data: function () {
        //是否显示的开关
        return {
            show: true
        }
    },
    methods: {
        //调用父组件的更新
        updateNav: function () {
            this.$parent.updateNav();

        }
    },
    watch: {
        //前台传入的内容 更新标题内容
        label: function () {
            this.updateNav();
        }
    },
    mounted: function () {
        //调用父组件的更新
        this.updateNav();
    }

})

tabs.js内容

Vue.component('tabs', {
    template: '\<div class="tabs">\
                <div class="tabs-bar">\
                 <div\
                :class="tabCls(item)"\
                v-for="(item,index) in navlist"\
                @click="handleChange(index)">\
                 {{item.label}}\
                </div>\
                </div>\
                <div class="tabs-content">\
                <slot></slot>\
                </div>\
                </div>',
    props: {
        //前台设置的activeKey 传入组件的值
        value: {
            type: [String, Number]
        }
    },
    data: function () {
        return {
            //当前索引为前台设置的activeKey 传入组件的值
            currentValue: this.value,
            navlist: []
        }
    },
    methods: {
        tabCls: function (item) {
            //绑定了当前选择Tab的激活样式
            return [
                'tabs-tab',
                {
                    'tabs-tab-active':item.name === this.currentValue
                }
            ]
        },
        getTabs: function () {
            //在子组件中过滤出pane的对象
            return this.$children.filter(function (item) {
                return item.$options.name === 'pane';
            })
        },
        updateNav: function () {
            //更新标题
            this.navlist = [];
            var _this = this;
            this.getTabs().forEach(function (pane, index) {
                //取出所有pane中的名字和内容放进数组
                _this.navlist.push({
                    label: pane.label,
                    name: pane.name || index
                });
                //如果没用标题名字则用序号
                if (!pane.name) pane.name = index;
                //设置当前选中的索引
                if (index === 0) {
                    if (!_this.currentValue) {
                        _this.currentValue = pane.name || index;
                    }
                }
            });
            this.updateStatus();
        },
        updateStatus: function () {
            //获取所有的子组件
            var tabs = this.getTabs();
            var _this = this;
            //显示当前选中Tab对应的子组件,隐藏别的子组件
            tabs.forEach(function (tab) {
                //子组件是否显示决定于  当前索引等于子组件名称
                return tab.show = tab.name === _this.currentValue;
            }
       )
        },
        handleChange: function (index) {
            //获取点击的选项卡
            var nav = this.navlist[index];
            //获取点击的选项卡序号
            var name = nav.name;
            //设置当前索引为点击的值
            this.currentValue = name;
            //返回父组件v-model的值
            this.$emit('input', name);
            //返回点击事件的值
            this.$emit('on-click', name);
        }
    },
    watch: {
        //监控默认设置的值
        value: function (val) {
            //设置当前索引为默认设置的值
            this.currentValue = val;
        },
        //监控设置索引值变化
        currentValue: function () {
            //让当前索引值对应选项卡显示 别的隐藏
            this.updateStatus();
        }
    }

})

发布了17 篇原创文章 · 获赞 4 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/ruo40018293/article/details/100159993