Skip to content

Commit df653e7

Browse files
authoredJan 16, 2025··
fix(helper): fix getHeaders function (#342)
1 parent bcf4a89 commit df653e7

File tree

5 files changed

+51
-76
lines changed

5 files changed

+51
-76
lines changed
 

‎docs/tools/helper/client.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ locale.value // '标题'
7171
Get headers from current page.
7272

7373
```ts
74-
export const getHeaders: (options: GetHeadersOptions) => MenuItem[]
74+
export const getHeaders: (options: GetHeadersOptions) => HeaderItem[]
7575
```
7676
7777
**Params:**
@@ -112,7 +112,7 @@ export interface GetHeadersOptions {
112112
**Result:**
113113

114114
```ts
115-
export interface Header {
115+
interface PageHeader {
116116
/**
117117
* The level of the header
118118
*
@@ -138,14 +138,14 @@ export interface Header {
138138
/**
139139
* The children of the header
140140
*/
141-
children: Header[]
141+
children: MarkdownItHeader[]
142142
}
143143

144144
export type HeaderLevels = number | 'deep' | false | [number, number]
145145

146-
export type MenuItem = Omit<Header, 'children' | 'slug'> & {
147-
element: HTMLHeadElement
148-
children?: MenuItem[]
146+
export type HeaderItem = Omit<PageHeader, 'children'> & {
147+
element: HTMLHeadingElement
148+
children?: HeaderItem[]
149149
}
150150
```
151151

‎docs/zh/tools/helper/client.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ locale.value // '标题'
7171
获取当前页面指定的 标题列表。
7272

7373
```ts
74-
export const getHeaders: (options: GetHeadersOptions) => MenuItem[]
74+
export const getHeaders: (options: GetHeadersOptions) => HeaderItem[]
7575
```
7676
7777
**参数:**
@@ -112,7 +112,7 @@ export interface GetHeadersOptions {
112112
**返回结果:**
113113

114114
```ts
115-
export interface Header {
115+
interface PageHeader {
116116
/**
117117
* 当前标题的层级
118118
*
@@ -143,9 +143,9 @@ export interface Header {
143143

144144
export type HeaderLevels = number | 'deep' | false | [number, number]
145145

146-
export type MenuItem = Omit<Header, 'children' | 'slug'> & {
147-
element: HTMLHeadElement
148-
children?: MenuItem[]
146+
export type HeaderItem = Omit<PageHeader, 'children'> & {
147+
element: HTMLHeadingElement
148+
children?: HeaderItem[]
149149
}
150150
```
151151

‎themes/theme-default/src/client/composables/useHeaders.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { useThemeLocaleData } from '@theme/useThemeData'
2-
import type { MenuItem } from '@vuepress/helper/client'
2+
import type { HeaderItem } from '@vuepress/helper/client'
33
import { getHeaders } from '@vuepress/helper/client'
44
import { injectLocal, provideLocal, watchImmediate } from '@vueuse/core'
55
import type { InjectionKey, Ref } from 'vue'
66
import { computed, onMounted, ref } from 'vue'
77
import { usePageFrontmatter, useRoutePath } from 'vuepress/client'
88
import type { DefaultThemeNormalPageFrontmatter } from '../../shared/index.js'
99

10-
export type HeadersRef = Ref<MenuItem[]>
10+
export type HeadersRef = Ref<HeaderItem[]>
1111

1212
export const headersSymbol: InjectionKey<HeadersRef> = Symbol('headers')
1313

‎themes/theme-default/src/client/composables/useSidebarItems.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { resolveAutoLink } from '@theme/resolveAutoLink'
22
import { resolvePrefix } from '@theme/resolvePrefix'
33
import { useHeaders } from '@theme/useHeaders'
44
import { useThemeLocaleData } from '@theme/useThemeData'
5-
import type { MenuItem } from '@vuepress/helper/client'
5+
import type { HeaderItem } from '@vuepress/helper/client'
66
import { isLinkRelative, keys, startsWith } from '@vuepress/helper/client'
77
import type { ComputedRef, InjectionKey } from 'vue'
88
import { computed, inject, provide } from 'vue'
@@ -28,7 +28,7 @@ import type { SidebarHeaderItem, SidebarItem } from '../typings.js'
2828
* Util to transform page header to sidebar item
2929
*/
3030
export const resolveSidebarHeaderItem = (
31-
header: MenuItem,
31+
header: HeaderItem,
3232
): SidebarHeaderItem => ({
3333
text: header.title,
3434
link: header.link,
@@ -37,7 +37,7 @@ export const resolveSidebarHeaderItem = (
3737
})
3838

3939
export const resolveSidebarHeaderItems = (
40-
headers?: MenuItem[],
40+
headers?: HeaderItem[],
4141
): SidebarHeaderItem[] =>
4242
headers ? headers.map((header) => resolveSidebarHeaderItem(header)) : []
4343

@@ -46,7 +46,7 @@ export const resolveSidebarHeaderItems = (
4646
*/
4747
export const resolveSidebarHeadingItem = (
4848
page: PageData,
49-
headers: MenuItem[],
49+
headers: HeaderItem[],
5050
): SidebarItem[] => [
5151
{
5252
text: page.title,
@@ -59,7 +59,7 @@ export const resolveSidebarHeadingItem = (
5959
*/
6060
export const resolveArraySidebarItems = (
6161
sidebarConfig: SidebarArrayOptions,
62-
headers: MenuItem[],
62+
headers: HeaderItem[],
6363
path: string,
6464
prefix = '',
6565
): SidebarItem[] => {
@@ -112,7 +112,7 @@ export const resolveArraySidebarItems = (
112112
export const resolveMultiSidebarItems = (
113113
sidebarConfig: SidebarObjectOptions,
114114
page: PageData,
115-
headers: MenuItem[],
115+
headers: HeaderItem[],
116116
path: string,
117117
): SidebarItem[] => {
118118
const sidebarRoutes = keys(sidebarConfig).sort((x, y) => y.length - x.length)
@@ -161,7 +161,7 @@ export const resolveSidebarItems = (
161161
page: PageData,
162162
path: string,
163163
routeLocale: string,
164-
headers: MenuItem[],
164+
headers: HeaderItem[],
165165
): SidebarItem[] => {
166166
// resolve sidebar items according to the config
167167
if (sidebarConfig === false) {
+31-56
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,16 @@
1-
export interface Header {
2-
/**
3-
* The level of the header
4-
*
5-
* `1` to `6` for `<h1>` to `<h6>`
6-
*/
7-
level: number
8-
/**
9-
* The title of the header
10-
*/
11-
title: string
12-
/**
13-
* The slug of the header
14-
*
15-
* Typically the `id` attr of the header anchor
16-
*/
17-
slug: string
18-
/**
19-
* Link of the header
20-
*
21-
* Typically using `#${slug}` as the anchor hash
22-
*/
23-
link: string
24-
/**
25-
* The children of the header
26-
*/
27-
children: Header[]
28-
}
1+
import type { PageHeader } from 'vuepress/shared'
292

303
export type HeaderLevels = number | 'deep' | false | [number, number]
314

32-
export type MenuItem = Omit<Header, 'children' | 'slug'> & {
33-
element: HTMLHeadElement
34-
children?: MenuItem[]
5+
export type HeaderItem = Omit<PageHeader, 'children'> & {
6+
element: HTMLHeadingElement
7+
children?: HeaderItem[]
358
}
369

3710
export const resolveHeaders = (
38-
headers: MenuItem[],
11+
headers: HeaderItem[],
3912
levels: HeaderLevels = 2,
40-
): MenuItem[] => {
13+
): HeaderItem[] => {
4114
if (levels === false) {
4215
return []
4316
}
@@ -49,29 +22,30 @@ export const resolveHeaders = (
4922
? [2, 6]
5023
: levels
5124
const allowedHeaders = headers.filter(
52-
(h) => h.level >= high && h.level <= low,
25+
(header) => header.level >= high && header.level <= low,
5326
)
5427

55-
const res: MenuItem[] = []
28+
const result: HeaderItem[] = []
5629

5730
// eslint-disable-next-line no-restricted-syntax
5831
outer: for (let i = 0; i < allowedHeaders.length; i++) {
59-
const cur = allowedHeaders[i]
32+
const current = allowedHeaders[i]
33+
6034
if (i === 0) {
61-
res.push(cur)
35+
result.push(current)
6236
} else {
6337
for (let j = i - 1; j >= 0; j--) {
6438
const prev = allowedHeaders[j]
65-
if (prev.level < cur.level) {
66-
;(prev.children ??= []).push(cur)
39+
if (prev.level < current.level) {
40+
;(prev.children ??= []).push(current)
6741
continue outer
6842
}
6943
}
70-
res.push(cur)
44+
result.push(current)
7145
}
7246
}
7347

74-
return res
48+
return result
7549
}
7650

7751
const serializeHeader = (h: Element, ignore: string[] = []): string => {
@@ -92,6 +66,20 @@ const serializeHeader = (h: Element, ignore: string[] = []): string => {
9266
return text.trim()
9367
}
9468

69+
export const getHeadersFromDom = (
70+
selector: string,
71+
ignore: string[],
72+
): HeaderItem[] =>
73+
Array.from(document.querySelectorAll(selector))
74+
.filter((el) => el.id && el.hasChildNodes())
75+
.map((el) => ({
76+
element: el as HTMLHeadingElement,
77+
title: serializeHeader(el, ignore),
78+
link: `#${el.id}`,
79+
slug: el.id,
80+
level: Number(el.tagName[1]),
81+
}))
82+
9583
export interface GetHeadersOptions {
9684
/**
9785
* The selector of the headers.
@@ -134,18 +122,5 @@ export const getHeaders = ({
134122
.join(','),
135123
levels = 2,
136124
ignore = [],
137-
}: GetHeadersOptions = {}): MenuItem[] => {
138-
const headers = Array.from(document.querySelectorAll(selector))
139-
.filter((el) => el.id && el.hasChildNodes())
140-
.map((el) => {
141-
const level = Number(el.tagName[1])
142-
return {
143-
element: el as HTMLHeadElement,
144-
title: serializeHeader(el, ignore),
145-
link: `#${el.id}`,
146-
slug: el.id,
147-
level,
148-
}
149-
})
150-
return resolveHeaders(headers, levels)
151-
}
125+
}: GetHeadersOptions = {}): HeaderItem[] =>
126+
resolveHeaders(getHeadersFromDom(selector, ignore), levels)

0 commit comments

Comments
 (0)
Please sign in to comment.