LineClamp 按行折叠

把长内容折叠到指定行数,超出时显示展开按钮。

转学第一天,我在天台遇见了那个抱着旧相机的少女。她说这台相机拍得到明天。那之后的每一天,我们都在放学后爬上那道生锈的铁梯。她按下快门,我负责记录时间。照片里的明天总是准确无误:打翻的牛奶、迟到的电车、突然落下的雨。直到某个傍晚,取景框里出现了不该出现的东西,而她第一次没有按下快门。
<script setup lang="ts">
  import { LineClamp } from '@hina-ui/vue'
</script>

<template>
  <LineClamp class="w-full max-w-md">
    转学第一天,我在天台遇见了那个抱着旧相机的少女。她说这台相机拍得到明天。那之后的每一天,我们都在放学后爬上那道生锈的铁梯。她按下快门,我负责记录时间。照片里的明天总是准确无误:打翻的牛奶、迟到的电车、突然落下的雨。直到某个傍晚,取景框里出现了不该出现的东西,而她第一次没有按下快门。
  </LineClamp>
</template>
vue

用法

import { LineClamp } from '@hina-ui/vue'
ts

把内容放入默认插槽。超过 3 行的部分被折叠,底部渐隐,下方出现「展开全部」按钮;展开后按钮变为「收起」。内容没有超过行数时不显示按钮。

<LineClamp>{{ synopsis }}</LineClamp>
vue

宽度由容器或 class 决定。遮住剧透内容使用 Spoiler,展开与收起一整块区域使用 Collapsible。

示例

行数

lines 设置折叠后保留的行数,默认为 3。小数向下取整,小于 1 时按 1 处理。

旧书商人每年秋天沿着运河北上,把一船的书卖给沿岸的小镇。今年船上多了一位不请自来的乘客:一个自称在找一本不存在的书的少女。她记得那本书的每一页,却说不出书名与作者。两人约定,她沿途替他整理书目,他带她到运河尽头的图书馆。每停靠一座小镇,就有一位读者认出她口中的某个段落,也各自讲出一个不同的结局。
旧书商人每年秋天沿着运河北上,把一船的书卖给沿岸的小镇。今年船上多了一位不请自来的乘客:一个自称在找一本不存在的书的少女。她记得那本书的每一页,却说不出书名与作者。两人约定,她沿途替他整理书目,他带她到运河尽头的图书馆。每停靠一座小镇,就有一位读者认出她口中的某个段落,也各自讲出一个不同的结局。
<script setup lang="ts">
  import { LineClamp, Stack } from '@hina-ui/vue'

  const synopsis =
    '旧书商人每年秋天沿着运河北上,把一船的书卖给沿岸的小镇。今年船上多了一位不请自来的乘客:一个自称在找一本不存在的书的少女。她记得那本书的每一页,却说不出书名与作者。两人约定,她沿途替他整理书目,他带她到运河尽头的图书馆。每停靠一座小镇,就有一位读者认出她口中的某个段落,也各自讲出一个不同的结局。'
</script>

<template>
  <Stack class="w-full max-w-md" gap="lg">
    <LineClamp :lines="2">{{ synopsis }}</LineClamp>
    <LineClamp :lines="4">{{ synopsis }}</LineClamp>
  </Stack>
</template>
vue

块级内容

默认插槽可以放 Text 段落或 Prose 等块级内容。行数跨段落累计,按内部文字的行高计算。

第一卷收录连载的前十二话,从转学第一天写到那年的文化祭。单行本修订了连载时的全部对白,并重绘了三处跨页。

卷末附有两篇未公开的短篇。一篇以摄影部顾问的视角补完了旧相机的来历,另一篇是发生在暑假的番外,讲两人为了拍到一场流星雨在天台守了整整一夜。

初版随书附赠一张明信片,图案为封面的线稿。电子版不含赠品,正文内容与纸质版一致。

<script setup lang="ts">
  import { LineClamp, Text } from '@hina-ui/vue'
</script>

<template>
  <LineClamp :lines="4" class="w-full max-w-md">
    <Text size="sm" tone="muted">
      第一卷收录连载的前十二话,从转学第一天写到那年的文化祭。单行本修订了连载时的全部对白,并重绘了三处跨页。
    </Text>
    <Text size="sm" tone="muted">
      卷末附有两篇未公开的短篇。一篇以摄影部顾问的视角补完了旧相机的来历,另一篇是发生在暑假的番外,讲两人为了拍到一场流星雨在天台守了整整一夜。
    </Text>
    <Text size="sm" tone="muted">
      初版随书附赠一张明信片,图案为封面的线稿。电子版不含赠品,正文内容与纸质版一致。
    </Text>
  </LineClamp>
