tabs组件

使用tabs还是使用路由

1 .单页面应用中,一个页面中选项卡太多的话,是把所有的逻辑写在一个组件中,用tabs组件,还是拆分称过多个路由比较好。
2 .在Vue里面使用动态组件
3 .算了,都实现一遍,到时候选吧。做完这个看下路由的高级
4 .分享的时候无法准确定位每个tab

动态组件

1 .为什么vue的出名组件库,组件的写法都使用了jsx

核心代码:内外解耦的情况下
<div class="tabs">
        <div class="tab-nav">
            <div 
                v-for="tab in tablist"
//传入一个数组,里面包含了要导航的信息
                :class=" tabIndex == tab.index ? 'tabs-active' : '' "
//通过当前tab的index,和传入的currentindex两个变量来判断当前该选那个组件,这个是tab的css渲染,要是之前就要在这里面包一个v-if来判断,现在使用跟这个就简单了
                @click="changeTab(tab)"
//每一次点击切换的事件
            >
                {{tab.name}}
            </div>
        </div>
    </div>
//第一部分:切换按钮选项
    <transition name="component-fade" mode="out-in" class="tabs-content">
       <keep-alive>
//缓存之前渲染过的tabitem
           <slot></slot>
//使用slot动态分发下面的item
       </keep-alive>
    </transition>

组件使用:

<tabs
            :tablist="tablist"
            :tabIndex="tabIndex"
            @changeTab="changeTab"
        >
            <component :is="currentContent">
            </component>

</tabs>

 tablist:[
                {
                    index:0,
                    name:'选项1',
                    component:'one'
                },{
                    index:1,
                    name:'选项2',
                    component:'two'
                }
            ],
            tabIndex:0,
            currentContent:'one'

功能实现

1 .切换的过渡,要顺滑,或者有配置参数可以选择
2 .位置:通过配置参数来对布局进行定位
3 .动态增加标签?真实的项目会有需求么?
4 .切换到tab加载数据,数据传递。
5 .这个和走马灯的区别
6 .页签要可以加图标
7 .鼠标选中页面icon会动。
8 .鼠标切入,相应文字按钮出现复杂动画。比如标签进来的动画,按钮的border-top变颜色,如果使用active来操作的话,非常的不自然,所以需要加个辅助元素。使用i标签。
9 .js去掉字符串的最后两位str.substring(0,str.length-3)

支持传入的css参数

1 .整个tab的宽,高
2 .上面转换标签的高度,下面的显示是自适应

vue缺点

1 .style绑定的时候,return 的时候是不能使用transform,这个里面是不能返回函数的。
2 .这样就可以通过切换class来实现。但是切换class需要提前写好样式。还是直接写style可以
3 .其实通过配置项是很容易改写组件的布局样式,主要是代码的量变多,所以在实际写的时候还是需要结合项目实际的需求,在传入配置需求和实际项目之间进行取舍。
4 .

遇到问题

1 .svg图标使用animejs进行动画的时候会出现残留,只能使用js操作style来模拟了。。

IMG20181012_113932.png

2 .鼠标mouse事件
3 .缓动函数参考 https://easings.net/zh-cn

<template>
<div :style="tabs" class="tabs">
    <div    
            :style="tabsNav"
            class="tabs-nav">
            <div 
                v-for='tab in tablist'
                :class=" tabIndex == tab.index ? 'tabs-active' : '' "
                 @mouseenter="changeTab(tab,$event)"
                 @mouseleave="outSome()"
                class="tabs-item"
            >
                <span>{{tab.name}}</span>
                <svg v-if="tab.icon" class="icon tabsicon" aria-hidden="true">
                    <use :xlink:href="tab.icon"></use>
                </svg>

            </div>
            <i 
                class="iactive-top"
                :style="activeTop"
            ></i>
    </div>
    <div class="tabs-content">
        <transition name="component-fade" mode="out-in" >
            <keep-alive>
                <slot></slot>
            </keep-alive>
        </transition>
    </div>
