在 bootstrap vue 中单击新行时如何关闭前一行详细信息?

How to close previous row details when clicking a new one in bootstrap vue?

Bootstrap Vue documentation 之后,我有以下代码:

<template>
  <div>
    <b-table :items="items" :fields="fields" striped responsive="sm">
      <template #cell(show_details)="row">
        <b-button size="sm" @click="row.toggleDetails" class="mr-2">
          {{ row.detailsShowing ? 'Hide' : 'Show'}} Details
        </b-button>

        <!-- As `row.showDetails` is one-way, we call the toggleDetails function on @change -->
        <b-form-checkbox v-model="row.detailsShowing" @change="row.toggleDetails">
          Details via check
        </b-form-checkbox>
      </template>

      <template #row-details="row">
        <b-card>
          <b-row class="mb-2">
            <b-col sm="3" class="text-sm-right"><b>Age:</b></b-col>
            <b-col>{{ row.item.age }}</b-col>
          </b-row>

          <b-row class="mb-2">
            <b-col sm="3" class="text-sm-right"><b>Is Active:</b></b-col>
            <b-col>{{ row.item.isActive }}</b-col>
          </b-row>

          <b-button size="sm" @click="row.toggleDetails">Hide Details</b-button>
        </b-card>
      </template>
    </b-table>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        fields: ['first_name', 'last_name', 'show_details'],
        items: [
          { isActive: true, age: 40, first_name: 'Dickerson', last_name: 'Macdonald' },
          { isActive: false, age: 21, first_name: 'Larsen', last_name: 'Shaw' },
          {
            isActive: false,
            age: 89,
            first_name: 'Geneva',
            last_name: 'Wilson',
            _showDetails: true
          },
          { isActive: true, age: 38, first_name: 'Jami', last_name: 'Carney' }
        ]
      }
    }
  }
</script>

可以找到完整示例 here

根据这个例子,如果我点击每一行上的 Show Details 按钮,它将显示其各自的行详细信息,但我希望它在点击时关闭所有以前的行它并且只打开当前单击行的详细信息。

我知道遍历行并将 detailsShowing 设置为 false 可以像下面这样解决它:

this.rownames.forEach(item => {
  this.$set(item, 'detailsShowing', false)
})

但我不知道该怎么做。谢谢。

添加名为 visibleRow 的新数据 属性 并将其设置为 null

然后创建一个 getter 计算 returns 您的项目,但具有 _showDetails 属性 集。默认情况下,该值应为 false,除非 visibleRow 与项目匹配:

computed: {
  tableItems () {
    return this.items.map((item) => {
      return Object.assign({}, item, {
        _showDetails: this.visibleRow && this.visibleRow.first_name === item.first_name && this.visibleRow.last_name === item.last_name
      })
    })

  }
}

I've taken some liberties in determining what makes your rows unique but you're free to use whatever you want in the above comparison

创建一个新方法并修改您的行点击功能以设置 visibleRow 切换:

methods: {
  setVisibleRow (row) {
    this.$set(this, 'visibleRow', row)
  }
}

更新您的点击方法:

@click="setVisileRow(row.item._showDetails ? null : row.item)"

最后,更新您在 b-table 上的 items 绑定:

<b-table :items="tableItems"

我觉得接受的答案有点过度设计,所以我想提出一个我认为更简单的解决方案。

这是通过将“当前”打开的行保存在一个变量中,并在打开另一行时将其 _showDetails 设置为 false 来实现的。这样我们就避免了做任何类型的循环。

new Vue({
  el: "#app",
  data() {
    return {
      detailsRow: null,
      items: [
        { age: 40, first_name: "Dickerson", last_name: "Macdonald" },
        { age: 21, first_name: "Larsen", last_name: "Shaw" },
        { age: 89, first_name: "Geneva", last_name: "Wilson" },
        { age: 38, first_name: "Jami", last_name: "Carney" }
      ]
    };
  },
  methods: {
    onRowClicked(item) {
      const { detailsRow } = this
      if (detailsRow && detailsRow !== item) {
        detailsRow._showDetails = false;
      }

      this.$set(item, "_showDetails", !item._showDetails);
      this.detailsRow = item;
    }
  }
});
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap-vue@2.21.2/dist/bootstrap-vue.min.css" />
<script src="https://unpkg.com/vue@2.6.2/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue@2.21.2/dist/bootstrap-vue.min.js"></script>

<div id="app">
  <b-table :items="items" @row-clicked="onRowClicked">
    <template #row-details="{ item }">
      <pre>{{ item }}</pre>
    </template>
  </b-table>
</div>