vue实现动态展开与折叠内联块元素

功能需求

当多个内联块元素(比如div)在一个固定宽度的父元素内自动排列换行时,如果这些元素的行数超过四行,那么默认折叠超出的部分,并在第四行末尾显示一个按钮供用户切换展开或折叠状态。在折叠状态下,为了确保展开/折叠按钮能够显示在第四行末尾,会隐藏第四行的最后一个元素。在展开状态下,所有元素都会显示,并且展开/折叠按钮会显示在所有元素的末尾。

效果预览

代码实现

<template>
  <div>
    <div class="container" ref="container">
      <!-- 遍历每一个项目并根据条件决定是否隐藏 -->
      <div
        v-for="(item, index) in items"
        :key="index"
        :class="{ hidden: shouldHideItem(index) }"
        class="inline-block-item"
      >
        {{ item }}
      </div>
      <!-- 只有当需要显示切换按钮时,才渲染此按钮 -->
      <button 
        v-if="showToggle" 
        @click="toggle" 
        class="inline-block-item" 
        ref="toggleButton"
      >
        {{ isCollapsed ? '展开' : '折叠' }}
      </button>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      // 初始项目列表
      items: Array.from({ length: 20 }, (_, i) => `Item ${i + 1}`),
      // 默认为折叠状态
      isCollapsed: true,
      // 是否需要显示切换按钮
      showToggle: false,
      // 第四行后的第一个项目的索引
      firstItemIndexAfterFourRows: Infinity,
    };
  },
  mounted() {
    // 当组件加载完成后,检查是否需要显示切换按钮
    this.$nextTick(() => {
      this.checkIfNeedToggle();
    });
  },
  methods: {
    // 切换展开/折叠状态
    toggle() {
      this.isCollapsed = !this.isCollapsed;
    },
    // 根据当前状态和项目索引判断是否应该隐藏项目
    shouldHideItem(index) {
      if (this.isCollapsed) {
        // 折叠状态时,隐藏第四行的最后一个项目
        if (index === this.firstItemIndexAfterFourRows - 1) return true;
        // 以及所有在第四行之后的项目
        return index >= this.firstItemIndexAfterFourRows;
      }
      // 展开状态时不隐藏任何项目
      return false; 
    },
    // 检查是否需要显示切换按钮
    checkIfNeedToggle() {
      const container = this.$refs.container;
      const children = container.children;
      if (!children.length) return;

      let rowCount = 1;
      let prevTop = children[0].getBoundingClientRect().top;

      for (let i = 1; i < children.length; i++) {
        const currTop = children[i].getBoundingClientRect().top;

        // 如果当前项目的顶部位置大于前一个项目,说明它在一个新的行
        if (currTop > prevTop) {
          rowCount++;
          // 如果行数超过4行,记录索引并设置 showToggle 为 true
          if (rowCount > 4) {
            this.firstItemIndexAfterFourRows = i;
            this.showToggle = true;
            break;
          }
        }

        prevTop = currTop;
      }
    },
  },
};
</script>

<style scoped>
.container {
  width: 200px;
}

.inline-block-item {
  display: inline-block;
  margin: 2px;
  white-space: nowrap;
}

.hidden {
  display: none;
}
</style>

posted @ 2023-10-25 14:54  余以为  阅读(169)  评论(0编辑  收藏  举报