美文网首页
标签页组件开发

标签页组件开发

作者: 咸鱼前端 | 来源:发表于2019-03-27 17:28 被阅读0次

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>
    <style>
        [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
        }

        .fade-enter-active,
        .fade-leave-active {
            transform: translateX(0);
            transition: transform .6s;
        }

        .fade-enter,
        .fade-leave-to {
            opacity: 0;
            transform: translateX(100%);
            transition: transform .1s;
        }

        .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;
            transform: translateY(-1px);
            transition: transform .5s;
        }

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

        .tabs-content {
            padding: 8px 0;
            opacity: 1;
            transition: opacity 20s;
        }
    </style>
</head>

<body>
    <div id="app" v-cloak>
        <tabs v-model="activeKey">
            <pane label="游泳123" name="游泳">标签一的内容</pane>
            <pane label="标签二" name="2">标签二的内容</pane>
            <pane label="标签三" name="3">标签三的内容</pane>
        </tabs>
    </div>
    <script src="/node_modules/vue/dist/vue.js"></script>
    <script src="/js/pane.js"></script>
    <script src="/js/tabs.js"></script>

    <script>
        let vm = new Vue({
            el: "#app",
            data: {
                activeKey: "游泳" // 设置一个默认选中的选项卡
            }
        })
    </script>
</body>

</html>
pane.js
Vue.component("pane", {
    name: "pane",
    template: "\
    <transition name='fade' tag='div'> \
        <div class='pane' v-show='show'>\
            <slot></slot> \
        </div> \
    </transition>",
    data() {
        return {
            show: false
        }
    },
    props: {
        name: {
            type: String,
            default: ""
        },
        label: {
            type: String
        },
        closable: {
            type: Boolean,
            default: true
        }
    },
    methods: {
        updateNav() {
            this.$parent.updateNav();
        }
    },
    mounted() {
        this.updateNav();
    },
    watch: {
        label() {
            this.updateNav(); // 调用父组件的updateNav方法实现组件的循环和更新组件显示
        }
    }
})
tabs.js
Vue.component("tabs", {
    template: `\
    <div class="tabs">\
        <div class="tabs-bar">\
                <div \
                    :class="tabCls(item)" \
                    :key="item.id" \
                    v-for="(item, index) in navList" \
                    @click="handleChange(index)" \
                    >{{item.label}} \
                    <span v-show="isShown(item)" @click.stop="deletTab(index)">x</span> \
                </div> \
        </div> \
        <div class="tabs-content"> \
            <slot></slot> \
        </div> \
    </div>`,
    props: {
        value: {
            type: [String, Number], // 接收父组件设置的默认显示的name
        }
    },
    data() {
        return {
            currentValue: this.value, // 用一个参数接收父组件传递过来的值,单独维护
            navList: [] // 这个数组用来装子组件的label和name
        }
    },
    methods: {
        tabCls(item) {
            return [
                "tabs-tab", {
                    "tabs-tab-active": item.name === this.currentValue // 动态设置样式,只有item.name等于当前currentValue才会添加选中样式
                }
            ]
        },
        getTabs() {
            return this.$children.filter((item) => {
                return item.$options.name === "pane" // 因为后面会经常用到子组件,这里单独定义一个方法获取所有的子组件,约定好子组件的name为"pane"
            })
        },
        updateNav() {
            this.navList = []; // 数组置空,初始化
            this.getTabs().forEach((pane, index) => { // 获取到所有的子组件之后遍历
                this.navList.push({ // 往数组中存子组件的label和name还有是否可关闭当前选项卡的布尔值
                    label: pane.label,
                    name: pane.name || index,
                    closable: pane.closable
                });
                if (!pane.name) pane.name = index; // 因为子组件接收的name值非必需,所以存在没有name的情况下,将索引值赋值上去。
                if (index === 0) { // 如果是第一个子组件
                    if (!this.currentValue) { // 当前并没有currentValue值,即为页面刚加载,所以这里初始化
                        this.currentValue = pane.name || index // 默认选中第一个
                    }
                }
            });
            this.updateStatus(); // 调用更新视图的方法
        },
        updateStatus() {
            var tabs = this.getTabs(); // 获取到所有子组件
            tabs.forEach((tab) => { // 遍历所有的子组件
                return tab.show = tab.name === this.currentValue
                // 如果子组件的name等于当前的currentValue,即将子组件的show设置为true显示当前的子组件
            })
        },
        handleChange(index) {
            var nav = this.navList[index]; // 拿到当前点击的选项卡的索引值
            this.currentValue = nav.name; // 将currentValue设置为当前点击组件的name值,完成切换选项卡
        },
        isShown(item) {
            var flag = item.closable; // 如果子组件传递的参数是可关闭的,会在页面渲染的时候有个关闭的按钮
            return flag;
        },
        deletTab(index) {
            if (this.navList[index].name === this.currentValue) { 
            // 如果当前点击的name等于currentValue,代表是关闭当前选中的选项卡
                if (index > 0) { // 如果不是第一个
                    this.navList.splice(index, 1); // 数组删除掉当前的数据
                    this.currentValue = this.navList[index - 1].name; // 将上一个选项卡设置为选中
                } else { // 如果是第一个
                    this.navList.splice(index, 1); // 数组删除掉当前的数据
                    if (this.navList.length > 0) { // 如果数组中有1条数据以上
                        this.currentValue = this.navList[0].name; // 将第一条数据设置为选中
                    } else { // 如果数组中没有了数据
                        this.currentValue = ""; // 将currentValue置空, 如果不置空,这里会有多出的一点显示
                    }
                }
            } else { // 如果当前点击的name不等于currentValue
                this.navList.splice(index, 1); // 直接将改数据从数组中删除
            }
        }
    },
    watch: {
        value() {
            this.updateStatus();
            // 如果value的值变化了,直接调用更新视图的方法
        },
        currentValue(val) {
            this.$emit("input", val); 
            // 这里监测currentValue的变化,如果变化利用父子特殊的通信方式,直接更新value的值
        }
    }
})

相关文章

网友评论

      本文标题:标签页组件开发

      本文链接:https://www.haomeiwen.com/subject/jyktbqtx.html