iviewUI-Tabs选项卡切换组件

概述 

选项卡切换组件,常用于平级区域大块内容的的收纳和展现。

源码地址:https://github.com/iview/iview/tree/2.0/src/components/tabs

使用:

<template>
    <Tabs name="first">
        <TabPane label="macOS" icon="logo-apple" tab="first">
            <Tabs name="second" >
                <TabPane label="macOS" icon="logo-apple" tab="second">标签一的内容</TabPane>
                <TabPane label="Windows" icon="logo-windows" tab="second">标签二的内容</TabPane>
                <TabPane label="Linux" icon="logo-tux" tab="second">标签三的内容</TabPane>
            </Tabs>
        </TabPane>
        <TabPane label="Windows" icon="logo-windows" tab="first">标签二的内容</TabPane>
    </Tabs>
</template>

在源码的tabs文件下有三个文件:index.js,tabs.vue,pane.vue

index.js中引入了tabs.vue和pane.vue.

import Tabs from './tabs.vue';
import Pane from './pane.vue';

Tabs.Pane = Pane;
export default Tabs;

tabs.vue

tabs.vue是整个组件的容器,分为三部分:

1 通过<slot name="extra"></slot> 扩展tabs选项的附加内容。

2 通过this.$children获取tabs下的每一个TabPane并放进navLIst,遍历navLIst设置tabs选项标签。

3 声明slot接收整个panes。

this.$children查找当前组件的直接子组件,可以遍历全部子组件, 需要注意 $children 并不保证顺序,也不是响应式的。

slot 插槽
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。Slot分发的内容,作用域是在父组件上
<template>
    <div :class="classes">
        <div :class="[prefixCls + '-bar']">
            <div :class="[prefixCls + '-nav-right']" v-if="showSlot"><slot name="extra"></slot></div>
            <div
                :class="[prefixCls + '-nav-container']"
                tabindex="0"
                ref="navContainer"
                @keydown="handleTabKeyNavigation"
                @keydown.space.prevent="handleTabKeyboardSelect(false)"
            >
                <div ref="navWrap" :class="[prefixCls + '-nav-wrap', scrollable ? prefixCls + '-nav-scrollable' : '']">
                    <span :class="[prefixCls + '-nav-prev', scrollable ? '' : prefixCls + '-nav-scroll-disabled']" @click="scrollPrev"><Icon type="ios-arrow-back"></Icon></span>
                    <span :class="[prefixCls + '-nav-next', scrollable ? '' : prefixCls + '-nav-scroll-disabled']" @click="scrollNext"><Icon type="ios-arrow-forward"></Icon></span>
                    <div ref="navScroll" :class="[prefixCls + '-nav-scroll']">
                        <div ref="nav" :class="[prefixCls + '-nav']" :style="navStyle">
                            <div :class="barClasses" :style="barStyle"></div>
                            <div :class="tabCls(item)" v-for="(item, index) in navList" @click="handleChange(index)">
                                <Icon v-if="item.icon !== ''" :type="item.icon"></Icon>
                                <Render v-if="item.labelType === 'function'" :render="item.label"></Render>
                                <template v-else>{{ item.label }}</template>
                                <Icon :class="[prefixCls + '-close']" v-if="showClose(item)" :type="arrowType" :custom="customArrowType" :size="arrowSize" @click.native.stop="handleRemove(index)"></Icon>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div :class="contentClasses" :style="contentStyle" ref="panes"><slot></slot></div>
    </div>
</template>

pane.vue

pane窗格文件主要作用是,接收传进来name,label,icon,disabled,closable,tab,index参数,和父组件传进来的注入inject: ['TabsInstance'],以获取父组件的this引用.以便在参数及销毁时调用父组件的updateNav更新每一个tab.

provide/inject

在vue中不同组件通信方式如下:
1.父子组件,通过prop
2.非父子组件,通过vuex或根vue转载器

通常是以上两种情况,然而还有一种比较特殊的情况,即孙子组件或更深层次的组件通信

为什么不用vuex,简单省事????
有很多为了这个引入vuex会导致代码性价比比较低,项目本身没有使用vuex的必要
1.provide就相当于加强版父组件prop
2.inject就相当于加强版子组件的props 

缺点
这么做也是有明显的缺点的,在任意层级都能访问导致数据追踪比较困难,因此这个属性通常并不建议使用。能用vuex的使用vuex,但是在做组件库开发时,不对vuex进行依赖,且不知道用户使用环境的情况下可以很好的使用 

<template>
    <div :class="prefixCls" v-show="show" :style="contentStyle"><slot></slot></div>
</template>
<script>
    const prefixCls = 'ivu-tabs-tabpane';

    export default {
        name: 'TabPane',
        inject: ['TabsInstance'],
        props: {
            name: {
                type: String
            },
            label: {
                type: [String, Function],
                default: ''
            },
            icon: {
                type: String
            },
            disabled: {
                type: Boolean,
                default: false
            },
            closable: {
                type: Boolean,
                default: null
            },
            // Tabs 嵌套时,用 tab 区分层级,指向对应的 Tabs 的 name
            tab: {
                type: String
            },
            // 在 TabPane 使用 v-if 时,并不会按照预先的顺序渲染,这时可设置 index,并从小到大排序
            // 数值需大于 0
            index: {
                type: Number
            }
        },
        data () {
            return {
                prefixCls: prefixCls,
                show: true,
                currentName: this.name
            };
        },
        computed: {
            contentStyle () {
                return {
                    visibility: this.TabsInstance.activeKey !== this.currentName ? 'hidden' : 'visible'
                };
            }
        },
        methods: {
            updateNav () {
                this.TabsInstance.updateNav();
            }
        },
        watch: {
            name (val) {
                this.currentName = val;
                this.updateNav();
            },
            label () {
                this.updateNav();
            },
            icon () {
                this.updateNav();
            },
            disabled () {
                this.updateNav();
            }
        },
        mounted () {
            this.updateNav();
        },
        destroyed () {
            this.updateNav();
        }
    };
</script>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章