Vue实战--标签页组件
好久没有写文章了,这一段时间在忙着准备期末考试和找实习,上周已经在一家公司开始实习了,公司是用Vue开发项目,Boss让我们实习生看几个项目的代码,第一次接触完整的上线项目,发现代码结构分的很细,几乎每个文件都在使用export、import导入导出,有些Vue用法是之前没有接触过的,实习一周下来看代码看的有点蒙。。。所以打算利用空余时间,重新学习Vue,至少一周写一篇Vue实践总结~
这是我第一次在CSDN写文章,有些地方可能有误或描述不清楚,请谅解。本篇文章首发于掘金
Vue作为一个前端轻量级的MVVM框架,组件化是其一个重要的功能和特点,组件化的优点是显而易见的,一个页面的不同部分可以拆分成独立的组件,然后在不同的页面就可以共享这些组件,避免重复开发。下面是我编写的一个标签页组件,先上最终效果图~
组件文件结构
- index.html 入口页
- style.css 样式页
- tab.js 标签页组件 tabs
- pane.js 标签页组件 pane
初始化各个文件
index.js:
<html> <head> <meta charset="UTF-8"> <title>标签页组件</title> <link rel="stylesheet" href="style.css"> </head> <body> <div id="app" v-cloak> <tabs v-model="activeKey"> <pane label="标签一" name="1"> 标签一的内容 </pane> <pane label="标签二" name="2" :closable="false"> 标签二的内容很重要,不能关闭 </pane> <pane label="标签三" name="3"> 标签三的内容 </pane> </tabs> </div> <script src="https://unpkg.com/vue@2.6.10/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>
tab.js:
Vue.component('tabs',{ template:'\ <div class="tabs">\ <div class="tabs-bar">\ <!--标签页的标题,需要使用v-for-->\ <div \ </div>\ </div>\ <div class="tabs-content">\ <!--这里的slot即是嵌套的pane组件-->\ <sl 3ff7 ot></slot>\ </div>\ </div>', })
pane.js
Vue.component('pane',{ name:'pane', template: '\ <div>\ <slot></slot>\ </div>', data: function(){ return{ show:true } } })
pane需要控制标签页内容的显示与隐藏,设置一个data:show,通过这个属性来动态添加class
功能实现
在pane.js里设置
prop: name唯一的值来标识这个 pane,但它不是必需的,如果使用者不设置,可以默认从0开始自动设置;设置
prop: label其内容显示在标签页标题里;还有
prop: closable用来是否显示关闭标签按钮。这部分代码如下:
props:{ name: { type:String }, label: { type:String, default:'' }, closable: { type: Boolean, default: true } }
由于上面的
prop: label用户是可以动态调整的,所以在pane初始化及label更新时,都要通知父组件更新,更新方法定为
updateNav
methods:{ updateNav (){ this.$parent.updateNav(); } }, watch:{ label(){ this.updateNav(); } }, mounted(){ this.updateNav(); }
pane.js功能基本实现了,剩余任务就是完成tabs.js组件。
首先需要把pane组件设置的标题动态谊染出来,也就是当pane触发tabs的updateNav方法时,更新标题内容。这部分的代码:
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当前的状态:是否选择,是否可以关闭。这部分代码如下:
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}} \ <span v-if="ifShowClose(item)" class="close icon" @click.stop="closeTab(index)"></span> \ </div> \ </div> \ <div class="tabs-content"> \ <slot></slot> \ </div> \ </div>' })
上面标签绑定了三个方法:
handleChange,
ifShowClose,
closeTab,其代码如下
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.< 4000 /span>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来增加标签页内容切换动画:
.pane { visibility: hidden; width: 100%; height: 0; transform: translateX(-100%); transition: all .5s ease-in; } .pane-active { visibility: visible; transform: translateX(0); }
完整代码
完整代码已经上传到github上了,传送门
最后
以上是该组件的基本实现,这是我结合《Vue.js实战》这本书完成的,通过这个实例,巩固了Vue的一些基本用法,对Vue的组件化思想有了更清晰的认识。另外这是我第一次在CSDN写文章,有些地方可能有误或描述不清楚,请谅解。个人感觉标签页切换动画比较生硬,如果有更好的实现方法欢迎提出了~
- vue.js实战笔记:父子组件之间的那些事儿
- VUE入门到实战--Vue多个元素或者组件的过渡动画、列表过度,动画封装
- 详解vue2.0 使用动态组件实现 Tab 标签页切换效果(vue-cli)
- vue.js+koa2项目实战(五)axios 及 vue2.0 子组件和父组件之间的传值
- Vue实战——注册组件
- [直播预告] Vue.js 实战之 组件篇(上)
- VUE入门到实战--Vue组件参数校验和非props特性,给组件绑定原生事件
- Vue 初接触实战之账单组件
- Vue $mount实战之实现消息弹窗组件
- VUE入门到实战--Vue非父子组件传值、插槽、动态组件和v-once
- Vue组件实战之ivew源码Icon篇
- Vue组件实战之ivew源码button篇
- 项目实战之vue爬坑之路:vue框架中如何注册全局公共过滤器filter、全局公共插件、全局公共组件component
- Vue.js实战之组件的进阶
- Vue.js实战—组件详解
- 详解vue2.0 使用动态组件实现 Tab 标签页切换效果(vue-cli)
- VUE入门到实战--Vue组件细节问题
- 打通前后端全栈开发node+vue进阶【课程学习系统项目实战详细讲解】(3):用户添加/修改/删除 vue表格组件 vue分页组件
- Vue项目实战(三)- 组件的注册和使用
- Vue项目实战(四)- 组件之间的通信