-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathindex.js
More file actions
209 lines (184 loc) · 6.04 KB
/
Copy pathindex.js
File metadata and controls
209 lines (184 loc) · 6.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
class PathParser {
/**
* 解析URL路径,提取路径片段和查询参数
* @param {string} path - 可选,要解析的路径,默认使用当前页面URL
* @returns {Object} 解析结果
*/
static parse(path) {
// 默认使用当前页面的路径
const currentPath = path || window.location.pathname + window.location.search;
// 分离路径和查询参数
const [pathname, queryString] = currentPath.split('?');
// 解析路径片段(去除空字符串)
const segments = pathname.split('/').filter(segment => segment);
// 解析查询参数
const queryParams = {};
if (queryString) {
queryString.split('&').forEach(param => {
const [key, value] = param.split('=');
if (key) {
queryParams[decodeURIComponent(key)] = value ? decodeURIComponent(value) : '';
}
});
}
return {
pathname,
segments,
queryParams,
fullPath: currentPath
};
}
/**
* 匹配路由规则并提取参数
* @param {string} route - 路由规则,如 '/user/:id/posts/:postId'
* @param {string} path - 要匹配的路径,默认使用当前路径
* @returns {Object|null} 匹配结果,包含params和isExact(是否完全匹配)
*/
static match(route, path) {
const parsedPath = this.parse(path);
const routeSegments = route.split('/').filter(segment => segment);
const pathSegments = parsedPath.segments;
// 路由段数量不匹配,直接返回null
if (routeSegments.length !== pathSegments.length) {
return null;
}
const params = {};
// 逐个匹配路由段
for (let i = 0; i < routeSegments.length; i++) {
const routeSegment = routeSegments[i];
const pathSegment = pathSegments[i];
// 匹配参数段(如:id)
if (routeSegment.startsWith(':')) {
const paramName = routeSegment.slice(1);
params[paramName] = decodeURIComponent(pathSegment);
}
// 静态段必须完全匹配
else if (routeSegment !== pathSegment) {
return null;
}
}
return {
params,
isExact: parsedPath.pathname === route,
path: parsedPath.pathname,
queryParams: parsedPath.queryParams
};
}
/**
* 根据路由规则和参数生成路径
* @param {string} route - 路由规则,如 '/user/:id'
* @param {Object} params - 路径参数
* @param {Object} queryParams - 查询参数
* @returns {string} 生成的路径
*/
static generate(route, params = {}, queryParams = {}) {
let path = route;
// 替换路径参数
Object.entries(params).forEach(([key, value]) => {
const placeholder = `:${key}`;
if (path.includes(placeholder)) {
path = path.replace(placeholder, encodeURIComponent(value));
}
});
// 检查是否有未替换的参数
if (path.includes(':')) {
console.warn(`路径生成警告: 存在未替换的参数 ${path}`);
}
// 添加查询参数
const queryItems = Object.entries(queryParams)
.filter(([_, value]) => value !== undefined && value !== null)
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
if (queryItems.length > 0) {
path += `?${queryItems.join('&')}`;
}
return path;
}
/**
* 监听路径变化
* @param {Function} callback - 路径变化时的回调函数
* @returns {Function} 取消监听的函数
*/
static listen(callback) {
// 初始触发一次
const handleChange = () => {
callback(this.parse());
};
// 监听popstate事件(前进/后退按钮)
window.addEventListener('popstate', handleChange);
// 重写pushState和replaceState方法以监听手动导航
const originalPushState = history.pushState;
const originalReplaceState = history.replaceState;
history.pushState = function(...args) {
originalPushState.apply(this, args);
handleChange();
};
history.replaceState = function(...args) {
originalReplaceState.apply(this, args);
handleChange();
};
// 返回取消监听的函数
return () => {
window.removeEventListener('popstate', handleChange);
history.pushState = originalPushState;
history.replaceState = originalReplaceState;
};
}
/**
* 导航到指定路径
* @param {string} path - 目标路径
* @param {boolean} replace - 是否替换当前历史记录
*/
static navigate(path, replace = false) {
if (replace) {
history.replaceState(null, '', path);
} else {
history.pushState(null, '', path);
}
// 手动触发一次popstate事件以通知监听器
window.dispatchEvent(new PopStateEvent('popstate'));
}
}
(function() {
/**
*
* @param {*} urlOjb
*/
function loadMarkdown(urlObj) {
let markdownUrl = '';
const pathname = urlObj.pathname;
if (!pathname || pathname === '/') {
markdownUrl = 'README.md';
} else if (pathname.startsWith('/list/')) {
const result = PathParser.match('/list/:channel')
if (result) {
markdownUrl = '/list/' + result.params.channel + '.md';
}
}
if (!markdownUrl) {
return false;
}
fetch(markdownUrl)
.then(response => response.text()) // 获取响应并将其转化为文本
.then(data => {
document.getElementById('content').innerHTML = marked.parse(data); // 使用 marked.js 解析 markdown 内容
})
.catch(error => {
console.error('Error loading the markdown file:', error);
});
return true;
}
const urlOjb = PathParser.parse();
loadMarkdown(urlOjb);
document.addEventListener('click', (event) => {
const path = event.target.getAttribute('href')
if (event.target.tagName === 'A' && path?.startsWith('/list/')) {
event.preventDefault();
PathParser.navigate(path);
}
});
// 监听路径变化
PathParser.listen(parsedPath => {
console.log('路径变化:', parsedPath);
loadMarkdown(parsedPath);
});
})();