Vue 组件封装之 Tab 切换
实战 Vue 第5天:封装一个tab切换组件前言使用现存组件面临的问题封装 tab 组件的思路封装 tab 组件代码总结前言以上 tab 切换功能在前端开发中司空见惯。各种现存的组件也随手拈来。在 Vue 中,有配套的 element-ui 组件,也有 vue-ant-design。element-ui 中 el-tabs 效果如下:vue-ant-design 中 a-tabs 效果...
Vue 组件封装之 tab 切换
一、Tab 切换组件
组件说明:
实现 tab 切换。
效果展示:
实现 tab 切换,改变激活样式,切换到对应的页面
以上 tab 切换功能在前端开发中司空见惯。各种现存的组件也随手拈来。在 Vue 中,有配套的 element-ui 组件,也有 vue-ant-design。
element-ui 中 el-tabs 效果如下:
vue-ant-design 中 a-tabs 效果如下:
但是使用现存组件面临的问题如下
- element-ui 中 el-tabs 使用问题
tab 标签文本没有居中,整体靠左,通过复写样式也不行,因为下面的高亮下划线是通过 JS 动态控制。 - vue-ant-design 中 a-tabs 使用问题
tab 标签文本间的距离太大。
- 基于以上问题,所以打算自己封装一个 tab 组件。
二、使用案例
该组件有两种使用方式。
- 只有一个主页面,切换时更新数据源即可,用法如下。
<template>
<el-tab defaultKey="1" @on-click="changeTab">
<el-tab-panes actKey="1" label="全部"></el-tab-panes>
<el-tab-panes actKey="2" label="推荐"></el-tab-panes>
<el-tab-panes actKey="3" label="最新"></el-tab-panes>
</el-tab>
<div>只有我一个页面,更新数据源即可</div>
</template>
<script>
export default{
data(){
return{
}
},
methods:{
changeTab(item,index){
//调数据
}
}
}
</script>
- 有几个tab,就有几个主页面,切换时切换到不同的页面,用法如下。
<template>
<el-tab defaultKey="1" @on-click="changeTab">
<el-tab-panes actKey="1" label="全部">
<div>页面1</div>
</el-tab-panes>
<el-tab-panes actKey="2" label="推荐">
<div>页面2</div>
</el-tab-panes>
<el-tab-panes actKey="3" label="最新">
<div>页面3</div>
</el-tab-panes>
</el-tab>
</template>
<script>
export default{
data(){
return{
}
},
methods:{
changeTab(item,index){
//调数据
}
}
}
</script>
三、API 使用指南
属性 | 说明 | 类型 | 默认值 |
---|---|---|---|
defaultKey | 默认选中的tab | String | 1 |
actKey | 每个tab的唯一key | String | 无 |
label | 每个tab的标题 | String | 无 |
on-click | tab 被选中时触发 | 点击按钮的回调函数 | (e: Object): void |
四、源代码
实现思路
(1) tab 标签文本样式高亮;
(2) tab 下面的下划线调整到相应位置;
(3) tab 对应的内容切换。
- tabs 组件
<template>
<div>
<div class="tabs">
<div ref="line" class="tab-line"></div>
<div :class="[activeKey == item.actKey? 'active-tab' : 'tab']" @click="changeTab($event,item,index)" v-for="(item,index) in childList">{{item.label}}</div>
</div>
<slot></slot>
</div>
</template>
<script>
let self;
export default {
name: "ElTab",
data(){
return {
childList:[],
activeKey:this.defaultKey,//将初始化tab赋值给activeKey
slideWidth:0
}
},
//获取子组件传过来的激活tab
props:{
defaultKey:{
type: String,
default: "1"
}
},
created(){
self = this;
},
mounted(){
//循环tab标签
this.childList = this.$children;
//设置滑动距离。平分设备宽度
this.slideWidth = window.innerWidth/this.childList.length;
//设置状态线初始化滑动位置
this.$refs.line.style.width = this.slideWidth+"px";
},
methods:{
//切换tab触发事件
changeTab:(event,item,index)=>{
self.activeKey = item.actKey;
self.$refs.line.style.transform = "translateX("+self.slideWidth*index+"px)";
self.$refs.line.style.transition = "transform .3s";
self.$emit('on-click',item,index);//将切换tab的事件暴露给父组件
},
//初始化时tab状态设置与相应内容显示
updateNav:()=>{
self.$children.map((item,index)=>{
if(item.actKey == self.activeKey){
item.show = true;
self.$nextTick(function() {
self.$refs.line.style.transform = "translateX("+self.slideWidth*index+"px)";
self.$refs.line.style.transition = "transform 0s";
});
}else {
item.show = false;
}
})
}
},
watch: {
//监听当前tab,显示相应内容
activeKey() {
self.$children.map((item)=>{
if(item.actKey == self.activeKey){
item.show = true;
}else {
item.show = false;
}
})
}
}
}
</script>
<style>
.active-tab{
color:#158ef3;
height: 50px;
font-weight: bold;
line-height: 50px;
font-size: 16px;
}
.tab{
color:#333;
height: 50px;
line-height: 50px;
font-size: 16px;
}
.tabs{
display: flex;
justify-content: space-around;
align-items: center;
height: 50px;
border-bottom: 1px solid #f6f6f6;
}
.tab-line{
position: absolute;
left: 0;
border-bottom: 2px solid #158ef3;
height: 50px;
}
</style>
- tab-pane 组件
<template>
<div v-if="show">
<slot></slot>
</div>
</template>
<script>
export default {
name: "ElTabPanes",
data(){
return {
show: false //初始时将所有内容隐藏
}
},
props:{
actKey:{
type: String,
default: "1"
}, label:{
type: String,
default: ""
},
},
mounted(){
this.$parent.updateNav();
},
}
</script>
五、总结
最后总结一下封装一个 tabs 的核心思路和方法。
1. 设置初始化 tab 标签
在 tab-pane 子组件中将所有的内容隐藏(show 属性设置为 false),在 tabs 父组件内接收由开发者自定义的 activeKey,定义一个方法,将 activeKey与子组件的 actKey 比较,如果相同,则该 tab 为初始化时激活的 tab 标签,将相应 tab 的 show 属性设置为 true,并修改 tab 样式。该方法在 tab-pane 子组件中调用。
将 tab-pane 子组件中所有的开发者添加的内容隐藏:
tabs 父组件提供的方法:
tab-pane 子组件调用:
- tabs 组件内部循环 tab-pane 子组件的标签。接收 activeKey,点击时将 tab-pane 子组件的 actKey 赋值给 activeKey。然后每个 tab 的样式通过当前 activeKey 与 actKey 比较,判断是否是当前 tab 标签。如果是,则样式设置为激活样式。
<div :class="[activeKey == item.actKey? 'active-tab' : 'tab']" @click="changeTab($event,item.actKey,index)" v-for="(item,index) in childList">{{item.label}}</div>
changeTab:(event,tab,index)=>{
self.activeKey = tab;
self.$refs.line.style.transform = "translateX("+self.slideWidth*index+"px)";
self.$refs.line.style.transition = "transform .3s";
self.$emit('on-click',event,tab)
},
- 在 tab-pane 上方添加状态线,状态线的样式需要注意一下。
<div ref="line" class="tab-line"></div>
.tab-line{
height: 2px;
background: #409eff;
position: absolute;
left: 0;
margin-top: 20px;
}
- 切换 tab 时,改变相应的内容。
这一步最关键,需要在 tabs 组件中使用 watch 监听当前状态,如果子组件中的 actKey 等于当前状态,则显示相应的内容。
activeKey() {
self.$children.map((item)=>{
if(item.actKey == self.activeKey){
item.show = true;
}else {
item.show = false;
}
})
}
更多推荐
所有评论(0)