💻 G.Ark Blog

个人技术笔记与生活记录

节点分享网站代码分享

1. 项目结构

1
2
3
4
/project-root

├── index.html # 网站主页面
└── nodes.json # 节点数据文件,存储节点信息

2. 代码详解

2.1 index.html

这是网站的主页面,使用纯前端技术实现,包含:

  • 页面结构和样式设计
  • 节点列表动态渲染
  • 复制节点链接功能
  • 刷新按钮重新加载节点数据
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
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>G.Ark 节点列表</title>
<style>
body {
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
background-color: #f5f7fa;
margin: 0;
padding: 20px;
color: #333;
}
header {
text-align: center;
margin-bottom: 30px;
}
header h1 {
margin: 0;
font-size: 2rem;
color: #2c3e50;
}
header p {
margin: 5px 0 0;
color: #666;
font-size: 1rem;
}
#refresh-btn {
display: inline-block;
margin: 10px auto 30px;
padding: 10px 20px;
background-color: #3498db;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1rem;
transition: background-color 0.3s ease;
}
#refresh-btn:hover {
background-color: #2980b9;
}
.node-list {
max-width: 900px;
margin: 0 auto;
background: white;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
padding: 20px;
}
.node-item {
border-bottom: 1px solid #eee;
padding: 15px 0;
display: flex;
flex-wrap: wrap;
align-items: center;
}
.node-item:last-child {
border-bottom: none;
}
.node-info {
flex: 1 1 70%;
min-width: 250px;
}
.node-title {
font-weight: 600;
font-size: 1.1rem;
margin-bottom: 6px;
color: #34495e;
}
.node-protocol {
font-size: 0.9rem;
color: #7f8c8d;
margin-bottom: 6px;
}
.node-link {
font-family: monospace;
font-size: 0.85rem;
word-break: break-all;
background: #ecf0f1;
padding: 6px 8px;
border-radius: 4px;
margin-bottom: 6px;
user-select: text;
}
.node-meta {
font-size: 0.85rem;
color: #95a5a6;
}
.copy-btn {
flex: 0 0 100px;
background-color: #27ae60;
color: white;
border: none;
border-radius: 5px;
padding: 8px 12px;
cursor: pointer;
font-size: 0.9rem;
transition: background-color 0.3s ease;
margin-left: 15px;
white-space: nowrap;
}
.copy-btn:hover {
background-color: #1e8449;
}
@media (max-width: 600px) {
.node-item {
flex-direction: column;
align-items: flex-start;
}
.copy-btn {
margin-left: 0;
margin-top: 8px;
width: 100%;
}
}
</style>
</head>
<body>
<header>
<h1>G.Ark</h1>
<p>不定时更新 节点投稿: <a href="mailto:[email protected]">[email protected]</a></p>
<button id="refresh-btn" title="刷新页面">刷新</button>
</header>

<section class="node-list" aria-label="节点列表">
<!-- 节点条目将由 JS 动态生成 -->
</section>

<script>
const nodeListEl = document.querySelector('.node-list');

function createNodeItem(node) {
const item = document.createElement('article');
item.className = 'node-item';

const info = document.createElement('div');
info.className = 'node-info';

const title = document.createElement('h3');
title.className = 'node-title';
title.textContent = node.title;
info.appendChild(title);

const protocol = document.createElement('div');
protocol.className = 'node-protocol';
protocol.textContent = `协议: ${node.protocol}`;
info.appendChild(protocol);

const link = document.createElement('div');
link.className = 'node-link';
link.textContent = node.link;
info.appendChild(link);

const meta = document.createElement('div');
meta.className = 'node-meta';
meta.textContent = `添加时间: ${node.added}`;
info.appendChild(meta);

const copyBtn = document.createElement('button');
copyBtn.className = 'copy-btn';
copyBtn.textContent = '复制';
copyBtn.setAttribute('aria-label', `复制节点链接: ${node.title}`);
copyBtn.addEventListener('click', () => {
navigator.clipboard.writeText(node.link).then(() => {
copyBtn.textContent = '已复制';
setTimeout(() => {
copyBtn.textContent = '复制';
}, 1500);
}).catch(() => {
alert('复制失败,请手动复制');
});
});

item.appendChild(info);
item.appendChild(copyBtn);

return item;
}

function renderNodes(nodes) {
nodeListEl.innerHTML = '';
nodes.forEach(node => {
nodeListEl.appendChild(createNodeItem(node));
});
}

async function loadNodes() {
try {
const response = await fetch('nodes.json');
if (!response.ok) throw new Error('网络错误,加载节点失败');
const nodes = await response.json();
renderNodes(nodes);
} catch (error) {
nodeListEl.innerHTML = `<p style="color:red; text-align:center;">加载节点失败:${error.message}</p>`;
}
}

document.getElementById('refresh-btn').addEventListener('click', () => {
loadNodes();
});

// 页面加载时初始化
loadNodes();
</script>
</body>
</html>

2.2 nodes.json

这是节点数据文件,采用 JSON 格式存储节点信息。每个节点包含:

  • title:节点名称
  • protocol:协议类型(如 V2ray、VLESS、Hysteria2 等)
  • link:节点链接
  • added:添加时间

