function countParagraphsInSelection() {
const selection = window.getSelection();
if (!selection.rangeCount) return 0;
const range = selection.getRangeAt(0);
const container = range.commonAncestorContainer;
// 获取选区覆盖的所有文本节点及其父块级元素
const walker = document.createTreeWalker(
range.commonAncestorContainer,
NodeFilter.SHOW_ELEMENT,
{
acceptNode: (node) => {
// 仅接受块级元素(常见段落容器)
const display = getComputedStyle(node).display;
if (['block', 'flex', 'grid', 'list-item'].includes(display)) {
return NodeFilter.FILTER_ACCEPT;
}
// 特别允许 <p>, <pre>, <blockquote> 等语义化标签
if (['P', 'PRE', 'BLOCKQUOTE', 'LI', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6'].includes(node.tagName)) {
return NodeFilter.FILTER_ACCEPT;
}
return NodeFilter.FILTER_REJECT;
}
}
);
const paragraphElements = new Set();
let node;
while (node = walker.nextNode()) {
if (range.intersectsNode(node)) {
paragraphElements.add(node);
}
}
return paragraphElements.size;
}
// 使用示例
document.addEventListener('mouseup', () => {
setTimeout(() => {
console.log('检测到的段落数:', countParagraphsInSelection());
}, 0);
});⚠️ 重要注意事项:
- 不要用 document.body.innerText 或 textContent 后 .split('\n\n'):innerText 会模拟渲染效果(折叠空白),textContent 保留源码换行但不反映真实视觉段落,二者均不可靠。
和
:它们保留原始换行,若需支持此类内容,应在上述逻辑中单独处理其子文本节点的 \n 分割。元素例外- 动态内容需监听变化:SPA 页面段落可能异步加载,建议结合 MutationObserver 监听 DOM 变更。
- 用户选区边界复杂:上述 intersectsNode 是近似判断;追求高精度时,可用 Range.getBoundingClientRect() 与元素 getBoundingClientRect() 做交集检测。
总结:段落数统计的本质是语义识别,而非字符串解析。放弃对 \n\n 的执念,转向 DOM 结构分析,才能获得稳定、准确、符合 Web 标准的结果。
理论要掌握,实操不能落!以上关于《浏览器中如何用双换行分割文本统计段落数》的详细介绍,大家都掌握了吧!如果想要继续提升自己的能力,那么就来关注golang学习网公众号吧!
