vue3 elementplus tabs切换实现

Tabs 标签页 | Element Plus

html 复制代码
<template>
  <!-- editableTabsValue 是当前tab 的 name -->
  <el-tabs
    v-model="editableTabsValue"
    type="border-card"
    editable
    @edit="handleTabsEdit"
  >
    <!-- 这个是标签面板 面板数据 遍历 editableTabs 渲染-->
    <el-tab-pane
      v-for="item in editableTabs"
      :key="item.name"
      :label="item.title"
      :name="item.name"
    >
      <!-- 页面内容 采用这种写法 包裹 keep-alive 标签是 组件保持keep-alive -->
      <router-view v-slot="{ Component }">
        <keep-alive>
          <component :is="Component" />
        </keep-alive>
      </router-view>
    </el-tab-pane>
  </el-tabs>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import type { TabPaneName } from 'element-plus'

import { useRoute, useRouter } from 'vue-router'
import { watch } from 'vue'

const route = useRoute()
const router = useRouter()

const initTab = {
  title: route.meta.title || 'New Tab',
  name: '1',
  url: route.fullPath,
}
// 使用对象张开运算符 复制 initTab 直接使用 inittab指向的是同一个对象
// editableTabs tabs 数据 是一个数组 里面是对象 每个对象是一个标签页
const editableTabs = ref([{ ...initTab }])
// tabindex 是最新标签 name 新标签为 tabIndex = tabIndex + 1
let tabIndex = editableTabs.value.length
// 当前的激活页 name
const editableTabsValue = ref(editableTabs.value[0].name)

// 监听 $route 对象的变化 如果路由发生变化 就更新 editableTabs 中的 url 和 title
watch(
  () => route.fullPath,
  (newPath) => {
    editableTabs.value.forEach((tab) => {
      if (tab.name === editableTabsValue.value) {
        if (tab.url === newPath) {
          return
        }
        tab.url = newPath
        tab.title = route.meta.title || 'New Tab'
      }
    })
  },
  { deep: true },
)
// 监听 editableTabsValue 的变化
//如果 editableTabsValue 变化了 就是切换了标签页 就更新路由到对应标签页
watch(
  () => editableTabsValue.value,
  (newValue) => {
    editableTabs.value.forEach((tab) => {
      if (tab.name === newValue) {
        if (tab.url === route.fullPath) {
          return
        }
        router.push(tab.url)
      }
    })
  },
)
// 处理标签页的编辑事件
// targetName 是当前标签页的 name
const handleTabsEdit = (
  targetName: TabPaneName | undefined,
  action: 'remove' | 'add',
) => {
  if (action === 'add') {
    const newTabName = `${++tabIndex}`
    const newtab = { ...initTab }
    newtab.name = newTabName
    editableTabs.value.push(newtab)
    editableTabsValue.value = newTabName
  } else if (action === 'remove') {
    const tabs = editableTabs.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
    editableTabs.value = tabs.filter((tab) => tab.name !== targetName)
  }
}
</script>
<style>
.el-tabs__new-tab {
  margin-right: 20px;
}
</style>
相关推荐
摘星编程23 分钟前
React Native + OpenHarmony:UniversalLink通用链接
javascript·react native·react.js
qq_1777673744 分钟前
React Native鸿蒙跨平台数据使用监控应用技术,通过setInterval每5秒更新一次数据使用情况和套餐使用情况,模拟了真实应用中的数据监控场景
开发语言·前端·javascript·react native·react.js·ecmascript·harmonyos
烬头88211 小时前
React Native鸿蒙跨平台应用实现了onCategoryPress等核心函数,用于处理用户交互和状态更新,通过计算已支出和剩余预算
前端·javascript·react native·react.js·ecmascript·交互·harmonyos
程序员清洒2 小时前
Flutter for OpenHarmony:Text — 文本显示与样式控制
开发语言·javascript·flutter
雨季6663 小时前
Flutter 三端应用实战:OpenHarmony 简易“动态内边距调节器”交互模式深度解析
javascript·flutter·ui·交互·dart
会飞的战斗鸡3 小时前
JS中的链表(含leetcode例题)
javascript·leetcode·链表
方也_arkling4 小时前
别名路径联想提示。@/统一文件路径的配置
前端·javascript
qq_177767374 小时前
React Native鸿蒙跨平台剧集管理应用实现,包含主应用组件、剧集列表、分类筛选、搜索排序等功能模块
javascript·react native·react.js·交互·harmonyos
qq_177767374 小时前
React Native鸿蒙跨平台自定义复选框组件,通过样式数组实现选中/未选中状态的样式切换,使用链式调用替代样式数组,实现状态驱动的样式变化
javascript·react native·react.js·架构·ecmascript·harmonyos·媒体
web打印社区4 小时前
web-print-pdf:突破浏览器限制,实现专业级Web静默打印
前端·javascript·vue.js·electron·html