示例内容如下:

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
[
{
"title": "V2ray Nodeloc@October1899<侵删>",
"protocol": "URL",
"link": "<https://vlog.573193.xyz/aliyun/alist/apikey?token=009d1d8592249e0165799c2c60d0de38>",
"added": "2025/10/18 14:46:55"
},
{
"title": "V2ray Linux@LS131<侵删>",
"protocol": "URL",
"link": "<https://v1.mk/nUscDPS>",
"added": "2025/10/16 20:47:16"
},
{
"title": "V2ray Linux@liui<侵删>",
"protocol": "URL",
"link": "<https://pastee.dev/d/HhB0GgfI/0>",
"added": "2025/10/13 01:20:16"
},
{
"title": "美国IP 匿名大佬分享<侵删>",
"protocol": "Hysteria2",
"link": "hysteria2://[email protected]:27015?sni=us.hyleet.fitness&obfs=salamander&obfs-password=7ORoCXVodF1kVmro&insecure=0#%F0%9F%87%BA%F0%9F%87%B8%7CUS%7C%40wxgqlfx%7C385",
"added": "2025/10/11 10:20:16"
},
{
"title": "美国IP 匿名大佬分享<侵删>",
"protocol": "VLESS",
"link": "vless://[email protected]:2087?encryption=none&security=tls&sni=frag2.mAhSaAMiNi.CC&alpn=h2%2Chttp%2F1.1&fp=chrome&type=ws&path=%2FCPI#%F0%9F%8C%90%7CUN%7C%40wxgqlfx%7C370",
"added": "2025/10/11 10:15:45"
},
{
"title": "美国IP 匿名大佬分享<侵删>",
"protocol": "VLESS",
"link": "vless://[email protected]:2096?encryption=none&security=tls&sni=J0in-Te1egram-eiiim.danesh-bonyan.Store&fp=chrome&type=ws&host=eiiim.danesh-bonyan.Store&path=%2Fjoin.----------------Telegram-EiiiM----------------Telegram-EiiiM---------------.Telegram-EiiiM.#%F0%9F%8C%90%7CUN%7C%40wxgqlfx%7C361",
"added": "2025/10/11 10:14:37"
},
{
"title": "v2ray订阅 Github @v2rayfree<侵删>",
"protocol": "tuic",
"link": "<https://raw.githubusercontent.com/free-nodes/v2rayfree/main/v2>",
"added": "2025/10/7 12:51:37"
},
{
"title": "IPV6小鸡TUIC 理解 @caanyying 佬友分享<侵删>",
"protocol": "tuic",
"link": "tuic://c44e5941-82a3-41d8-8b77-65df629aab4a%3Ac44e5941-82a3-41d8-8b77-65df629aab4a@[2001:470:1f18:7c::29]:60604?sni=www.bing.com&alpn=h3&congestion_control=bbr#LinuxDo@caanyying",
"added": "2025/10/7 09:35:37"
},
{
"title": "IPV6小鸡Hy2 歇斯底里 @caanyying 佬友分享<侵删>",
"protocol": "hysteria2",
"link": "hysteria2://c44e5941-82a3-41d8-8b77-65df629aab4a@[2001:470:1f18:7c::29]:30168?sni=www.bing.com&alpn=h3&insecure=1#LinuxDo@caanyying",
"added": "2025/10/7 09:34:42"
},
{
"title": "土耳其Hy2 歇斯底里 佬友分享<侵删>",
"protocol": "hysteria2",
"link": "hysteria2://[email protected]:50443?alpn=h3&insecure=1#LinuxDo@ZSF",
"added": "2025/10/7 09:31:00"
},
{
"title": "波兰家宽Hy2 歇斯底里 大口机 佬友分享<侵删>",
"protocol": "hysteria2",
"link": "hysteria2://[email protected]:40443?insecure=1#LinuxDo@ZSF",
"added": "2025/10/7 08:57:56"
}
]

3. 使用说明

  1. index.htmlnodes.json 放在同一目录下。
  2. 使用支持静态文件服务的环境打开 index.html,例如本地启动一个简单的 HTTP 服务器(推荐使用 VSCode 的 Live Server 插件,或命令行 python -m http.server)。
  3. 页面会自动加载 nodes.json 中的节点数据并展示。
  4. 点击“复制”按钮即可将节点链接复制到剪贴板,方便粘贴使用。
  5. 点击“刷新”按钮可以重新加载最新的节点数据。

4. 代码亮点

  • 纯前端实现:无需后端支持,简单易用。
  • 响应式设计:适配手机和桌面端,用户体验良好。
  • 无刷新复制功能:使用 Clipboard API 实现一键复制。
  • 易于扩展:只需更新 nodes.json 即可动态更新节点列表。

5. 后续优化建议

  • 增加节点搜索和筛选功能,方便用户快速定位所需节点。
  • 支持节点分类展示,提升页面结构清晰度。
  • 增加用户投稿功能,方便社区共同维护节点库。
  • 使用框架(如 React/Vue)重构,提高代码可维护性。