Vue实战--标签页组件

好久没有写文章了,这一段时间在忙着准备期末考试和找实习,上周已经在一家公司开始实习了,公司是用Vue开发项目,Boss让我们实习生看几个项目的代码,第一次接触完整的上线项目,发现代码结构分的很细,几乎每个文件都在使用export、import导入导出,有些Vue用法是之前没有接触过的,实习一周下来看代码看的有点蒙。。。所以打算利用空余时间,重新学习Vue,至少一周写一篇Vue实践总结~

Vue作为一个前端轻量级的MVVM框架,组件化是其一个重要的功能和特点,组件化的优点是显而易见的,一个页面的不同部分可以拆分成独立的组件,然后在不同的页面就可以共享这些组件,避免重复开发。下面是我编写的一个标签页组件,先上最终效果图~

![演示图](https://user-gold-cdn.xitu.io/2019/7/7/16bcc09348961dc9?w=435&h=235&f=gif&s=42077 "演示图")

### 组件文件结构

- index.html 入口页

- style.css 样式页

- tab.js 标签页组件 tabs

- pane.js 标签页组件 pane

![文件目录](https://user-gold-cdn.xitu.io/2019/7/7/16bcc09348bf725c?w=312&h=181&f=png&s=7738 "文件目录")

### 初始化各个文件

index.js:

```javascript

   

    标签页组件

   

   

       

           

                标签一的内容

           

           

                标签二的内容很重要,不能关闭

           

           

                标签三的内容

           

       

   

   

   

   

   

```

tab.js:

```javascript

Vue.component('tabs',{

    template:'\

       

\

           

\

                \

               

               

\

           

\

           

\

                \

                \

           

\

       

',

})

```

pane.js

```javascript

Vue.component('pane',{

    name:'pane',

    template: '\

       

\

            \

       

',

    data: function(){

        return{

            show:true

        }

    }

})

```

pane需要控制标签页内容的显示与隐藏,设置一个data:show,通过这个属性来动态添加class

### 功能实现

在pane.js里设置`prop: name`唯一的值来标识这个 pane,但它不是必需的,如果使用者不设置,可以默认从0开始自动设置;设置`prop: label`其内容显示在标签页标题里;还有`prop: closable`用来是否显示关闭标签按钮。这部分代码如下:

```javascript

props:{

    name: {

        type:String

    },

    label: {

        type:String,

        default:''

    },

    closable: {

        type: Boolean,

        default: true

    }

}

```

由于上面的`prop: label`用户是可以动态调整的,所以在pane初始化及label更新时,都要通知父组件更新,更新方法定为`updateNav`

```javascript

    methods:{

        updateNav (){

            this.$parent.updateNav();

        }

    },

    watch:{

        label(){

            this.updateNav();

        }

    },

    mounted(){

        this.updateNav();

    }

```

pane.js功能基本实现了,剩余任务就是完成tabs.js组件。

首先需要把pane组件设置的标题动态谊染出来,也就是当pane触发tabs的updateNav方法时,更新标题内容。这部分的代码:

```javascript

    methods: {

        getTabs () {

            // 通过遍历子组件,得到所有的pane组件

            return this.$children.filter(function(item){

                return item.$options.name==='pane';

            })

        },

        updateNav () {

            this.navList=[];

            var _this=this;

            this.getTabs().forEach(function(pane,index){

                _this.navList.push({

                    label: pane.label,

                    name: pane.name||index,

                    closable: pane.closable

                });

                if(!pane.name){

                        pane.name=index;

                }

                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;

            })

        }

    }

```

拿到navList后,就需要对它用v-for指令把tab的标题渲染出来,并且判断每个tab当前的状态:是否选择,是否可以关闭。这部分代码如下:

```javascript

Vue.component('tabs',{

    template:' \

 

\

     

\

         

                :class="tabCls(item)" \

                v-for="(item,index) in navList" \

                @click="handleChange(index)">\

                    {{item.label}} \

                    \

         

\

     

\

     

\

        \

     

\

     

'

})

```

上面标签绑定了三个方法:`handleChange`,`ifShowClose`,`closeTab`,其代码如下

```javascript

    handleChange: function(index){

        var nav=this.navList[index];

        var name=nav.name;

        // 更新当前选择的tab

        this.currentValue=name;

        // 更新value

        this.$emit('input',name);

    },

    ifShowClose (item) {

        // 是否显示关闭标签按钮

        return item.closable;

    },

    // 点击关闭按钮触发的事件

    closeTab (index) {

        // console.log(this.navList[index].name, this.currentValue);

        // 如果关闭的是当前选择的tab,则将currentValue转到前一个tab

        if (this.navList[index].name == this.currentValue) {

            let toIndex = index - 1;

            toIndex = toIndex >=0 ? toIndex : this.navList.length + toIndex;

            console.log(toIndex);

            this.currentValue = this.navList[toIndex].name;

        }

        //关闭当前标签页

        this.navList.splice(index, 1);

    }

```

另外通过CSS3的`transform: translateX`来增加标签页内容切换动画:

```css

.pane {

    visibility: hidden;

    width: 100%;

    height: 0;

    transform: translateX(-100%);

    transition: all .5s ease-in;

}

.pane-active {

    visibility: visible;

    transform: translateX(0);

}

```

### 完整代码

完整代码已经上传到github上了,[传送门](https://github.com/libilin2018/learn-Vue.js)

### 最后

以上是该组件的基本实现,这是我结合《Vue.js实战》这本书完成的,通过这个实例,巩固了Vue的一些基本用法,对Vue的组件化思想有了更清晰的认识。另外我添加的标签切换动画感觉比较生硬,简友们如果有更好的办法欢迎提出来~

你可能感兴趣的:(Vue实战--标签页组件)