</div>
</template>
<script>
import anime from 'animejs'
export default {
    data:function(){
        return {
            left:0,
        }
    },
    props:{
        tablist:{
            type:Array,
            require:true,
        },
        tabIndex:{
            type:Number,
            require:true,
        },
        tabswh:{
            type:Object,
            default:function(){
                return {
                    w:'478',
                    h:'460',
                    navh:'60px',
                    navw:'100',
                }
            }
        },
        type:{
            type:String,
            default:'youzuo'
        }
    },
    methods:{
        changeTab:function(tab,event){
            this.$emit('changeTab',tab)
            this.left=tab.index;
            let _this=this
            if(tab.icon){
                event.stopPropagation()
               this.svgSrc=event.target.querySelector('svg')
            //    this.svgSrc.style.left='3px'
               this.anime=anime({
                   targets:this.svgSrc,
                   left:'5px',
                   easing: 'easeInQuint',
                   duration:100,
                   
                   
               })
            }  
        },
        outSome:function(){
            this.anime=anime({
                targets:this.svgSrc,
                left:'0px',
                duration:0,
            })
        }

    },
    computed:{
        tabs:function(){
            if(this.type=='default'||this.type=="xiashang"){
                // 上下
                return {
                        'width':this.tabswh.w+'px',
                        'height':this.tabswh.h+'px',
                        'flex-direction': 'column'

                }
            }else if(this.type=="zuoyou"||this.type=="youzuo"){
                // 左右
                return {
                    'width':this.tabswh.w+'px',
                    'height':this.tabswh.h+'px',
                    'just-content':'center'
                }
            }  
        },
        //整体布局

        tabsNav:function(){
            if(this.type=='default'){
                return{
                    height:this.tabswh.navh,
                    'flex-direction':'row'
                }
            }else if(this.type=="zuoyou"){
                return {
                    width:this.tabswh.navw+'px',
                    'flex-direction':'column'
                }
            }else if(this.type=="youzuo"){
                return {
                     width:this.tabswh.navw+'px',
                    'flex-direction':'column',
                     order:2
                }
            }else if(this.type=="xiashang"){
                return{
                    height:this.tabswh.navh,
                    'flex-direction':'row',
                    order:2
                }
            }
        },
        //标签的样式

        activeTop:function(){
            if(this.type=="default"||this.type=='xiashang'){
                let width=Math.ceil(this.tabswh.w/this.tablist.length)
                return{
                        'width':width+'px',
                        left:this.left*width+'px',
                        height: '3px',
                        top:0,          
                    }
                }
            if(this.type=="youzuo"||this.type=="zuoyou"){
                let height=Math.ceil(this.tabswh.h/this.tablist.length)
                return {
                    'height':height+'px',
                     width:'3px',
                     right:0,
                     top:this.left*height+'px'
                }
            }

        },
        //横线有关的样式
        iwidth:function(){
            // console.log(Math.ceil(this.tabswh.w/this.tablist.length))
            // return Math.ceil(this.tabswh.w/this.tablist.length)
        }

    },
    mounted:function(){
        // console.log(this.activeTop)
    }
}
</script>
<style>
.component-fade-enter-active, .component-fade-leave-active{
  transition: opacity .3s ease;
}
.component-fade-enter, .component-fade-leave-to{
  opacity: 0;
}

.tabs{
    display: flex;
}
.tabs-nav{
    display: flex;
    position: relative;
}
.tabs-item{
    display: flex;
    justify-content: center;
    align-items: center;
    flex:1;
    color:#3c3c3c;
    text-overflow: ellipsis;
    white-space: normal;
    font-family: 'fantasy';
    cursor: pointer;
    font-size: 16px;
    border-top:transparent solid 3px;  
}
.tabs-item span{
    /* flex:1;
    height: 100%; */
}
.tabs-active{
    color:#f24854;
}
.iactive-top{
    position:absolute;
    background: #f24854;
    transition:all ease .3s;

}

.tabs-content{
    flex:1
}
.tabsicon{
    position: relative;
    transition:all 0.2s ease-in-out;
    /* left: 3px; */
}
</style>


未来要做

1 .含有下拉菜单的选项卡
2 .含有翻页的选项卡,一般来说这么多就够了,6个页签了。。
3 .标签文字产生换行的时候,最多可以有两行
4 .切换的滚动画面,现在是淡入淡出的,左右移动的。
5 .

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • awesome-github-vue 是由OpenDigg[https://blog.csdn.net/opend...
    我是七月阅读 2,400评论 0 20
  • 内容 UI组件 开发框架 实用库 服务端 辅助工具 应用实例 Demo示例 UI组件 element ★13489...
    秋玄语道阅读 13,692评论 3 116
  • 转载 :OpenDiggawesome-github-vue 是由OpenDigg整理并维护的Vue相关开源项目库...
    果汁密码阅读 23,083评论 8 124
  • 逛超市小记 早上大宝这个小打鸣鸡又是不到六点就起来,让最近一直晚睡的我都崩溃了。今早等给他收拾好去散步时人家又睡了...
    糖糖小窝阅读 125评论 0 1
  • 调和和 递归简论-递归的基本准则 学习数据结构与算法的一个重要是帮助我们写出高效的程序(在巨大数据集上运行时在合理...
    借东西的小矮人阅读 143评论 0 0