vue - element ui 实现 tab 选项卡的动态增删

注意 this.$refs.tabs[i] 的属性对应

参考的原帖貌似是没对应好。
本人在使用时出现几个问题:

  • title无法显示
  • 只能添加一个tab
  • tab会重复添加
  • 默认打开的首页也能再创建
  • 修改之后,功能正常。
<template>
  <el-tabs v-model="activeTab" type="card"
           @tab-remove="removeTab" @tab-click="tabClick">
    <el-tab-pane v-for="(item, index) in tabsItem"
                 :key="item.name"
                 :label="item.title"
                 :name="item.name"
                 :closable="item.closable"
                 :ref="item.ref">
    </el-tab-pane>
  </el-tabs>
</template>

<script>

export default {
  name: "Tabs",
  data() {
    return {
      activeTab: '1', //默认显示的tab
      tabIndex: 1,  //tab目前显示数
      tabsItem: [{
        title: '库存预警',
        name: '1',
        closable: false,
        ref: 'tabs',
      }],
      tabsPath: [{
        name: "1",
        path: '/index'
      }]
    }
  },
  watch: {
    // 监听路由的变化,动态生成tabs
    '$route': function (to) {
      // 判断是否需要新增页面
      let flag = true;
      const path = to.path;
      if (Object.keys(to.meta).length !== 0) {
        for (let i = 0; i < this.$refs.tabs.length; i++) {
          // 如果页面已存在,则直接定位当页面,否则新增tab页面
          if (this.$refs.tabs[i].label === to.meta.title) {
            //定位到已打开页面
            this.activeTab = this.$refs.tabs[i].name;
            flag = false;
            break;
          }
        }
        // 新增页面
        if (flag) {
          // 获得路由元数据的name和组件名
          const thisName = to.meta.title
          // const thisComp = to.meta.comp
          //对tabs的当前激活下标和tabs数量进行自加
          let newActiveIndex = ++this.tabIndex + '';
          // 动态双向追加tabs
          this.tabsItem.push({
            title: thisName,
            name: String(newActiveIndex),
            closable: true,
            ref: 'tabs',
          })
          this.activeTab = newActiveIndex;
          // 后面需要得到当前tabs的时候可以通过当前tabs的name获得path
          if (this.tabsPath.indexOf(path) === -1) {
            this.tabsPath.push({
              name: newActiveIndex,
              path: path
            })
          }
        }
      }
    }
  },
  methods: {
    removeTab(targetName) { //删除Tab
      let tabs = this.tabsItem; //当前显示的tab数组
      let activeName = this.activeTab; //点前活跃的tab
      //如果当前tab正活跃 被删除时执行
      if (activeName === targetName) {
        tabs.forEach((tab, index) => {
          if (tab.name === targetName) {
            let nextTab = tabs[index + 1] || tabs[index - 1];
            if (nextTab) {
              activeName = nextTab.name;
              this.tabClick(nextTab);
            }
          }
        });
      }
      this.activeTab = activeName;
      this.tabsItem = tabs.filter(tab => tab.name !== targetName);
      //在tabsPath中删除当前被删除tab的path
      this.tabsPath = this.tabsPath.filter(item => item.name !== targetName)
    },
    tabClick(thisTab) {
      /*
      * thisTab:当前选中的tabs的实例
      * 通过当前选中tabs的实例获得当前实例的path 重新定位路由
      * */
      let val = this.tabsPath.filter(item => thisTab.name === item.name)
      this.$router.push({
        path: val[0].path
      })
    }
  },
  mounted() {
    /*
    * 监听页面刷新事件
    * 页面刷新前 需要保存当前打开的tabs的位置,刷新后按刷新前的顺序展示
    * 使用js的sessionStorage保存刷新页面前的数据
    * */
    window.addEventListener('beforeunload', e => {
      sessionStorage.setItem("tabsItem", JSON.stringify({
        currTabsItem: this.tabsItem.filter(item => item.name !== "1"),
        currTabsPath: this.tabsPath.filter(item => item.name !== "1"),
        currActiveTabs: this.activeTab,
        currIndex: this.tabIndex
      }))
    });
  },
  created() {
    // 使用js的sessionStorage读取刷新前的数据,并按刷新前的tabs顺序重新生成tabs
    const sessionTabs = JSON.parse(sessionStorage.getItem("tabsItem"))
    if (sessionTabs.currTabsItem.length !== 0 && sessionTabs.currTabsPath.length !== 0) {
      for (let i = 0; i < sessionTabs.currTabsItem.length; i++) {
        this.tabsItem.push({
          title: sessionTabs.currTabsItem[i].title,
          name: sessionTabs.currTabsItem[i].name,
          closable: true,
          ref: sessionTabs.currTabsItem[i].ref,
          content: sessionTabs.currTabsItem[i].content
        })
      }
      for (let j = 0; j < sessionTabs.currTabsPath.length; j++) {
        this.tabsPath.push({
          name: sessionTabs.currTabsPath[j].name,
          path: sessionTabs.currTabsPath[j].path
        })
      }
      this.activeTab = sessionTabs.currActiveTabs
      this.tabIndex = sessionTabs.currIndex
      // 避免强制修改url 出现浏览器的url输入框的路径和当前tabs选中的路由路径不匹配
      const activePath = this.tabsPath.filter(item => item.name === this.activeTab)
      this.$router.push({
        path: activePath[0].path
      })
    }
  },
}
</script>

<style scoped>
/deep/ .el-tabs__header {
  margin: 0;
}
</style>

你可能感兴趣的:(前端,elementui,vue)