Skip to content

ReadMore 查看更多 ​

长内容(公告、评论、文章详情)预先收起一部分的展开/收起容器:收起态内容裁到指定高度、底部盖渐变遮罩;展开/收起由同一按钮行完成。内容自然高度不足时退化为普通内容块(撤除收起高度,不渲染遮罩与按钮)。

平台兼容性 ​

App Web 微信小程序
✓ ✓ ✓

展开高度切换带过渡动画;内容自然高度在挂载时自动测量,异步内容变化后自动重测。

基础用法 ​

html
<n-read-more :height="88">
	<text>很长的内容……</text>
</n-read-more>

受控与拦截(付费解锁模式) ​

html
<n-read-more v-model="expanded" disabled index="article-1" expand-text="付费解锁" @click="onPayClick">
	<text>付费专栏内容……</text>
</n-read-more>
js
const expanded = ref(false);
// disabled 态 click 仍触发并返回 index;toggle 返回点击前状态和 index;
// 在回调里完成确认后置 expanded = true 放行,watch 同步展开
function onPayClick(index: string) {
	uni.showModal({
		title: "提示",
		content: `解锁 ${index} 的全部内容?`,
		success: (res) => {
			if (res.confirm) expanded.value = true;
		}
	});
}

自定义收展按钮 ​

html
<n-read-more>
	<text>内容……</text>
	<template #toggle="{ isExpanded }">
		<text>{{ isExpanded ? "收起文章" : "展开阅读全文" }}</text>
	</template>
</n-read-more>

#toggle 接管展开/收起按钮行;渐变遮罩只负责内容渐隐,不承载按钮。

动态内容与程序化收展 ​

插槽内列表异步刷新、图片撑高后高度自动重测;也可手动触发,toggle() 等价点击收展按钮行(事件序列一致):

js
const readMore = ref<NReadMoreComponentPublicInstance | null>(null);
if (readMore.value != null) readMore.value.remeasure();
readMore.value?.toggle();

API ​

Props ​

属性 类型 说明
modelValue boolean 展开状态(受控),默认 false
height number 收起态内容可见高度(px),默认 88
content string 默认插槽缺省文本,默认 ""
expandText string 展开按钮文字,空 = 语言包文案,默认 ""
collapseText string 收起按钮文字,空 = 语言包文案,默认 ""
expandIcon string 收起态展开按钮图标名,默认 "down"
collapseIcon string 展开态收起按钮图标名,默认 "up"
showToggle boolean 是否显示收展按钮行;关闭后只能由外部改 modelValue 切换,默认 true
showMask boolean 是否显示收起态渐变遮罩;不影响收展按钮交互,默认 true
textSize number 切换按钮文字字号(px),默认 14
color string 切换按钮与图标颜色,空 = 主题品牌色,默认 ""
textColor string 切换按钮文字颜色,空时沿用 color,再回落主题品牌色,默认 ""
iconSize number 切换按钮图标字号(px),默认 16
disabled boolean 禁用(拦截收展,click 与 toggle 仍触发),默认 false
index string 组件索引标识,随 click、change 和 toggle 返回,默认 ""
contentStyle string 缺省文本行内样式,默认 ""
maskStyle string 遮罩行内样式(渐变色之外的部分),默认 ""
customClass string 根节点额外 class,默认 ""
customStyle string 根节点行内样式,默认 ""

Events ​

事件 参数 说明
update:modelValue isExpanded: boolean 展开状态变化;配合 :model-value 手动双向绑定
change isExpanded: boolean, index: string 展开状态变化;禁用态不触发
click index: string, isExpanded: boolean 点击收展按钮行时触发,禁用态仍触发
toggle isExpanded: boolean, index: string 禁用态点击收展入口时触发

Slots ​

插槽 参数 说明
default — 收展的内容
toggle isExpanded: boolean, value: boolean, index: string 自定义收展按钮行(整行接管);value 与 isExpanded 表示相同状态

Expose ​

方法 说明
remeasure(): void 强制重测内容自然高度(内容异步刷新后;一般无需手动调用)
toggle(): void 程序化收展,等价点击收展按钮行(事件序列一致;禁用态只发 click 与 toggle)

实现说明 ​

与参考实现(同类展开/收起组件)的机制对照:

机制 参考做法 本库做法
收起高度 固定值(约 40px)或字符串高度 数字 px,默认 88(约 4 行正文);自然高不超该值时整体退化为普通内容块
展开入口 按钮行 按钮行在展开与收起态保持一致;showMask 只控制视觉遮罩
高度动画 CSS height 过渡(iOS 端个别版本关闭) 同款 height 过渡;首测定型前不播动画,挂载即展开不从 0 播放
内容高度测量 挂载 + 内容变化重测 同款;50ms 合并高频更新,另暴露 remeasure() 手动触发
测量不可得时 无降级 显式降级:有限重试耗尽后进入降级模式 —— 收起 max-height 裁切、展开自适应、无过渡,收展入口始终提供(内容不足判定失效,入口不消失);后续测量成功自动退出降级(部分小程序环境组件作用域查询不可用,降级保证功能完整)
遮罩与主题 56px 遮罩,页面底色从遮罩底部向上渐隐,深浅主题分别使用对应底色 同为 56px;浅色与深色分别使用静态 RGBA 渐变(渐变上 35% 全透明、渐隐集中到贴裁切线段,避免整行雾蒙);主题类并入装配位键,深浅翻转整根重建——background-image 换类不重绘是已知平台行为,残留会在浅色卡上呈灰影带
遮罩定位 absolute + bottom(锚定折叠区底边,随裁切线移动) absolute + bottom(锚定折叠区底边,随裁切线移动)
遮罩显隐 收起态显示,展开态隐藏,并过渡透明度 遮罩常驻渲染(节点不销毁),行内 opacity 200ms 渐隐;显隐走行内样式是因为微信端类切换的过渡不生效(瞬跳),行内变更与折叠区高度过渡同机制
切换事件 click(index) / toggle(禁用态) click 返回实例 index 与点击前状态,toggle 为禁用态拦截事件(付费解锁等场景),change 返回状态与 index
程序化收展 toggle()(另有 getContentHeight / init 等辅助) toggle() 等价点击收展按钮行;重测走 remeasure(),事件序列与手动点击完全一致
短内容表现 入口不渲染;折叠区仍钉收起高(留底部空白) 入口不渲染且折叠区撤除高度约束(保持原样);两处装配等首测定型后再翻转,长内容不闪整屏展开、短内容不闪入口
遮罩定制 maskStyle 可整体覆盖渐变 渐变随深浅主题自动适配(换主题整根重建遮罩),maskStyle 只开放渐变之外部分;App 端行内渐变改值存在不重绘的已知平台问题,不开放以避免配置踩坑
文案 默认中文 语言包(expand / collapse 两键),切换语言即时刷新

记录 · 思考 · 创作