用一种特殊方法在Collapse折叠面板的标题上加按钮

68 阅读2分钟

需求

书接上回 折叠面板上其实还有一个需求 在标题栏上加按钮 用于和面板内容交互

屏幕截图 2025-02-27 175700.png
这也是要求滚动被限制在面板内部的原因 因为客户需要随时看到这个按钮

分析

我接手代码的时候 感觉水平很低 不忍卒读 但它对按钮的处理让我起了点兴趣
大概是这样

    <el-collapse-item style="position:relative">
      <template #default>
        <some-comp/>
      </template>
    </el-collapse-item>

然后内容组件是

<template>
  <button style="position:absolute">btn</button>
  // xx
<template>

虽然从vue组件结构和html结构上看 按钮组件是内容面板内容的一部分
但由于css的效果 它看起来位于标题里
这种写法的好处是为按钮写事件很方便 不需要把面板组件的状态提升到父组件

解决

按照这个思路 我写出代码如下

<script setup>
import { ElCollapse, ElCollapseItem } from "element-plus";
</script>
<template>
  <el-collapse style="width: 500px; height: 200px">
    <el-collapse-item title="title">
      <template #default>
          // 可滚动元素
        <div style="max-height: 100%; overflow: auto">
          <div style="background-color: #4096ff; height: 600px">
            <button style="position: absolute; bottom: 100%">111</button>
          </div>
        </div>
      </template>
    </el-collapse-item>
  </el-collapse>
</template>
<style scoped>
.el-collapse {
  display: flex;
  flex-direction: column;

  & > :deep(.el-collapse-item) {
    display: flex;
    flex-direction: column;

    &.is-active {
      flex: auto;
      & > .el-collapse-item__wrap {
        flex: auto;
        position: relative;
        & > .el-collapse-item__content {
          position: absolute;
          inset: 0;
          overflow: hidden;
        }
      }
    }

    & > .el-collapse-item__wrap {
      transition: 0s;
    }
  }
}
//.el-collapse-item__content 现在不可滚动了
</style>

与之前的自适应面板相比 增加了一个用于滚动的容器 且没设置定位 而.el-collapse-item__content不再滚动
此时button会脱离文档流 其包含元素就是.el-collapse-item__content 它将固定在此元素上方 不随滚动而移动
效果是

image.png
这个按钮的位置是正确的 也不会受滚动影响
但是被遮挡的问题始终无法解决 我尝试过很多方法 包括为其父元素设置很高的z-index 将标题的透明度设置为0查看效果等 都无事发生
这种情况只能解释为.el-collapse-item__content脱离文档流后 溢出元素不会与其他元素进行常规堆叠

然后最终的解决方案是fixed定位

<script setup>
import { ElCollapse, ElCollapseItem } from "element-plus";
</script>
<template>
  <el-collapse style="width: 500px; height: 200px">
    <el-collapse-item title="title">
      <template #default>
        <div style="background-color: #4096ff; height: 600px">
          <button style="position: fixed; top: 0">111</button>
        </div>
      </template>
    </el-collapse-item>
  </el-collapse>
</template>
<style scoped>
.el-collapse {
  display: flex;
  flex-direction: column;

  & > :deep(.el-collapse-item) {
    display: flex;
    flex-direction: column;
    translate: 0 0;

    &.is-active {
      flex: auto;
      & > .el-collapse-item__wrap {
        flex: auto;
        position: relative;
        & > .el-collapse-item__content {
          position: absolute;
          inset: 0;
          overflow: auto;
        }
      }
    }

    & > .el-collapse-item__wrap {
      transition: 0s;
    }
  }
}
</style>

为.el-collapse-item设置transform属性 将button定位改成fixed 强行将button提升至.el-collapse-item的文档流里 当然bottom:100%也要对应改成top:0
效果还可以

image.png