transition-group without wrapping in a span

和自甴很熟 提交于 2020-06-01 07:36:46

问题


I am trying to apply a transition to a Vuetify v-data-table so that when I delete a tbody in my table, it fades out instead of just vanishing off the screen. If I wrap the tbody in a transition-group the tbody fades out as expected. However, it's wrapped in a span tag which means all of the columns in the tbody get shoved into the first column of my table.

I know I can specify a different tag other than a span, but they all cause my table layout to break. How can I apply a fade transition to the tbody and maintain my table layout?

  <v-data-table
    ref="dataTable"
    :headers="headers"
    fixed-header
    :height="height"
    :items="invoices"
    item-key="id"
    :search="search"
    class="elevation-1"
    disable-pagination
    :loading="loading"
    loading-text="Loading invoices... please wait..."
    :no-data-text="this.noDataText"
    no-results-text="No invoices found for your search."
    :hide-default-footer="true"
  >
    <template v-slot:headers="props">
      <thead>
        <tr>
          <th
            v-for="header in props.headers"
            :key="header.text"
            ref="dataTableHdr"
            :class="['column sortable', pagination.descending ? 'desc' : 'asc', header.value === pagination.sortBy ? 'active' : '', header.class === '']"
            @click="changeSort(header.value)"
          >
            <v-icon small>arrow_upward</v-icon>
            {{ header.text }}
          </th>
        </tr>
      </thead>
    </template>

    <template v-slot:body="{ items }">
      <transition-group tag="boo" name="invoice">
        <tbody v-for="(item, index) in items" :key="item.id" @click="items.splice(index,1)">
          <tr>
            <td
              :rowspan="updateRowCount(item.invoiceSections)"
              valign="top"
              class="pt-3 text-left font-weight-medium"
            >{{ item.vendorCode }}</td>
            <td>CONTENT</td>
            <td>CONTENT</td>
            <td>CONTENT</td>
            <td>CONTENT</td>
            <td>CONTENT</td>
          </tr>
          <tr>
            <td>{{ item.vendorName }}</td>
            <td>CONTENT</td>
            <td>CONTENT</td>
            <td>CONTENT</td>
            <td>CONTENT</td>
            <td>CONTENT</td>
          </tr>
        </tbody>
      </transition-group>
    </template>
  </v-data-table>

Revised Code:

<template v-slot:body="{ items }">
  <tbody v-for="(item, index) in items" :key="item.id">
    <transition-group tag="tbody" name="invoice">
      <tr key="row1">
        <td
          :rowspan="updateRowCount(item.invoiceSections)"
          valign="top"
          class="pt-3 text-left font-weight-medium"
        >{{ item.vendorCode }}</td>
        <td>CONTENT</td>
        <td>CONTENT</td>
        <td>CONTENT</td>
        <td>CONTENT</td>
        <td>
          <v-btn @click="reject(items, index)" class="mx-2" v-blur fab small>
            <v-icon color="red">mdi-cancel</v-icon>
          </v-btn>
        </td>
      </tr>
      <tr key="row2">
        <td>{{ item.vendorName }}</td>
        <td>CONTENT</td>
        <td>CONTENT</td>
        <td>CONTENT</td>
        <td>CONTENT</td>
        <td>CONTENT</td>
      </tr>
    </transition-group>
  </tbody>
</template>

<style>
.invoice-leave-active tr,
.invoice-leave-active tr:hover {
  background-color: yellow !important;
}
.invoice-enter-active,
.invoice-leave-active {
  transition: opacity 1s;
}
.invoice-enter, .invoice-leave-to /* .invoice-leave-active below version 2.1.8 */ {
  opacity: 0;
}
</style>

Here is my final, super complex template, using v-if with changing the item.id to null.

