Compare commits
32 Commits
12181dbdcd
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 82324f6274 | |||
| 3531360974 | |||
| da188afd82 | |||
|
|
8ad5c45a42 | ||
|
|
bca2e0619c | ||
|
|
5d510b0433 | ||
| 2f55fc7184 | |||
| 474f335e94 | |||
|
|
2b9e5f9bd1 | ||
|
|
43aa3f07e5 | ||
|
|
c3e8cad947 | ||
| b7c97d0f17 | |||
| 2391018d79 | |||
|
|
b28ed8ebfe | ||
| 799551073c | |||
|
|
3f8169ae56 | ||
|
|
8c7e8ea6e3 | ||
| 669f62549e | |||
| c95b09f329 | |||
|
|
868cc9b514 | ||
|
|
60b9923302 | ||
|
|
4db01489ee | ||
| c365afbd8a | |||
|
|
b860b75dc8 | ||
|
|
a037e09c17 | ||
|
|
faac3d94ff | ||
|
|
09ce0b7b78 | ||
|
|
95de5b4d3e | ||
|
|
7b04ffbedd | ||
|
|
c51e0977d7 | ||
|
|
7e1131844f | ||
|
|
566b6cd385 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@ docs/.vuepress/dist
|
|||||||
.trae/
|
.trae/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
*.log
|
*.log
|
||||||
|
_publish/
|
||||||
|
|||||||
133
build-and-publish.bat
Normal file
133
build-and-publish.bat
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal EnableExtensions
|
||||||
|
|
||||||
|
chcp 65001 >nul
|
||||||
|
|
||||||
|
REM Paths and settings
|
||||||
|
set "ROOT_DIR=%~dp0"
|
||||||
|
set "PROJECT_DIR=%ROOT_DIR%"
|
||||||
|
set "DIST_DIR=%PROJECT_DIR%docs\.vuepress\dist"
|
||||||
|
set "PUBLISH_DIR=%PROJECT_DIR%_publish"
|
||||||
|
set "REMOTE_URL=https://gitea.simengweb.com/si-meng-spec/build_notes_simengweb.git"
|
||||||
|
set "BRANCH=main"
|
||||||
|
|
||||||
|
REM Args
|
||||||
|
set "LIGHT_FLAG=%~1"
|
||||||
|
set "COMMIT_MSG=%~2"
|
||||||
|
|
||||||
|
echo [Info] Working dir: %PROJECT_DIR%
|
||||||
|
|
||||||
|
REM Pre-checks
|
||||||
|
where npm >nul 2>&1
|
||||||
|
if errorlevel 1 goto :npm_missing
|
||||||
|
where git >nul 2>&1
|
||||||
|
if errorlevel 1 goto :git_missing
|
||||||
|
|
||||||
|
REM Install deps on first run
|
||||||
|
if not exist "%PROJECT_DIR%node_modules" (
|
||||||
|
echo [Info] Installing deps ^(npm ci^)...
|
||||||
|
call npm ci
|
||||||
|
if errorlevel 1 goto :fail
|
||||||
|
) else (
|
||||||
|
echo [Info] node_modules exists, skip install.
|
||||||
|
)
|
||||||
|
|
||||||
|
REM Light build mode
|
||||||
|
if /I "%LIGHT_FLAG%"=="light" (
|
||||||
|
set "LIGHT_BUILD=1"
|
||||||
|
echo [Info] LIGHT_BUILD=1 enabled
|
||||||
|
)
|
||||||
|
|
||||||
|
set "NODE_OPTIONS=--max-old-space-size=4096"
|
||||||
|
|
||||||
|
echo [Info] Building docs...
|
||||||
|
call npm run docs:build
|
||||||
|
if errorlevel 1 goto :fail
|
||||||
|
|
||||||
|
if not exist "%DIST_DIR%" goto :no_dist
|
||||||
|
|
||||||
|
REM Prepare publish repo
|
||||||
|
if not exist "%PUBLISH_DIR%\.git" (
|
||||||
|
echo [Info] Cloning publish repo...
|
||||||
|
git clone "%REMOTE_URL%" "%PUBLISH_DIR%"
|
||||||
|
if errorlevel 1 goto :fail
|
||||||
|
) else (
|
||||||
|
echo [Info] Updating publish repo...
|
||||||
|
pushd "%PUBLISH_DIR%"
|
||||||
|
git fetch --all
|
||||||
|
if errorlevel 1 goto :gitfail
|
||||||
|
git checkout "%BRANCH%"
|
||||||
|
if errorlevel 1 goto :gitfail
|
||||||
|
git reset --hard "origin/%BRANCH%"
|
||||||
|
if errorlevel 1 goto :gitfail
|
||||||
|
popd
|
||||||
|
)
|
||||||
|
|
||||||
|
echo [Info] Cleaning publish directory ^(keep .git^)...
|
||||||
|
pushd "%PUBLISH_DIR%"
|
||||||
|
for /f "delims=" %%F in ('dir /a /b') do (
|
||||||
|
if /I not "%%F"==".git" (
|
||||||
|
if exist "%%F" (
|
||||||
|
attrib -R "%%F" >nul 2>&1
|
||||||
|
rd /s /q "%%F" 2>nul
|
||||||
|
del /f /q "%%F" 2>nul
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
popd
|
||||||
|
|
||||||
|
echo [Info] Copying dist to publish...
|
||||||
|
robocopy "%DIST_DIR%" "%PUBLISH_DIR%" *.* /E /NFL /NDL /NP /NJH /NJS >nul
|
||||||
|
if errorlevel 8 goto :fail
|
||||||
|
|
||||||
|
pushd "%PUBLISH_DIR%"
|
||||||
|
if defined GIT_USERNAME git config user.name "%GIT_USERNAME%"
|
||||||
|
if defined GIT_EMAIL git config user.email "%GIT_EMAIL%"
|
||||||
|
|
||||||
|
git add -A
|
||||||
|
|
||||||
|
if "%COMMIT_MSG%"=="" set "COMMIT_MSG=Build: %DATE% %TIME%"
|
||||||
|
|
||||||
|
set "HAS_CHANGES=1"
|
||||||
|
git diff --cached --quiet
|
||||||
|
if not errorlevel 1 set "HAS_CHANGES=0"
|
||||||
|
|
||||||
|
if "%HAS_CHANGES%"=="0" (
|
||||||
|
echo [Info] No changes to commit; skipping push.
|
||||||
|
) else (
|
||||||
|
git commit -m "%COMMIT_MSG%"
|
||||||
|
if errorlevel 1 (
|
||||||
|
popd
|
||||||
|
goto :fail
|
||||||
|
)
|
||||||
|
git push origin "%BRANCH%"
|
||||||
|
if errorlevel 1 (
|
||||||
|
popd
|
||||||
|
goto :fail
|
||||||
|
)
|
||||||
|
echo [Info] Pushed to %REMOTE_URL% ^(branch %BRANCH%^).
|
||||||
|
)
|
||||||
|
popd
|
||||||
|
|
||||||
|
echo [Success] Build and publish done.
|
||||||
|
exit /b 0
|
||||||
|
|
||||||
|
:npm_missing
|
||||||
|
echo [ERROR] npm not found. Please install Node.js.
|
||||||
|
goto :fail
|
||||||
|
|
||||||
|
:git_missing
|
||||||
|
echo [ERROR] git not found. Please install Git.
|
||||||
|
goto :fail
|
||||||
|
|
||||||
|
:no_dist
|
||||||
|
echo [ERROR] Dist directory not found: %DIST_DIR%
|
||||||
|
goto :fail
|
||||||
|
|
||||||
|
:gitfail
|
||||||
|
echo [ERROR] Git operation failed.
|
||||||
|
popd
|
||||||
|
goto :fail
|
||||||
|
|
||||||
|
:fail
|
||||||
|
exit /b 1
|
||||||
@@ -7,21 +7,30 @@ import { umamiAnalyticsPlugin } from '@vuepress/plugin-umami-analytics'
|
|||||||
export default defineUserConfig({
|
export default defineUserConfig({
|
||||||
base: '/',
|
base: '/',
|
||||||
lang: 'zh-CN',
|
lang: 'zh-CN',
|
||||||
title: '祀梦的花园',
|
title: '仲夏夜之梦',
|
||||||
description: '爱与回忆的小世界,记录生活中的每一份温暖与感动',
|
description: '爱与回忆的小世界,记录生活中的每一份温暖与感动',
|
||||||
|
|
||||||
head: [
|
head: [
|
||||||
// 配置站点图标
|
|
||||||
['link', { rel: 'icon', type: 'image/png', href: 'https://theme-plume.vuejs.press/favicon-32x32.png' }],
|
['link', { rel: 'icon', type: 'image/png', href: 'https://theme-plume.vuejs.press/favicon-32x32.png' }],
|
||||||
],
|
],
|
||||||
|
|
||||||
bundler: viteBundler(),
|
bundler: viteBundler(),
|
||||||
shouldPrefetch: false, // 站点较大,页面数量较多时,不建议启用
|
shouldPrefetch: false,
|
||||||
|
|
||||||
theme: plumeTheme({
|
theme: plumeTheme({
|
||||||
|
/* 站点域名,启动 SEO 优化 */
|
||||||
|
hostname: 'https://notes.simengweb.com',
|
||||||
/* 博客文章页面链接前缀 */
|
/* 博客文章页面链接前缀 */
|
||||||
article: '/article/',
|
article: '/article/',
|
||||||
|
|
||||||
|
/* 启用数学公式支持和Mermaid图表 */
|
||||||
|
markdown: {
|
||||||
|
math: {
|
||||||
|
type: 'katex',
|
||||||
|
},
|
||||||
|
mermaid: true,
|
||||||
|
demo: true,
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* 编译缓存,加快编译速度
|
* 编译缓存,加快编译速度
|
||||||
*/
|
*/
|
||||||
@@ -44,7 +53,6 @@ export default defineUserConfig({
|
|||||||
/**
|
/**
|
||||||
* 文章贡献者配置
|
* 文章贡献者配置
|
||||||
*/
|
*/
|
||||||
// 修改contributors配置
|
|
||||||
contributors: {
|
contributors: {
|
||||||
mode: 'inline',
|
mode: 'inline',
|
||||||
info: [
|
info: [
|
||||||
@@ -64,9 +72,6 @@ export default defineUserConfig({
|
|||||||
git: true
|
git: true
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* 代码块配置
|
|
||||||
*/
|
|
||||||
codeHighlighter: {
|
codeHighlighter: {
|
||||||
lineNumbers: true,
|
lineNumbers: true,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,8 +33,21 @@ export default defineNavbarConfig([
|
|||||||
text: 'Solidity',
|
text: 'Solidity',
|
||||||
link: '/programming/solidity/',
|
link: '/programming/solidity/',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text: 'Web 开发',
|
||||||
|
link: '/programming/web/',
|
||||||
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
text:"技术理论",
|
||||||
|
items:[
|
||||||
|
{
|
||||||
|
text: '密码学基础',
|
||||||
|
link: '/theory/cryptography/',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
text: '运维',
|
text: '运维',
|
||||||
items: [
|
items: [
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ const english = defineNoteConfig({
|
|||||||
{ text: "阅读提升", link: "/subject/english/reading-writing/" }
|
{ text: "阅读提升", link: "/subject/english/reading-writing/" }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: "写译", prefix: "/writing-translation", items: [
|
text: "写译", prefix: "/writing-translation", items: [
|
||||||
{ text: "写作与翻译指南", link: "/subject/english/writing-translation/" }
|
{ text: "写作与翻译指南", link: "/subject/english/writing-translation/" }
|
||||||
]
|
]
|
||||||
@@ -97,6 +97,19 @@ const solidity = defineNoteConfig({
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
const cryptography = defineNoteConfig({
|
||||||
|
dir: 'theory',
|
||||||
|
link: '/theory/cryptography/',
|
||||||
|
sidebar: [
|
||||||
|
{ text: "密码学基础", link: "/theory/cryptography/" },
|
||||||
|
{
|
||||||
|
text: "古典加密算法", prefix: "/theory", items: [
|
||||||
|
{ text: "替换密码", link: "/theory/cryptography/substitution-ciphers/" },
|
||||||
|
{ text: "置换密码", link: "/theory/cryptography/permutation-encryption/" },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
const blockchain = defineNoteConfig({
|
const blockchain = defineNoteConfig({
|
||||||
dir: 'ops',
|
dir: 'ops',
|
||||||
link: '/ops/blockchain',
|
link: '/ops/blockchain',
|
||||||
@@ -129,11 +142,26 @@ const linux = defineNoteConfig({
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
const web = defineNoteConfig({
|
||||||
|
dir: 'programming',
|
||||||
|
link: '/programming/web/',
|
||||||
|
sidebar: [
|
||||||
|
{ text: "Web 开发学习笔记", link: "/programming/web/" },
|
||||||
|
{
|
||||||
|
text: "基础知识", prefix: "/basic-syntax", items: [
|
||||||
|
{ text: "Web 前端基础讲解", link: "/programming/web/basic-syntax/html-css-js/" },
|
||||||
|
{ text: "HTML 常用标签与属性", link: "/programming/web/basic-syntax/html-tags-attributes/" },
|
||||||
|
{ text: "HTML 列表与语义布局", link: "/programming/web/basic-syntax/html-lists-and-semantic-layout/" },
|
||||||
|
{ text: "JavaScript 基础知识", link: "/programming/web/basic-syntax/javascript-basics/" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
/**
|
/**
|
||||||
* 导出所有的 note
|
* 导出所有的 note
|
||||||
*/
|
*/
|
||||||
export default defineNotesConfig({
|
export default defineNotesConfig({
|
||||||
dir: 'notes',
|
dir: 'notes',
|
||||||
link: '/',
|
link: '/',
|
||||||
notes: [LeetCode, english, cPlusPlus, solidity, blockchain, linux],
|
notes: [LeetCode, english, cPlusPlus, solidity, blockchain, linux, cryptography, web],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ config:
|
|||||||
full: true
|
full: true
|
||||||
background: tint-plate
|
background: tint-plate
|
||||||
hero:
|
hero:
|
||||||
name: 祀梦和小小夏的花园
|
name: 仲夏夜之梦
|
||||||
tagline: 记录点滴,收藏时光
|
tagline: 祀梦和小小夏的花园
|
||||||
text: 在这里,每一个文字都承载着温暖与美好 🌸
|
text: 在这里,每一个文字都承载着温暖与美好 🌸
|
||||||
actions:
|
actions:
|
||||||
-
|
-
|
||||||
|
|||||||
249
docs/blog/collect/free_model_pai.md
Normal file
249
docs/blog/collect/free_model_pai.md
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
---
|
||||||
|
title: 便宜免费的大模型 API 整合 ( 2025年11月11日 )
|
||||||
|
createTime: 2025/11/11 13:54:02
|
||||||
|
permalink: /article/free_model_api/
|
||||||
|
---
|
||||||
|
|
||||||
|
## 免费的大模型 API 整合
|
||||||
|
|
||||||
|
嗨~如果你在找既温柔又省荷包的小模型,就把它们悄悄收进这里吧!它们也许不是夜空最亮的那颗星,却能在摘要、划重点、轻声问答的小角落里,给你软软又稳稳的陪伴哦~
|
||||||
|
|
||||||
|
|
||||||
|
### 百度千帆大模型平台
|
||||||
|
|
||||||
|
先从千帆开始吧~下面是常用模型的参考价格:
|
||||||
|
|
||||||
|
| 模型名称 | 版本名称 | 服务内容 | 子项 | 在线推理 | 批量推理 | 单位 |
|
||||||
|
|---|---|---|---|---|---|---|
|
||||||
|
| ERNIE Speed | ernie-speed-128k | 推理服务 | 输入 | 0 | 0.00012 | 元/千tokens |
|
||||||
|
| ERNIE Speed | ernie-speed-128k | 推理服务 | 输出 | 0 | 0.00024 | 元/千tokens |
|
||||||
|
| ERNIE Lite | ernie-lite-8k | 推理服务 | 输入 | 0 | 0.0012 | 元/千tokens |
|
||||||
|
| ERNIE Lite | ernie-lite-8k | 推理服务 | 输出 | 0 | 0.0024 | 元/千tokens |
|
||||||
|
| ERNIE Tiny | ernie-tiny-8k | 推理服务 | 输入 | 0 | 0.00008 | 元/千tokens |
|
||||||
|
| ERNIE Tiny | ernie-tiny-8k | 推理服务 | 输出 | 0 | 0.00016 | 元/千tokens |
|
||||||
|
|
||||||
|
> 提示:单纯调用 API 接口属于在线推理,当前显示为 0 元;批量推理按量计费。
|
||||||
|
|
||||||
|
#### 快速上手
|
||||||
|
|
||||||
|
1. 访问控制台并获取 API Key。
|
||||||
|
2. 使用下方示例进行快速测试。
|
||||||
|
3. 若遇错误,请检查模型名称与凭证有效期。
|
||||||
|
|
||||||
|
控制台:[https://console.bce.baidu.com/qianfan/ais/console/apiKey](https://console.bce.baidu.com/qianfan/ais/console/apiKey)
|
||||||
|
|
||||||
|
```python
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
|
||||||
|
def main():
|
||||||
|
url = "https://qianfan.baidubce.com/v2/chat/completions"
|
||||||
|
API_KEY = 'YOUR_API_KEY'
|
||||||
|
payload = json.dumps({
|
||||||
|
"model": "ernie-speed-128k",
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"content": "You are a helpful assistant."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "你好"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
headers = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': F'Bearer {API_KEY}'
|
||||||
|
}
|
||||||
|
response = requests.request("POST", url, headers=headers, data=payload)
|
||||||
|
print(response.text)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
```
|
||||||
|
|
||||||
|
> 小贴士:将 `YOUR_API_KEY` 替换为你的密钥,建议使用环境变量管理凭证;请勿在公共仓库提交 Key。
|
||||||
|
|
||||||
|
更多文档:[https://cloud.baidu.com/doc/qianfan-api/s/3m9b5lqft](https://cloud.baidu.com/doc/qianfan-api/s/3m9b5lqft)
|
||||||
|
|
||||||
|
### 讯飞星火大模型
|
||||||
|
|
||||||
|
接着,我们轻盈地来到星火~
|
||||||
|
|
||||||
|
- 官网:[https://xinghuo.xfyun.cn/sparkapi](https://xinghuo.xfyun.cn/sparkapi)
|
||||||
|
- 控制台:[https://console.xfyun.cn/services/cbm?from=desk](https://console.xfyun.cn/services/cbm?from=desk)
|
||||||
|
- 模型说明:可见 Spark Lite,Token 余量为无限。
|
||||||
|
|
||||||
|
#### 快速上手
|
||||||
|
|
||||||
|
> 小贴士:如需联网检索,启用 `web_search`;流式输出可以提升交互体验。
|
||||||
|
|
||||||
|
1. 在控制台获取授权凭证并替换到示例中。
|
||||||
|
2. 选择 `Lite` 模型,按需开启 `web_search` 与 `stream`。
|
||||||
|
3. 若需要长内容输出,注意 8K tokens 限制,合理裁剪上下文。
|
||||||
|
|
||||||
|
```python
|
||||||
|
# encoding:UTF-8
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
# 请替换XXXXXXXXXX为您的 APIpassword, 获取地址:https://console.xfyun.cn/services/bmx1
|
||||||
|
api_key = "Bearer XXXXXXXXXX"
|
||||||
|
url = "https://spark-api-open.xf-yun.com/v1/chat/completions"
|
||||||
|
|
||||||
|
# 请求模型,并将结果输出
|
||||||
|
def get_answer(message):
|
||||||
|
#初始化请求体
|
||||||
|
headers = {
|
||||||
|
'Authorization':api_key,
|
||||||
|
'content-type': "application/json"
|
||||||
|
}
|
||||||
|
body = {
|
||||||
|
"model": "Lite",
|
||||||
|
"user": "user_id",
|
||||||
|
"messages": message,
|
||||||
|
# 下面是可选参数
|
||||||
|
"stream": True,
|
||||||
|
"tools": [
|
||||||
|
{
|
||||||
|
"type": "web_search",
|
||||||
|
"web_search": {
|
||||||
|
"enable": True,
|
||||||
|
"search_mode":"deep"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
full_response = "" # 存储返回结果
|
||||||
|
isFirstContent = True # 首帧标识
|
||||||
|
|
||||||
|
response = requests.post(url=url,json= body,headers= headers,stream= True)
|
||||||
|
# print(response)
|
||||||
|
for chunks in response.iter_lines():
|
||||||
|
# 打印返回的每帧内容
|
||||||
|
# print(chunks)
|
||||||
|
if (chunks and '[DONE]' not in str(chunks)):
|
||||||
|
data_org = chunks[6:]
|
||||||
|
|
||||||
|
# print(f"DEBUG: raw data_org: {data_org}")
|
||||||
|
chunk = json.loads(data_org)
|
||||||
|
text = chunk['choices'][0]['delta']
|
||||||
|
|
||||||
|
# 判断最终结果状态并输出
|
||||||
|
if ('content' in text and '' != text['content']):
|
||||||
|
content = text["content"]
|
||||||
|
if (True == isFirstContent):
|
||||||
|
isFirstContent = False
|
||||||
|
print(content, end="")
|
||||||
|
full_response += content
|
||||||
|
return full_response
|
||||||
|
|
||||||
|
|
||||||
|
# 管理对话历史,按序编为列表
|
||||||
|
def getText(text,role, content):
|
||||||
|
jsoncon = {}
|
||||||
|
jsoncon["role"] = role
|
||||||
|
jsoncon["content"] = content
|
||||||
|
text.append(jsoncon)
|
||||||
|
return text
|
||||||
|
|
||||||
|
# 获取对话中的所有角色的content长度
|
||||||
|
def getlength(text):
|
||||||
|
length = 0
|
||||||
|
for content in text:
|
||||||
|
temp = content["content"]
|
||||||
|
leng = len(temp)
|
||||||
|
length += leng
|
||||||
|
return length
|
||||||
|
|
||||||
|
# 判断长度是否超长,当前限制8K tokens
|
||||||
|
def checklen(text):
|
||||||
|
while (getlength(text) > 11000):
|
||||||
|
del text[0]
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
#主程序入口
|
||||||
|
if __name__ =='__main__':
|
||||||
|
|
||||||
|
#对话历史存储列表
|
||||||
|
chatHistory = []
|
||||||
|
#循环对话轮次
|
||||||
|
while (1):
|
||||||
|
# 等待控制台输入
|
||||||
|
Input = input("\n" + "我:")
|
||||||
|
question = checklen(getText(chatHistory,"user", Input))
|
||||||
|
# 开始输出模型内容
|
||||||
|
print("星火:", end="")
|
||||||
|
getText(chatHistory,"assistant", get_answer(question))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 腾讯混元大模型
|
||||||
|
|
||||||
|
- 计费与价格:[https://cloud.tencent.com/document/product/1729/97731](https://cloud.tencent.com/document/product/1729/97731)
|
||||||
|
- 文档与控制台:[https://cloud.tencent.com/document/product/1729/111008](https://cloud.tencent.com/document/product/1729/111008)
|
||||||
|
- 模型说明:`hunyuan-lite` 免费可用,适合轻量任务。
|
||||||
|
|
||||||
|
```python
|
||||||
|
import os
|
||||||
|
from openai import OpenAI
|
||||||
|
|
||||||
|
# 构造 client(建议使用环境变量管理密钥)
|
||||||
|
api_key = os.getenv("HUNYUAN_API_KEY", "YOUR_API_KEY")
|
||||||
|
client = OpenAI(
|
||||||
|
api_key=api_key, # 混元 APIKey
|
||||||
|
base_url="https://api.hunyuan.cloud.tencent.com/v1", # 混元 endpoint
|
||||||
|
)
|
||||||
|
|
||||||
|
completion = client.chat.completions.create(
|
||||||
|
model="hunyuan-lite",
|
||||||
|
messages=[
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": "泥嚎"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
extra_body={
|
||||||
|
"enable_enhancement": True,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
print(completion.choices[0].message.content)
|
||||||
|
```
|
||||||
|
|
||||||
|
> 小贴士:请勿在公共仓库提交任何真实密钥;使用环境变量或密钥管理服务更安全。
|
||||||
|
|
||||||
|
## 低价大模型
|
||||||
|
|
||||||
|
### SCNet 平台
|
||||||
|
|
||||||
|
#### 简介
|
||||||
|
SCNet 是一个面向人工智能和科学计算的一站式算力与 AI 平台,提供从数据管理、模型训练到部署的完整链路服务,同时结合国产超算硬件和多模态模型生态,让企业和开发者能更高效地使用 AI。
|
||||||
|
|
||||||
|
#### 链接与文档
|
||||||
|
- 官网:[https://www.scnet.cn/](https://www.scnet.cn/)
|
||||||
|
#### 价格一览
|
||||||
|
| 模型 | 上下文长度 | 百万 tokens 输入价格 | 百万 tokens 输出价格 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Qwen3-235B-A22B | 32K | 0.1 元 | 0.1 元 |
|
||||||
|
| DeepSeek-R1-Distill-Qwen-7B | 32K | 0.1 元 | 0.1 元 |
|
||||||
|
| DeepSeek-R1-Distill-Qwen-32B | 32K | 1 元 | 4 元 |
|
||||||
|
| DeepSeek-R1-Distill-Llama-70B | 32K | 0.1 元 | 6 元 |
|
||||||
|
| QwQ-32B | 32K | 1 元 | 4 元 |
|
||||||
|
| Qwen3-30B-A3B | 128K | 1 元 | 6 元 |
|
||||||
|
| Qwen3-Embedding-8B | - | 0.1 元 | - |
|
||||||
|
|
||||||
|
- 文档(计费与说明):[https://www.scnet.cn/ac/openapi/doc/2.0/moduleapi/tutorial/modulefee.html](https://www.scnet.cn/ac/openapi/doc/2.0/moduleapi/tutorial/modulefee.html)
|
||||||
|
|
||||||
|
目前看到的价格最低的 Qwen3-235B-A22B 模型的 API,相比前面的免费模型,性能更强。
|
||||||
|
- API 接口使用样例:[https://www.scnet.cn/ac/openapi/doc/2.0/moduleapi/tutorial/apicall.html](https://www.scnet.cn/ac/openapi/doc/2.0/moduleapi/tutorial/apicall.html)
|
||||||
|
|
||||||
|
## 小结
|
||||||
|
|
||||||
|
把上面这些“零钱包”级别的模型都翻完啦~
|
||||||
|
- 百度千帆、讯飞星火、腾讯混元都给出「免费在线额度」,日常轻量问答、摘要、润色完全够用;记得把 Key 藏进环境变量,别手滑推到 GitHub。
|
||||||
|
- 如果任务量突然暴涨,SCNet 的 Qwen3-235B-A22B 只要 0.1 元/百万 tokens,性价比直接拉满,当“备胎”也安心。
|
||||||
|
|
||||||
|
一句话:先薅免费的,薅不动再掏 0.1 元,让荷包和模型一起“稳稳幸福”吧!
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
title: 2025 一带一路金砖 - 区块链应用开发与运维 样题详解
|
title: 2025 一带一路金砖 - 区块链应用开发与运维 样题详解
|
||||||
createTime: 2025/09/30 19:57:14
|
createTime: 2025/09/30 19:57:14
|
||||||
permalink: /article/2025-BR-BRICS-BC-App-Develop-Op-Sample-Q&A/
|
permalink: /article/2025-BR-BRICS-BC-App-Develop-Op-Sample-Q&A/
|
||||||
# password: simeng
|
password: simeng
|
||||||
---
|
---
|
||||||
|
|
||||||
## 第一部分:区块链平台运维
|
## 第一部分:区块链平台运维
|
||||||
|
|||||||
75
docs/blog/technology/Xinchuang_Competition.md
Normal file
75
docs/blog/technology/Xinchuang_Competition.md
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
---
|
||||||
|
title: Linux 系统适配环境搭建
|
||||||
|
createTime: 2025/10/29 15:39:35
|
||||||
|
permalink: /article/xinchuang-competition-2025/
|
||||||
|
password: simeng
|
||||||
|
---
|
||||||
|
|
||||||
|
## 赛题要求
|
||||||
|
- yum 仓库地址:http://192.168.122.1:58000/content
|
||||||
|
- 软件包下载地址:http://192.168.122.1:58000/software
|
||||||
|
|
||||||
|
系统信息列表
|
||||||
|
|
||||||
|
| 序号 | 标签名称 | 操作系统 | 账号信息 |
|
||||||
|
|----|---------|----------|----------|
|
||||||
|
| 1 | Server1 | openEuler 22.03(已安装) | root / openEuler12#$ |
|
||||||
|
| 2 | Server2 | openEuler 22.03(已安装) | root / openEuler12#$ |
|
||||||
|
| 3 | Server3 | openEuler 22.03(待安装) | N/A |
|
||||||
|
| 4 | Desktop | Kylin v10(已安装) | admin / admin@0000 |
|
||||||
|
|
||||||
|
## 第一部分 【适配环境搭建】
|
||||||
|
|
||||||
|
### 基础配置 yum 源
|
||||||
|
这里题目中没有提到,但是需要进行一下配置
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 系统安装与配置
|
||||||
|
为 Server3 安装 openEuler 操作系统
|
||||||
|
|
||||||
|
配置系统语言:English
|
||||||
|
|
||||||
|
配置系统时区:Asia/Shanghai
|
||||||
|
|
||||||
|
配置安装类型:Server
|
||||||
|
|
||||||
|
系统启动分区保持不变,其他分区要求如下:
|
||||||
|
|
||||||
|
位置 容量 文件系统
|
||||||
|
|
||||||
|
| 挂载点 | 容量 | 文件系统 |
|
||||||
|
|--------|------|----------|
|
||||||
|
| / | 剩余所有容量 | ext4 |
|
||||||
|
| swap | 4G | swap |
|
||||||
|
| /opt | 40G | xfs |
|
||||||
|
|
||||||
|
其他未提及的配置内容保持系统默认设置。
|
||||||
|
|
||||||
|
确认并且配置服务器地址及名称:
|
||||||
|
|
||||||
|
| 服务器 | FQDN | IP |
|
||||||
|
|---------|-----------------------|------------------|
|
||||||
|
| Server1 | app1.system.org.cn | 172.16.50.101/24 |
|
||||||
|
| Server2 | app2.system.org.cn | 172.16.50.102/24 |
|
||||||
|
| Server3 | sts.system.org.cn | 172.16.50.103/24 |
|
||||||
|
| Desktop | - | 172.16.50.111/24 |
|
||||||
|
|
||||||
|
```bash title='配置服务器地址以及名称'
|
||||||
|
hostnamectl
|
||||||
|
```
|
||||||
|
|
||||||
|
确认并且配置系统网关为 172.16.50.1,确保服务器能与网关通信。
|
||||||
|
|
||||||
|
为所有 Server 主机启用防火墙,防火墙区域为 public ,根据不同服务在防火墙中使用添加端口的方式添加策略。
|
||||||
|
|
||||||
|
确认并且保持 root 用户密码为:admin@0000,确保该账户能够通过 SSH 远程登录
|
||||||
|
|
||||||
|
为所有 Server 主机生成 2 组(RSA 算法和国密算法)SSH 公私钥对,其中 RSA 密钥长度为 4096。配置实现 Server 主机之间的 SSH 免密登录。
|
||||||
|
|
||||||
|
所有主机间的访问均通过 FQDN 的形式进行访问。
|
||||||
|
|
||||||
|
使用 chrony 进行时间同步。Server1 与 172.16.50.1 进行时间同步,同时为其他服务器提供时间服务。
|
||||||
|
## 第一部分
|
||||||
|
## 第一部分
|
||||||
|
## 第一部分
|
||||||
@@ -22,4 +22,9 @@ list:
|
|||||||
link: https://www.ajohn.top/
|
link: https://www.ajohn.top/
|
||||||
avatar: https://github.com/zzyAJohn.png
|
avatar: https://github.com/zzyAJohn.png
|
||||||
desc: 我希望正在读这句话的人永远开心
|
desc: 我希望正在读这句话的人永远开心
|
||||||
|
-
|
||||||
|
name: 小小夏
|
||||||
|
link: https://notes.simengweb.com
|
||||||
|
avatar: https://image.simengweb.com/images/xxx.jpg
|
||||||
|
desc: Kawasaki天下第一!
|
||||||
---
|
---
|
||||||
|
|||||||
90
docs/notes/programming/web/README.md
Normal file
90
docs/notes/programming/web/README.md
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
---
|
||||||
|
title: Web 概览与学习路径
|
||||||
|
permalink: /programming/web/
|
||||||
|
createTime: 2025/10/28 22:20:00
|
||||||
|
---
|
||||||
|
|
||||||
|
# Web 是什么?
|
||||||
|
|
||||||
|
Web(万维网)是一个基于浏览器与服务器的“信息与应用平台”。用户通过浏览器访问网站,浏览器通过 **HTTP/HTTPS** 与服务器交互,服务器返回页面或数据,最终在浏览器中呈现并产生交互。
|
||||||
|
|
||||||
|
- 浏览器:渲染页面(HTML/CSS/JS)、执行脚本、发起网络请求。
|
||||||
|
- 服务器:处理业务逻辑、读写数据库、对外提供 API。
|
||||||
|
- 数据库:持久化存储(MySQL/PostgreSQL/MongoDB 等)。
|
||||||
|
|
||||||
|
简而言之:浏览器负责“看与用”,服务器负责“算与存”。
|
||||||
|
|
||||||
|
## 前端基础概念
|
||||||
|
|
||||||
|
- HTML:结构与语义(页面“骨架”)。
|
||||||
|
- CSS:表现与布局(页面“外观”)。
|
||||||
|
- JavaScript:交互与逻辑(页面“大脑”)。
|
||||||
|
- 现代前端:模块化、构建工具、组件化框架(Vue/React/Svelte 等)。
|
||||||
|
|
||||||
|
入门建议:先掌握原生 HTML/CSS/JS,再学习框架。你可以从本站文章开始:
|
||||||
|
- 基础教程 → `/programming/web/basic-syntax/html-css-js/`
|
||||||
|
|
||||||
|
## 后端基础概念
|
||||||
|
|
||||||
|
- 服务器与框架:Node.js(Express/NestJS)、Python(Flask/Django/FastAPI)、Java(Spring Boot)、Go(Gin/Fiber)。
|
||||||
|
- API 风格:REST(常见)、GraphQL(灵活查询)。
|
||||||
|
- 数据库与 ORM:MySQL/PostgreSQL(关系型)、MongoDB(文档型);ORM 如 Prisma/TypeORM/SQLAlchemy。
|
||||||
|
- 常见能力:认证授权(Session/JWT/OAuth)、文件上传、任务队列、缓存、日志与监控。
|
||||||
|
|
||||||
|
## 前后端如何协作
|
||||||
|
|
||||||
|
- 约定接口:路径、方法(GET/POST/PUT/DELETE)、参数与返回 JSON。
|
||||||
|
- 跨域与安全:CORS、CSRF/XSS/SQL 注入防护、HTTPS。
|
||||||
|
- 开发流程:
|
||||||
|
1) 需求与原型 → 2) API 设计 → 3) 前端页面与交互 → 4) 后端实现与测试 → 5) 联调与验收 → 6) 部署与监控。
|
||||||
|
|
||||||
|
## 学习路径(从 0 到 1)
|
||||||
|
|
||||||
|
1. 基础三件套:HTML + CSS + JavaScript(建议用 VSCode + Live Server)。
|
||||||
|
2. 工具与方法:Git/GitHub、浏览器开发者工具、HTTP/REST、请求调试(Postman/Insomnia)。
|
||||||
|
3. 进阶前端:布局(Flex/Grid)、响应式、ES6+、模块化、打包与构建(Vite/Webpack)。
|
||||||
|
4. 后端入门:选择一种语言与框架(如 Node.js + Express),完成 CRUD 与认证。
|
||||||
|
5. 数据库:会建表、会写基本查询;理解事务与索引。
|
||||||
|
6. 部署与上线:Nginx 反向代理、Docker、环境变量、日志与监控。
|
||||||
|
|
||||||
|
建议开发一个“待办清单 + 登录 + 数据持久化”的完整小项目,贯穿前后端与部署。
|
||||||
|
|
||||||
|
## 推荐学习资源
|
||||||
|
|
||||||
|
通用与入门:
|
||||||
|
- [MDN Web Docs(HTML/CSS/JS 全面权威)](https://developer.mozilla.org/)
|
||||||
|
- [freeCodeCamp(系统课程与练习)](https://www.freecodecamp.org/)
|
||||||
|
- [Roadmap.sh(前端/后端学习路径图)](https://roadmap.sh/)
|
||||||
|
|
||||||
|
前端:
|
||||||
|
- [HTML/CSS 基础(MDN)](https://developer.mozilla.org/en-US/docs/Learn)
|
||||||
|
- [CSS-Tricks(样式与布局技巧)](https://css-tricks.com/)
|
||||||
|
- [JavaScript 基础与进阶(MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
|
||||||
|
- [Vue 官方文档](https://vuejs.org/)
|
||||||
|
|
||||||
|
后端:
|
||||||
|
- [Node.js 文档](https://nodejs.org/en/docs)
|
||||||
|
- [Express](https://expressjs.com/)
|
||||||
|
- [NestJS](https://docs.nestjs.com/)
|
||||||
|
- [Spring Boot](https://spring.io/projects/spring-boot)
|
||||||
|
- [Django](https://docs.djangoproject.com/)
|
||||||
|
- [Flask](https://flask.palletsprojects.com/)
|
||||||
|
- [FastAPI](https://fastapi.tiangolo.com/)
|
||||||
|
|
||||||
|
数据库与 ORM:
|
||||||
|
- [MySQL](https://dev.mysql.com/doc/)
|
||||||
|
- [PostgreSQL](https://www.postgresql.org/docs/)
|
||||||
|
- [MongoDB](https://www.mongodb.com/docs/)
|
||||||
|
- [Prisma(Node.js ORM)](https://www.prisma.io/docs)
|
||||||
|
- [TypeORM](https://typeorm.io/)
|
||||||
|
|
||||||
|
工具:
|
||||||
|
- [VSCode](https://code.visualstudio.com/)
|
||||||
|
- [Postman](https://www.postman.com/)
|
||||||
|
- [Insomnia](https://insomnia.rest/)
|
||||||
|
- [Docker](https://docs.docker.com/)
|
||||||
|
|
||||||
|
## 本站相关内容
|
||||||
|
|
||||||
|
- Web 前端基础讲解 → `/programming/web/basic-syntax/html-css-js/`
|
||||||
|
- 后续将补充:前端工程化、接口联调、部署与运维实战等专题。
|
||||||
535
docs/notes/programming/web/basic-syntax/html-css-js.md
Normal file
535
docs/notes/programming/web/basic-syntax/html-css-js.md
Normal file
@@ -0,0 +1,535 @@
|
|||||||
|
---
|
||||||
|
title: Web 前端基础讲解
|
||||||
|
createTime: 2025/10/28 21:23:48
|
||||||
|
permalink: /programming/web/basic-syntax/html-css-js/
|
||||||
|
---
|
||||||
|
|
||||||
|
## 前端开发到底是什么?
|
||||||
|
|
||||||
|
前端开发,简单来说,就是**你能在网页上看到和互动的一切**。
|
||||||
|
|
||||||
|
想象一下你正在看一个网站:
|
||||||
|
|
||||||
|
* **文字、图片、按钮、菜单**:这些都是前端开发人员用代码“画”出来的。
|
||||||
|
* **点击按钮会发生什么、输入框能打字、图片能放大缩小**:这些互动效果也是前端开发人员用代码实现的。
|
||||||
|
|
||||||
|
所以,前端开发就是负责把设计师画好的网站样子,用代码变成用户可以在浏览器里真实看到、摸到、用的东西。它主要涉及三种技术:
|
||||||
|
|
||||||
|
1. **HTML**:就像网页的“骨架”,决定了网页上有什么内容(标题、段落、图片等)。
|
||||||
|
2. **CSS**:就像网页的“衣服”,决定了网页看起来怎么样(颜色、字体、布局等)。
|
||||||
|
3. **JavaScript**:就像网页的“大脑”,决定了网页能做什么(动画、交互、数据处理等)。
|
||||||
|
|
||||||
|
总而言之,前端开发就是让网站变得好看、好用、能互动。
|
||||||
|
|
||||||
|
## 开发工具
|
||||||
|
|
||||||
|
进行前端开发,我们需要一个好用的“工具箱”。其中,**Visual Studio Code (VS Code)** 是一个非常受欢迎且功能强大的选择。
|
||||||
|
|
||||||
|
VsCode 官网:[https://code.visualstudio.com/](https://code.visualstudio.com/)
|
||||||
|
|
||||||
|
**为什么推荐 VS Code?**
|
||||||
|
|
||||||
|
* **免费且开源**:你可以免费使用它,并且它的代码是公开的,有很多人一起维护和改进。
|
||||||
|
* **轻量级但功能强大**:它启动速度快,占用资源少,但通过安装各种“插件”,可以实现非常多的功能,比如代码高亮、智能提示、调试、版本控制等等。
|
||||||
|
* **支持多种语言**:不仅对 HTML、CSS、JavaScript 有很好的支持,也支持其他很多编程语言。
|
||||||
|
* **丰富的生态系统**:有大量的插件可以帮助你提高开发效率,比如 Live Server(实时预览网页)、Prettier(代码格式化)等。
|
||||||
|
* **跨平台**:无论你使用 Windows、macOS 还是 Linux,都可以安装和使用 VS Code。
|
||||||
|
|
||||||
|
### VsCode 前端开发插件推荐
|
||||||
|
- **Chinese (Simplified) Language Pack for Visual Studio Code**:中文语言包,方便中文用户使用。
|
||||||
|
- **Live Server**:实时预览网页,修改代码后自动刷新。
|
||||||
|
- **Prettier**:代码格式化,保持代码风格统一。
|
||||||
|
- **HTML CSS Support**:HTML 和 CSS 代码智能提示。
|
||||||
|
|
||||||
|
参考文章:
|
||||||
|
1. [VSCode安装配置使用教程(最新版超详细保姆级含插件)一文就够了](https://blog.csdn.net/2303_82176667/article/details/137193809)
|
||||||
|
2. [快速上手web前端开发(超详细教程)](https://blog.csdn.net/2303_82176667/article/details/137193809)
|
||||||
|
|
||||||
|
## HTML5 基础知识讲解
|
||||||
|
|
||||||
|
HTML 是一种用来描述网页的语言,用于描述网页的结构和内容。
|
||||||
|
|
||||||
|
HTML 并不是一种编程语言,而是一种标记语言。它使用标签来描述网页上的不同元素,比如标题、段落、图片、链接等。
|
||||||
|
|
||||||
|
标签指的是由尖括号 `<` 和 `>` 包围的关键词,通常成对出现,用来表示元素的开始和结束。
|
||||||
|
|
||||||
|
一个简单的 HTML 实例,用于初步的了解效果:
|
||||||
|
```html title='index.html'
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>仲夏夜之梦(notes.simengweb.com)</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>我的第一个标题</h1>
|
||||||
|
<p>我的第一个段落。</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
小提示:可以将代码复制到 VsCode 中,然后使用 Live Server 插件就可以实时预览效果啦。
|
||||||
|
|
||||||
|
### HTML5 文档分析
|
||||||
|
我们以前面的样例代码为例,来对 HTML 文档进行讲解
|
||||||
|
|
||||||
|
第一行:`<!DOCTYPE html>`,这是一个文档类型声明,用于告诉浏览器这是一个 HTML5 文档。
|
||||||
|
|
||||||
|
第二行:`<html>`,这是 HTML 文档的根元素,所有其他元素都必须嵌套在这个元素中,`<html>` 和 `</html>` 之间的内容就是文档的主体。
|
||||||
|
|
||||||
|
第三行到第六行:`<head>`,这是文档的头部元素,用于包含文档的元数据(比如标题、字符编码、外部资源引用等)。
|
||||||
|
|
||||||
|
第四行:`<meta charset="utf-8">`,这是一个元数据标签,用于指定文档的字符编码为 UTF-8。UTF-8 是一种常用的字符编码,能够表示世界上几乎所有的字符。如果不写的话可能会导致中文乱码的问题。
|
||||||
|
|
||||||
|
第五行:`<title>仲夏夜之梦(notes.simengweb.com)</title>`,这是文档的标题,会显示在浏览器的标题栏或标签页上。
|
||||||
|
|
||||||
|
第七行:`<body>`,这是文档的主体元素,用于包含文档的可见内容(比如文字、图片、按钮等),`<body>` 和 `</body>` 之间的内容就是文档的主体内容。
|
||||||
|
|
||||||
|
第八行:`<h1>我的第一个标题</h1>`,这是一个一级标题元素,用于表示文档的主要主题。`h1` 元素的内容会显示为较大的字体,通常用于页面的主标题。
|
||||||
|
|
||||||
|
第九行:`<p>我的第一个段落。</p>`,这是一个段落元素,用于表示文档中的一个段落。`p` 元素的内容会显示为普通的段落文本。
|
||||||
|
|
||||||
|
小提示:在浏览器中打开 F12 开启开发者工具,就可以查看和调试 HTML 文档啦。
|
||||||
|
|
||||||
|
## CSS3 基础知识讲解
|
||||||
|
|
||||||
|
CSS 是一种用来描述 HTML 文档“长什么样”的语言,专门负责网页的样式、排版与视觉效果。
|
||||||
|
|
||||||
|
CSS 也不是编程语言,而是一种“样式表”语言。它通过“选择器”找到 HTML 元素,再给它挂上一条或多条“声明”,告诉浏览器“这个元素应该是什么颜色、多大字号、放在哪里”。
|
||||||
|
|
||||||
|
一条 CSS 声明由“属性”和“值”组成,用冒号分隔,以分号结尾;多条声明放在花括号里,就组成了一条“样式规则”。
|
||||||
|
|
||||||
|
一个最简单的 CSS 示例,让页面里的标题变成红色、居中显示:
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>仲夏夜之梦(notes.simengweb.com)</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>我的第一个标题</h1>
|
||||||
|
<p>我的第一个段落。</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab style.css
|
||||||
|
```css
|
||||||
|
body {
|
||||||
|
background-color:#d0e4fe;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
color:orange;
|
||||||
|
text-align:center;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
font-family:"Times New Roman";
|
||||||
|
font-size:20px;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
这里的 index.html 中需要添加一条语句,用于引入 CSS 样式表。
|
||||||
|
```html
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
```
|
||||||
|
然后通过浏览器打开 index.html 就可以看到效果啦。
|
||||||
|
|
||||||
|
### CSS 文档分析
|
||||||
|
|
||||||
|
我们以前面的样例代码为例,来对 CSS 文档进行讲解
|
||||||
|
|
||||||
|
第一到三行:`body { background-color:#d0e4fe; }`,这是一条针对 `<body>` 元素的样式规则。
|
||||||
|
- `body` 是“选择器”,表示要把样式应用到整个网页主体。
|
||||||
|
- `background-color` 是属性,用来设置背景颜色;`#d0e4fe` 是一个淡蓝色色值,因此整个页面会呈现淡蓝色背景。
|
||||||
|
|
||||||
|
第四行到第七行:`h1 { color:orange; text-align:center; }`,这是一条针对 `<h1>` 元素的样式规则。
|
||||||
|
- `h1` 是“选择器”,对应 HTML 中的一级标题。
|
||||||
|
- `color:orange;` 把标题文字设为橙色。
|
||||||
|
- `text-align:center;` 让标题在水平方向上居中显示。
|
||||||
|
|
||||||
|
第八行到第十一行:`p { font-family:"Times New Roman"; font-size:20px; }`,这是一条针对 `<p>` 元素的样式规则。
|
||||||
|
- `p` 是“选择器”,对应 HTML 中的段落。
|
||||||
|
- `font-family:"Times New Roman";` 指定段落使用 Times New Roman 字体。
|
||||||
|
- `font-size:20px;` 把段落文字大小设为 20 像素,让文字看起来更大、更清晰。
|
||||||
|
|
||||||
|
小提示:在 VsCode 中安装“Live Server”插件后,修改并保存 CSS 文件,浏览器会自动刷新,立即看到样式变化,方便调试。
|
||||||
|
|
||||||
|
## JavaScript 基础知识讲解
|
||||||
|
|
||||||
|
JavaScript(简称 JS)是让网页“动起来、能互动”的语言。它可以:
|
||||||
|
- 响应用户操作(点击、输入、滚动等)
|
||||||
|
- 修改页面内容与样式(增删节点、改文字/颜色)
|
||||||
|
- 与服务器通信、处理数据与状态
|
||||||
|
- 实现动画与复杂交互逻辑
|
||||||
|
|
||||||
|
下面用一个小示例,演示 JS 如何让页面产生交互效果:
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>仲夏夜之梦(notes.simengweb.com)</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<!-- 样式写在外部 CSS 中 -->
|
||||||
|
<!-- JavaScript 推荐放在 body 末尾,或使用 defer 属性 -->
|
||||||
|
<!-- 这里在 body 末尾通过 src 引入外部脚本 -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>我的第一个标题</h1>
|
||||||
|
<p id="message">我的第一个段落。</p>
|
||||||
|
|
||||||
|
<button id="btn">点我试试</button>
|
||||||
|
<input id="name" placeholder="输入你的名字" />
|
||||||
|
|
||||||
|
<script src="script.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab script.js
|
||||||
|
```js
|
||||||
|
// 等页面元素加载完成后再执行(避免找不到节点)
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const msg = document.getElementById('message'); // 选择段落节点
|
||||||
|
const btn = document.getElementById('btn'); // 选择按钮
|
||||||
|
const nameInput = document.getElementById('name'); // 选择输入框
|
||||||
|
|
||||||
|
// 点击按钮,修改段落文本与颜色
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
msg.textContent = '你点击了按钮!';
|
||||||
|
msg.style.color = 'green';
|
||||||
|
console.log('按钮被点击'); // 打开浏览器控制台可见
|
||||||
|
});
|
||||||
|
|
||||||
|
// 输入时,实时更新欢迎语
|
||||||
|
nameInput.addEventListener('input', (e) => {
|
||||||
|
const name = e.target.value.trim();
|
||||||
|
msg.textContent = name ? `你好,${name}!` : '我的第一个段落。';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
### JavaScript 文档分析
|
||||||
|
我们以前面的样例代码为例,来对 JS 的关键点进行讲解:
|
||||||
|
|
||||||
|
- `<script src="script.js"></script>`:在 HTML 中通过 `script` 标签引入外部 JS 文件。常见放置位置是 `</body>` 之前,避免脚本执行时页面元素尚未加载。
|
||||||
|
- `document.addEventListener('DOMContentLoaded', ...)`:等待文档结构加载完成再运行 JS,确保能获取到页面元素。
|
||||||
|
- `document.getElementById('...')`:选择页面中的元素节点,便于后续读写或绑定事件。
|
||||||
|
- `addEventListener('click'/'input', ...)`:给元素绑定事件监听器,描述“发生什么事时要做什么”。
|
||||||
|
- `textContent / style`:修改文本与内联样式,从而即时改变页面显示效果。
|
||||||
|
- `console.log(...)`:在开发者工具控制台输出调试信息,便于观察程序执行。
|
||||||
|
|
||||||
|
### 小提示
|
||||||
|
- 打开浏览器开发者工具(F12),切到“Console”能查看 `console.log` 输出;在 “Elements”/“Inspector” 面板能查看并调试 DOM 结构与样式。
|
||||||
|
- 在 VSCode 中使用 “Live Server”,保存 `script.js` 后浏览器会自动刷新,方便快速迭代。
|
||||||
|
- 现代 JS 推荐使用 `const` 与 `let` 替代 `var`;多用箭头函数与模板字符串(如 `` `你好,${name}` ``)让代码更简洁。
|
||||||
|
|
||||||
|
到这里,我们已经分别了解了 HTML(结构)、CSS(样式)与 JavaScript(交互)三者如何协同工作。接下来可以尝试把它们组合起来,做一个小页面练手。
|
||||||
|
|
||||||
|
## 动手练习:小作业(只改 HTML/CSS,JS 已提供)
|
||||||
|
|
||||||
|
目标:做一个“欢迎卡片”,包含标题、说明文字、输入框与按钮。
|
||||||
|
- 点击按钮时切换页面主题(浅色/深色),JS 会自动完成;
|
||||||
|
- 输入名字时实时显示欢迎语;
|
||||||
|
- 你只需要修改 HTML 和 CSS 来达到视觉与布局效果。
|
||||||
|
|
||||||
|
### 作业要求(验收标准)
|
||||||
|
- 卡片居中显示,具有圆角、阴影与内边距;
|
||||||
|
- 标题居中,段落有合适的行高与间距;
|
||||||
|
- 按钮有悬停(hover)与按下(active)的视觉反馈;
|
||||||
|
- 输入框获得焦点(focus)时有明显强调样式;
|
||||||
|
- 在移动端(窄屏)不溢出,布局能自适应;
|
||||||
|
- 深色主题下文字可读、对比度合理。提示:JS 会在 `<body>` 上切换 `theme-dark` 类,你可以在 CSS 中基于该类进行主题覆盖。
|
||||||
|
|
||||||
|
### 起步模板
|
||||||
|
将以下三份代码保存为同目录下的 `index.html`、`style.css` 与 `script.js`,用 VSCode 的 Live Server 打开 `index.html` 进行预览。完成作业时,请只修改 HTML 和 CSS(保留 JS 的 id 与类名依赖)。
|
||||||
|
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>小作业:欢迎卡片</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="page">
|
||||||
|
<div class="card" id="card">
|
||||||
|
<h1 class="card__title">欢迎来到我的页面</h1>
|
||||||
|
<p class="card__text" id="message">请点击按钮或输入你的名字</p>
|
||||||
|
<div class="card__actions">
|
||||||
|
<input id="name" class="input" placeholder="输入你的名字" />
|
||||||
|
<button id="btn" class="btn btn--primary">点我切换主题</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="script.js" defer></script>
|
||||||
|
<!-- 注意:JS 依赖 #message、#btn、#name 这几个 id,请不要改动它们的命名 -->
|
||||||
|
<!-- 你可以新增或调整 class 名,或增删结构,来实现更好的视觉与布局 -->
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab style.css
|
||||||
|
```css
|
||||||
|
/* 目标:只通过 CSS 实现卡片的视觉与响应式,并支持深色主题 */
|
||||||
|
/* 建议:使用 CSS 变量管理主题;在 .theme-dark 上覆盖变量 */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bg: #f7f9fc;
|
||||||
|
--text: #222;
|
||||||
|
--primary: #ff7a45; /* 可调整为你的品牌色 */
|
||||||
|
--card-bg: #fff;
|
||||||
|
--card-shadow: 0 10px 20px rgba(0,0,0,0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--text);
|
||||||
|
font-family: system-ui, -apple-system, Segoe UI, Roboto, 'Helvetica Neue', Arial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page {
|
||||||
|
min-height: 100vh;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
width: min(640px, 100%);
|
||||||
|
background: var(--card-bg);
|
||||||
|
border-radius: 16px;
|
||||||
|
box-shadow: var(--card-shadow);
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card__title {
|
||||||
|
margin: 0 0 12px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card__text {
|
||||||
|
margin: 0 0 16px;
|
||||||
|
line-height: 1.6;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card__actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
padding: 10px 12px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 8px;
|
||||||
|
outline: none;
|
||||||
|
min-width: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input:focus {
|
||||||
|
border-color: var(--primary);
|
||||||
|
box-shadow: 0 0 0 3px rgba(255, 122, 69, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 10px 16px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 999px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform .08s ease, box-shadow .2s ease, background-color .2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn--primary {
|
||||||
|
background: var(--primary);
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 6px 12px rgba(255, 122, 69, .3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn--primary:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 8px 16px rgba(255, 122, 69, .4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn--primary:active {
|
||||||
|
transform: translateY(0);
|
||||||
|
box-shadow: 0 4px 8px rgba(255, 122, 69, .3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 任务:为深色主题定义样式。JS 会在 <body> 上切换 `.theme-dark` 类。*/
|
||||||
|
body.theme-dark {
|
||||||
|
--bg: #0f172a;
|
||||||
|
--text: #e5e7eb;
|
||||||
|
--primary: #60a5fa; /* 深色下可更柔和 */
|
||||||
|
--card-bg: #1f2937;
|
||||||
|
--card-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 可选:为移动端优化 */
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.card { padding: 18px; }
|
||||||
|
.input { min-width: 100%; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
@tab script.js
|
||||||
|
```js
|
||||||
|
// JS 已提供:负责交互逻辑,切换主题与显示欢迎语
|
||||||
|
// 你只需要改 HTML 和 CSS 即可达成作业要求
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const msg = document.getElementById('message');
|
||||||
|
const btn = document.getElementById('btn');
|
||||||
|
const nameInput = document.getElementById('name');
|
||||||
|
|
||||||
|
// 切换深色主题(在 <body> 上切换 theme-dark 类)
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
document.body.classList.toggle('theme-dark');
|
||||||
|
const dark = document.body.classList.contains('theme-dark');
|
||||||
|
msg.textContent = dark ? '深色主题已开启' : '浅色主题已开启';
|
||||||
|
});
|
||||||
|
|
||||||
|
// 实时欢迎语
|
||||||
|
nameInput.addEventListener('input', (e) => {
|
||||||
|
const name = e.target.value.trim();
|
||||||
|
msg.textContent = name ? `你好,${name}!` : '请点击按钮或输入你的名字';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
### 提示与加分项
|
||||||
|
- 可以用 `:root`+CSS 变量统一管理主题色,在 `.theme-dark` 中覆盖变量即可完成切换;
|
||||||
|
- 尝试为按钮增加平滑过渡与阴影层次感;
|
||||||
|
- 在移动端下让输入框占满一行,按钮在下一行显示;
|
||||||
|
- 可自行优化字体、字号与间距,让视觉更加舒适;
|
||||||
|
- 加分:实现卡片在深色主题下的微动效(例如背景色淡入)。
|
||||||
|
|
||||||
|
## 入门版(更简单,建议先做这个)
|
||||||
|
|
||||||
|
目标:做一个“欢迎卡片”,内容包括标题、说明文字、一个输入框和一个按钮。
|
||||||
|
- 点击按钮时高亮卡片(JS 已完成,你只需让 `.card.highlight` 在 CSS 里更显眼)。
|
||||||
|
- 输入名字时实时显示欢迎语(JS 已完成)。
|
||||||
|
- 你只需要修改 HTML 和 CSS,让页面好看、布局合理即可。
|
||||||
|
|
||||||
|
验收标准(入门)
|
||||||
|
- 卡片居中、圆角、阴影、内边距,整体观感舒适。
|
||||||
|
- 按钮有 `hover/active` 反馈,输入框 `focus` 有强调样式。
|
||||||
|
- 窄屏下不溢出,内容能自适应。
|
||||||
|
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>入门版小作业</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<!-- 保留以下 id:message / btn / name / card -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="page">
|
||||||
|
<div class="card" id="card">
|
||||||
|
<h1>欢迎</h1>
|
||||||
|
<p id="message">在输入框里写下你的名字</p>
|
||||||
|
<input id="name" placeholder="输入你的名字">
|
||||||
|
<button id="btn">高亮卡片</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="script.js"></script>
|
||||||
|
<!-- 用 VSCode Live Server 打开 index.html 预览效果 -->
|
||||||
|
<!-- 完成作业时,请只修改 HTML 和 CSS -->
|
||||||
|
<!-- 你可以自由调整颜色、间距、字体与布局,使页面更美观 -->
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab style.css
|
||||||
|
```css
|
||||||
|
/* 极简样式:你可以在此基础上美化与调整 */
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background: #f5f7fa;
|
||||||
|
font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page {
|
||||||
|
min-height: 100vh;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
width: min(360px, 100%);
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 6px 12px rgba(0,0,0,0.08);
|
||||||
|
padding: 16px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 10px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 8px;
|
||||||
|
outline: none;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus {
|
||||||
|
border-color: #1677ff;
|
||||||
|
box-shadow: 0 0 0 2px rgba(22,119,255,.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #1677ff;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover { filter: brightness(1.05); }
|
||||||
|
button:active { filter: brightness(0.95); }
|
||||||
|
|
||||||
|
/* JS 点击按钮时会在卡片上切换 .highlight 类 */
|
||||||
|
.card.highlight {
|
||||||
|
background: #fffbe6; /* 浅黄色高亮 */
|
||||||
|
box-shadow: 0 8px 16px rgba(0,0,0,0.10);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
@tab script.js
|
||||||
|
```js
|
||||||
|
// JS 已提供:负责简单交互。请只改 HTML/CSS。
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const msg = document.getElementById('message');
|
||||||
|
const btn = document.getElementById('btn');
|
||||||
|
const nameInput = document.getElementById('name');
|
||||||
|
const card = document.getElementById('card');
|
||||||
|
|
||||||
|
// 实时欢迎语
|
||||||
|
nameInput.addEventListener('input', (e) => {
|
||||||
|
const name = e.target.value.trim();
|
||||||
|
msg.textContent = name ? `你好,${name}!` : '在输入框里写下你的名字';
|
||||||
|
});
|
||||||
|
|
||||||
|
// 切换卡片高亮
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
card.classList.toggle('highlight');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,468 @@
|
|||||||
|
---
|
||||||
|
title: html 列表与语义布局
|
||||||
|
createTime: 2025/11/02 20:47:50
|
||||||
|
permalink: /programming/web/basic-syntax/html-lists-and-semantic-layout/
|
||||||
|
---
|
||||||
|
## 四、列表(UL/OL/LI)
|
||||||
|
|
||||||
|
无序列表(圆点):
|
||||||
|
```html title="index.html"
|
||||||
|
<ul>
|
||||||
|
<li>学习笔记</li>
|
||||||
|
<li>工具推荐</li>
|
||||||
|
<li>友情链接</li>
|
||||||
|
</ul>
|
||||||
|
```
|
||||||
|
|
||||||
|
有序列表(数字):
|
||||||
|
```html title="index.html"
|
||||||
|
<ol>
|
||||||
|
<li>需求与原型</li>
|
||||||
|
<li>API 设计</li>
|
||||||
|
<li>联调与验收</li>
|
||||||
|
</ol>
|
||||||
|
```
|
||||||
|
|
||||||
|
**小案例:展示清单与步骤**
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>列表案例</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<script defer src="app.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h2>我的清单</h2>
|
||||||
|
<ul>
|
||||||
|
<li>学习笔记</li>
|
||||||
|
<li>工具推荐</li>
|
||||||
|
<li>友情链接</li>
|
||||||
|
</ul>
|
||||||
|
<h2>项目步骤</h2>
|
||||||
|
<ol>
|
||||||
|
<li>需求与原型</li>
|
||||||
|
<li>API 设计</li>
|
||||||
|
<li>联调与验收</li>
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab style.css
|
||||||
|
```css
|
||||||
|
ul, ol { margin: .5rem 0 1rem; padding-left: 1.5rem; }
|
||||||
|
li { margin: .25rem 0; }
|
||||||
|
```
|
||||||
|
@tab app.js
|
||||||
|
```js
|
||||||
|
document.querySelectorAll('li').forEach(li => li.addEventListener('click', () => li.classList.toggle('done')));
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
**小作业:做一个“今日任务清单”**
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>今日任务清单</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>今天要做的事</h1>
|
||||||
|
<ul>
|
||||||
|
<li>阅读 30 分钟</li>
|
||||||
|
<li>练习 1 个算法题</li>
|
||||||
|
<li>整理房间</li>
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab style.css
|
||||||
|
```css
|
||||||
|
body { font-family: system-ui; margin: 2rem; }
|
||||||
|
li { cursor: pointer; }
|
||||||
|
.done { text-decoration: line-through; color: #888; }
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
## 五、语义化布局(Header/Nav/Main/Section/Article/Aside/Footer)
|
||||||
|
|
||||||
|
语义化标签让结构更清晰,搜索引擎更友好:
|
||||||
|
```html title="index.html"
|
||||||
|
<header>
|
||||||
|
<h1>我的网站</h1>
|
||||||
|
<nav>
|
||||||
|
<a href="/blog/">博客</a>
|
||||||
|
<a href="/notes/">笔记</a>
|
||||||
|
</nav>
|
||||||
|
<!-- 注意:更复杂的导航通常配合 CSS/JS 做响应式菜单 -->
|
||||||
|
<!-- 小提示:块级容器的外层仍可使用 <div> 来做网格或栅格布局 -->
|
||||||
|
<!-- 例如 <div class="container"> 包裹全站 -->
|
||||||
|
<!-- 只是这些语义标签会让搜索引擎更理解结构 -->
|
||||||
|
<!-- 语义标签与 <div> 并不冲突,可以配合使用 -->
|
||||||
|
<!-- 选择语义标签能让你的 HTML 更“有含义”而非只是分区 -->
|
||||||
|
<!-- 如果仅用于布局、无明确语义,用 <div> 即可 -->
|
||||||
|
<!-- 这段说明旨在帮助你建立语义化与布局之间的直觉 -->
|
||||||
|
<!-- 逐步养成好的结构化写法 -->
|
||||||
|
<!-- 让内容更可维护,更易被机器理解 -->
|
||||||
|
<!-- (继续往下看,还会介绍 Article/Section 等) -->
|
||||||
|
```
|
||||||
|
|
||||||
|
> 语义化标签的要点:这些标签表达了“这是什么内容”,而不是“怎么显示”。更容易被搜索引擎和读屏工具理解。
|
||||||
|
|
||||||
|
**小案例:语义化布局入门**
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>语义化布局案例</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<script defer src="app.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>我的网站</h1>
|
||||||
|
<nav>
|
||||||
|
<a href="#home">首页</a>
|
||||||
|
<a href="#blog">博客</a>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section>
|
||||||
|
<h2>最新文章</h2>
|
||||||
|
<article>
|
||||||
|
<h3>用语义标签改造你的页面</h3>
|
||||||
|
<p>示例段落:用 header/nav/main/section/article/aside/footer 组织结构。</p>
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
<aside>
|
||||||
|
<h2>侧栏</h2>
|
||||||
|
<p>这里可以放导航、标签云或广告位。</p>
|
||||||
|
</aside>
|
||||||
|
</main>
|
||||||
|
<footer>© 2025 祀梦</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab style.css
|
||||||
|
```css
|
||||||
|
body { font-family: system-ui; margin: 0; }
|
||||||
|
header, footer { padding: 1rem 2rem; background: #f7f7f7; }
|
||||||
|
nav { display: flex; gap: 1rem; }
|
||||||
|
main { display: grid; grid-template-columns: 1fr 240px; gap: 1rem; padding: 1rem 2rem; }
|
||||||
|
article { background: #fff; padding: 1rem; border: 1px solid #eee; border-radius: 8px; }
|
||||||
|
aside { background: #fff; padding: 1rem; border: 1px solid #eee; border-radius: 8px; }
|
||||||
|
```
|
||||||
|
@tab app.js
|
||||||
|
```js
|
||||||
|
document.querySelectorAll('nav a').forEach(a => a.addEventListener('click', () => {
|
||||||
|
document.querySelectorAll('nav a').forEach(x => x.classList.remove('active'));
|
||||||
|
a.classList.add('active');
|
||||||
|
}));
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
**小作业:用语义标签搭一个博客首页**
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>博客首页</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>博客名称</h1>
|
||||||
|
<nav>
|
||||||
|
<a href="#">首页</a>
|
||||||
|
<a href="#">归档</a>
|
||||||
|
<a href="#">关于</a>
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<section>
|
||||||
|
<article>
|
||||||
|
<h2>第一篇文章标题</h2>
|
||||||
|
<p>摘要内容……</p>
|
||||||
|
</article>
|
||||||
|
<article>
|
||||||
|
<h2>第二篇文章标题</h2>
|
||||||
|
<p>摘要内容……</p>
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
<aside>
|
||||||
|
<h2>侧栏</h2>
|
||||||
|
<p>分类、标签或个人简介。</p>
|
||||||
|
</aside>
|
||||||
|
</main>
|
||||||
|
<footer>© 2025 你的名字</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab style.css
|
||||||
|
```css
|
||||||
|
/* 与案例类似的栅格布局样式 */
|
||||||
|
main { display: grid; grid-template-columns: 1fr 240px; gap: 1rem; padding: 1rem 2rem; }
|
||||||
|
article { background: #fff; padding: 1rem; border: 1px solid #eee; border-radius: 8px; }
|
||||||
|
aside { background: #fff; padding: 1rem; border: 1px solid #eee; border-radius: 8px; }
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
## 六、表格(Table/TR/TH/TD)
|
||||||
|
|
||||||
|
```html title="index.html"
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>姓名</th>
|
||||||
|
<th>职业</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>祀梦</td>
|
||||||
|
<td>开发者</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
```
|
||||||
|
小提示:表格样式通常用 CSS 来美化(边框、间距、对齐等)。
|
||||||
|
|
||||||
|
**小案例:信息表格**
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>信息表格案例</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<script defer src="app.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr><th>姓名</th><th>职业</th><th>城市</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td>祀梦</td><td>开发者</td><td>上海</td></tr>
|
||||||
|
<tr><td>小李</td><td>产品经理</td><td>杭州</td></tr>
|
||||||
|
<tr><td>小王</td><td>设计师</td><td>北京</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab style.css
|
||||||
|
```css
|
||||||
|
table { border-collapse: collapse; width: 100%; }
|
||||||
|
th, td { border: 1px solid #ddd; padding: .5rem .75rem; text-align: left; }
|
||||||
|
thead th { background: #f7f7f7; }
|
||||||
|
tbody tr:nth-child(odd) { background: #fafafa; }
|
||||||
|
```
|
||||||
|
@tab app.js
|
||||||
|
```js
|
||||||
|
document.querySelectorAll('tbody tr').forEach(tr => tr.addEventListener('click', () => tr.classList.toggle('highlight')));
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
**小作业:制作“课程表”**
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>课程表</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr><th>时间</th><th>课程</th><th>教室</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td>周一 9:00</td><td>数学</td><td>A101</td></tr>
|
||||||
|
<tr><td>周三 14:00</td><td>英语</td><td>B302</td></tr>
|
||||||
|
<tr><td>周五 10:00</td><td>计算机</td><td>C210</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab style.css
|
||||||
|
```css
|
||||||
|
table { border-collapse: collapse; width: 100%; }
|
||||||
|
th, td { border: 1px solid #ddd; padding: .5rem .75rem; }
|
||||||
|
thead th { background: #f0f0f0; }
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
## 七、媒体(Audio/Video/Source)
|
||||||
|
|
||||||
|
```html title="index.html"
|
||||||
|
<audio src="bgm.mp3" controls loop></audio>
|
||||||
|
|
||||||
|
<video src="intro.mp4" controls width="480" poster="cover.jpg" muted></video>
|
||||||
|
<!-- 常用属性:controls / autoplay / loop / muted / poster(封面) -->
|
||||||
|
```
|
||||||
|
|
||||||
|
补充说明:
|
||||||
|
- `controls` 提供播放控制;一般不建议隐藏,保证可用性。
|
||||||
|
- `autoplay` 可能被浏览器限制;若需自动播放,通常需同时设置 `muted`。
|
||||||
|
- `preload` 控制预加载策略(`none`/`metadata`/`auto`),根据页面性能需求选择。
|
||||||
|
- `poster` 为视频未播放时的封面图;音频没有封面属性。
|
||||||
|
- 使用 `<source>` 指定多种格式与 MIME 类型,提升兼容性:`<source src="xxx.mp4" type="video/mp4">`。
|
||||||
|
|
||||||
|
**小案例:嵌入音视频**
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>媒体案例</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h2>背景音乐</h2>
|
||||||
|
<audio src="bgm.mp3" controls loop></audio>
|
||||||
|
<h2>介绍视频</h2>
|
||||||
|
<video src="intro.mp4" controls width="480" poster="cover.jpg" muted></video>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab style.css
|
||||||
|
```css
|
||||||
|
video { display: block; margin-top: .5rem; }
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
**小作业:添加一段你喜欢的音乐与视频**
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>我的媒体</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<audio src="music.mp3" controls></audio>
|
||||||
|
<video src="movie.mp4" controls width="480" poster="cover.jpg"></video>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab style.css
|
||||||
|
```css
|
||||||
|
audio, video { display: block; margin: .5rem 0; }
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
|
||||||
|
## 八、全局常用属性(任何标签几乎都能用)
|
||||||
|
|
||||||
|
- `id`:唯一标识,用于 JS/CSS 精确选择。
|
||||||
|
- `class`:分组与样式选择(上一课已讲)。
|
||||||
|
- `style`:内联样式(不推荐大量使用,建议写到 CSS 文件)。
|
||||||
|
- `title`:悬停提示文字。
|
||||||
|
- `data-*`:自定义数据属性(如 `data-user-id="42"`)。
|
||||||
|
- `aria-*`:无障碍相关属性,帮助读屏工具理解(如 `aria-label`)。
|
||||||
|
|
||||||
|
**小案例:使用 id/class/data/title/aria**
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>全局属性案例</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<script defer src="app.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<button id="likeBtn" class="btn" title="点赞一下" data-count="0" aria-label="点赞">👍 喜欢</button>
|
||||||
|
<p id="msg" class="note" aria-live="polite">点击按钮试试。</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab style.css
|
||||||
|
```css
|
||||||
|
.btn { padding: .5rem .75rem; border: 1px solid #ccc; border-radius: 6px; background: #fff; }
|
||||||
|
.note { color: #555; }
|
||||||
|
```
|
||||||
|
@tab app.js
|
||||||
|
```js
|
||||||
|
const btn = document.getElementById('likeBtn');
|
||||||
|
const msg = document.getElementById('msg');
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
const count = Number(btn.dataset.count || 0) + 1;
|
||||||
|
btn.dataset.count = String(count);
|
||||||
|
msg.textContent = `已点赞 ${count} 次`;
|
||||||
|
});
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
**小作业:做一个带计数的按钮**
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>计数按钮</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<script defer src="app.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<button id="counter" class="btn" title="点击增加" data-count="0">点击我</button>
|
||||||
|
<p id="status" class="note">当前计数:0</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab style.css
|
||||||
|
```css
|
||||||
|
.btn { padding: .5rem .75rem; border: 1px solid #ccc; border-radius: 6px; background: #fff; }
|
||||||
|
.note { margin-top: .5rem; }
|
||||||
|
```
|
||||||
|
@tab app.js
|
||||||
|
```js
|
||||||
|
const counter = document.getElementById('counter');
|
||||||
|
const statusEl = document.getElementById('status');
|
||||||
|
counter.addEventListener('click', () => {
|
||||||
|
const count = Number(counter.dataset.count || 0) + 1;
|
||||||
|
counter.dataset.count = String(count);
|
||||||
|
statusEl.textContent = `当前计数:${count}`;
|
||||||
|
});
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
## 结尾:先结构清晰,再上样式与交互
|
||||||
|
|
||||||
|
写网页像搭房子:先把房间(结构标签)安排好,再选家具颜色(CSS),最后加智能设备(JS)。
|
||||||
|
|
||||||
|
建议你先用这些常用标签做一个“个人名片页”,含标题、段落、头像图片、导航链接和一个简单表单。练熟后再加样式与交互。
|
||||||
|
|
||||||
|
**延伸阅读**:
|
||||||
|
- HTML 规范与参考(MDN):https://developer.mozilla.org/en-US/docs/Web/HTML
|
||||||
|
- 无障碍与语义化:https://developer.mozilla.org/en-US/docs/Glossary/Semantics
|
||||||
424
docs/notes/programming/web/basic-syntax/html-tags-attributes.md
Normal file
424
docs/notes/programming/web/basic-syntax/html-tags-attributes.md
Normal file
@@ -0,0 +1,424 @@
|
|||||||
|
---
|
||||||
|
title: HTML 常用标签与属性
|
||||||
|
createTime: 2025/11/2 19:30:00
|
||||||
|
permalink: /programming/web/basic-syntax/html-tags-attributes/
|
||||||
|
---
|
||||||
|
|
||||||
|
## 文本与标题(H/P/Span/Strong/Em/Div)
|
||||||
|
|
||||||
|
**标题**:从重要到不重要,`<h1>` ~ `<h6>`。
|
||||||
|
```html title="index.html"
|
||||||
|
<h1>我的网站</h1>
|
||||||
|
<h2>关于我</h2>
|
||||||
|
<h3>联系方式</h3>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 认识div标签
|
||||||
|
|
||||||
|
**什么是 `<div>`?**
|
||||||
|
|
||||||
|
`<div>` 是 "division"(分区)的缩写,可以理解为网页中的"容器"或"盒子"。
|
||||||
|
|
||||||
|
想象一下搬家时的纸箱:
|
||||||
|
|
||||||
|
* 网页 = 整个房间
|
||||||
|
* `<div>` = 一个个纸箱
|
||||||
|
* 箱子里 = 可以放各种物品(文字、图片、按钮等)
|
||||||
|
|
||||||
|
### `<div>` 的基本特点
|
||||||
|
|
||||||
|
1. 块级元素
|
||||||
|
`<div>` 是块级元素,这意味着:
|
||||||
|
|
||||||
|
* 默认会占据整行的宽度
|
||||||
|
* 前后会自动换行
|
||||||
|
* 就像段落一样,每个`<div>`都会从新的一行开始
|
||||||
|
|
||||||
|
**`<div>` 本身没有特定含义,它只是用来分组和布局。**
|
||||||
|
|
||||||
|
### 为什么要使用 `<div>`?
|
||||||
|
|
||||||
|
没有`<div>`的情况:
|
||||||
|
```html title='index.html'
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>仲夏夜之梦</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>我的网站</h1>
|
||||||
|
<p>欢迎来到我的个人网站!</p>
|
||||||
|
<img src="photo.jpg" alt="我的照片">
|
||||||
|
<p>这是我的个人介绍...</p>
|
||||||
|
<button>联系我</button>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
所有元素都堆在一起,很难分别控制样式。
|
||||||
|
|
||||||
|
使用 `<div>` 的情况:
|
||||||
|
```html title='index.html'
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>仲夏夜之梦</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="header">
|
||||||
|
<h1>我的网站</h1>
|
||||||
|
<p>欢迎来到我的个人网站!</p>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<img src="photo.jpg" alt="我的照片">
|
||||||
|
<p>这是我的个人介绍...</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<button>联系我</button>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
这样我就可以分别控制每个部分的样式啦!
|
||||||
|
|
||||||
|
这个时候又有聪明的小朋友问了:这个class是什么呀?难道说?!是**起的名字!!**
|
||||||
|
|
||||||
|
太好了,恭喜你答对了,那么我们为什么要用class呢?
|
||||||
|
|
||||||
|
### Class
|
||||||
|
|
||||||
|
Class 可以理解为给 HTML 元素起的"组名"或"类别名",让 CSS 能够精确地找到并美化特定的元素。
|
||||||
|
|
||||||
|
想象一个学校:
|
||||||
|
* HTML 元素 = 学生
|
||||||
|
* Class = 学生的身份(如"三年级一班"、"篮球队员")
|
||||||
|
* CSS = 老师,根据身份给学生安排不同的任务和服装
|
||||||
|
|
||||||
|
class基本用法此处就不举例了,详情参照上面的代码。
|
||||||
|
|
||||||
|
如果没有class的情况:
|
||||||
|
```html title='index.html'
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>仲夏夜之梦</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>我的网站</h1>
|
||||||
|
<p>普通段落</p>
|
||||||
|
<p>个人介绍</p>
|
||||||
|
<p>重要提示</p>
|
||||||
|
<button>普通按钮</button>
|
||||||
|
<button>重要按钮</button>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
如果我们想给"重要提示"和"重要按钮"设置特殊样式,很难精确选择!像之前我教的一样css直接用p或者h1来选择的话就无法区分具体每一段的区别了。
|
||||||
|
|
||||||
|
这时候就可以用class了!
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>仲夏夜之梦</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>我的网站</h1>
|
||||||
|
<p class="normal">普通段落</p>
|
||||||
|
<p class="intro">个人介绍</p>
|
||||||
|
<p class="warning">重要提示</p>
|
||||||
|
<button class="normal-btn">普通按钮</button>
|
||||||
|
<button class="important-btn">重要按钮</button>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab style.css
|
||||||
|
```css
|
||||||
|
.warning {
|
||||||
|
color: red;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.important-btn {
|
||||||
|
background-color: red;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
**现在自己动手尝试一下**
|
||||||
|
|
||||||
|
## 动手练习:小作业
|
||||||
|
|
||||||
|
运用所学的 HTML 和 CSS 知识,创建一个美观的个人名片页面。不确定的时候翻翻文档
|
||||||
|
|
||||||
|
```html title='index.html'
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<!-- 在这里添加字符编码和标题 -->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- 创建一个名片容器 div,class 为 "card" -->
|
||||||
|
|
||||||
|
<!-- 在卡片内部分为三个区域: -->
|
||||||
|
|
||||||
|
<!-- 1. 头部区域:包含姓名和职位 -->
|
||||||
|
<div class="card-header">
|
||||||
|
<!-- 添加 h1 标题显示你的姓名 -->
|
||||||
|
<!-- 添加 p 段落显示你的职位或专业 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 2. 主体区域:包含联系信息 -->
|
||||||
|
<div class="card-body">
|
||||||
|
<!-- 添加至少3个联系信息,使用 p 标签 -->
|
||||||
|
<!-- 例如:电话、邮箱、地址等 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 3. 底部区域:包含个人简介 -->
|
||||||
|
<div class="card-footer">
|
||||||
|
<!-- 添加一个个人简介段落 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
css样式自定,发挥自己的创作力,创建一个独特的个人名片页面。
|
||||||
|
|
||||||
|
**段落与换行**:
|
||||||
|
```html title="index.html"
|
||||||
|
<p>这是一个段落,里面可以有<strong>加粗</strong>和<em>强调</em>。</p>
|
||||||
|
<p>这是另一个段落。<br>需要换行时用 <code><br></code>。</p>
|
||||||
|
<hr> <!-- 水平分割线 -->
|
||||||
|
```
|
||||||
|
|
||||||
|
**行内 vs 块级**:
|
||||||
|
- `<div>` 是块级元素(换行占整行),用于分区布局;
|
||||||
|
- `<span>` 是行内元素(不换行),用于强调局部文字。
|
||||||
|
|
||||||
|
使用建议与解释:
|
||||||
|
- 语义优先:`<strong>` 表示“语义上的重点”,`<b>` 仅表示“加粗外观”;`<em>` 表示“语气强调”,`<i>` 仅表示“斜体外观”。优先使用语义标签,样式交给 CSS。
|
||||||
|
- 标题层级:通常一个页面只有一个 `<h1>`,下面按层级组织为 `<h2>/<h3>...`。不要为求大小随意跳级或用标题替代普通文本。
|
||||||
|
- 段落与换行:换行请优先使用分段(`<p>`),只有在同段内需要视觉换行时使用 `<br>`。`<hr>` 适合用于内容分隔或主题切换。
|
||||||
|
|
||||||
|
**小案例:文本与标题**
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>文本与标题案例</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>我的网站</h1>
|
||||||
|
<h2>关于我</h2>
|
||||||
|
<p>我是一名<strong>前端开发者</strong>,喜欢<em>简洁的设计</em>与清晰的结构。</p>
|
||||||
|
<hr>
|
||||||
|
<h3>联系方式</h3>
|
||||||
|
<p>Email: hello@example.com</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab style.css
|
||||||
|
```css
|
||||||
|
body { font-family: system-ui; margin: 2rem; }
|
||||||
|
h1 { font-size: 2rem; margin-bottom: .5rem; }
|
||||||
|
h2 { margin-top: 1.5rem; }
|
||||||
|
p { margin: .5rem 0; }
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
**小作业:写一段个人简介**
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>个人简介</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>你的名字</h1>
|
||||||
|
<h2>一句话介绍</h2>
|
||||||
|
<p>用两段文字,分别写你现在在做什么、你感兴趣的方向。</p>
|
||||||
|
<p>使用 <strong>strong</strong> 与 <em>em</em> 做重点强调。</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab style.css
|
||||||
|
```css
|
||||||
|
body { font-family: system-ui; margin: 2rem; line-height: 1.8; }
|
||||||
|
p { max-width: 60ch; }
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
## 三、链接与图片(A/IMG)
|
||||||
|
|
||||||
|
### 什么是 `<img>` 标签
|
||||||
|
|
||||||
|
`<img>` 标签用于在网页中插入图片,它是自闭合标签(不需要结束标签)。
|
||||||
|
|
||||||
|
### `<img>` 标签的基本属性
|
||||||
|
|
||||||
|
* src:指定图片的路径(必填)
|
||||||
|
* alt:指定图片的替代文本(必填,用于图片加载失败时显示)
|
||||||
|
* width:指定图片的宽度(可选)
|
||||||
|
* height:指定图片的高度(可选)
|
||||||
|
|
||||||
|
基本语法:
|
||||||
|
```html title='index.html'
|
||||||
|
<img src="photo.jpg" alt="我的照片" width="200" height="300">
|
||||||
|
```
|
||||||
|
|
||||||
|
### HTML 超链接
|
||||||
|
|
||||||
|
HTML 链接(Anchor)是网页之间跳转的核心部分。
|
||||||
|
|
||||||
|
HTML 使用链接与网络上的另一个文档相连。
|
||||||
|
|
||||||
|
HTML中的链接是一种用于在不同网页之间导航的元素。
|
||||||
|
|
||||||
|
链接通常用于将一个网页与另一个网页或资源(如文档、图像、音频文件等)相关联。
|
||||||
|
|
||||||
|
链接允许用户在浏览网页时单击文本或图像来跳转到其他位置,从而实现网页之间的互联。
|
||||||
|
|
||||||
|
HTML 链接 通过 `<a>` 标签创建,通常用于将用户从一个页面导航到另一个页面、从一个部分跳转到页面中的另一个部分、下载文件、打开电子邮件应用程序或执行 JavaScript 函数等。
|
||||||
|
|
||||||
|
超链接可以是一个字,一个词,或者一组词,也可以是一幅图像,可以点击这些内容来跳转到新的文档或者当前文档中的某个部分。
|
||||||
|
|
||||||
|
当把鼠标指针移动到网页中的某个链接上时,箭头会变为**一只小手**。
|
||||||
|
|
||||||
|
## `<a>` 标签的基本属性
|
||||||
|
|
||||||
|
* href:指定链接的目标 URL(必填)
|
||||||
|
* target:指定链接在何处打开(可选)
|
||||||
|
* _blank:在新窗口或标签页中打开链接
|
||||||
|
* _self:在当前窗口或标签页中打开链接(默认)
|
||||||
|
* _parent:在父框架中打开链接
|
||||||
|
* _top:在顶部框架中打开链接
|
||||||
|
|
||||||
|
基本语法:
|
||||||
|
```html title='index.html'
|
||||||
|
<a href="https://www.example.com">链接文本</a>
|
||||||
|
```
|
||||||
|
- `<a>` 标签:定义了一个超链接(anchor)。它是 HTML 中用来创建可点击链接的主要标签。
|
||||||
|
- href 属性:指定目标 URL,当点击链接时,浏览器将导航到此 URL。
|
||||||
|
|
||||||
|
**这里还有一个target 属性**:
|
||||||
|
- _blank:在新窗口或标签页中打开链接
|
||||||
|
- _self:在当前窗口或标签页中打开链接(默认)
|
||||||
|
- _parent:在父框架中打开链接
|
||||||
|
- _top:在顶部框架中打开链接
|
||||||
|
|
||||||
|
```html title='index.html'
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>target属性示例</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h2>target属性示例</h2>
|
||||||
|
|
||||||
|
<!-- 在当前窗口打开(默认) -->
|
||||||
|
<a href="https://www.baidu.com" target="_self">当前窗口打开</a>
|
||||||
|
|
||||||
|
<!-- 在新窗口打开 -->
|
||||||
|
<a href="https://www.baidu.com" target="_blank">新窗口打开</a>
|
||||||
|
|
||||||
|
<!-- 在父窗口打开 -->
|
||||||
|
<a href="https://www.baidu.com" target="_parent">父窗口打开</a>
|
||||||
|
|
||||||
|
<!-- 建议:新窗口打开外部链接 -->
|
||||||
|
<a href="https://www.example.com" target="_blank" rel="noopener">
|
||||||
|
外部网站(安全的新窗口)
|
||||||
|
</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
复制代码到自己的html文件中,尝试一下不同的target属性值。
|
||||||
|
|
||||||
|
常用属性:
|
||||||
|
- `href`:目标地址;
|
||||||
|
- `target="_blank"`:新窗口打开;
|
||||||
|
- `rel="noopener"`:安全与性能(避免旧窗口被新页面控制)。
|
||||||
|
|
||||||
|
补充说明:
|
||||||
|
- 链接安全:外链新窗口打开时同时设置 `rel="noopener"` 或 `rel="noreferrer"`,避免安全与性能问题。
|
||||||
|
- 图片可使用 `loading="lazy"` 懒加载,减少首屏资源压力;`alt` 请写出图片用途或内容摘要。
|
||||||
|
- 设定 `width/height` 可以预留占位,减少页面布局抖动(CLS)。复杂场景可考虑 `<picture>` + `<source>` 做响应式图片。
|
||||||
|
- 与图片相关的配套标签:`<figure>` + `<figcaption>` 用于图片与说明文字的组合。
|
||||||
|
|
||||||
|
**小案例:链接与图片**
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>链接与图片案例</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav>
|
||||||
|
<a href="/" >首页</a>
|
||||||
|
<a href="https://developer.mozilla.org/" target="_blank" rel="noopener">MDN</a>
|
||||||
|
</nav>
|
||||||
|
<img src="avatar.jpg" alt="我的头像" width="160" height="160">
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab style.css
|
||||||
|
```css
|
||||||
|
nav { display: flex; gap: 1rem; margin-bottom: 1rem; }
|
||||||
|
nav a { color: #06c; text-decoration: none; }
|
||||||
|
nav a:hover { text-decoration: underline; }
|
||||||
|
img { border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,.1); }
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
**小作业:做一个“友链”与头像区块**
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>友链与头像</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section>
|
||||||
|
<h2>友情链接</h2>
|
||||||
|
<p>
|
||||||
|
<a href="https://notes.simengweb.com" target="_blank" rel="noopener">祀梦笔记</a>
|
||||||
|
·
|
||||||
|
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue.js</a>
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h2>头像</h2>
|
||||||
|
<img src="avatar.jpg" alt="你的头像" width="160" height="160">
|
||||||
|
</section>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab style.css
|
||||||
|
```css
|
||||||
|
section { margin-bottom: 1rem; }
|
||||||
|
img { border: 2px solid #eee; border-radius: 50%; }
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
606
docs/notes/programming/web/basic-syntax/javascript-basics.md
Normal file
606
docs/notes/programming/web/basic-syntax/javascript-basics.md
Normal file
@@ -0,0 +1,606 @@
|
|||||||
|
---
|
||||||
|
title: JavaScript 基础知识
|
||||||
|
createTime: 2025/11/2 21:30:00
|
||||||
|
permalink: /programming/web/basic-syntax/javascript-basics/
|
||||||
|
---
|
||||||
|
|
||||||
|
## JavaScript 是什么?
|
||||||
|
|
||||||
|
JavaScript 是一种广泛用于网页开发的脚本语言,它使网页能够实现交互式功能。与 HTML(负责结构)和 CSS(负责样式)不同,JavaScript 专注于**行为**,可以让网页变得动态和响应式。
|
||||||
|
|
||||||
|
|
||||||
|
## 第一个 JavaScript 程序
|
||||||
|
|
||||||
|
JavaScript 代码可以直接写在 HTML 文件中,通常放在 `<body>` 标签的底部,使用 `<script>` 标签包裹。
|
||||||
|
|
||||||
|
```html title="index.html"
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>我的第一个 JavaScript 程序</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>你好,世界!</h1>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 这是注释,不会被执行
|
||||||
|
console.log('Hello, JavaScript!'); // 在控制台输出文本
|
||||||
|
alert('欢迎学习 JavaScript!'); // 弹出提示框
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
**提示**:你可以在浏览器中按下 F12 打开开发者工具,然后切换到 "Console" 标签查看 `console.log()` 的输出。
|
||||||
|
|
||||||
|
`console.log()` 是 JavaScript 中最常用、最重要的调试工具,可以说是每个开发者的"最佳朋友"!
|
||||||
|
|
||||||
|
### 基本输出 ###
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 输出字符串
|
||||||
|
console.log("Hello World!");
|
||||||
|
|
||||||
|
// 输出变量
|
||||||
|
const name = "小明";
|
||||||
|
console.log(name);
|
||||||
|
|
||||||
|
// 输出多个值
|
||||||
|
const age = 18;
|
||||||
|
const isStudent = true;
|
||||||
|
console.log("学生信息:", name, age, isStudent);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 输出不同类型的数据 ###
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 各种数据类型
|
||||||
|
console.log("字符串:", "Hello");
|
||||||
|
console.log("数字:", 42);
|
||||||
|
console.log("布尔值:", true);
|
||||||
|
console.log("数组:", [1, 2, 3]);
|
||||||
|
console.log("对象:", {name: "李华", age: 20});
|
||||||
|
console.log("函数:", function() {});
|
||||||
|
console.log("undefined:", undefined);
|
||||||
|
console.log("null:", null);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 字符串插值 ###
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const userName = "张三";
|
||||||
|
const userAge = 25;
|
||||||
|
const score = 95.5;
|
||||||
|
|
||||||
|
// 传统方式
|
||||||
|
console.log("用户 " + userName + " 年龄 " + userAge + " 分数 " + score);
|
||||||
|
|
||||||
|
// 模板字符串(推荐)
|
||||||
|
console.log(`用户 ${userName} 年龄 ${userAge} 分数 ${score}`);
|
||||||
|
|
||||||
|
// 带表达式的插值
|
||||||
|
console.log(`${userName} 是 ${userAge >= 18 ? "成年人" : "未成年人"}`);
|
||||||
|
```
|
||||||
|
|
||||||
|
### 格式化输出 ###
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const product = {
|
||||||
|
name: "笔记本电脑",
|
||||||
|
price: 5999,
|
||||||
|
brand: "Dell",
|
||||||
|
inStock: true
|
||||||
|
};
|
||||||
|
|
||||||
|
// %s - 字符串
|
||||||
|
console.log("产品名称: %s", product.name);
|
||||||
|
|
||||||
|
// %d - 数字
|
||||||
|
console.log("价格: %d 元", product.price);
|
||||||
|
|
||||||
|
// %f - 浮点数
|
||||||
|
console.log("折扣价: %f", product.price * 0.9);
|
||||||
|
|
||||||
|
// %o - 对象
|
||||||
|
console.log("完整产品信息: %o", product);
|
||||||
|
|
||||||
|
// %c - CSS样式
|
||||||
|
console.log("%c重要信息!", "color: red; font-size: 20px; font-weight: bold;");
|
||||||
|
```
|
||||||
|
|
||||||
|
## JavaScript 变量
|
||||||
|
|
||||||
|
变量是用来存储信息的容器。在 JavaScript 中,我们使用 `let`、`const` 或 `var` 关键字来声明变量。
|
||||||
|
|
||||||
|
### 变量声明方式
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 使用 let 声明可变变量
|
||||||
|
let name = "小明";
|
||||||
|
name = "小红"; // 可以修改
|
||||||
|
|
||||||
|
// 使用 const 声明常量(不可变)
|
||||||
|
const PI = 3.14159;
|
||||||
|
// PI = 3.14; // 错误!常量不能修改
|
||||||
|
|
||||||
|
// 使用 var 声明变量(旧方式,现在推荐使用 let 和 const)
|
||||||
|
var age = 25;
|
||||||
|
```
|
||||||
|
|
||||||
|
**注意**:
|
||||||
|
- 使用 `let` 声明的变量可以重新赋值
|
||||||
|
- 使用 `const` 声明的变量不能重新赋值(常量)
|
||||||
|
- 尽量避免使用 `var`,因为它有一些奇怪的作用域规则
|
||||||
|
|
||||||
|
|
||||||
|
## 数据类型
|
||||||
|
|
||||||
|
JavaScript 有几种基本数据类型:
|
||||||
|
|
||||||
|
### 1. 字符串(String)
|
||||||
|
|
||||||
|
用于表示文本,可以使用单引号或双引号。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const greeting = "你好";
|
||||||
|
const name = 'JavaScript';
|
||||||
|
const message = `${greeting}, ${name}!`; // 使用模板字符串(ES6 特性)
|
||||||
|
console.log(message); // 输出:你好, JavaScript!
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 数字(Number)
|
||||||
|
|
||||||
|
用于表示数值。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const age = 25;
|
||||||
|
const price = 99.99;
|
||||||
|
const PI = 3.14159;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 布尔值(Boolean)
|
||||||
|
|
||||||
|
用于表示真或假,只有两个值:`true` 和 `false`。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const isStudent = true;
|
||||||
|
const hasGraduated = false;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 数组(Array)
|
||||||
|
|
||||||
|
用于存储多个值的集合。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const fruits = ["苹果", "香蕉", "橙子"];
|
||||||
|
console.log(fruits[0]); // 输出:苹果(数组索引从0开始)
|
||||||
|
|
||||||
|
// 添加元素
|
||||||
|
fruits.push("葡萄");
|
||||||
|
console.log(fruits); // 输出:["苹果", "香蕉", "橙子", "葡萄"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 对象(Object)
|
||||||
|
|
||||||
|
用于存储键值对集合。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const person = {
|
||||||
|
name: "小明",
|
||||||
|
age: 25,
|
||||||
|
isStudent: true,
|
||||||
|
greet: function() {
|
||||||
|
console.log(`你好,我是${this.name}!`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(person.name); // 输出:小明
|
||||||
|
person.greet(); // 输出:你好,我是小明!
|
||||||
|
```
|
||||||
|
|
||||||
|
## 运算符
|
||||||
|
|
||||||
|
### 算术运算符
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const a = 10;
|
||||||
|
const b = 5;
|
||||||
|
|
||||||
|
console.log(a + b); // 15 加法
|
||||||
|
console.log(a - b); // 5 减法
|
||||||
|
console.log(a * b); // 50 乘法
|
||||||
|
console.log(a / b); // 2 除法
|
||||||
|
console.log(a % b); // 0 取余
|
||||||
|
console.log(a ** b); // 100000 幂运算(ES6)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 赋值运算符
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const x = 10;
|
||||||
|
|
||||||
|
x += 5; // 等同于 x = x + 5
|
||||||
|
console.log(x); // 15
|
||||||
|
|
||||||
|
x -= 3; // 等同于 x = x - 3
|
||||||
|
console.log(x); // 12
|
||||||
|
```
|
||||||
|
|
||||||
|
### 比较运算符
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const a = 10;
|
||||||
|
const b = 5;
|
||||||
|
|
||||||
|
console.log(a > b); // true
|
||||||
|
console.log(a < b); // false
|
||||||
|
console.log(a >= b); // true
|
||||||
|
console.log(a <= b); // false
|
||||||
|
console.log(a === b); // false(严格相等,比较值和类型)
|
||||||
|
console.log(a == b); // false(宽松相等,只比较值)
|
||||||
|
console.log(a !== b); // true(严格不相等)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 条件语句
|
||||||
|
|
||||||
|
### if 语句
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const age = 18;
|
||||||
|
|
||||||
|
if (age >= 18) {
|
||||||
|
console.log("你已经成年了!");
|
||||||
|
} else if (age >= 13) {
|
||||||
|
console.log("你是青少年。");
|
||||||
|
} else {
|
||||||
|
console.log("你还是个孩子。");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## 循环
|
||||||
|
|
||||||
|
### for 循环
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 打印1到5
|
||||||
|
for (const i = 1; i <= 5; i++) {
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历数组
|
||||||
|
const fruits = ["苹果", "香蕉", "橙子"];
|
||||||
|
for (const i = 0; i < fruits.length; i++) {
|
||||||
|
console.log(fruits[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 for...of 遍历(ES6)
|
||||||
|
for (const fruit of fruits) {
|
||||||
|
console.log(fruit);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### while 循环
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const count = 1;
|
||||||
|
while (count <= 5) {
|
||||||
|
console.log(count);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 函数
|
||||||
|
|
||||||
|
函数是一段可重复使用的代码块,可以接受输入(参数),执行操作,并返回输出(返回值)。
|
||||||
|
|
||||||
|
### 函数声明
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
function greet(name) {
|
||||||
|
return `你好,${name}!`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = greet("小明");
|
||||||
|
console.log(message); // 输出:你好,小明!
|
||||||
|
```
|
||||||
|
|
||||||
|
格式如下
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
function 函数名(参数1, 参数2, ...参数N) {
|
||||||
|
// 函数体:要执行的代码
|
||||||
|
return 返回值; // 可选
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 箭头函数(ES6)
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const sum = (a, b) => {
|
||||||
|
return a + b;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 简化写法(当只有一行返回语句时)
|
||||||
|
const multiply = (a, b) => a * b;
|
||||||
|
|
||||||
|
console.log(sum(3, 4)); // 7
|
||||||
|
console.log(multiply(3, 4)); // 12
|
||||||
|
```
|
||||||
|
|
||||||
|
## DOM 操作
|
||||||
|
|
||||||
|
DOM(文档对象模型)是 HTML 和 XML 文档的编程接口。JavaScript 可以通过 DOM 来操作网页元素。
|
||||||
|
|
||||||
|
### 选择元素
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 通过 id 选择元素
|
||||||
|
const title = document.getElementById("title");
|
||||||
|
|
||||||
|
// 通过 class 选择元素(返回元素集合)
|
||||||
|
const items = document.getElementsByClassName("item");
|
||||||
|
|
||||||
|
// 通过标签名选择元素
|
||||||
|
const paragraphs = document.getElementsByTagName("p");
|
||||||
|
|
||||||
|
// 通过 CSS 选择器选择元素(ES5+)
|
||||||
|
const header = document.querySelector("header"); // 选择第一个匹配的元素
|
||||||
|
const allLinks = document.querySelectorAll("a"); // 选择所有匹配的元素
|
||||||
|
```
|
||||||
|
|
||||||
|
### 修改元素内容
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 修改文本内容
|
||||||
|
const title = document.getElementById("title");
|
||||||
|
title.textContent = "新标题";
|
||||||
|
|
||||||
|
// 修改 HTML 内容
|
||||||
|
title.innerHTML = "<strong>加粗的新标题</strong>";
|
||||||
|
```
|
||||||
|
|
||||||
|
### 修改元素样式
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const element = document.getElementById("box");
|
||||||
|
element.style.color = "red";
|
||||||
|
element.style.fontSize = "20px";
|
||||||
|
element.style.backgroundColor = "#f0f0f0";
|
||||||
|
```
|
||||||
|
|
||||||
|
### 添加事件监听器
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const button = document.getElementById("myButton");
|
||||||
|
|
||||||
|
button.addEventListener("click", function() {
|
||||||
|
console.log("按钮被点击了!");
|
||||||
|
alert("你好,欢迎使用!");
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## 小案例:交互式计算器
|
||||||
|
|
||||||
|
下面是一个简单的交互式计算器示例,演示如何结合 HTML、CSS 和 JavaScript。
|
||||||
|
|
||||||
|
::: code-tabs
|
||||||
|
@tab index.html
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>简易计算器</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="calculator">
|
||||||
|
<h2>简易计算器</h2>
|
||||||
|
<input type="number" id="num1" placeholder="输入第一个数字">
|
||||||
|
<select id="operation">
|
||||||
|
<option value="add">+</option>
|
||||||
|
<option value="subtract">-</option>
|
||||||
|
<option value="multiply">×</option>
|
||||||
|
<option value="divide">÷</option>
|
||||||
|
</select>
|
||||||
|
<input type="number" id="num2" placeholder="输入第二个数字">
|
||||||
|
<button id="calculate">计算</button>
|
||||||
|
<div id="result">结果将显示在这里</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="script.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
@tab style.css
|
||||||
|
```css
|
||||||
|
.calculator {
|
||||||
|
max-width: 300px;
|
||||||
|
margin: 2rem auto;
|
||||||
|
padding: 1.5rem;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 8px;
|
||||||
|
text-align: center;
|
||||||
|
font-family: system-ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, select, button {
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
padding: 0.5rem;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background: #007bff;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background: #0056b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#result {
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
@tab script.js
|
||||||
|
```javascript
|
||||||
|
// 获取DOM元素
|
||||||
|
const num1Input = document.getElementById('num1');
|
||||||
|
const num2Input = document.getElementById('num2');
|
||||||
|
const operationSelect = document.getElementById('operation');
|
||||||
|
const calculateButton = document.getElementById('calculate');
|
||||||
|
const resultDiv = document.getElementById('result');
|
||||||
|
|
||||||
|
// 添加点击事件监听器
|
||||||
|
calculateButton.addEventListener('click', function() {
|
||||||
|
// 获取输入值
|
||||||
|
const num1 = parseFloat(num1Input.value);
|
||||||
|
const num2 = parseFloat(num2Input.value);
|
||||||
|
const operation = operationSelect.value;
|
||||||
|
const result;
|
||||||
|
|
||||||
|
// 检查输入是否有效
|
||||||
|
if (isNaN(num1) || isNaN(num2)) {
|
||||||
|
resultDiv.textContent = '请输入有效的数字!';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行计算
|
||||||
|
switch (operation) {
|
||||||
|
case 'add':
|
||||||
|
result = num1 + num2;
|
||||||
|
break;
|
||||||
|
case 'subtract':
|
||||||
|
result = num1 - num2;
|
||||||
|
break;
|
||||||
|
case 'multiply':
|
||||||
|
result = num1 * num2;
|
||||||
|
break;
|
||||||
|
case 'divide':
|
||||||
|
// 检查除数是否为0
|
||||||
|
if (num2 === 0) {
|
||||||
|
resultDiv.textContent = '除数不能为0!';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
result = num1 / num2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示结果
|
||||||
|
resultDiv.textContent = `计算结果:${result}`;
|
||||||
|
});
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
## JavaScript 的异步编程
|
||||||
|
|
||||||
|
JavaScript 是单线程的,但它可以通过异步编程模型来处理耗时操作,如网络请求、定时器等。
|
||||||
|
|
||||||
|
### setTimeout 和 setInterval
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// setTimeout - 延迟执行一次
|
||||||
|
setTimeout(function() {
|
||||||
|
console.log('2秒后执行');
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
// setInterval - 定期重复执行
|
||||||
|
const count = 0;
|
||||||
|
const timer = setInterval(function() {
|
||||||
|
count++;
|
||||||
|
console.log(`执行第 ${count} 次`);
|
||||||
|
|
||||||
|
if (count >= 5) {
|
||||||
|
clearInterval(timer); // 清除定时器
|
||||||
|
console.log('定时器已停止');
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Promise(ES6)
|
||||||
|
|
||||||
|
Promise 是异步编程的一种解决方案,用于处理异步操作。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// 创建一个Promise
|
||||||
|
const fetchData = new Promise((resolve, reject) => {
|
||||||
|
// 模拟网络请求
|
||||||
|
setTimeout(() => {
|
||||||
|
const success = true;
|
||||||
|
if (success) {
|
||||||
|
resolve('数据获取成功');
|
||||||
|
} else {
|
||||||
|
reject('数据获取失败');
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 使用Promise
|
||||||
|
fetchData
|
||||||
|
.then(data => {
|
||||||
|
console.log(data);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## 常见错误和调试技巧
|
||||||
|
|
||||||
|
### 常见错误
|
||||||
|
|
||||||
|
1. **语法错误**:代码不符合 JavaScript 语法规则
|
||||||
|
2. **引用错误**:使用了未定义的变量或函数
|
||||||
|
3. **类型错误**:对错误类型的值进行操作
|
||||||
|
4. **范围错误**:数值超出有效范围
|
||||||
|
|
||||||
|
### 调试技巧
|
||||||
|
|
||||||
|
1. **使用 console.log()**:在控制台输出变量值或执行流程
|
||||||
|
2. **使用断点**:在浏览器开发者工具中设置断点,逐步执行代码
|
||||||
|
3. **检查错误信息**:仔细阅读错误提示,找出问题所在
|
||||||
|
4. **检查变量类型**:使用 `typeof` 操作符检查变量类型
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
console.log(typeof "hello"); // "string"
|
||||||
|
console.log(typeof 42); // "number"
|
||||||
|
console.log(typeof true); // "boolean"
|
||||||
|
console.log(typeof {}); // "object"
|
||||||
|
console.log(typeof []); // "object"(数组也是对象的一种)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 实践练习
|
||||||
|
|
||||||
|
### 练习1:创建一个简单的待办事项列表
|
||||||
|
|
||||||
|
使用 HTML、CSS 和 JavaScript 创建一个待办事项列表,包含添加、删除和标记完成功能。
|
||||||
|
|
||||||
|
提示:
|
||||||
|
- 使用数组存储待办事项
|
||||||
|
- 使用 DOM 操作动态更新列表
|
||||||
|
- 为按钮添加事件监听器
|
||||||
|
|
||||||
|
### 练习2:实现一个数字猜谜游戏
|
||||||
|
|
||||||
|
计算机随机生成一个1到100之间的数字,玩家通过输入框猜测,程序提示"猜大了"或"猜小了",直到猜对为止。
|
||||||
|
|
||||||
|
提示:
|
||||||
|
- 使用 `Math.random()` 生成随机数
|
||||||
|
- 使用条件语句判断猜测结果
|
||||||
|
- 记录并显示猜测次数
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
JavaScript 是现代 web 开发的核心技术之一,它可以让网页变得动态和交互。通过学习变量、数据类型、运算符、条件语句、循环、函数和 DOM 操作等基础知识,你已经迈出了学习 JavaScript 的第一步。
|
||||||
|
|
||||||
|
继续练习和探索,你会发现 JavaScript 的强大功能和灵活性!
|
||||||
@@ -6,7 +6,79 @@ permalink: /subject/english/grammar/
|
|||||||
|
|
||||||
# 核心语法与句型
|
# 核心语法与句型
|
||||||
|
|
||||||
- 时态与语态
|
## 时态与语态
|
||||||
- 从句(名词性、定语、状语)
|
- 16 种时态的构成与用法(一般/进行/完成/完成进行 × 现在/过去/将来/过去将来)
|
||||||
- 非谓语动词与倒装虚拟
|
- 被动语态的转换规则与适用场景
|
||||||
- 句式与信息焦点(强调、分裂句)
|
- 时态一致原则(主将从现、过去时一致等)
|
||||||
|
- 情态动词 + 完成体(must have done / should have done 等)的推测与虚拟含义
|
||||||
|
|
||||||
|
## 从句
|
||||||
|
### 名词性从句
|
||||||
|
- 主语从句(That he failed surprised us. / Whether she comes matters.)
|
||||||
|
- 宾语从句(I think (that) you are right.)
|
||||||
|
- 表语从句(The truth is that he lied.)
|
||||||
|
- 同位语从句(The fact that he lied shocked us.)
|
||||||
|
|
||||||
|
### 定语从句
|
||||||
|
- 限定性 vs. 非限定性
|
||||||
|
- 关系代词(who / whom / whose / which / that)与关系副词(when / where / why)
|
||||||
|
- 介词 + 关系代词(the house in which I live)
|
||||||
|
- 省略与替代(the book (that) I bought; the place (where) we met)
|
||||||
|
|
||||||
|
### 状语从句
|
||||||
|
- 时间(when / while / before / after / as soon as / until)
|
||||||
|
- 条件(if / unless / provided that / on condition that)
|
||||||
|
- 让步(though / although / even if / while)
|
||||||
|
- 原因(because / since / as / now that)
|
||||||
|
- 结果(so...that / such...that)
|
||||||
|
- 目的(so that / in order that)
|
||||||
|
- 比较(than / as...as / the more...the more)
|
||||||
|
|
||||||
|
## 非谓语动词
|
||||||
|
- 不定式(to do):作主语、宾语、定语、状语、补语
|
||||||
|
- 动名词(doing):作主语、宾语、表语、定语
|
||||||
|
- 现在分词(doing)与过去分词(done):作定语、状语、补语、表语
|
||||||
|
- 独立主格结构(with + O + OC; N + doing / done...)
|
||||||
|
- 非谓语动词的时态与语态(to be doing / to have done / being done / having been done)
|
||||||
|
|
||||||
|
## 倒装与虚拟
|
||||||
|
### 倒装
|
||||||
|
- 否定副词置前(Never have I seen...)
|
||||||
|
- Only + 状语置前(Only then did I realize...)
|
||||||
|
- So / Such 置前(So fast did he run that...)
|
||||||
|
- 方位/时间副词置前(Out rushed the children.)
|
||||||
|
- 虚拟条件句省略 if(Were I you... / Had I known...)
|
||||||
|
|
||||||
|
### 虚拟语气
|
||||||
|
- 与现在事实相反(If I were you, I would...)
|
||||||
|
- 与过去事实相反(If I had known, I would have...)
|
||||||
|
- 与将来事实相反(If it should rain tomorrow...)
|
||||||
|
- 省略 if 的倒装(Were / Should / Had...)
|
||||||
|
- 含蓄虚拟(without / but for / otherwise)
|
||||||
|
- 名词性从句中的虚拟(insist that... (should) do; It is important that... (should) do)
|
||||||
|
|
||||||
|
## 句式与信息焦点
|
||||||
|
### 强调结构
|
||||||
|
- It is / was...that / who...(It was John that/who broke the window.)
|
||||||
|
- 助动词 do / does / did(She did tell me the truth.)
|
||||||
|
- 副词强调(absolutely / definitely / simply)
|
||||||
|
|
||||||
|
### 分裂句(Cleft Sentence)
|
||||||
|
- 主语分裂(What I need is time.)
|
||||||
|
- 宾语分裂(What he bought was a Ferrari.)
|
||||||
|
- 状语分裂(Where we met was in Paris.)
|
||||||
|
|
||||||
|
### 平行与省略
|
||||||
|
- 并列结构中的省略(He likes tea and she coffee.)
|
||||||
|
- 比较结构中的省略(I like her better than him.)
|
||||||
|
- 替代(do / so / one / that / those)
|
||||||
|
|
||||||
|
### 插入语与同位语
|
||||||
|
- 破折号、括号、逗号插入(The book—which I bought yesterday—is amazing.)
|
||||||
|
- 同位语短语(Mr. Smith, CEO of the company, will attend.)
|
||||||
|
|
||||||
|
### 长难句拆解策略
|
||||||
|
- 找谓语,定主干
|
||||||
|
- 划从句,标连接词
|
||||||
|
- 去插入,还省略
|
||||||
|
- 调语序,还原文
|
||||||
|
|||||||
193
docs/notes/theory/cryptography/README.md
Normal file
193
docs/notes/theory/cryptography/README.md
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
---
|
||||||
|
title: 密码学基础
|
||||||
|
createTime: 2025/10/27 10:38:57
|
||||||
|
permalink: /theory/cryptography/
|
||||||
|
---
|
||||||
|
|
||||||
|
# 密码学基础
|
||||||
|
|
||||||
|
## 1. 密码学的定义
|
||||||
|
|
||||||
|
### 1.1 基本概念
|
||||||
|
|
||||||
|
**密码学(Cryptography)** 是一门研究信息安全的学科,主要关注如何在不安全的环境中实现安全通信。其核心是通过数学方法对信息进行变换,使得只有授权方能够理解信息内容。
|
||||||
|
|
||||||
|
### 1.2 核心目标
|
||||||
|
|
||||||
|
密码学追求以下四个主要安全目标:
|
||||||
|
|
||||||
|
- **机密性(Confidentiality)**:确保信息只能被授权的人访问
|
||||||
|
- **完整性(Integrity)**:确保信息在传输过程中不被篡改
|
||||||
|
- **认证性(Authentication)**:确认通信双方的身份真实性
|
||||||
|
- **不可否认性(Non-repudiation)**:防止发送方事后否认发送过信息
|
||||||
|
|
||||||
|
### 1.3 重要作用
|
||||||
|
|
||||||
|
密码学在现代信息安全中扮演着至关重要的角色:
|
||||||
|
|
||||||
|
- 保护个人隐私和商业机密
|
||||||
|
- 确保金融交易的安全性
|
||||||
|
- 维护国家安全和军事通信
|
||||||
|
- 支撑互联网基础设施的安全运行
|
||||||
|
|
||||||
|
### 1.4 主要应用场景
|
||||||
|
|
||||||
|
- **网络安全**:HTTPS、VPN、SSL/TLS协议
|
||||||
|
- **数字身份认证**:数字证书、数字签名、双因素认证
|
||||||
|
- **区块链技术**:加密货币、智能合约、分布式账本
|
||||||
|
- **移动通信**:SIM卡加密、移动支付安全
|
||||||
|
- **物联网安全**:设备身份认证、数据传输加密
|
||||||
|
|
||||||
|
### 1.5 基础概念与术语(入门)
|
||||||
|
|
||||||
|
为方便初学者快速建立直觉,先认识密码学中最核心的几个概念:
|
||||||
|
|
||||||
|
**明文(Plaintext)与密文(Ciphertext)**
|
||||||
|
- 明文:未加密的原始消息,例如“HELLO”。
|
||||||
|
- 密文:加密后的消息,人类或未授权系统难以直接理解。
|
||||||
|
|
||||||
|
**加密(Encryption)与解密(Decryption)**
|
||||||
|
- 加密:用密钥将明文转换为密文,记为:
|
||||||
|
|
||||||
|
$$
|
||||||
|
C = E_k(P)
|
||||||
|
$$
|
||||||
|
|
||||||
|
- 解密:用密钥将密文还原为明文,记为:
|
||||||
|
|
||||||
|
$$
|
||||||
|
P = D_k(C)
|
||||||
|
$$
|
||||||
|
|
||||||
|
其中,$P$ 表示明文,$C$ 表示密文,$k$ 表示密钥,$E$ 为加密算法,$D$ 为解密算法。
|
||||||
|
|
||||||
|
**密钥(Key):对称密钥 vs 非对称密钥**
|
||||||
|
- 对称密钥:加密和解密使用相同的密钥,速度快,但密钥分发与管理是难点。
|
||||||
|
- 非对称密钥(公钥密码):加密使用“公钥”,解密使用“私钥”,便于密钥分发,还能支持数字签名。
|
||||||
|
|
||||||
|
对称加密流程示意(同一把密钥):
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
S[发送者] -- 使用共享密钥 K 加密 --> C[(密文)]
|
||||||
|
C -- 使用共享密钥 K 解密 --> R[接收者]
|
||||||
|
```
|
||||||
|
|
||||||
|
非对称加密流程示意(公钥/私钥):
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
S[发送者] -- 使用接收者公钥加密 --> C[(密文)]
|
||||||
|
C -- 使用接收者私钥解密 --> R[接收者]
|
||||||
|
```
|
||||||
|
|
||||||
|
在典型的 RSA 公钥体制中,还可以用一个简洁的数学表达式表示加解密:
|
||||||
|
|
||||||
|
$$
|
||||||
|
\begin{aligned}
|
||||||
|
c &= m^{e} \bmod n,\\
|
||||||
|
m &= c^{d} \bmod n,
|
||||||
|
\end{aligned}
|
||||||
|
$$
|
||||||
|
|
||||||
|
其中 $(e, n)$ 为公钥,$(d, n)$ 为私钥,$m$ 为明文,$c$ 为密文。
|
||||||
|
|
||||||
|
**常见攻击模型简介(只需直观理解)**
|
||||||
|
- 唯密文攻击(COA):攻击者只有密文,尝试恢复明文或密钥。
|
||||||
|
- 已知明文攻击(KPA):攻击者拥有部分“明文-密文”对,用于分析算法或密钥。
|
||||||
|
- 选择明文攻击(CPA):攻击者可选择明文并获取其密文,用于推断密钥或算法结构。
|
||||||
|
- 选择密文攻击(CCA):攻击者可选择密文并得到其解密结果,进一步分析系统弱点。
|
||||||
|
|
||||||
|
直观结论:设计良好的现代密码系统,应当在这些攻击模型下仍保持安全(在合理的参数与假设下)。
|
||||||
|
|
||||||
|
## 2. 密码学历史简述
|
||||||
|
|
||||||
|
### 2.1 古代密码学(公元前-15世纪)
|
||||||
|
|
||||||
|
**凯撒密码(Caesar Cipher)**
|
||||||
|
- 时间:公元前1世纪
|
||||||
|
- 原理:字母移位加密
|
||||||
|
- 示例:将字母向后移动3位,A→D,B→E
|
||||||
|
|
||||||
|
**斯巴达密码棒(Scytale)**
|
||||||
|
- 时间:公元前5世纪
|
||||||
|
- 原理:缠绕在特定直径木棒上的皮条
|
||||||
|
|
||||||
|
古典密码简述:
|
||||||
|
- 核心思路:替换或移位(重新排列)字符。
|
||||||
|
- 代表示例:凯撒(替换)、栅栏(移位)、维吉尼亚(多表替换)。
|
||||||
|
- 直觉目标:混淆结构、增加猜测难度;但易受频率分析。
|
||||||
|
|
||||||
|
### 2.2 文艺复兴时期(15-18世纪)
|
||||||
|
|
||||||
|
**维吉尼亚密码(Vigenère Cipher)**
|
||||||
|
- 时间:16世纪
|
||||||
|
- 原理:多表替换密码
|
||||||
|
- 特点:比单表替换更安全
|
||||||
|
|
||||||
|
**博福特密码(Beaufort Cipher)**
|
||||||
|
- 时间:18世纪
|
||||||
|
- 原理:改进的维吉尼亚密码
|
||||||
|
|
||||||
|
### 2.3 近代密码学(19-20世纪中期)
|
||||||
|
|
||||||
|
**恩尼格玛密码机(Enigma)**
|
||||||
|
- 时间:二战时期
|
||||||
|
- 原理:机械转子密码机
|
||||||
|
- 重要性:推动了现代密码分析的发展
|
||||||
|
|
||||||
|
**香农的信息论**
|
||||||
|
- 时间:1949年
|
||||||
|
- 贡献:为密码学奠定了数学理论基础
|
||||||
|
|
||||||
|
### 2.4 现代密码学(1970年代至今)
|
||||||
|
|
||||||
|
**DES算法**
|
||||||
|
- 时间:1977年
|
||||||
|
- 意义:第一个公开的加密标准
|
||||||
|
|
||||||
|
**RSA算法**
|
||||||
|
- 时间:1977年
|
||||||
|
- 意义:第一个实用的公钥密码系统
|
||||||
|
|
||||||
|
**AES算法**
|
||||||
|
- 时间:2001年
|
||||||
|
- 意义:取代DES的新一代加密标准
|
||||||
|
|
||||||
|
现代密码简述:
|
||||||
|
- 对称加密:同一密钥加解密,适合大量数据(示例:AES/DES/3DES)。
|
||||||
|
|
||||||
|
$$
|
||||||
|
C = E_k(P), \quad P = D_k(C)
|
||||||
|
$$
|
||||||
|
|
||||||
|
- 非对称加密:公钥加密、私钥解密,便于密钥分发与数字签名(示例:RSA/ECC)。
|
||||||
|
|
||||||
|
$$
|
||||||
|
c = m^{e} \bmod n, \quad m = c^{d} \bmod n
|
||||||
|
$$
|
||||||
|
|
||||||
|
- 密钥交换:Diffie–Hellman 在不安全信道建立共享密钥。
|
||||||
|
- 数字签名:私钥签名、公钥验证,保障真实性与不可否认性。
|
||||||
|
|
||||||
|
### 2.5 关键历史时间线
|
||||||
|
|
||||||
|
```
|
||||||
|
公元前5世纪:斯巴达密码棒
|
||||||
|
公元前1世纪:凯撒密码
|
||||||
|
16世纪:维吉尼亚密码
|
||||||
|
1918年:一次一密密码本
|
||||||
|
1949年:香农信息论
|
||||||
|
1977年:DES和RSA算法
|
||||||
|
2001年:AES标准
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 总结
|
||||||
|
|
||||||
|
密码学作为信息安全的基石,经历了从简单替换到复杂数学算法的漫长发展历程。现代密码学建立在严格的数学基础之上,通过对称加密、非对称加密等多种技术手段,为数字世界提供了可靠的安全保障。
|
||||||
|
|
||||||
|
理解密码学的基本原理和分类,有助于我们更好地应用这些技术来保护信息安全,同时也为深入学习更高级的密码学概念奠定基础。
|
||||||
|
|
||||||
|
本篇笔记的所有代码开源于:[https://gitea.simengweb.com/si-meng-spec/cryptography-example-code](https://gitea.simengweb.com/si-meng-spec/cryptography-example-code)
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
---
|
||||||
|
title: 置换密码 - 等待完善
|
||||||
|
createTime: 2025/10/29 13:50:49
|
||||||
|
permalink: /theory/cryptography/permutation-encryption/
|
||||||
|
---
|
||||||
|
|
||||||
|
# 置换密码(Permutation / Transposition Ciphers)
|
||||||
|
|
||||||
|
置换密码的核心思想不是“把字母换成别的字母”(替换),而是**重新排列明文字符的位置**。也就是说:
|
||||||
|
- 明文字母的集合不变,顺序发生了改变;
|
||||||
|
- 由于字母频率不变,置换密码依然会暴露统计特征,但单词的结构与位置模式被打散。
|
||||||
|
|
||||||
|
与“替换密码”相比,置换密码更像是“洗牌”:把原本顺序排列的牌重新打乱。单独使用时并不安全,但与替换联合使用(乘积密码)能显著增强安全性。
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
P[明文] --> A{根据密钥生成位置}
|
||||||
|
A --> B[重新排列字符]
|
||||||
|
B --> C[密文]
|
||||||
|
```
|
||||||
|
|
||||||
|
## 一、栅栏密码(Rail Fence Cipher)
|
||||||
|
|
||||||
|
**工作原理**:
|
||||||
|
将明文按“Z字形”写入若干行(称为“栅栏/轨道”),再按行依次读出即得到密文。轨道数即为密钥。
|
||||||
|
|
||||||
|
**示意**(以 3 轨为例):
|
||||||
|
```
|
||||||
|
轨1: 0 4 8 ...
|
||||||
|
轨2: 1 3 5 7 9 ...
|
||||||
|
轨3: 2 6 ...
|
||||||
|
```
|
||||||
|
|
||||||
|
**示例**:
|
||||||
|
明文:`HELLOWORLD`
|
||||||
|
轨道数:`3`
|
||||||
|
- 轨1(索引 0,4,8):`H O L`
|
||||||
|
- 轨2(索引 1,3,5,7,9):`E L W R D`
|
||||||
|
- 轨3(索引 2,6):`L O`
|
||||||
|
|
||||||
|
密文为各轨串联:`HOL` + `ELWRD` + `LO` → `HOLELWRDLO`
|
||||||
|
|
||||||
|
**数学表示**:
|
||||||
|
设明文 $P = p_0 p_1 \dots p_{n-1}$,根据密钥生成一个位置序列 $s_0, s_1, \dots, s_{n-1}$(即置换次序),则:
|
||||||
|
$$
|
||||||
|
C_j = p_{s_j}, \quad j = 0,1,\dots,n-1
|
||||||
|
$$
|
||||||
|
解密使用逆序列 $t = s^{-1}$:
|
||||||
|
$$
|
||||||
|
p_i = C_{t_i}, \quad i = 0,1,\dots,n-1
|
||||||
|
$$
|
||||||
|
|
||||||
|
**特点**:
|
||||||
|
- 实现简单,直观“打乱顺序”
|
||||||
|
- 频率不变,难以抵抗纯统计分析;但位置模式被破坏,较难直接猜词
|
||||||
|
- 作为教学与与替换密码的组合(乘积密码)更有价值
|
||||||
|
|
||||||
|
## 二、列移位置换(Columnar Transposition)
|
||||||
|
|
||||||
|
**工作原理**:
|
||||||
|
选择一个关键词,将明文按列填入表格,再按关键词的字母排序对列进行重排,最终按列或按行读出密文。
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
A[明文填入表格] --> B{按关键词排序列}
|
||||||
|
B --> C[重排读取]
|
||||||
|
C --> D[密文]
|
||||||
|
```
|
||||||
|
|
||||||
|
**简例(概念演示)**:
|
||||||
|
明文:`ATTACKATDAWN`
|
||||||
|
关键词:`ZEBRA`(按字母表排序为 `A B E R Z`)
|
||||||
|
1) 将明文逐行填入 5 列表格;
|
||||||
|
2) 按关键词排序(A→B→E→R→Z)重排列;
|
||||||
|
3) 按重排后的列依次读出密文。
|
||||||
|
|
||||||
|
(实际实现时需要处理明文长度不足一整行的填充策略,如使用 `X` 或留空。)
|
||||||
|
|
||||||
|
**数学表示(一般置换模型)**:
|
||||||
|
关键词决定一个列置换 $\pi$,其作用是重新排列列索引。若把明文按列读取为序列 $P$,加密可抽象为:
|
||||||
|
$$
|
||||||
|
C = \operatorname{Permute}_{\pi}(P), \quad P = \operatorname{Permute}_{\pi^{-1}}(C)
|
||||||
|
$$
|
||||||
|
|
||||||
|
**特点**:
|
||||||
|
- 比栅栏更灵活,关键词让置换更“难猜”
|
||||||
|
- 仍保留频率分布,易受已知明文/选择明文的结构分析攻击
|
||||||
|
- 常与替换结合形成更强的乘积密码(如 ADFGX/ADFGVX 密码)
|
||||||
|
|
||||||
|
## 三、联合与加固:置换 × 替换
|
||||||
|
|
||||||
|
将“替换”与“置换”组合(先替换后置换,或多轮交替)能显著增强安全性:
|
||||||
|
- 替换打乱统计特征(字母频率分布变平)
|
||||||
|
- 置换打乱位置结构(模式与相邻关系被破坏)
|
||||||
|
|
||||||
|
这种思路在现代密码设计中仍然常见(“混淆与扩散”理念),尽管算法形式已经大为不同。
|
||||||
|
|
||||||
|
## 四、安全性与弱点(直观理解)
|
||||||
|
- 单独的置换密码不改变字母频率,抵抗统计攻击能力有限
|
||||||
|
- 容易受到已知明文/选择明文攻击(通过结构猜测置换)
|
||||||
|
- 多轮、复杂置换能提高攻击成本,但不建议单独用于实际安全场景
|
||||||
|
|
||||||
|
## 五、小练习(可选)
|
||||||
|
试着把你自己的名字用 3 轨栅栏加密;然后写出解密过程(先确定轨道索引,再按逆序重建原文)。
|
||||||
|
|
||||||
|
## 附件:
|
||||||
|
具体的使用样例代码请参考:[https://gitea.simengweb.com/si-meng-spec/cryptography-example-code](https://gitea.simengweb.com/si-meng-spec/cryptography-example-code)
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
---
|
||||||
|
title: 替换密码
|
||||||
|
createTime: 2025/10/27 10:47:42
|
||||||
|
permalink: /theory/cryptography/substitution-ciphers/
|
||||||
|
---
|
||||||
|
|
||||||
|
# 替换密码(Substitution Ciphers)
|
||||||
|
|
||||||
|
我们一起来系统梳理古典加密算法(Classical Ciphers)。这些算法虽然在现代已不再安全,但它们是密码学发展的基石,蕴含了替换、置换、密钥等核心思想,非常适合理解密码学的基本原理。
|
||||||
|
|
||||||
|
替换密码的核心思想是“一对一”或“多对一”的字符映射:把明文中的每一个字母(或符号)按照事先约定好的规则,替换成另一个字母(或符号)。
|
||||||
|
|
||||||
|
这种映射可以是固定不变的(如凯撒密码的“统一移位”),也可以是依赖密钥动态变化的(如维吉尼亚密码的“周期移位”)。
|
||||||
|
|
||||||
|
由于密文保留了原始字母的出现频率,只是“换了一张皮”,所以替换密码在本质上没有改变字母的统计特性,这也为频率分析攻击留下了突破口。
|
||||||
|
|
||||||
|
替换操作可以手工完成,也可以通过查表、转盘、甚至机械电路实现,是后续更复杂多表替换与乘积密码的雏形。
|
||||||
|
|
||||||
|
## 一、凯撒密码(Caesar Cipher)
|
||||||
|
|
||||||
|
**工作原理**:
|
||||||
|
凯撒密码是一种循环移位密码,将字母表视为一个环形结构。加密时每个字母向后移动固定位置 $k$,解密时向前移动相同位置。
|
||||||
|
|
||||||
|
**数学表示**:
|
||||||
|
设字母 A-Z 对应数字 0-25,则:
|
||||||
|
|
||||||
|
加密公式:
|
||||||
|
$$E(x) = (x + k) \mod 26$$
|
||||||
|
|
||||||
|
解密公式:
|
||||||
|
$$D(x) = (x - k) \mod 26$$
|
||||||
|
|
||||||
|
其中 $x$ 是明文字母编号,$k$ 是密钥(0 ≤ k ≤ 25)。
|
||||||
|
|
||||||
|
**特点**:
|
||||||
|
- 实现简单,易于理解
|
||||||
|
- 密钥空间仅 $26$ 种可能,安全性极低
|
||||||
|
- 易受频率分析攻击
|
||||||
|
- 主要具有教学价值
|
||||||
|
|
||||||
|
|
||||||
|
## 二、单表替换密码(Simple Substitution Cipher)
|
||||||
|
|
||||||
|
**工作原理**:
|
||||||
|
单表替换密码是凯撒密码的泛化形式,它使用一个随机的字母替换表,而不是固定的移位。每个明文字母都被唯一地映射到一个密文字母,形成一对一的替换关系。
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
A[明文字母] --> B{替换表}
|
||||||
|
B --> C[密文字母]
|
||||||
|
```
|
||||||
|
|
||||||
|
**数学表示**:
|
||||||
|
设字母表 $\Sigma = \{A,B,C,...,Z\}$,替换函数 $f: \Sigma \rightarrow \Sigma$ 是一个双射(一一对应),则:
|
||||||
|
|
||||||
|
加密公式:
|
||||||
|
$$E(x) = f(x)$$
|
||||||
|
|
||||||
|
解密公式:
|
||||||
|
$$D(y) = f^{-1}(y)$$
|
||||||
|
|
||||||
|
其中 $f^{-1}$ 是 $f$ 的逆函数。
|
||||||
|
|
||||||
|
**密钥空间**:
|
||||||
|
单表替换密码的密钥空间是所有可能的字母排列,大小为:
|
||||||
|
$$|K| = 26! \approx 4.03 \times 10^{26}$$
|
||||||
|
|
||||||
|
这个巨大的密钥空间使得暴力破解在计算上不可行。
|
||||||
|
|
||||||
|
**示例**:
|
||||||
|
假设替换表为:
|
||||||
|
```
|
||||||
|
A→Q, B→W, C→E, D→R, E→T, F→Y, G→U, H→I, I→O, J→P,
|
||||||
|
K→A, L→S, M→D, N→F, O→G, P→H, Q→J, R→K, S→L, T→Z,
|
||||||
|
U→X, V→C, W→V, X→B, Y→N, Z→M
|
||||||
|
```
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
A[明文: HELLO] --> B[替换加密]
|
||||||
|
B --> C[密文: ITSSG]
|
||||||
|
C --> D[逆替换解密]
|
||||||
|
D --> E[明文: HELLO]
|
||||||
|
```
|
||||||
|
|
||||||
|
**安全性分析**:
|
||||||
|
虽然单表替换密码的密钥空间巨大,但它仍然易受**频率分析攻击**。因为:
|
||||||
|
|
||||||
|
1. **字母频率保留**:高频字母(如E、T、A)在密文中仍然是高频
|
||||||
|
2. **单词模式保留**:常见单词模式(如"THE"、"ING")在密文中保持相同模式
|
||||||
|
3. **双字母频率**:常见字母对(如"TH"、"ER")的频率特征仍然存在
|
||||||
|
|
||||||
|
**攻击方法**:
|
||||||
|
- 单字母频率分析
|
||||||
|
- 双字母频率分析
|
||||||
|
- 单词长度和模式分析
|
||||||
|
- 已知明文攻击
|
||||||
|
|
||||||
|
**特点**:
|
||||||
|
- 密钥空间巨大($26!$),理论上难以暴力破解
|
||||||
|
- 仍然易受统计攻击
|
||||||
|
- 是密码学历史上重要的里程碑
|
||||||
|
- 为现代密码学提供了重要启示
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 三、维吉尼亚密码(Vigenère Cipher)
|
||||||
|
|
||||||
|
**工作原理**:
|
||||||
|
维吉尼亚密码是一种多表替换密码,它使用一个关键词来决定每次替换的凯撒密码移位量。关键词的每个字母对应一个移位量,明文的每个字母根据关键词的循环使用进行替换。
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph LR
|
||||||
|
A[明文] --> B{关键词循环扩展}
|
||||||
|
B --> C[明文与关键词按位组合]
|
||||||
|
C --> D{多表替换}
|
||||||
|
D --> E[密文]
|
||||||
|
```
|
||||||
|
|
||||||
|
**数学表示**:
|
||||||
|
设字母 A-Z 对应数字 0-25。
|
||||||
|
明文 $P = p_0 p_1 ... p_{n-1}$
|
||||||
|
关键词 $K = k_0 k_1 ... k_{m-1}$ (长度为 $m$)
|
||||||
|
|
||||||
|
加密公式:
|
||||||
|
$$E(p_i) = (p_i + k_{i \pmod m}) \mod 26$$
|
||||||
|
|
||||||
|
解密公式:
|
||||||
|
$$D(c_i) = (c_i - k_{i \pmod m}) \mod 26$$
|
||||||
|
|
||||||
|
其中 $p_i$ 是明文第 $i$ 个字母的数字表示,$k_{i \pmod m}$ 是关键词循环后对应第 $i$ 个字母的数字表示,$c_i$ 是密文第 $i$ 个字母的数字表示。
|
||||||
|
|
||||||
|
**示例**:
|
||||||
|
明文:`ATTACKATDAWN`
|
||||||
|
关键词:`LEMON`
|
||||||
|
|
||||||
|
1. **关键词循环扩展**:
|
||||||
|
将关键词 `LEMON` 循环扩展至与明文等长:`LEMONLEMONLE`
|
||||||
|
|
||||||
|
2. **明文与关键词按位组合(数字表示)**:
|
||||||
|
将明文和扩展后的关键词转换为数字 (A=0, B=1, ..., Z=25)。
|
||||||
|
明文数字: `0 19 19 0 2 10 0 19 3 0 22 13`
|
||||||
|
关键词数字: `11 4 12 14 13 11 4 12 14 13 11 4`
|
||||||
|
|
||||||
|
3. **加密运算**:
|
||||||
|
对每对明文数字 $p_i$ 和关键词数字 $k_{i \pmod m}$ 执行 $(p_i + k_{i \pmod m}) \mod 26$ 运算。
|
||||||
|
例如:
|
||||||
|
- 第一个字母:明文 A (0) + 关键词 L (11) = $(0 + 11) \mod 26 = 11 \rightarrow L$
|
||||||
|
- 第二个字母:明文 T (19) + 关键词 E (4) = $(19 + 4) \mod 26 = 23 \rightarrow X$
|
||||||
|
- 第三个字母:明文 T (19) + 关键词 M (12) = $(19 + 12) \mod 26 = 5 \rightarrow F$
|
||||||
|
...
|
||||||
|
最终密文:`LXFOPVEFRNHR`
|
||||||
|
|
||||||
|
|
||||||
|
**安全性分析**:
|
||||||
|
维吉尼亚密码比单表替换密码更安全,因为它引入了**多表替换**,使得密文的字母频率分布趋于平坦,从而抵抗了简单的频率分析攻击。
|
||||||
|
|
||||||
|
然而,它并非绝对安全,主要弱点在于**关键词的周期性**:
|
||||||
|
1. **Kasiski 测试**:通过分析密文中重复出现的字母组,可以推断出关键词的长度。
|
||||||
|
2. **频率分析(针对子密码)**:一旦关键词长度确定,密文可以被分成若干个凯撒密码,然后对每个子密码进行频率分析。
|
||||||
|
|
||||||
|
**特点**:
|
||||||
|
- 多表替换,比单表替换密码更安全
|
||||||
|
- 引入了关键词的概念,增强了密钥的复杂性
|
||||||
|
- 易受Kasiski测试和频率分析的组合攻击
|
||||||
|
- 在历史上曾被认为是“牢不可破的密码”
|
||||||
|
|
||||||
|
|
||||||
|
## 附件:
|
||||||
|
具体的使用样例代码请参考:[https://gitea.simengweb.com/si-meng-spec/cryptography-example-code](https://gitea.simengweb.com/si-meng-spec/cryptography-example-code)
|
||||||
1116
package-lock.json
generated
1116
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,7 @@
|
|||||||
"vuepress-theme-plume": "1.0.0-rc.164"
|
"vuepress-theme-plume": "1.0.0-rc.164"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@waline/client": "^3.6.0"
|
"@waline/client": "^3.6.0",
|
||||||
|
"mermaid": "^11.12.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user