</template>
vue

受控

v-model:expanded 绑定展开状态,页面上的其他控件可以展开或收起同一段内容。

山顶的气象站只剩下一名观测员。每天早晨六点,他把前一夜的风速与气压抄进日志,再用无线电报给山下的小镇。入冬后的第一场雪封住了山路,无线电的另一端却换成了一个陌生的声音,自称来自三十年前的同一座气象站。
<script setup lang="ts">
  import { ref } from 'vue'
  import { Button, LineClamp, Stack } from '@hina-ui/vue'

  const expanded = ref(false)
</script>

<template>
  <Stack class="w-full max-w-md">
    <Button
      variant="outline"
      tone="neutral"
      size="sm"
      class="self-start"
      @click="expanded = !expanded"
    >
      {{ expanded ? '收起简介' : '展开简介' }}
    </Button>
    <LineClamp v-model:expanded="expanded" :lines="2">
      山顶的气象站只剩下一名观测员。每天早晨六点,他把前一夜的风速与气压抄进日志,再用无线电报给山下的小镇。入冬后的第一场雪封住了山路,无线电的另一端却换成了一个陌生的声音,自称来自三十年前的同一座气象站。
    </LineClamp>
  </Stack>
</template>
vue

自定义文案

按钮文案默认取自界面语言的 lineClamp.expand 与 lineClamp.collapse。expand-label 与 collapse-label 替换单个组件的文案。

读到第三卷才发现,前两卷里那些看似随手写下的天气记录全是伏笔。作者没有用任何一句解释去点破它,只是让同一段无线电通话在不同的季节里重复了三次。合上书以后我把第一卷又翻了一遍,这一次每一页都像是另一本书。推荐给喜欢慢节奏叙事的读者。
<script setup lang="ts">
  import { LineClamp } from '@hina-ui/vue'
</script>

<template>
  <LineClamp expand-label="查看全文" collapse-label="收起全文" class="w-full max-w-md">
    读到第三卷才发现,前两卷里那些看似随手写下的天气记录全是伏笔。作者没有用任何一句解释去点破它,只是让同一段无线电通话在不同的季节里重复了三次。合上书以后我把第一卷又翻了一遍,这一次每一页都像是另一本书。推荐给喜欢慢节奏叙事的读者。
  </LineClamp>
</template>
vue

行为

  • 折叠高度由 CSS 按行截断得出。按钮始终由服务端输出,是否显示按钮与渐隐由 CSS 按内容是否溢出决定,首帧就是最终状态,激活前后的布局与外观一致。
  • 不支持滚动驱动动画(animation-timeline)的浏览器在激活前按内容超出处理:显示按钮,不显示渐隐,末行以省略号结尾;激活后按测量结果修正。
  • expanded 初始为 true 时,激活前显示「收起」;激活后内容不超过行数则移除按钮。
  • 激活后,容器宽度、内容或 lines 变化时重新测量,字体加载完成后再测量一次。按钮随测量结果显示或隐藏,展开状态下的「收起」同样如此。
  • 展开与收起带高度过渡,底部的渐隐随之淡出与淡入;过渡途中再次切换时,从当前高度折回。系统开启减少动态效果时不播放过渡。
  • 渐隐用遮罩实现,不依赖背景色;最多覆盖 1.5 行,行数较少时按比例缩短。展开稳定后移除遮罩。
  • 通过按钮收起后,过渡结束时组件滚动回可视范围内。
  • 折叠只裁切显示范围,完整内容始终保留在 DOM 中。

无障碍

  • 按钮是原生 button,可以聚焦,回车键与空格键都能触发。
  • aria-expanded 反映当前是否展开,aria-controls 指向内容区域。
  • 被裁切的文字不对辅助技术隐藏。
  • 内容不超过行数时,按钮不显示,也不进入焦点顺序与无障碍树。

API

Props

属性
类型
默认值
说明
lines
number
3
折叠后保留的行数,向下取整,最小为 1
expanded
boolean
false
是否展开,支持 v-model:expanded
expandLabel
string
取自界面语言
展开按钮的文案
collapseLabel
string
取自界面语言
收起按钮的文案
class
string
—
追加至根元素的类名

未声明的属性都会传给根元素。

插槽

插槽
说明
default
被折叠的内容

事件

事件
参数
说明
update:expanded
expanded: boolean
展开状态变化