在 Vuetify v-data-table 中为截断的长文本添加“查看更多”功能

问题描述 投票:0回答:1

我正在开发 Vuetify 3 数据表,需要实现一个“查看更多”按钮来描述超过三行的描述。我想使用

scrollHeight
clientHeight
来确定文本是否被截断并提供扩展它的选项。

Vuetify Playground:Playground 链接

这是我的实现的简化版本:

<template>
  <v-data-table :headers="headers" :items="items">
    <template #item.description="{ item }">
      <div>
        <div
          ref="descriptionRef"
          class="three_lines_description"
          :style="{ overflow: isExpanded[item.name] ? 'visible' : 'hidden' }"
        >
          {{ item.description }}
        </div>
        <v-btn
          v-if="isTruncated[item.name]"
          @click="toggleExpand(item.name)"
          text
        >
          {{ isExpanded[item.name] ? 'View Less' : 'View More' }}
        </v-btn>
      </div>
    </template>
  </v-data-table>
</template>

<script>
import { ref, onMounted } from 'vue';

export default {
  data() {
    return {
      headers: [
        { title: "Name", key: "name" },
        { title: "Email", key: "email" },
        { title: "Description", key: "description" },
      ],
      items: [
        // Sample items...
      ],
      isExpanded: {},
      isTruncated: {},
    };
  },
  methods: {
    toggleExpand(name) {
      this.isExpanded[name] = !this.isExpanded[name];
    },
    checkTruncation() {
      // Logic to check if the text is truncated...
    }
  },
  mounted() {
    this.checkTruncation();
  }
};
</script>

<style scoped>
.three_lines_description {
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
}
</style>

问题

  • 超过三行的描述不会出现“查看更多”按钮。
  • 我不确定如何在 v-data-table 中正确使用
    refs
    来确定文本是否被截断。

这是我现在代码的简化设计,仅更改

description
列的格式。在 Vuetify 数据表中实现“查看更多”功能的正确方法是什么?

如果解决方案有效,我将接受它作为答案并投票。

vue.js vuejs3 vuetify.js ref v-data-table
1个回答
0
投票

这是 Vue.js 3 可能的解决方案:

<script setup lang="ts">
  import { ref, onMounted, nextTick } from "vue";

  const headers = [
    { title: 'Name', key: 'name' },
    { title: 'Email', key: 'email' },
    { title: 'Description', key: 'description' },
  ];

  const items = ref([
    {
      name: 'John Rambo',
      email: '[email protected]',
      description: 'This a very short description.',
      showButton: false,
      showButtonText: "View More",
    },
    {
      name: 'John Doe',
      email: '[email protected]',
      description: 'This a short test description for the sake of testing.',
      showButton: false,
      showButtonText: "View More",
    },
    {
      name: 'Jane Doe',
      email: '[email protected]',
      description:
        'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi et nunc id augue imperdiet tempor. Duis leo nisl, aliquet et dapibus ut, eleifend sed nunc. Aenean vulputate purus tellus, ac rutrum quam mattis ac. Quisque et nunc hendrerit, pretium quam eget, dictum mauris. Aliquam pulvinar velit ac tellus porttitor, quis sagittis diam consequat. Nulla facilisi. Morbi a tempor ex. Integer tempus est ipsum, id pretium magna maximus at. Praesent finibus tempus tempus. Proin fringilla imperdiet odio eget semper. Maecenas tempus ipsum sit amet luctus tincidunt. Mauris consectetur risus in lacus placerat congue. Quisque quis arcu ut ligula finibus dapibus eu sit amet nisl. Maecenas a mi rhoncus, bibendum erat vel, pretium arcu. Vestibulum eu lectus laoreet, efficitur quam sed, ultricies risus. Morbi pharetra mauris vel venenatis lacinia.',
      showButton: false,
      showButtonText: "View More",
    },
    {
      name: 'Random Guy',
      email: '[email protected]',
      description:
        'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi et nunc id augue imperdiet tempor. Duis leo nisl, aliquet et dapibus ut, eleifend sed nunc. Aenean vulputate purus tellus, ac rutrum quam mattis ac. Quisque et nunc hendrerit, pretium quam eget, dictum mauris. Aliquam pulvinar velit ac tellus porttitor, quis sagittis diam consequat. Nulla facilisi. Morbi a tempor ex. Integer tempus est ipsum, id pretium magna maximus at. Praesent finibus tempus tempus. Proin fringilla imperdiet odio eget semper. Maecenas tempus ipsum sit amet luctus tincidunt. Mauris consectetur risus in lacus placerat congue. Quisque quis arcu ut ligula finibus dapibus eu sit amet nisl. Maecenas a mi rhoncus, bibendum erat vel, pretium arcu. Vestibulum eu lectus laoreet, efficitur quam sed, ultricies risus. Morbi pharetra mauris vel venenatis lacinia.',
      showButton: false,
      showButtonText: "View More",
    },
  ]);
  const descriptionRefs = ref([]);

  function increaseSize(index: number) {
    const divElement: HTMLDivElement = descriptionRefs.value[index];

    if (divElement.dataset.expanded === "true") {
      nextTick(() => {
        divElement.dataset.expanded = "false"
        divElement.classList.add('three_lines_description');
        items.value[index].showButtonText = "View More";
      })
      return;
    }

    nextTick(() => {
      divElement.dataset.expanded = "true"
      divElement.dataset.showButton = "true"
      divElement.classList.remove("three_lines_description");
      items.value[index].showButtonText = "Show less";
    });
  }

  function checkIfNeedsButton() {
    descriptionRefs.value.forEach((item: HTMLDivElement, index) => {
      if (item.scrollHeight > item.clientHeight) {
        items.value[index].showButton = true;
      }
    });
  }

  onMounted(() => {
    nextTick(() => {
      checkIfNeedsButton();
    })
  });
</script>

<template>
  <v-data-table :headers="headers" :items="items">
    <template #item.description="{ item, index }">
      <div>
        <div
          :ref="(el) => {
            descriptionRefs.push(el);
          }"
          class="three_lines_description px-1 py-1"
        >
          {{ item.description }}
        </div>
        <v-btn
          v-if="item.showButton"
          class="mt-2 mb-2"
          @click="increaseSize(index)"
        >
          {{ item.showButtonText }}
        </v-btn>
      </div>
    </template>
  </v-data-table>
</template>

<style scoped>
  .three_lines_description {
    overflow: hidden;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    line-clamp: 3;
  }
</style>

使用以下工具:

  • 函数 refs:将每个描述分配给 refs 数组。
  • NextTick 实用程序这是必需的,因为:当您在 Vue 中改变响应式状态时,生成的 DOM 更新不会同步应用。
  • 反应性:在需要时改变itemsdescriptionRefs

Vuetify Playground:示例

PD:Vuetify

中还有可扩展的 Row 功能
© www.soinside.com 2019 - 2024. All rights reserved.