Доброе утро,

Моя цель следующая:

Каждый раз, когда открывается новая вкладка, она становится «активной», и браузер отображает ее содержимое

  • Проблема: каждый раз, когда открывается новая вкладка, ранее открытая вкладка остается «активной».

Посмотрите на банальный пример проблемы.

Чтобы воспроизвести проблему:

  1. Зайдите на BootstrapVue Playground;
  2. Прокрутите страницу вниз до раздела «Динамические вкладки + конец вкладки» (присутствует в разделе расширенных примеров);
  3. Дважды щелкните в области кода (чтобы изменить его);
  4. Вставьте следующий код
<template>
  <div>
    <b-card no-body>
      <b-tabs card>
        <!-- Render Tabs, supply a unique `key` to each tab -->
        <b-tab v-for="tab in tabs" :key="tab.id" :class="{active:tab.isActive}" :title="'Tab ' + tab.id">
          Tab contents {{ tab.id }}
          <b-button size="sm" variant="danger" class="float-right" @click="closeTab(tab.id)">
            Close tab
          </b-button>
        </b-tab>

        <!-- New Tab Button (Using tabs-end slot) -->
        <template v-slot:tabs-end>
          <b-nav-item role="presentation" @click.prevent="newTab" href="#"><b>+</b></b-nav-item>
        </template>

        <!-- Render this if no tabs -->
        <template v-slot:empty>
          <div class="text-center text-muted">
            There are no open tabs<br>
            Open a new tab using the <b>+</b> button above.
          </div>
        </template>
      </b-tabs>
    </b-card>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        tabs: [],
        tabCounter: 0,
        activeTab: {}
      }
    },
    methods: {
      closeTab(x) {
        for (let i = 0; i < this.tabs.length; i++) {
          if (this.tabs[i].id === x) {
            this.tabs.splice(i, 1)
          }
        }
      },
      newTab() {
        const newTab = {
          id: this.tabCounter,
          isActive: true
        };
        this.tabCounter++;
        this.tabs.push(newTab);
        this.setActive(newTab);
      },
      setActive(tab) {
        tab.isActive = true;
        this.activeTab = tab;
        this.tabs.forEach((tab) => {
          if (tab.id !== this.activeTab.id) {
            tab.isActive = false;
          }
        })
      }
    }
  }
</script>
  1. Попробуйте добавить новые вкладки, нажав кнопку «+» в области рендеринга, присутствующую в начале вставленного кода.

Что я делаю не так?

0
MIchele Rosito 2 Сен 2020 в 10:22

2 ответа

Лучший ответ

Вы можете сделать это, добавив опору active к <b-tab>, это сделает вновь созданную вкладку активной.

<b-tab active ...>

Примере

new Vue({
  el: "#app",
  data() {
    return {
      tabs: [],
      tabCounter: 0
    }
  },
  methods: {
    closeTab(x) {
      for (let i = 0; i < this.tabs.length; i++) {
        if (this.tabs[i] === x) {
          this.tabs.splice(i, 1)
        }
      }
    },
    newTab() {
      this.tabs.push(this.tabCounter++)
    }
  }
});
<link href="https://unpkg.com/bootstrap@4.5.2/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue@2.16.0/dist/bootstrap-vue.css" rel="stylesheet" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue@2.16.0/dist/bootstrap-vue.js"></script>

<div id="app">
  <b-card no-body>
    <b-tabs card>
      <!-- Render Tabs, supply a unique `key` to each tab -->
      <b-tab v-for="i in tabs" :key="'dyn-tab-' + i" :title="'Tab ' + i" active>
        Tab contents {{ i }}
        <b-button size="sm" variant="danger" class="float-right" @click="closeTab(i)">
          Close tab
        </b-button>
      </b-tab>

      <!-- New Tab Button (Using tabs-end slot) -->
      <template v-slot:tabs-end>
        <b-nav-item role="presentation" @click.prevent="newTab" href="#"><b>+</b></b-nav-item>
      </template>

      <!-- Render this if no tabs -->
      <template v-slot:empty>
        <div class="text-center text-muted">
          There are no open tabs<br>
          Open a new tab using the <b>+</b> button above.
        </div>
      </template>
    </b-tabs>
  </b-card>
</div>
1
Hiws 2 Сен 2020 в 08:08

Привет, Мичеле Росито,

Компонент b-tabs принимает значение, это значение является индексом выбранной вкладки (передать его через v-модель)

Ниже у меня есть упрощенная версия рабочего прототипа, который, как мне кажется, делает то, что вам нужно.

Но есть одна загвоздка: при добавлении новой вкладки она будет отображаться при загрузке в (виртуальной) DOM, и это займет некоторое время, и мы не можем выбрать вкладку, которая еще не отображена.

«Решение» (не очень хорошая повязка) - дать ему несколько миллисекунд и только потом изменить tabIndex, чтобы дать время для отображения вкладки.

Это не лучшее решение для продакшена, но я думаю, что оно может указать вам правильное направление.

<template>
  <div>
    <b-card no-body>
      <b-tabs card v-model="tabIndex">
        <!-- Render Tabs, supply a unique `key` to each tab -->
        <b-tab v-for="tab in tabs" :key="tab.id" :class="{active:tab.isActive}" :title="'Tab ' + tab.id">
          Tab contents {{ tab.id }}
          <b-button size="sm" variant="danger" class="float-right" @click="closeTab(tab.id)">
            Close tab
          </b-button>
        </b-tab>

        <!-- New Tab Button (Using tabs-end slot) -->
        <template v-slot:tabs-end>
          <b-nav-item role="presentation" @click.prevent="newTab" href="#"><b>+</b></b-nav-item>
        </template>

        <!-- Render this if no tabs -->
        <template v-slot:empty>
          <div class="text-center text-muted">
            There are no open tabs<br>
            Open a new tab using the <b>+</b> button above.
          </div>
        </template>
      </b-tabs>
    </b-card>
 </div>
</template>

<script>
  export default {
    data() {
      return {
        tabs: [],
        tabIndex: 0,
        tabCounter: 0,
        activeTab: {}
      }
    },
    methods: {
      closeTab(x) {
        for (let i = 0; i < this.tabs.length; i++) {
          if (this.tabs[i].id === x) {
            this.tabs.splice(i, 1)
          }
        }
      },
      newTab() {
        const newTab = {
          id: this.tabCounter,
        };
        this.tabCounter++;
        this.$set(this, tabs, this.tabs.push(newTab));  
        setTimeout(() => { this.tabIndex = this.tabs.length;}, 100);      
      }
    }
  }
</script>

Было ли это полезно?

0
Fábio Garcia 2 Сен 2020 в 08:13