如何利用Vue3+Element?Plus實(shí)現(xiàn)動(dòng)態(tài)標(biāo)簽頁(yè)及右鍵菜單
1 前言
1.1 目的
Tabs 動(dòng)態(tài)標(biāo)簽頁(yè)實(shí)現(xiàn)右鍵菜單【關(guān)閉當(dāng)前標(biāo)簽頁(yè)】、【關(guān)閉左側(cè)標(biāo)簽頁(yè)】、【關(guān)閉右側(cè)標(biāo)簽頁(yè)】、【關(guān)閉其他標(biāo)簽頁(yè)】、【關(guān)閉全部標(biāo)簽頁(yè)】功能

1.2 普通右鍵菜單
網(wǎng)上使用比較多的是v-contextmenu插件實(shí)現(xiàn)右鍵菜單,但該插件對(duì)于v-for循環(huán)生成的元素失效,插件內(nèi)部右鍵菜單顯示執(zhí)行的是emit('show')未傳入當(dāng)前元素節(jié)點(diǎn)(可能后續(xù)會(huì)修復(fù)),且樣式需要自行修改
1.3 本文右鍵菜單方式
本文使用element-plus自帶的el-dropdown實(shí)現(xiàn)右鍵菜單
2 生成動(dòng)態(tài)標(biāo)簽頁(yè)
2.1 準(zhǔn)備變量容器
<script setup lang="ts">
import { ref } from 'vue'
interface TabType {
title: string //標(biāo)簽頁(yè)顯示名稱
componentName: string //動(dòng)態(tài)組件名
data: any //動(dòng)態(tài)組件傳參
}
interface TabListType extends TabType {
name: string //標(biāo)簽頁(yè)唯一標(biāo)識(shí),添加標(biāo)簽頁(yè)時(shí)根據(jù) componentName 自動(dòng)生成
}
const tabList = ref<TabListType[]>([]) //存放標(biāo)簽頁(yè)數(shù)組
const tabValue = ref('home') //存放當(dāng)前激活標(biāo)簽頁(yè),默認(rèn)激活首頁(yè)
</script>
2.2 構(gòu)造標(biāo)簽頁(yè)
- 可動(dòng)態(tài)添加標(biāo)簽頁(yè)
- 除【首頁(yè)】外,可動(dòng)態(tài)移除標(biāo)簽頁(yè)
<template>
<el-tabs v-model="tabValue" type="card" @tab-remove="removeTab">
<el-tab-pane label="首頁(yè)" name="home">
<Home />
</el-tab-pane>
<el-tab-pane v-for="item in tabList" :name="item.name" :key="item.name" closable>
<component :is="item.componentName" v-bind="item.data">
</component>
</el-tab-pane>
</el-tabs>
</template>
2.3 動(dòng)態(tài)添加標(biāo)簽頁(yè)
const addTab = (tab: TabType) => {
//保證相同組件路徑標(biāo)簽頁(yè) name 標(biāo)識(shí)唯一
const name = `${tab.componentName}_${Date.now()}`
tabList.value.push({
...tab,
name
})
tabValue.value = name
}
addTab({
title: '標(biāo)簽1',
componentName: 'tag1',
data: {
test: '這是測(cè)試數(shù)據(jù)'
}
})
2.4 動(dòng)態(tài)移除標(biāo)簽頁(yè)
const removeTab = (targetName: string) => {
const index = tabList.value.findIndex((item) => item.name === targetName)
tabList.value.splice(index, 1)
//當(dāng)前激活標(biāo)簽頁(yè)與觸發(fā)右鍵菜單標(biāo)簽頁(yè)是同一頁(yè)
if (targetName === tabValue.value) {
//當(dāng)前激活標(biāo)簽頁(yè)是標(biāo)簽頁(yè)數(shù)組的第一個(gè),則將激活標(biāo)簽頁(yè)設(shè)置為 home
//當(dāng)前激活標(biāo)簽頁(yè)不是標(biāo)簽頁(yè)數(shù)組的第一個(gè),則將激活標(biāo)簽頁(yè)設(shè)置為當(dāng)前激活標(biāo)簽頁(yè)的前一頁(yè)
tabValue.value = index === 0 ? 'home' : tabList.value[index - 1].name
}
}
removeTab('tag1')
3 生成右鍵菜單
3.1 擴(kuò)展標(biāo)簽頁(yè)
<template>
<el-tabs v-model="tabValue" type="card" @tab-remove="removeTab">
<el-tab-pane label="首頁(yè)" name="home">
<Home />
</el-tab-pane>
<el-tab-pane v-for="item in tabList" :name="item.name" :key="item.name" closable>
<!-- 右鍵菜單開(kāi)始:自定義標(biāo)簽頁(yè)顯示名稱,保證每個(gè)標(biāo)簽頁(yè)都能實(shí)現(xiàn)右鍵菜單 -->
<template #label>
<el-dropdown
trigger="contextmenu"
:id="item.name"
@visible-change="handleChange($event, item.name)"
ref="dropdownRef"
>
<span :class="tabValue === item.name ? 'label' : ''">{{ item.title }}</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="removeTab(item.name)">
<el-icon><Close /></el-icon>關(guān)閉當(dāng)前標(biāo)簽頁(yè)
</el-dropdown-item>
<el-dropdown-item
@click="removeTab(item.name, 'left')"
v-if="show(item.name, 'left')"
>
<el-icon><DArrowLeft /></el-icon>關(guān)閉左側(cè)標(biāo)簽頁(yè)
</el-dropdown-item>
<el-dropdown-item
@click="removeTab(item.name, 'right')"
v-if="show(item.name, 'right')"
>
<el-icon><DArrowRight /></el-icon>關(guān)閉右側(cè)標(biāo)簽頁(yè)
</el-dropdown-item>
<el-dropdown-item
@click="removeTab(item.name, 'other')"
v-if="tabList.length > 1"
>
<el-icon><Operation /></el-icon>關(guān)閉其他標(biāo)簽頁(yè)
</el-dropdown-item>
<el-dropdown-item @click="removeTab(item.name, 'all')">
<el-icon><Minus /></el-icon>關(guān)閉全部標(biāo)簽頁(yè)
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
<!-- 右鍵菜單結(jié)束 -->
<component :is="item.componentName" v-bind="item.data">
</component>
</el-tab-pane>
</el-tabs>
</template>
3.2 增加 show 方法
- 觸發(fā)右鍵菜單標(biāo)簽頁(yè)為第一個(gè)時(shí),不展示【關(guān)閉左側(cè)標(biāo)簽頁(yè)】
- 觸發(fā)右鍵菜單標(biāo)簽頁(yè)為最后一個(gè)時(shí),不展示【關(guān)閉右側(cè)標(biāo)簽頁(yè)】
const show = (name: string, type: string) => {
const index = tabList.value.findIndex((item) => name === item.name)
return type === 'left' ? index !== 0 : index !== tabList.value.length - 1
}
3.3 擴(kuò)展 removeTab 方法
const removeTab = (targetName: string, type?: string) => {
const index = tabList.value.findIndex((item) => item.name === targetName) //查找觸發(fā)右鍵菜單所在標(biāo)簽頁(yè)index
const currentIndex = tabList.value.findIndex((item) => item.name === tabValue.value) //查找當(dāng)前激活標(biāo)簽頁(yè)index,存在當(dāng)前激活標(biāo)簽頁(yè)與觸發(fā)右鍵菜單標(biāo)簽頁(yè)不是同一個(gè)的情況
switch (type) {
case 'all': //關(guān)閉全部標(biāo)簽頁(yè)
tabList.value = [] //清空除【首頁(yè)】外所有標(biāo)簽頁(yè)
tabValue.value = 'home' //修改標(biāo)簽激活頁(yè)
break
case 'other': //關(guān)閉其他標(biāo)簽頁(yè)
tabList.value = [tabList.value[index]]
if (targetName !== tabValue.value) {
tabValue.value = targetName
}
break
case 'left': //關(guān)閉左側(cè)標(biāo)簽頁(yè)
tabList.value.splice(0, index)
if (currentIndex < index) {
tabValue.value = targetName
}
break
case 'right': //關(guān)閉右側(cè)標(biāo)簽頁(yè)
tabList.value.splice(index + 1)
if (currentIndex > index) {
tabValue.value = targetName
}
break
default: //默認(rèn)關(guān)閉當(dāng)前標(biāo)簽頁(yè)
tabList.value.splice(index, 1)
//當(dāng)前激活標(biāo)簽頁(yè)與觸發(fā)右鍵菜單標(biāo)簽頁(yè)是同一頁(yè)
if (targetName === tabValue.value) {
//當(dāng)前激活標(biāo)簽頁(yè)是標(biāo)簽頁(yè)數(shù)組的第一個(gè),則將激活標(biāo)簽頁(yè)設(shè)置為 home
//當(dāng)前激活標(biāo)簽頁(yè)不是標(biāo)簽頁(yè)數(shù)組的第一個(gè),則將激活標(biāo)簽頁(yè)設(shè)置為當(dāng)前激活標(biāo)簽頁(yè)的前一頁(yè)
tabValue.value = index === 0 ? 'home' : tabList.value[index - 1].name
}
break
}
}
3.4 解決重復(fù)出現(xiàn)菜單問(wèn)題
當(dāng)連續(xù)在多個(gè)標(biāo)簽頁(yè)觸發(fā)右鍵時(shí),會(huì)出現(xiàn)多個(gè)菜單,解決方案為:在觸發(fā)右鍵菜單后,關(guān)閉其他右鍵菜單
const dropdownRef = ref()
const handleChange = (visible: boolean, name: string) => {
if (!visible) return
dropdownRef.value.forEach((item: { id: string; handleClose: () => void }) => {
if (item.id === name) return
item.handleClose()
})
}
3.5 解決自定義標(biāo)簽樣式問(wèn)題
<style lang="scss" scoped>
.label {
color: var(--el-color-primary); //激活標(biāo)簽頁(yè)高亮
}
:deep(.el-tabs__item) {
&:hover {
span {
color: var(--el-color-primary); //鼠標(biāo)移到標(biāo)簽頁(yè)高亮
}
}
.el-dropdown {
line-height: inherit; // 統(tǒng)一標(biāo)簽頁(yè)顯示名稱行高
}
}
</style>
總結(jié)
到此這篇關(guān)于如何利用Vue3+Element Plus實(shí)現(xiàn)動(dòng)態(tài)標(biāo)簽頁(yè)及右鍵菜單的文章就介紹到這了,更多相關(guān)Vue3 Element Plus動(dòng)態(tài)標(biāo)簽頁(yè)及右鍵菜單內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
elementui[el-table]toggleRowSelection默認(rèn)多選事件無(wú)法選中問(wèn)題
這篇文章主要介紹了elementui[el-table]toggleRowSelection默認(rèn)多選事件無(wú)法選中問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11
vue 判斷兩個(gè)時(shí)間插件結(jié)束時(shí)間必選大于開(kāi)始時(shí)間的代碼
這篇文章主要介紹了vue 判斷兩個(gè)時(shí)間插件結(jié)束時(shí)間必選大于開(kāi)始時(shí)間的代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11
Vue實(shí)現(xiàn)移動(dòng)端頁(yè)面切換效果【推薦】
這篇文章主要介紹了Vue實(shí)現(xiàn)移動(dòng)端頁(yè)面切換效果,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-11-11
vue的el-select綁定的值無(wú)法選中el-option問(wèn)題及解決
這篇文章主要介紹了vue的el-select綁定的值無(wú)法選中el-option問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09
Vue3在history模式下如何通過(guò)vite打包部署白屏
這篇文章主要介紹了Vue3在history模式下如何通過(guò)vite打包部署白屏問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07
sublime如何配置開(kāi)發(fā)VUE環(huán)境自動(dòng)格式化代碼
這篇文章主要介紹了sublime如何配置開(kāi)發(fā)VUE環(huán)境自動(dòng)格式化代碼問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03
vue-cli4項(xiàng)目開(kāi)啟eslint保存時(shí)自動(dòng)格式問(wèn)題
這篇文章主要介紹了vue-cli4項(xiàng)目開(kāi)啟eslint保存時(shí)自動(dòng)格式的問(wèn)題小結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07

