Vue.js学习笔记—tabs:实战:开发一个标签页组件

参考《Vue,js》实战(梁灏编著)

tabs:实战:开发一个标签页组件

git代码
index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</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.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>',
    date:function(){
        return{
            show: true
        }
    },
    props:{
        name:{
            type:String
        },
        label:{
            type:String,
            default:''
        }
    },
    methods:{
        updateNav(){
            this.$parent.updateNav();
        }
    },
    watch:{
        label(){
            this.updateNav();
        }
    },
    mouted(){
        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就是嵌套的pane -->\
                <slot></slot>\
            </div>\
        </div>',
    props:{
        //这里的value是为了可以使用v-model
        value:{
            type: [String,Number]
        }
    },
    data:function(){
        return {
            //因为不能修改value,所以复制一份自己维护
            currentValue: this.value,
            //用于渲染tabls的标题
            navList: []
        }
    },
    methods:{
        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(function(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(function(tab){
                return tab.show = tab.name === _this.currentValue;
            })
        },
        tabCls:function(item){
            return [
                'tabs-tab',
                {
                    //给当前选中的tab加一个class
                    'tabs-tab-active' : item.name === this.currentValue
                }
            ]
        },
        //点击tab标题时触发
        handleChange:function(index){
            var nav = this.navList[index];
            var name = nav.name;
            //改变当前选中的tab,并触发下面的watch
            this.currentValue=name;
            //更新value
            this.$emit('input',name);
            //触发一个自定义事件,供父级使用
            this.$emit('on-click',name);
        }
    },
    watch:{
        value: function(val){
            this.currentValue=val;
        },
        currentValue:function(){
            //在当前选中的tab发生变化时,更新pane的显示状态
            this.updateStatus();
        }
    }
})

style.css

[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;
}
.tabs-bar{
    display: inline-block;
    padding: 4px 16px;
    margin-right: 6px;
    background: #fff;
    border: 1px solid #d7dde4;
    cursor: pointer;
    position: relative;
}
.tabs-bar-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;
}

本实战代码尚未成功实现相关效果,期望大佬指点

2020/7/15检查代码 发现tabs组件template和pans组件mounted方法相关代码书写错误,更正后即可正常实现功能(上述代码尚未改变读者可以自己发现哦)也可以访问git代码地址tabs:实战:开发一个标签页组件

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值