最直接可靠的方式是用 document.queryselectorall('ul > li') 获取顶层列表项,再通过 map(el => el.textcontent.trim()) 提取并去除空白,filter(boolean) 过滤空值;避免 innerhtml 正则解析和过早执行。

用 querySelectorAll 选中列表项再遍历取 textContent
最直接可靠的方式是用原生 DOM API:先选中所有 <li> 元素,再逐个读取 textContent。注意别用 innerText——它受 CSS 样式影响(比如 display: none 的元素内容会被忽略),而 textContent 只看 DOM 结构,更稳定。
常见错误是只写 document.querySelector('ul').textContent,这会把整个 <ul></ul> 内所有文本(包括嵌套标签的、换行符、多余空格)全拼起来,无法区分条目。
- 用
document.querySelectorAll('li')精准定位每一项 - 对每个
li调用.textContent.trim()去除首尾空白 - 过滤掉空字符串(比如纯空白或注释节点导致的空值)
const items = Array.from(
document.querySelectorAll('ul li')
).map(el => el.textContent.trim())
.filter(text => text.length > 0);
处理嵌套列表时避免重复提取子项
如果 HTML 中有 <ul><li>A<ul><li>A1</li></ul>
</li></ul> 这类结构,直接用 'ul li' 选择器会把 A 和 A1 都抓进来,但你可能只想顶层的 A。
这时候得加层级限制:'ul > li' 表示只选 <ul></ul> 的直接子 <li>;或者用 document.querySelector('ul').children 配合 HTMLCollection 迭代,更可控。
-
'ul li'是后代选择器,会匹配所有嵌套层级 -
'ul > li'是子选择器,只匹配一级子元素 - 若列表在特定容器内(如
<div class="menu">),优先用 <code>'.menu > ul > li'缩小范围用正则从 innerHTML 提取文本?不推荐
有人想用
innerHTML.match(/<li>(.*?)/g)</li>解析,这很危险:HTML 不是正则友好格式,标签可能含属性、换行、自闭合写法(<li>)、CDATA 或注释,正则极易漏匹配或错切。
Wechat Article Html下载将 Markdown 文章转换为微信公众号兼容的纯 HTML 格式。当用户要求"转成微信格式"、"生成公众号文章 HTML"、"排版到微信草稿箱"、"微信粘贴格式"时触发。输出带内联样式的纯 HTML,微信编辑器可直接渲染,无需额外适配。支持标题、段落、列表、粗体、行内代码、表格、引用块、代码块、配图的完整转换。
浏览器已经帮你解析好 DOM 树了,绕过 DOM 直接字符串操作,等于放弃结构语义,还引入不可控的边界问题。
- 哪怕只是简单列表,
<li title=">">abc</li>就会让/<li>(.*?)/</li>失效 -
innerHTML中的实体(如)不会自动解码,而textContent会返回真实字符 - 服务端渲染或 SSR 场景下,DOM 可能未就绪,需确保执行时机(如
DOMContentLoaded后)
遇到动态加载列表要等数据挂载完成
如果列表由 JavaScript 异步填充(比如 Vue/React 渲染、AJAX 加载后插入),
querySelectorAll在页面加载完立刻执行,很可能拿到空 NodeList。不能靠
setTimeout硬等,应该监听实际变化:用MutationObserver观察目标容器的子节点变动,或在业务逻辑中明确知道插入完成的时机(如 Promise resolve 后)再提取。- 检查是否真有
li:打印document.querySelectorAll('li').length,为 0 就说明还没加载 - 若用框架,优先走框架提供的 ref 或生命周期钩子获取真实 DOM 节点
- 服务端预渲染(SSR)+ 客户端激活(hydration)场景下,首次提取必须等 hydration 完成
console.dir(document.querySelector('ul'))看一眼真实结构,比猜选择器靠谱得多。 - 哪怕只是简单列表,










