
本文介绍一种基于 Django 模板过滤器与前端交互的“Read more / Read less”实现方案,通过 truncatewords_html 替代 slice,确保文本在单词边界处截断,彻底解决中英文混排或长词被意外切分的问题。
本文介绍一种基于 django 模板过滤器与前端交互的“read more / read less”实现方案,通过 `truncatewords_html` 替代 `slice`,确保文本在单词边界处截断,彻底解决中英文混排或长词被意外切分的问题。
在构建内容型 Django 应用(如游戏库、博客、产品详情页)时,常需对长文本(如 game.overview)做摘要展示,并提供“Read more”交互以展开全文。若直接使用 |slice:"300" 进行字符级截断,极易在单词中间切断(例如 "each" 被截为 "eac"),导致展开后语义断裂、阅读体验差。
✅ 推荐解法:语义化截断 + DOM 切换
Django 内置的 truncatewords_html 过滤器可按单词数安全截断,自动保留 HTML 标签结构(如 <p>、<strong>),且严格在空格处断开,杜绝单词撕裂问题:
<p><strong>Overview:</strong>
<span class="overview">{{ game.overview|default:"N/A"|truncatewords_html:"50" }}</span>
<span class="full-text" style="display: none;">{{ game.overview|default:"N/A" }}</span>
<button class="read-button" onclick="readMore(this);">[Read more...]</button>
</p>对应 JavaScript 逻辑简洁可靠,仅控制两个 <span> 的显隐切换,无需手动处理省略号或文本拼接:
function readMore(button) {
const parent = button.parentNode;
const truncatedText = parent.querySelector(".overview");
const fullText = parent.querySelector(".full-text");
if (truncatedText.style.display === "none") {
// 收起状态 → 显示摘要,隐藏全文
truncatedText.style.display = "inline";
fullText.style.display = "none";
button.innerHTML = "[Read more...]";
} else {
// 展开状态 → 隐藏摘要,显示全文
truncatedText.style.display = "none";
fullText.style.display = "inline";
button.innerHTML = "[Read less...]";
}
}⚠️ 注意事项与增强建议
- 性能友好:全文与摘要均在服务端渲染完成,无 AJAX 请求,首屏加载快;
- 无障碍支持:可为按钮添加 aria-expanded 属性,并用 aria-controls 关联目标元素;
- 样式优化:建议为 .dots 和过渡效果补充 CSS(如 transition: opacity 0.2s),提升视觉反馈;
- 移动端适配:truncatewords_html:"50" 可根据屏幕宽度动态调整(配合视口媒体查询或后端响应式上下文);
- 备选方案:若需更精细控制(如保留前 N 个字符但不破词),可自定义模板过滤器 smart_truncate,结合 Python 的 textwrap 实现。
该方案兼顾语义正确性、代码简洁性与用户体验,是 Django 项目中处理长文本摘要展开的经典实践。

















