Vue3+element动态增减el-tabs
⽂章⽬录
overview
这个问题我想了很久,怎么能优雅地实现点击左侧边栏,右边动态增减。现在有点眉⽬了
设计
容器
容器主体
主要思路:分为三个部分,容器整体,容器左侧,容器右侧。左侧是按钮组,右侧是待渲染部分。
我把侧边栏单独抽出来做了个组件,不重要。然后重点是动态增减Tabs,最重要的就是⽤component的:is属性,根据按钮的callBack动态渲染每⼀个Tab的内容。
代码如下:
<div class="root-ele">
<div class="root-title">
你好,世界!
</div>
<div class="root-body">
<div class="root-body root-body-item-left">
<!-- 侧边栏单独抽出组件 -->
<EventSide @openTab="toOpen"></EventSide>
</div>
<div class="root-body root-body-item-right">
<!-- v-model代表当前激活哪个页⾯,@tab-remove代表删除某个标签的回调 -->
<el-tabs
v-model="editableTabsValue"
type="card"
closable
@tab-remove="removeTab"
>
<el-tab-pane
v-for="(item, index) in allTabs.value"
:key="index"
:name="item.name"
:label="item.label"
>
<!-- 核⼼:⽤component的is功能动态选择要渲染的⼦组件 -->
<Component :is="item.name"></Component>
</el-tab-pane>
</el-tabs>
</div>
</div>
</div>
<script lang="ts">
import{ defineComponent, reactive, ref }from'vue'
// 样式⽂件
import'../RootElementStyle.css'
import MyHead from'../MyHead.vue'
import EventSide from'../../components/eventComponent/EventSide.vue'
import AllEvent from'../../components/eventComponent/AllEvent.vue'
import EventDetail from'../../components/eventComponent/EventDetail.vue'
export default defineComponent({
name:'EventPage',
components:{
MyHead,
EventSide,
EventSide,
allEvent: AllEvent,
eventDetail: EventDetail,
},
setup(){
// 定义接⼝,⽤于规定数组对象的类型
interface inter{
name: string
[propName: string]: any
}
const editableTabsValue =ref('')
const allTabs =reactive({
value:[]as inter[],
})
function toOpen(item:{name: string; label: string}){
for(let i =0; i < allTabs.value.length;++i){
if(allTabs.value[i].name === item.name){
return
}
}
allTabs.value.push(item)
editableTabsValue.value = item.name
}
function removeTab(targetName: string){
const tabs = allTabs.value
let activeName = editableTabsValue.value
if(activeName === targetName){
tabs.forEach((tab, index)=>{
if(tab.name === targetName){
const nextTab = tabs[index +1]|| tabs[index -1]
if(nextTab){
activeName = nextTab.name
}
}
})
}
editableTabsValue.value = activeName
allTabs.value = tabs.filter(tab => tab.name !== targetName) }
return{
toOpen,
editableTabsValue,
removeTab,
allTabs,
}
},
})
</script>
样式⽂件
font-size: medium;
position: absolute;
height: 100%;
width: 100%;
font-family:"montserrat", sans-serif;
}
.root-title{
min-height: 7%;
max-height: 9%;
box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
background-color: #f4f4f5;
backdrop-filter:blur(5px);
font-size: x-large;
font-weight: lighter;
line-height: 230%;
margin-bottom: 0.5%;
color: white;
border-left: black 4px solid;
background-image:linear-gradient(125deg, #409EFF, #E6A23C, #F56C6C, #67C23A, #909399); animation: bganimation 15s infinite;
background-size: 400%;
}
.root-body{
height: 88.5%;
overflow-y: auto;
display: flex;
border-radius: 4px;
}
.root-body .root-body-item-left{
width: 15%;
height: 100%;
background-image:linear-gradient(125deg, #DCDFE6, #E4E7ED, #EBEEF5, #F2F6FC, #C0C4CC); animation: bganimation 15s infinite;
background-size: 400%;
box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);
overflow-x: hidden;
}
.root-body .root-body-item-right{
display: block;
padding-left: 10px;
width: 84%;
height: 100%;
margin-left: 0.3%;
background-image:linear-gradient(125deg, #DCDFE6, #E4E7ED, #EBEEF5, #F2F6FC, #C0C4CC); animation: bganimation 15s infinite;
background-size: 400%;
}
容器左侧
不废话,代码如下
<div
v-for="(item, index) in sides.sides"
:key="index"
class="event-side-item"
@click="handleOpenTab(item)"
>
{{ item.label }}
vue element admin
</div>
</template>
<script lang="ts">
import{ defineComponent, reactive }from'vue'
import eventSideConfig from'./EventSideConfig'
export default defineComponent({
name:'EventSide',
emits:['openTab'],
setup(_,{ emit }){
const sides =reactive({
sides: eventSideConfig,
})
function handleOpenTab(item: any){
emit('openTab', item)
}
return{
sides,
handleOpenTab,
}
},
})
</script>
我把侧边栏和组件的对应关系放在EventSideConfig⾥⾯,直接读取,如果后期需要从后端动态读取,页⾯什么都不⽤改,直接赋个值就⾏。
定义⽂件如下:
const eventSideConfig =[
{
label:'allEvent',
name:'allEvent',
},
{
label:'eventDetail',
name:'eventDetail',
},
]
export default eventSideConfig
over
这就是我⽬前能想出来最优雅扩展性最强的解法。⽐之前那种强跳转的解法来说,更容易扩展,只要后端加载的数据格式约定好,直接就能由静态转动态。另外,没有强依赖跨组件的状态共享,耦合性低,更加安全
欢迎联系我 memeda