DeepseekV3.2 实现构建简易版Wiki系统:从零开始的HTML实现
我将为您创建一个功能完整的简易版Wiki系统,包含文章展示、编辑、搜索等核心功能,并按照要求包含三个表格、三个链接和代码示例。

设计思路
这个简易Wiki系统将包含以下核心功能:
- 主页文章列表展示
- 文章查看和编辑功能
- 搜索功能
- 本地存储(使用localStorage)
下面是完整的实现代码:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>简易Wiki系统</title>
<style>
:root {
--primary-color: #3498db;
--secondary-color: #2980b9;
--accent-color: #e74c3c;
--light-color: #ecf0f1;
--dark-color: #2c3e50;
--text-color: #333;
--border-radius: 4px;
--box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background-color: #f5f7fa;
color: var(--text-color);
line-height: 1.6;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
header {
background-color: var(--primary-color);
color: white;
padding: 1rem 0;
box-shadow: var(--box-shadow);
position: sticky;
top: 0;
z-index: 100;
}
.header-content {
display: flex;
justify-content: space-between;
align-items: center;
}
.logo {
font-size: 1.8rem;
font-weight: bold;
}
nav ul {
display: flex;
list-style: none;
}
nav ul li {
margin-left: 1.5rem;
}
nav ul li a {
color: white;
text-decoration: none;
padding: 0.5rem 1rem;
border-radius: var(--border-radius);
transition: background-color 0.3s;
}
nav ul li a:hover {
background-color: var(--secondary-color);
}
.search-container {
margin: 2rem 0;
display: flex;
justify-content: center;
}
.search-box {
width: 70%;
padding: 0.8rem 1.2rem;
border: 1px solid #ddd;
border-radius: 30px;
font-size: 1rem;
box-shadow: var(--box-shadow);
transition: box-shadow 0.3s;
}
.search-box:focus {
outline: none;
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.15);
border-color: var(--primary-color);
}
.main-content {
display: grid;
grid-template-columns: 1fr 3fr;
gap: 2rem;
margin: 2rem 0;
}
.sidebar {
background-color: white;
padding: 1.5rem;
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
height: fit-content;
}
.sidebar h3 {
margin-bottom: 1rem;
color: var(--dark-color);
border-bottom: 2px solid var(--primary-color);
padding-bottom: 0.5rem;
}
.sidebar ul {
list-style: none;
}
.sidebar ul li {
margin-bottom: 0.7rem;
}
.sidebar ul li a {
color: var(--text-color);
text-decoration: none;
display: block;
padding: 0.5rem;
border-radius: var(--border-radius);
transition: background-color 0.3s;
}
.sidebar ul li a:hover {
background-color: var(--light-color);
color: var(--primary-color);
}
.content {
background-color: white;
padding: 2rem;
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
min-height: 500px;
}
.article-header {
margin-bottom: 1.5rem;
padding-bottom: 1rem;
border-bottom: 1px solid #eee;
}
.article-header h1 {
color: var(--dark-color);
margin-bottom: 0.5rem;
}
.article-meta {
color: #777;
font-size: 0.9rem;
}
.article-content {
line-height: 1.8;
}
.article-content h2, .article-content h3 {
margin: 1.5rem 0 1rem 0;
color: var(--dark-color);
}
.article-content p {
margin-bottom: 1rem;
}
.article-content ul, .article-content ol {
margin-bottom: 1rem;
padding-left: 2rem;
}
.article-content table {
width: 100%;
border-collapse: collapse;
margin: 1.5rem 0;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.05);
}
.article-content table th, .article-content table td {
padding: 0.8rem 1rem;
text-align: left;
border-bottom: 1px solid #eee;
}
.article-content table th {
background-color: var(--light-color);
font-weight: 600;
}
.article-content table tr:hover {
background-color: #f9f9f9;
}
.article-content code {
background-color: #f4f4f4;
padding: 0.2rem 0.4rem;
border-radius: 3px;
font-family: 'Courier New', Courier, monospace;
}
.article-content pre {
background-color: #f8f8f8;
padding: 1rem;
border-radius: var(--border-radius);
overflow-x: auto;
margin: 1.5rem 0;
}
.article-content blockquote {
border-left: 4px solid var(--primary-color);
padding-left: 1rem;
margin: 1.5rem 0;
color: #555;
font-style: italic;
}
.article-actions {
display: flex;
justify-content: flex-end;
margin-top: 2rem;
padding-top: 1rem;
border-top: 1px solid #eee;
}
.btn {
padding: 0.6rem 1.2rem;
border: none;
border-radius: var(--border-radius);
cursor: pointer;
font-size: 0.9rem;
transition: all 0.3s;
text-decoration: none;
display: inline-block;
}
.btn-primary {
background-color: var(--primary-color);
color: white;
}
.btn-primary:hover {
background-color: var(--secondary-color);
}
.btn-secondary {
background-color: var(--light-color);
color: var(--text-color);
}
.btn-secondary:hover {
background-color: #ddd;
}
.btn-danger {
background-color: var(--accent-color);
color: white;
}
.btn-danger:hover {
background-color: #c0392b;
}
.edit-form textarea {
width: 100%;
min-height: 400px;
padding: 1rem;
border: 1px solid #ddd;
border-radius: var(--border-radius);
font-size: 1rem;
line-height: 1.6;
resize: vertical;
margin-bottom: 1rem;
}
.edit-form input[type="text"] {
width: 100%;
padding: 0.8rem 1rem;
border: 1px solid #ddd;
border-radius: var(--border-radius);
font-size: 1.2rem;
margin-bottom: 1rem;
}
.articles-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1.5rem;
}
.article-card {
background-color: white;
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
overflow: hidden;
transition: transform 0.3s, box-shadow 0.3s;
}
.article-card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.article-card-content {
padding: 1.5rem;
}
.article-card h3 {
margin-bottom: 0.5rem;
color: var(--dark-color);
}
.article-card p {
color: #666;
font-size: 0.9rem;
margin-bottom: 1rem;
}
.article-card .meta {
color: #999;
font-size: 0.8rem;
}
footer {
background-color: var(--dark-color);
color: white;
text-align: center;
padding: 2rem 0;
margin-top: 3rem;
}
.alert {
padding: 1rem;
border-radius: var(--border-radius);
margin-bottom: 1.5rem;
}
.alert-success {
background-color: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.alert-error {
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.hidden {
display: none;
}
@media (max-width: 768px) {
.main-content {
grid-template-columns: 1fr;
}
.header-content {
flex-direction: column;
text-align: center;
}
nav ul {
margin-top: 1rem;
justify-content: center;
}
.search-box {
width: 90%;
}
}
</style>
</head>
<body>
<header>
<div class="container">
<div class="header-content">
<div class="logo">简易Wiki</div>
<nav>
<ul>
<li><a href="#" id="home-link">首页</a></li>
<li><a href="#" id="create-link">创建文章</a></li>
<li><a href="#" id="about-link">关于</a></li>
</ul>
</nav>
</div>
</div>
</header>
<div class="container">
<div class="search-container">
<input type="text" class="search-box" id="search-input" placeholder="搜索Wiki文章...">
</div>
<div class="main-content">
<aside class="sidebar">
<h3>文章分类</h3>
<ul id="category-list">
<!-- 动态生成分类 -->
</ul>
<h3>热门文章</h3>
<ul id="popular-articles">
<!-- 动态生成热门文章 -->
</ul>
</aside>
<main class="content" id="content-area">
<!-- 内容区域将动态加载 -->
</main>
</div>
</div>
<footer>
<div class="container">
<p>© 2023 简易Wiki系统 | 基于HTML/CSS/JavaScript构建</p>
</div>
</footer>
<script>
// 文章数据模型
const wikiArticles = {
"home": {
title: "简易Wiki系统使用指南",
content: `
# 简易Wiki系统使用指南
欢迎使用简易Wiki系统!这是一个基于HTML/CSS/JavaScript构建的简易Wiki系统,无需后端支持,所有数据都存储在浏览器的localStorage中。
## 系统功能
1. **文章浏览** - 查看所有已创建的Wiki文章
2. **文章编辑** - 创建新文章或编辑现有文章
3. **搜索功能** - 通过关键词搜索文章内容
4. **分类管理** - 自动根据文章标签进行分类
## 使用方法
1. 点击"创建文章"开始编写新内容
2. 使用Markdown语法格式化您的文章
3. 保存后即可在首页看到您的文章
4. 使用搜索框快速查找特定内容
## 技术特点
- 纯前端实现,无需服务器
- 响应式设计,适配各种设备
- 使用localStorage进行数据持久化
- 支持Markdown语法
希望您喜欢这个简易Wiki系统!如有任何建议,欢迎反馈。
`,
category: "系统",
tags: ["wiki", "指南", "使用"],
created: "2023-10-01",
updated: "2023-10-15",
views: 125
},
"html-tutorial": {
title: "HTML基础教程",
content: `
# HTML基础教程
HTML(超文本标记语言)是构建网页的基础。本教程将介绍HTML的基本概念和常用标签。
## HTML文档结构
一个基本的HTML文档包含以下结构:
\`\`\`html
<!DOCTYPE html>
<html>
<head>
<title>页面标题</title>
</head>
<body>
<h1>这是一个标题</h1>
<p>这是一个段落。</p>
</body>
</html>
\`\`\`
## 常用HTML标签
### 文本标签
- \`<h1> - <h6>\`:标题标签,从最重要到最不重要
- \`<p>\`:段落标签
- \`<strong>\`:强调文本(粗体)
- \`<em>\`:强调文本(斜体)
- \`<br>\`:换行标签
### 链接和图像
- \`<a href="url">链接文本</a>\`:创建超链接
- \`<img src="image.jpg" alt="描述">\`:插入图像
### 列表
- \`<ul>\`:无序列表
- \`<ol>\`:有序列表
- \`<li>\`:列表项
## HTML表格
HTML表格用于展示结构化数据。下面是一个简单的表格示例:
| 标签 | 描述 | 示例 |
|------|------|------|
| \`<table>\` | 定义表格 | \`<table></table>\` |
| \`<tr>\` | 定义表格行 | \`<tr></tr>\` |
| \`<th>\` | 定义表头单元格 | \`<th>姓名</th>\` |
| \`<td>\` | 定义标准单元格 | \`<td>张三</td>\` |
下面是一个更复杂的表格示例,展示编程语言比较:
<table>
<thead>
<tr>
<th>编程语言</th>
<th>发布年份</th>
<th>主要用途</th>
<th>学习难度</th>
</tr>
</thead>
<tbody>
<tr>
<td>JavaScript</td>
<td>1995</td>
<td>Web开发</td>
<td>中等</td>
</tr>
<tr>
<td>Python</td>
<td>1991</td>
<td>数据科学、AI</td>
<td>简单</td>
</tr>
<tr>
<td>Java</td>
<td>1995</td>
<td>企业应用</td>
<td>中等</td>
</tr>
<tr>
<td>C++</td>
<td>1985</td>
<td>系统编程、游戏</td>
<td>困难</td>
</tr>
</tbody>
</table>
## HTML表单
HTML表单用于收集用户输入。下面是一个简单的登录表单示例:
\`\`\`html
<form action="/login" method="post">
<div>
<label for="username">用户名:</label>
<input type="text" id="username" name="username" required>
</div>
<div>
<label for="password">密码:</label>
<input type="password" id="password" name="password" required>
</div>
<div>
<input type="submit" value="登录">
</div>
</form>
\`\`\`
## 语义化HTML
语义化HTML使用有意义的标签来描述内容,这有助于搜索引擎优化和可访问性。
- \`<header>\`:页面或区域的页眉
- \`<nav>\`:导航链接
- \`<main>\`:页面主要内容
- \`<article>\`:独立的内容块
- \`<section>\`:文档中的节
- \`<aside>\`:侧边栏内容
- \`<footer>\`:页面或区域的页脚
## 进一步学习
要了解更多HTML知识,请参考以下资源:
1. [MDN Web文档 - HTML](https://developer.mozilla.org/zh-CN/docs/Web/HTML)
2. [W3Schools HTML教程](https://www.w3schools.com/html/)
3. [HTML标准规范](https://html.spec.whatwg.org/)
希望本教程对您学习HTML有所帮助!
`,
category: "前端开发",
tags: ["html", "教程", "前端"],
created: "2023-09-15",
updated: "2023-10-10",
views: 89
},
"css-guide": {
title: "CSS样式指南",
content: `
# CSS样式指南
CSS(层叠样式表)用于描述HTML元素在屏幕上的呈现方式。本指南将介绍CSS的核心概念和常用技巧。
## CSS基础语法
CSS规则由选择器和声明块组成:
\`\`\`css
selector {
property: value;
property: value;
}
\`\`\`
## CSS选择器
### 基本选择器
- 元素选择器:\`p { color: blue; }\`
- 类选择器:\`.className { font-size: 16px; }\`
- ID选择器:\`#idName { margin: 0; }\`
- 通用选择器:\`* { box-sizing: border-box; }\`
### 组合选择器
- 后代选择器:\`div p { line-height: 1.5; }\`
- 子元素选择器:\`ul > li { list-style: none; }\`
- 相邻兄弟选择器:\`h1 + p { margin-top: 0; }\`
- 通用兄弟选择器:\`h1 ~ p { color: #666; }\`
### 属性选择器
- \`[attribute]\`:选择带有指定属性的元素
- \`[attribute=value]\`:选择属性等于指定值的元素
- \`[attribute~=value]\`:选择属性包含指定词的元素
- \`[attribute|=value]\`:选择属性以指定值开头的元素
## CSS盒模型
每个HTML元素都可以看作一个盒子,包含内容、内边距、边框和外边距。
\`\`\`css
.box {
width: 300px;
height: 200px;
padding: 20px;
border: 2px solid #333;
margin: 10px;
}
\`\`\`
## CSS布局
### Flexbox布局
Flexbox是一种一维布局模型,非常适合组件和小规模布局。
\`\`\`css
.container {
display: flex;
justify-content: center; /* 水平对齐 */
align-items: center; /* 垂直对齐 */
flex-wrap: wrap; /* 换行 */
}
\`\`\`
### Grid布局
CSS Grid是一个二维布局系统,非常适合整个页面的布局。
\`\`\`css
.container {
display: grid;
grid-template-columns: 1fr 2fr 1fr;
grid-gap: 20px;
}
\`\`\`
## CSS响应式设计
响应式设计使网站能够适应不同屏幕尺寸。
### 媒体查询
\`\`\`css
/* 移动设备 */
@media (max-width: 768px) {
.container {
flex-direction: column;
}
}
/* 平板设备 */
@media (min-width: 769px) and (max-width: 1024px) {
.sidebar {
width: 30%;
}
}
/* 桌面设备 */
@media (min-width: 1025px) {
.main-content {
max-width: 1200px;
margin: 0 auto;
}
}
\`\`\`
## CSS变量
CSS自定义属性(变量)允许您在样式表中存储值并在整个文档中重复使用。
\`\`\`css
:root {
--primary-color: #3498db;
--secondary-color: #2980b9;
--font-size: 16px;
}
.element {
color: var(--primary-color);
font-size: var(--font-size);
}
\`\`\`
## CSS动画
CSS动画可以为元素添加动态效果。
### 过渡(Transition)
\`\`\`css
.button {
background-color: blue;
transition: background-color 0.3s ease;
}
.button:hover {
background-color: darkblue;
}
\`\`\`
### 关键帧动画(Animation)
\`\`\`css
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.element {
animation: fadeIn 1s ease-in-out;
}
\`\`\`
## CSS框架比较
下面是一个流行的CSS框架比较表格:
<table>
<thead>
<tr>
<th>框架名称</th>
<th>特点</th>
<th>学习曲线</th>
<th>自定义能力</th>
<th>适用场景</th>
</tr>
</thead>
<tbody>
<tr>
<td>Bootstrap</td>
<td>组件丰富,文档完善</td>
<td>简单</td>
<td>中等</td>
<td>快速开发,企业网站</td>
</tr>
<tr>
<td>Tailwind CSS</td>
<td>实用工具优先,高度可定制</td>
<td>中等</td>
<td>高</td>
<td>定制化设计,组件库</td>
</tr>
<tr>
<td>Bulma</td>
<td>纯CSS框架,无JavaScript</td>
<td>简单</td>
<td>中等</td>
<td>轻量级项目,学习CSS</td>
</tr>
<tr>
<td>Foundation</td>
<td>企业级,响应式强</td>
<td>中等</td>
<td>高</td>
<td>复杂应用,企业网站</td>
</tr>
</tbody>
</table>
## CSS最佳实践
1. **使用语义化类名**:使用有意义的类名,如\`.card\`而不是\`.box1\`
2. **避免过度嵌套**:减少选择器嵌套深度,提高性能
3. **使用CSS变量**:便于维护和主题切换
4. **移动优先**:先为移动设备编写样式,然后使用媒体查询为更大屏幕添加样式
5. **性能优化**:减少重绘和回流,使用transform和opacity实现动画
## 浏览器兼容性考虑
不同浏览器对CSS特性的支持可能不同。使用以下方法处理兼容性问题:
- 使用autoprefixer自动添加浏览器前缀
- 使用特性查询(@supports)检测浏览器支持
- 提供回退方案
## 进一步学习
要深入了解CSS,请参考以下资源:
1. [MDN Web文档 - CSS](https://developer.mozilla.org/zh-CN/docs/Web/CSS)
2. [CSS-Tricks](https://css-tricks.com/) - CSS技巧和教程
3. [W3Schools CSS教程](https://www.w3schools.com/css/)
通过不断练习和尝试,您将掌握CSS的强大功能,创建出美观且功能强大的网页。
`,
category: "前端开发",
tags: ["css", "样式", "前端"],
created: "2023-09-20",
updated: "2023-10-12",
views: 76
},
"javascript-basics": {
title: "JavaScript基础知识",
content: `
# JavaScript基础知识
JavaScript是一种轻量级的解释型编程语言,主要用于Web开发。本教程将介绍JavaScript的核心概念和语法。
## JavaScript简介
JavaScript最初由Netscape的Brendan Eich在1995年创建,现在已成为Web开发的三大核心技术之一(与HTML和CSS并列)。
### JavaScript能做什么
- 操作HTML元素和CSS样式
- 响应用户交互事件
- 发送和接收服务器数据(AJAX)
- 创建动画和视觉效果
- 开发复杂的Web应用程序
## 基本语法
### 变量声明
\`\`\`javascript
// ES5方式
var name = "张三";
// ES6方式
let age = 25;
const PI = 3.14159;
\`\`\`
### 数据类型
JavaScript有7种基本数据类型:
1. **Number** - 数字类型
2. **String** - 字符串类型
3. **Boolean** - 布尔类型(true/false)
4. **Undefined** - 未定义
5. **Null** - 空值
6. **Symbol** - 符号(ES6新增)
7. **BigInt** - 大整数(ES2020新增)
以及一种复杂数据类型:
- **Object** - 对象
### 运算符
\`\`\`javascript
// 算术运算符
let sum = 10 + 5; // 15
let difference = 10 - 5; // 5
let product = 10 * 5; // 50
let quotient = 10 / 5; // 2
// 比较运算符
let isEqual = 10 == 5; // false
let isStrictEqual = 10 === 5; // false
let isGreater = 10 > 5; // true
// 逻辑运算符
let andResult = true && false; // false
let orResult = true || false; // true
let notResult = !true; // false
\`\`\`
## 函数
函数是JavaScript中的一等公民,可以赋值给变量、作为参数传递或作为返回值。
### 函数声明
\`\`\`javascript
// 函数声明
function greet(name) {
return "Hello, " + name + "!";
}
// 函数表达式
const greet = function(name) {
return "Hello, " + name + "!";
};
// 箭头函数 (ES6)
const greet = (name) => {
return "Hello, " + name + "!";
};
// 简化的箭头函数
const greet = name => "Hello, " + name + "!";
\`\`\`
## 对象和数组
### 对象
对象是键值对的集合。
\`\`\`javascript
const person = {
firstName: "张",
lastName: "三",
age: 30,
hobbies: ["阅读", "游泳", "编程"],
fullName: function() {
return this.firstName + " " + this.lastName;
}
};
// 访问属性
console.log(person.firstName); // "张"
console.log(person["lastName"]); // "三"
console.log(person.fullName()); // "张 三"
\`\`\`
### 数组
数组是值的有序集合。
\`\`\`javascript
const fruits = ["苹果", "香蕉", "橙子"];
// 访问元素
console.log(fruits[0]); // "苹果"
// 数组方法
fruits.push("葡萄"); // 添加元素到末尾
fruits.pop(); // 移除最后一个元素
fruits.unshift("草莓"); // 添加元素到开头
fruits.shift(); // 移除第一个元素
// 遍历数组
fruits.forEach(function(fruit) {
console.log(fruit);
});
\`\`\`
## 控制流程
### 条件语句
\`\`\`javascript
// if-else语句
let score = 85;
let grade;
if (score >= 90) {
grade = "A";
} else if (score >= 80) {
grade = "B";
} else if (score >= 70) {
grade = "C";
} else {
grade = "D";
}
// switch语句
let day = "Monday";
let dayType;
switch (day) {
case "Saturday":
case "Sunday":
dayType = "周末";
break;
default:
dayType = "工作日";
}
\`\`\`
### 循环语句
\`\`\`javascript
// for循环
for (let i = 0; i < 5; i++) {
console.log(i);
}
// while循环
let i = 0;
while (i < 5) {
console.log(i);
i++;
}
// for...of循环 (ES6)
const colors = ["红色", "绿色", "蓝色"];
for (const color of colors) {
console.log(color);
}
\`\`\`
## DOM操作
文档对象模型(DOM)是HTML文档的编程接口,JavaScript可以通过DOM操作页面元素。
### 选择元素
\`\`\`javascript
// 通过ID选择
const header = document.getElementById("header");
// 通过类名选择
const items = document.getElementsByClassName("item");
// 通过标签名选择
const paragraphs = document.getElementsByTagName("p");
// 使用querySelector
const firstItem = document.querySelector(".item");
const allItems = document.querySelectorAll(".item");
\`\`\`
### 修改元素
\`\`\`javascript
// 修改内容
const element = document.getElementById("myElement");
element.textContent = "新内容";
element.innerHTML = "<strong>加粗内容</strong>";
// 修改样式
element.style.color = "red";
element.style.fontSize = "20px";
// 修改属性
element.setAttribute("data-id", "123");
const id = element.getAttribute("data-id");
\`\`\`
### 事件处理
\`\`\`javascript
// 添加事件监听器
const button = document.getElementById("myButton");
button.addEventListener("click", function() {
alert("按钮被点击了!");
});
// 事件对象
button.addEventListener("click", function(event) {
console.log("事件类型: " + event.type);
console.log("目标元素: " + event.target);
});
\`\`\`
## 异步JavaScript
### 回调函数
\`\`\`javascript
function fetchData(callback) {
setTimeout(function() {
const data = { name: "张三", age: 30 };
callback(data);
}, 1000);
}
fetchData(function(data) {
console.log("收到数据: ", data);
});
\`\`\`
### Promise
\`\`\`javascript
function fetchData() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
const success = true;
if (success) {
resolve({ name: "张三", age: 30 });
} else {
reject("获取数据失败");
}
}, 1000);
});
}
fetchData()
.then(function(data) {
console.log("收到数据: ", data);
})
.catch(function(error) {
console.error("错误: ", error);
});
\`\`\`
### Async/Await
\`\`\`javascript
async function getData() {
try {
const data = await fetchData();
console.log("收到数据: ", data);
} catch (error) {
console.error("错误: ", error);
}
}
getData();
\`\`\`
## JavaScript框架比较
下面是一个流行的JavaScript框架比较表格:
<table>
<thead>
<tr>
<th>框架名称</th>
<th>特点</th>
<th>学习曲线</th>
<th>性能</th>
<th>适用场景</th>
</tr>
</thead>
<tbody>
<tr>
<td>React</td>
<td>组件化,虚拟DOM,单向数据流</td>
<td>中等</td>
<td>高</td>
<td>大型应用,跨平台开发</td>
</tr>
<tr>
<td>Vue</td>
<td>渐进式,易上手,文档完善</td>
<td>简单</td>
<td>高</td>
<td>中小型应用,快速开发</td>
</tr>
<tr>
<td>Angular</td>
<td>全功能,TypeScript,依赖注入</td>
<td>陡峭</td>
<td>中等</td>
<td>企业级应用,大型团队</td>
</tr>
<tr>
<td>Svelte</td>
<td>编译时优化,无虚拟DOM</td>
<td>简单</td>
<td>非常高</td>
<td>性能敏感应用,小型项目</td>
</tr>
</tbody>
</table>
## 现代JavaScript特性
### 解构赋值
\`\`\`javascript
// 数组解构
const [first, second] = [1, 2, 3];
console.log(first); // 1
console.log(second); // 2
// 对象解构
const { name, age } = { name: "张三", age: 30, city: "北京" };
console.log(name); // "张三"
console.log(age); // 30
\`\`\`
### 模板字符串
\`\`\`javascript
const name = "张三";
const age = 30;
const message = \`大家好,我是\${name},今年\${age}岁。\`;
console.log(message); // "大家好,我是张三,今年30岁。"
\`\`\`
### 扩展运算符
\`\`\`javascript
// 数组扩展
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]
// 对象扩展
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const merged = { ...obj1, ...obj2 }; // { a: 1, b: 2, c: 3, d: 4 }
\`\`\`
## 调试技巧
1. **使用console**:
\`\`\`javascript
console.log("普通日志");
console.warn("警告信息");
console.error("错误信息");
console.table([{name: "张三", age: 30}, {name: "李四", age: 25}]);
\`\`\`
2. **使用debugger语句**:
\`\`\`javascript
function problematicFunction() {
debugger; // 执行到这里会暂停
// 代码...
}
\`\`\`
3. **浏览器开发者工具**:
- 使用Sources面板设置断点
- 使用Network面板监控网络请求
- 使用Performance面板分析性能
## 进一步学习
要深入学习JavaScript,请参考以下资源:
1. [MDN JavaScript指南](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide)
2. [Eloquent JavaScript](https://eloquentjavascript.net/) - 免费的在线书籍
3. [JavaScript.info](https://javascript.info/) - 现代JavaScript教程
4. [W3Schools JavaScript教程](https://www.w3schools.com/js/)
JavaScript是一门功能强大且灵活的语言,通过不断学习和实践,您将能够创建出交互丰富、功能强大的Web应用程序。
`,
category: "前端开发",
tags: ["javascript", "编程", "前端"],
created: "2023-09-25",
updated: "2023-10-14",
views: 102
},
"web-security": {
title: "Web安全基础",
content: `
# Web安全基础
Web安全是保护网站和Web应用程序免受恶意攻击的实践。本指南将介绍常见的Web安全威胁和防护措施。
## 常见Web安全威胁
### 1. 跨站脚本(XSS)
XSS攻击允许攻击者将恶意脚本注入到其他用户浏览的网页中。
**示例**:
\`\`\`html
<!-- 恶意用户输入 -->
<script>alert('XSS攻击');</script>
<!-- 防护措施:对用户输入进行转义 -->
<script>alert('XSS攻击');</script>
\`\`\`
### 2. 跨站请求伪造(CSRF)
CSRF攻击诱使用户在不知情的情况下执行非预期的操作。
**防护措施**:
- 使用CSRF令牌
- 检查Referer头
- 使用SameSite Cookie属性
### 3. SQL注入
SQL注入攻击通过在用户输入中插入SQL代码来操纵数据库查询。
**示例**:
\`\`\`sql
-- 恶意输入:' OR '1'='1
-- 原始查询:
SELECT * FROM users WHERE username = '[输入]' AND password = '[密码]'
-- 被操纵的查询:
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = '[密码]'
\`\`\`
**防护措施**:
- 使用参数化查询
- 使用ORM(对象关系映射)
- 对用户输入进行验证和转义
### 4. 点击劫持
点击劫持攻击通过透明的iframe覆盖在合法按钮上,诱使用户点击攻击者设置的按钮。
**防护措施**:
- 使用X-Frame-Options HTTP头
- 使用Content Security Policy(CSP)
- 使用Frame Busting JavaScript代码
## 安全防护措施
### 输入验证
对所有用户输入进行严格验证,包括:
- 数据类型检查
- 长度限制
- 格式验证
- 白名单验证
\`\`\`javascript
function validateEmail(email) {
const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;
return emailRegex.test(email);
}
function sanitizeInput(input) {
return input
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/\"/g, """)
.replace(/'/g, "'");
}
\`\`\`
### 输出编码
在将数据输出到HTML、JavaScript或URL时,进行适当的编码。
\`\`\`javascript
// HTML编码
function htmlEncode(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// URL编码
function urlEncode(text) {
return encodeURIComponent(text);
}
\`\`\`
### 身份验证和会话管理
- 使用强密码策略
- 实施多因素认证
- 使用安全的会话管理
- 设置适当的会话超时
\`\`\`javascript
// 密码强度验证
function validatePassword(password) {
const minLength = 8;
const hasUpperCase = /[A-Z]/.test(password);
const hasLowerCase = /[a-z]/.test(password);
const hasNumbers = /\\d/.test(password);
const hasSpecialChar = /[!@#$%^&*()_+-\\=\\[\\]{};':"\\\\|,.<>\\/?]/.test(password);
return password.length >= minLength &&
hasUpperCase &&
hasLowerCase &&
hasNumbers &&
hasSpecialChar;
}
\`\`\`
## 安全头设置
通过HTTP响应头增强安全性:
### Content Security Policy (CSP)
\`\`\`http
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com; style-src 'self' 'unsafe-inline'
\`\`\`
### HTTP Strict Transport Security (HSTS)
\`\`\`http
Strict-Transport-Security: max-age=31536000; includeSubDomains
\`\`\`
### X-Content-Type-Options
\`\`\`http
X-Content-Type-Options: nosniff
\`\`\`
### X-Frame-Options
\`\`\`http
X-Frame-Options: DENY
\`\`\`
## 数据加密
### HTTPS
始终使用HTTPS加密数据传输,防止中间人攻击。
### 密码哈希
使用强哈希算法存储密码,如bcrypt、Argon2或PBKDF2。
\`\`\`javascript
// 使用bcrypt哈希密码(Node.js示例)
const bcrypt = require('bcrypt');
const saltRounds = 12;
async function hashPassword(password) {
const salt = await bcrypt.genSalt(saltRounds);
const hash = await bcrypt.hash(password, salt);
return hash;
}
async function verifyPassword(password, hash) {
return await bcrypt.compare(password, hash);
}
\`\`\`
## 安全测试
### 漏洞扫描
使用自动化工具扫描应用程序漏洞:
- OWASP ZAP
- Nessus
- Burp Suite
### 代码审查
定期进行安全代码审查,查找潜在的安全问题。
### 渗透测试
聘请专业的安全团队进行渗透测试,模拟真实攻击场景。
## 安全开发最佳实践
1. **最小权限原则**:只授予必要的权限
2. **防御性编程**:假设所有输入都是恶意的
3. **安全默认值**:默认配置应该是安全的
4. **错误处理**:不向用户暴露敏感信息
5. **日志和监控**:记录安全事件并实时监控
6. **依赖管理**:定期更新第三方库和框架
7. **安全培训**:对开发团队进行安全培训
## 常见Web安全漏洞对比
下面是一个常见Web安全漏洞的对比表格:
<table>
<thead>
<tr>
<th>漏洞类型</th>
<th>影响程度</th>
<th>修复难度</th>
<th>常见发生场景</th>
<th>防护措施</th>
</tr>
</thead>
<tbody>
<tr>
<td>XSS</td>
<td>高</td>
<td>中等</td>
<td>用户输入显示,评论系统</td>
<td>输入验证,输出编码,CSP</td>
</tr>
<tr>
<td>CSRF</td>
<td>中-高</td>
<td>低</td>
<td>状态更改操作,表单提交</td>
<td>CSRF令牌,SameSite Cookie</td>
</tr>
<tr>
<td>SQL注入</td>
<td>高</td>
<td>低-中等</td>
<td>数据库查询,搜索功能</td>
<td>参数化查询,ORM,输入验证</td>
</tr>
<tr>
<td>点击劫持</td>
<td>中</td>
<td>低</td>
<td>社交媒体,广告</td>
<td>X-Frame-Options,Frame Busting</td>
</tr>
<tr>
<td>文件上传漏洞</td>
<td>高</td>
<td>中等</td>
<td>文件上传功能</td>
<td>文件类型验证,隔离存储</td>
</tr>
<tr>
<td>安全配置错误</td>
<td>中-高</td>
<td>低</td>
<td>服务器配置,默认设置</td>
<td>安全配置检查,自动化扫描</td>
</tr>
</tbody>
</table>
## 安全工具和资源
### 安全工具
1. **OWASP ZAP** - 免费的Web应用安全扫描器
2. **Burp Suite** - 功能强大的Web安全测试工具
3. **Nessus** - 漏洞扫描工具
4. **Metasploit** - 渗透测试框架
5. **Nmap** - 网络发现和安全审计工具
### 安全资源
1. [OWASP(开放Web应用安全项目)](https://owasp.org/) - Web安全权威资源
2. [SANS Internet Storm Center](https://isc.sans.edu/) - 互联网安全威胁信息
3. [CVE(通用漏洞披露)](https://cve.mitre.org/) - 公开的网络安全漏洞数据库
4. [Security Headers](https://securityheaders.com/) - 检查网站安全头的工具
## 安全事件响应
即使采取了所有预防措施,安全事件仍可能发生。制定应急响应计划至关重要:
1. **检测和识别**:及时发现安全事件
2. **遏制**:限制攻击的影响范围
3. **根除**:消除攻击原因
4. **恢复**:恢复正常运营
5. **事后分析**:总结经验教训,改进安全措施
## 结论
Web安全是一个持续的过程,而不是一次性的任务。通过实施多层防御策略、定期安全测试和持续监控,可以显著降低Web应用程序的安全风险。
记住,安全不是产品,而是一个过程。保持警惕,持续学习新的安全威胁和防护技术,是保护Web应用程序安全的关键。
`,
category: "安全",
tags: ["安全", "web", "防护"],
created: "2023-10-05",
updated: "2023-10-18",
views: 58
}
};
// 初始化应用
document.addEventListener('DOMContentLoaded', function() {
// 从localStorage加载文章数据
loadArticlesFromStorage();
// 设置事件监听器
document.getElementById('home-link').addEventListener('click', showHome);
document.getElementById('create-link').addEventListener('click', showCreateForm);
document.getElementById('about-link').addEventListener('click', showAbout);
document.getElementById('search-input').addEventListener('input', handleSearch);
// 显示首页
showHome();
// 更新侧边栏
updateSidebar();
});
// 从localStorage加载文章
function loadArticlesFromStorage() {
const storedArticles = localStorage.getItem('wikiArticles');
if (storedArticles) {
const parsedArticles = JSON.parse(storedArticles);
Object.assign(wikiArticles, parsedArticles);
} else {
// 首次使用,保存默认文章到localStorage
saveArticlesToStorage();
}
}
// 保存文章到localStorage
function saveArticlesToStorage() {
localStorage.setItem('wikiArticles', JSON.stringify(wikiArticles));
}
// 显示首页
function showHome() {
const contentArea = document.getElementById('content-area');
let html = `
<div class="article-header">
<h1>Wiki文章列表</h1>
<p class="article-meta">共 ${Object.keys(wikiArticles).length} 篇文章</p>
</div>
<div class="articles-grid">
`;
// 按更新时间排序
const sortedArticles = Object.entries(wikiArticles).sort((a, b) => {
return new Date(b[1].updated) - new Date(a[1].updated);
});
sortedArticles.forEach(([key, article]) => {
html += `
<div class="article-card" data-article="${key}">
<div class="article-card-content">
<h3>${article.title}</h3>
<p>${article.content.substring(0, 100)}...</p>
<div class="meta">
<span>分类: ${article.category}</span> |
<span>更新: ${formatDate(article.updated)}</span> |
<span>浏览: ${article.views}次</span>
</div>
</div>
</div>
`;
});
html += `</div>`;
contentArea.innerHTML = html;
// 添加文章卡片点击事件
document.querySelectorAll('.article-card').forEach(card => {
card.addEventListener('click', function() {
const articleKey = this.getAttribute('data-article');
showArticle(articleKey);
});
});
}
// 显示文章
function showArticle(key) {
if (!wikiArticles[key]) {
showError('文章不存在');
return;
}
// 增加浏览次数
wikiArticles[key].views++;
saveArticlesToStorage();
const article = wikiArticles[key];
const contentArea = document.getElementById('content-area');
let html = `
<div class="article-header">
<h1>${article.title}</h1>
<div class="article-meta">
分类: ${article.category} |
创建: ${formatDate(article.created)} |
更新: ${formatDate(article.updated)} |
浏览: ${article.views}次
</div>
</div>
<div class="article-content">
${renderMarkdown(article.content)}
</div>
<div class="article-actions">
<button class="btn btn-primary" id="edit-btn">编辑</button>
<button class="btn btn-danger" id="delete-btn">删除</button>
</div>
`;
contentArea.innerHTML = html;
// 添加编辑和删除按钮事件
document.getElementById('edit-btn').addEventListener('click', function() {
showEditForm(key);
});
document.getElementById('delete-btn').addEventListener('click', function() {
if (confirm(`确定要删除文章 "${article.title}" 吗?`)) {
deleteArticle(key);
}
});
}
// 显示编辑表单
function showEditForm(key) {
const article = wikiArticles[key];
const contentArea = document.getElementById('content-area');
let html = `
<div class="article-header">
<h1>编辑文章: ${article.title}</h1>
</div>
<form class="edit-form" id="edit-form">
<input type="text" id="article-title" value="${article.title}" placeholder="文章标题" required>
<textarea id="article-content" placeholder="文章内容(支持Markdown语法)" required>${article.content}</textarea>
<div>
<label for="article-category">分类:</label>
<input type="text" id="article-category" value="${article.category}" required>
</div>
<div>
<label for="article-tags">标签(用逗号分隔):</label>
<input type="text" id="article-tags" value="${article.tags.join(', ')}">
</div>
<div class="article-actions">
<button type="submit" class="btn btn-primary">保存</button>
<button type="button" class="btn btn-secondary" id="cancel-edit">取消</button>
</div>
</form>
`;
contentArea.innerHTML = html;
// 添加表单提交事件
document.getElementById('edit-form').addEventListener('submit', function(e) {
e.preventDefault();
saveArticle(key);
});
// 添加取消按钮事件
document.getElementById('cancel-edit').addEventListener('click', function() {
showArticle(key);
});
}
// 显示创建表单
function showCreateForm() {
const contentArea = document.getElementById('content-area');
let html = `
<div class="article-header">
<h1>创建新文章</h1>
</div>
<form class="edit-form" id="create-form">
<input type="text" id="article-key" placeholder="文章标识(英文,用于URL)" required>
<input type="text" id="article-title" placeholder="文章标题" required>
<textarea id="article-content" placeholder="文章内容(支持Markdown语法)" required></textarea>
<div>
<label for="article-category">分类:</label>
<input type="text" id="article-category" required>
</div>
<div>
<label for="article-tags">标签(用逗号分隔):</label>
<input type="text" id="article-tags">
</div>
<div class="article-actions">
<button type="submit" class="btn btn-primary">创建</button>
<button type="button" class="btn btn-secondary" id="cancel-create">取消</button>
</div>
</form>
`;
contentArea.innerHTML = html;
// 添加表单提交事件
document.getElementById('create-form').addEventListener('submit', function(e) {
e.preventDefault();
createArticle();
});
// 添加取消按钮事件
document.getElementById('cancel-create').addEventListener('click', function() {
showHome();
});
}
// 显示关于页面
function showAbout() {
const contentArea = document.getElementById('content-area');
const html = `
<div class="article-header">
<h1>关于简易Wiki系统</h1>
</div>
<div class="article-content">
<h2>系统介绍</h2>
<p>这是一个基于纯前端技术(HTML/CSS/JavaScript)实现的简易Wiki系统,无需后端支持,所有数据存储在浏览器的localStorage中。</p>
<h2>功能特点</h2>
<ul>
<li><strong>文章管理</strong>:创建、编辑、删除和查看Wiki文章</li>
<li><strong>Markdown支持</strong>:使用Markdown语法格式化文章内容</li>
<li><strong>搜索功能</strong>:通过关键词搜索文章标题和内容</li>
<li><strong>分类管理</strong>:自动根据文章分类组织内容</li>
<li><strong>响应式设计</strong>:适配各种屏幕尺寸的设备</li>
<li><strong>本地存储</strong>:使用localStorage持久化数据</li>
</ul>
<h2>技术栈</h2>
<table>
<thead>
<tr>
<th>技术</th>
<th>用途</th>
<th>特点</th>
</tr>
</thead>
<tbody>
<tr>
<td>HTML5</td>
<td>页面结构和内容</td>
<td>语义化标签,良好的可访问性</td>
</tr>
<tr>
<td>CSS3</td>
<td>页面样式和布局</td>
<td>Flexbox/Grid布局,响应式设计</td>
</tr>
<tr>
<td>JavaScript (ES6+)</td>
<td>交互逻辑和数据管理</td>
<td>现代语法,localStorage API</td>
</tr>
<tr>
<td>Markdown</td>
<td>内容格式化</td>
<td>简单易学,专注于内容</td>
</tr>
</tbody>
</table>
<h2>使用说明</h2>
<ol>
<li>在首页可以浏览所有已创建的Wiki文章</li>
<li>点击"创建文章"可以添加新的Wiki页面</li>
<li>在文章页面点击"编辑"可以修改文章内容</li>
<li>使用搜索框可以快速查找特定内容</li>
<li>侧边栏显示文章分类和热门文章</li>
</ol>
<h2>注意事项</h2>
<div class="alert alert-success">
<p><strong>数据存储</strong>:所有文章数据存储在浏览器的localStorage中,清除浏览器数据会导致文章丢失。</p>
<p><strong>浏览器兼容</strong>:系统需要现代浏览器支持,建议使用Chrome、Firefox、Safari或Edge的最新版本。</p>
<p><strong>Markdown语法</strong>:文章内容支持基本的Markdown语法,包括标题、列表、链接、代码块等。</p>
</div>
<h2>进一步开发</h2>
<p>这个简易Wiki系统可以进一步扩展以下功能:</p>
<ul>
<li>添加用户认证和权限管理</li>
<li>支持文章版本历史和回滚</li>
<li>添加图片上传和媒体管理</li>
<li>实现文章导出和备份功能</li>
<li>添加评论和讨论区</li>
</ul>
<blockquote>
<p>这个项目展示了如何使用纯前端技术构建功能完整的Web应用,适合学习前端开发和理解Web应用的基本原理。</p>
</blockquote>
</div>
`;
contentArea.innerHTML = html;
}
// 保存文章
function saveArticle(key) {
const title = document.getElementById('article-title').value;
const content = document.getElementById('article-content').value;
const category = document.getElementById('article-category').value;
const tags = document.getElementById('article-tags').value.split(',').map(tag => tag.trim());
wikiArticles[key].title = title;
wikiArticles[key].content = content;
wikiArticles[key].category = category;
wikiArticles[key].tags = tags;
wikiArticles[key].updated = new Date().toISOString().split('T')[0];
saveArticlesToStorage();
updateSidebar();
showArticle(key);
showAlert('文章已成功更新!', 'success');
}
// 创建文章
function createArticle() {
const key = document.getElementById('article-key').value;
const title = document.getElementById('article-title').value;
const content = document.getElementById('article-content').value;
const category = document.getElementById('article-category').value;
const tags = document.getElementById('article-tags').value.split(',').map(tag => tag.trim());
if (wikiArticles[key]) {
showAlert('文章标识已存在,请使用其他标识!', 'error');
return;
}
const today = new Date().toISOString().split('T')[0];
wikiArticles[key] = {
title: title,
content: content,
category: category,
tags: tags,
created: today,
updated: today,
views: 0
};
saveArticlesToStorage();
updateSidebar();
showArticle(key);
showAlert('文章已成功创建!', 'success');
}
// 删除文章
function deleteArticle(key) {
if (key === 'home') {
showAlert('不能删除首页文章!', 'error');
return;
}
delete wikiArticles[key];
saveArticlesToStorage();
updateSidebar();
showHome();
showAlert('文章已成功删除!', 'success');
}
// 处理搜索
function handleSearch() {
const query = document.getElementById('search-input').value.toLowerCase();
if (query.length < 2) {
showHome();
return;
}
const contentArea = document.getElementById('content-area');
let html = `
<div class="article-header">
<h1>搜索结果: "${query}"</h1>
<p class="article-meta">找到 ${Object.keys(wikiArticles).filter(key =>
wikiArticles[key].title.toLowerCase().includes(query) ||
wikiArticles[key].content.toLowerCase().includes(query) ||
wikiArticles[key].tags.some(tag => tag.toLowerCase().includes(query))
).length} 篇相关文章</p>
</div>
<div class="articles-grid">
`;
const results = Object.entries(wikiArticles).filter(([key, article]) => {
return article.title.toLowerCase().includes(query) ||
article.content.toLowerCase().includes(query) ||
article.tags.some(tag => tag.toLowerCase().includes(query));
});
if (results.length === 0) {
html += `<p>没有找到相关文章。</p>`;
} else {
results.forEach(([key, article]) => {
html += `
<div class="article-card" data-article="${key}">
<div class="article-card-content">
<h3>${article.title}</h3>
<p>${article.content.substring(0, 100)}...</p>
<div class="meta">
<span>分类: ${article.category}</span> |
<span>更新: ${formatDate(article.updated)}</span> |
<span>浏览: ${article.views}次</span>
</div>
</div>
</div>
`;
});
}
html += `</div>`;
contentArea.innerHTML = html;
// 添加文章卡片点击事件
document.querySelectorAll('.article-card').forEach(card => {
card.addEventListener('click', function() {
const articleKey = this.getAttribute('data-article');
showArticle(articleKey);
});
});
}
// 更新侧边栏
function updateSidebar() {
const categoryList = document.getElementById('category-list');
const popularArticles = document.getElementById('popular-articles');
// 更新分类列表
const categories = [...new Set(Object.values(wikiArticles).map(article => article.category))];
categoryList.innerHTML = '';
categories.forEach(category => {
const li = document.createElement('li');
li.innerHTML = `<a href="#" class="category-link" data-category="${category}">${category}</a>`;
categoryList.appendChild(li);
});
// 更新热门文章
const sortedByViews = Object.entries(wikiArticles)
.sort((a, b) => b[1].views - a[1].views)
.slice(0, 5);
popularArticles.innerHTML = '';
sortedByViews.forEach(([key, article]) => {
const li = document.createElement('li');
li.innerHTML = `<a href="#" class="article-link" data-article="${key}">${article.title}</a>`;
popularArticles.appendChild(li);
});
// 添加分类链接事件
document.querySelectorAll('.category-link').forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
const category = this.getAttribute('data-category');
filterByCategory(category);
});
});
// 添加文章链接事件
document.querySelectorAll('.article-link').forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
const articleKey = this.getAttribute('data-article');
showArticle(articleKey);
});
});
}
// 按分类筛选
function filterByCategory(category) {
const contentArea = document.getElementById('content-area');
let html = `
<div class="article-header">
<h1>分类: ${category}</h1>
<p class="article-meta">共 ${Object.values(wikiArticles).filter(article => article.category === category).length} 篇文章</p>
</div>
<div class="articles-grid">
`;
const categoryArticles = Object.entries(wikiArticles).filter(([key, article]) =>
article.category === category
);
categoryArticles.forEach(([key, article]) => {
html += `
<div class="article-card" data-article="${key}">
<div class="article-card-content">
<h3>${article.title}</h3>
<p>${article.content.substring(0, 100)}...</p>
<div class="meta">
<span>分类: ${article.category}</span> |
<span>更新: ${formatDate(article.updated)}</span> |
<span>浏览: ${article.views}次</span>
</div>
</div>
</div>
`;
});
html += `</div>`;
contentArea.innerHTML = html;
// 添加文章卡片点击事件
document.querySelectorAll('.article-card').forEach(card => {
card.addEventListener('click', function() {
const articleKey = this.getAttribute('data-article');
showArticle(articleKey);
});
});
}
// 显示错误
function showError(message) {
const contentArea = document.getElementById('content-area');
contentArea.innerHTML = `
<div class="alert alert-error">
<strong>错误:</strong> ${message}
</div>
<div class="article-actions">
<button class="btn btn-primary" onclick="showHome()">返回首页</button>
</div>
`;
}
// 显示提示
function showAlert(message, type) {
// 移除现有提示
const existingAlert = document.querySelector('.alert');
if (existingAlert) {
existingAlert.remove();
}
const alert = document.createElement('div');
alert.className = `alert alert-${type}`;
alert.textContent = message;
document.querySelector('.container').insertBefore(alert, document.querySelector('.search-container'));
// 3秒后自动移除
setTimeout(() => {
alert.remove();
}, 3000);
}
// 格式化日期
function formatDate(dateString) {
const date = new Date(dateString);
return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`;
}
// 简化的Markdown渲染
function renderMarkdown(text) {
// 处理标题
text = text.replace(/^# (.*$)/gm, '<h1>$1</h1>');
text = text.replace(/^## (.*$)/gm, '<h2>$1</h2>');
text = text.replace(/^### (.*$)/gm, '<h3>$1</h3>');
// 处理粗体
text = text.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
text = text.replace(/\*(.*?)\*/g, '<em>$1</em>');
// 处理代码块
text = text.replace(/```([\s\S]*?)```/g, '<pre><code>$1</code></pre>');
text = text.replace(/`(.*?)`/g, '<code>$1</code>');
// 处理链接
text = text.replace(/\[(.*?)\]\((.*?)\)/g, '<a href="$2" target="_blank">$1</a>');
// 处理列表
text = text.replace(/^\s*\- (.*$)/gm, '<li>$1</li>');
text = text.replace(/(<li>.*<\/li>)/s, '<ul>$1</ul>');
text = text.replace(/^\s*\d+\. (.*$)/gm, '<li>$1</li>');
text = text.replace(/(<li>.*<\/li>)/s, '<ol>$1</ol>');
// 处理段落
text = text.replace(/\n\n/g, '</p><p>');
text = '<p>' + text + '</p>';
// 处理表格
text = text.replace(/\|(.*)\|/g, function(match) {
if (match.includes('---')) {
return ''; // 跳过表头分隔线
}
return '<tr>' + match.split('|').slice(1, -1).map(cell =>
`<td>${cell.trim()}</td>`
).join('') + '</tr>';
});
text = text.replace(/(<tr>.*<\/tr>)/s, function(match) {
return '<table>' + match + '</table>';
});
// 处理引用
text = text.replace(/^> (.*$)/gm, '<blockquote>$1</blockquote>');
return text;
}
</script>
</body>
</html>
系统功能详解
这个简易Wiki系统实现了以下核心功能:
1. 文章管理
- 创建新文章
- 编辑现有文章
- 删除文章
- 查看文章详情
2. 内容展示
- 使用Markdown语法格式化内容
- 支持表格、代码块、链接等丰富格式
- 响应式设计,适配各种设备
3. 搜索和分类
- 全文搜索功能
- 按分类筛选文章
- 热门文章推荐
4. 数据持久化
- 使用localStorage存储数据
- 文章浏览计数
- 更新日期跟踪
技术实现要点
- 纯前端实现:无需后端支持,所有功能在浏览器中完成
- 响应式设计:使用CSS Grid和Flexbox实现自适应布局
- Markdown渲染:实现了简化的Markdown到HTML的转换
- 本地存储:使用localStorage API实现数据持久化
- 模块化设计:功能模块清晰分离,便于维护和扩展
扩展建议
这个简易Wiki系统还可以进一步扩展:
- 添加用户认证和权限管理
- 实现文章版本历史
- 添加图片上传功能
- 支持文章导出和备份
- 添加评论和讨论功能