<template v-slot:body="{ items }">
  <transition-group tag="tbody" name="invoice" v-for="(item, index) in items" :key="index">
    <tr
      key="row1"
      v-if="item.id"
      :class="[item.duplicate ? 'duplicateItemRow' : '', {'success': item.id===selectedId}]"
    >
      <td
        :rowspan="updateRowCount(item.invoiceSections)"
        valign="top"
        class="pt-3 text-left font-weight-medium"
      >{{ item.vendorCode }}</td>
      <td
        :rowspan="updateRowCount(item.invoiceSections)"
        valign="top"
        class="pt-3 text-left font-weight-medium"
      >{{ item.vendorName }}</td>
      <td
        :rowspan="updateRowCount(item.invoiceSections)"
        valign="top"
        class="pt-3 text-left font-weight-medium nowrap"
      >{{ item.poNumber }}</td>
      <td
        :rowspan="updateRowCount(item.invoiceSections)"
        valign="top"
        class="pt-3 text-left font-weight-medium"
      >
        <v-tooltip bottom>
          <template v-slot:activator="{ on }">
            <a
              :href="`/rvimain.pgm?rqstyp=senchcall1&isys=a&i7=INV&i4=${item.invoiceNumber}&i6=${item.poNumber}`"
              class="pa-0 ma-0"
              v-on="on"
              target="_blank"
            >{{ item.invoiceNumber }}</a>
          </template>
          <span>Click to view invoice</span>
        </v-tooltip>
      </td>
      <td
        :rowspan="updateRowCount(item.invoiceSections)"
        valign="top"
        class="pt-3 pr-6 text-right font-weight-medium"
      >{{ item.invoiceDate | moment("M/D/YYYY") }}</td>
      <td :class="item.invoiceAmount !== item.poAmount ? 'amountMismatchItemRow' : ''"></td>
      <td
        valign="top"
        :class="['pt-3', 'font-weight-medium', 'nowrap', item.invoiceAmount !== item.poAmount ? 'amountMismatchItemRow' : '']"
      >
        <div v-if="item.duplicate">{{ item.duplicate }}</div>
        <div
          v-if="item.invoiceAmount !== item.poAmount"
        >${{ item.poAmount | currency }} PURCHASE ORDER DOES NOT MATCH INVOICE</div>
      </td>
      <td :class="item.invoiceAmount !== item.poAmount ? 'amountMismatchItemRow' : ''"></td>
      <td :class="item.invoiceAmount !== item.poAmount ? 'amountMismatchItemRow' : ''"></td>
      <td :class="item.invoiceAmount !== item.poAmount ? 'amountMismatchItemRow' : ''"></td>
      <td :class="item.invoiceAmount !== item.poAmount ? 'amountMismatchItemRow' : ''">
        <CommentsDialog
          v-if="item.invoiceSections[0].comments"
          :itemId="item.invoiceSections[0].id"
          :comments="item.invoiceSections[0].comments"
        />
      </td>
      <td
        valign="top"
        :class="['pt-3', 'text-right', 'font-weight-medium', 'nowrap', item.invoiceAmount !== item.poAmount ? 'amountMismatchItemRow' : '']"
      >{{ item.invoiceAmount | currency }}</td>
      <td
        :rowspan="updateRowCount(item.invoiceSections)"
        valign="top"
        class="pt-3 text-center"
      >
        <div v-if="item.approvalDate && !item.rejectedDate">
          <v-icon color="green">mdi-check</v-icon>
        </div>
        <div
          v-if="!item.duplicate && !item.approvalDate && !item.rejectedDate && item.invoiceAmount === item.poAmount"
          class="mb-4"
        >
          <v-tooltip bottom>
            <template v-slot:activator="{ on }">
              <v-btn @click="approveInvoice(item)" v-on="on" v-blur class="mx-2" fab small>
                <v-icon color="green">mdi-check</v-icon>
              </v-btn>
            </template>
            <span>Approve invoice</span>
          </v-tooltip>
        </div>
        <RejectButton
          v-if="!item.approvalDate && !item.rejectedDate"
          :invoice="item"
          @removeInvoice="removeInvoice"
        />
        <div v-if="!item.approvalDate && item.rejectedDate">
          <v-icon color="red" class="mb-4">mdi-cancel</v-icon>
          <div>
            Rejected
            <br />
            {{item.rejectedDate | moment("M/D/YYYY")}}
            <br />
            {{ item.rejectedBy }}
            <br />
            <RejectReasonDialog
              v-if="item.rejectedReason"
              :itemId="item.id"
              :reason="item.rejectedReason"
            />
          </div>
        </div>
      </td>
    </tr>

    <!-- SECTIONS -->
    <template v-for="(section, index) in item.invoiceSections">
      <tr
        v-if="item.id && section.length > 0 && section.sectionDescription != ''"
        :class="item.duplicate ? 'duplicateItemRow' : 'darkTableRow'"
        :key="`${item.id}.${index}`"
      >
        <td class="text-left" colspan="2">{{ section.sectionDescription }}</td>
        <td class="text-left" colspan="3">{{ section.repairReason }}</td>
        <td class="text-right nowrap">{{ section.sectionTotal | currency }}</td>
        <td>
          <CommentsDialog
            v-if="section.comments"
            :itemId="section.id"
            :comments="section.comments"
          />
        </td>
      </tr>

      <!-- ITEMS -->
      <tr
        :class="[item.duplicate ? 'duplicateItemRow' : '', item.qtyRequested != item.qtyReceived ? 'qtyMismatchItemRow' : '' ]"
        v-show="item.id"
        v-for="(item, index) in section.invoiceItems"
        :key="`${item.id}.${item.id}.${index}`"
      >
        <td class="text-left">{{ item.partNumber }}</td>
        <td class="text-left">{{ item.partDescription }}</td>
        <td class="text-right">
          <v-tooltip v-if="item.qtyRequested != item.qtyReceived" bottom>
            <template v-slot:activator="{ on }">
              <span v-on="on" class="help">{{ item.qtyReceived }}</span>
            </template>
            <span>Requested {{ item.qtyRequested }}</span>
          </v-tooltip>
          <span v-else>{{ item.qtyReceived }}</span>
        </td>
        <td
          :class="['text-right nowrap nopaddingRight', item.each > item.avgChargeAmount && item.avgChargeAmount != 0 ? 'over help' : '', 
        item.each < item.avgChargeAmount && item.avgChargeAmount != 0 ? 'under help' : '']"
        >
          <v-tooltip
            v-if="item.each != item.avgChargeAmount && item.avgChargeAmount != 0"
            bottom
          >
            <template v-slot:activator="{ on }">
              <span v-on="on">{{ item.each | currency }}</span>
            </template>
            <span>Avg price: ${{ item.avgChargeAmount | currency }}</span>
          </v-tooltip>
          <span v-else>{{ item.each | currency }}</span>
        </td>
        <td
          :class="['text-left nowrap lowpaddingLeft', item.each > item.avgChargeAmount && item.avgChargeAmount != 0 ? 'over' : '', 
        item.each < item.avgChargeAmount && item.avgChargeAmount != 0 ? 'under' : '']"
        >
          <v-tooltip v-if="item.nationalAccount" bottom>
            <template v-slot:activator="{ on }">
              <span v-on="on" class="help">N</span>
            </template>
            <span>
              National
              <br />Account
            </span>
          </v-tooltip>
        </td>
        <td class="text-right nowrap">{{ item.lineTotal | currency }}</td>
        <td class="text-left">
          <v-btn
            outlined
            small
            color="primary"
            dark
            v-if="item.comments"
            @click.stop="$set(dialogComments, item.id, true)"
          >Comments</v-btn>
          <CommentsDialog v-if="item.comments" :itemId="item.id" :comments="item.comments" />
        </td>
      </tr>
    </template>
    <tr key="row3" v-if="item.id">
      <td colspan="13" class="divider">&nbsp;</td>
    </tr>
  </transition-group>
</template>

回答1:


You can use the transition group as your tbody, with the tag attribute like tag="tbody". So the transition group will display as a tbody instead of a span. The immediate children of the transition group also need unique keys and a v-if or v-show condition. The if or show condition also has to be triggered after whatever content you're looping through is ready, in order to se the transition. The click function will work inside of your table, but not on the tbody.

https://vuejs.org/v2/guide/transitions.html#List-Transitions

<transition-group tag="tbody" name="invoice" v-for="(item, index) in items" :key="index">
    <tr key="row1" v-if="showRow">
        // Your columns
    </tr>
    <tr key="row2" v-if="showRow">
        // Your columns
    </tr>
</transition-group>

You can also use a tbody with the is attribute: is="transition-group", but I prefer the above option because the required name attribute of transition-group is not an allowed attribute of tbody. https://vuejs.org/v2/api/#is

<tbody is="transition-group" name="invoice">
    ...
</tbody>


来源:https://stackoverflow.com/questions/61669544/transition-group-without-wrapping-in-a-span

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!