Compare commits
64 Commits
7ac31a3984
...
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 | ||
| 12181dbdcd | |||
| 02ec95b12d | |||
| e097e53603 | |||
| f3dda6078c | |||
|
|
5dba6ac5b4 | ||
| d7d342fd55 | |||
| b734f403b3 | |||
|
|
086835d409 | ||
|
|
69312a780e | ||
|
|
b3b5198eac | ||
|
|
771fa51fb9 | ||
|
|
90ed801658 | ||
|
|
f0e768d66f | ||
|
|
6a508cc8d4 | ||
|
|
6ac5000c86 | ||
|
|
df01754706 | ||
|
|
7e413866c2 | ||
| 95dc8fecf9 | |||
| 807e222e8a | |||
| ba6702c880 | |||
| 5984402fb2 | |||
| 9f28803260 | |||
| e2c883233c | |||
| 564040b8c3 | |||
| 44689736d5 | |||
| cb3747d38c | |||
| eeb0031bf5 | |||
| 3130dcbbc3 | |||
| 056e58c5bd | |||
| 89a3f2182a | |||
| 8eb832de6c | |||
| d831135553 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@ docs/.vuepress/dist
|
||||
.trae/
|
||||
.DS_Store
|
||||
*.log
|
||||
_publish/
|
||||
|
||||
40
README.md
40
README.md
@@ -22,11 +22,43 @@
|
||||
|
||||
## 安装
|
||||
|
||||
确保您的 Node.js 版本符合要求(^20.6.0 || >=22.0.0),然后执行以下命令:
|
||||
- 环境要求:
|
||||
- Node.js:`^20.6.0` 或 `>=22.0.0`(推荐使用当前 LTS 或稳定版)
|
||||
- npm:`>=10`
|
||||
|
||||
```sh
|
||||
npm i
|
||||
```
|
||||
- 安装步骤:
|
||||
1. 在项目根目录执行依赖安装:
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
2. 启动开发服务器(任选其一):
|
||||
- 常规方式:
|
||||
```sh
|
||||
npm run docs:dev
|
||||
```
|
||||
- Windows 快捷方式(尝试监听 `0.0.0.0` 以便局域网访问):
|
||||
```bat
|
||||
.\start.bat
|
||||
```
|
||||
- 若端口或权限受限,使用备用命令(绑定到本机并更换端口):
|
||||
```sh
|
||||
npx vuepress@2.0.0-rc.24 dev docs --port 5173 --host localhost
|
||||
```
|
||||
3. 打开浏览器访问:
|
||||
- `http://localhost:4567/`(默认)或
|
||||
- `http://localhost:5173/`(如果使用备用命令)
|
||||
|
||||
- 常见问题与排查:
|
||||
- “`vuepress` 不是内部或外部命令”:通常为依赖未安装或安装失败,执行 `npm install` 后重试。
|
||||
- “listen EACCES: permission denied 0.0.0.0:4567”:端口或绑定权限受限,改用 `--host localhost` 或更换端口(如 `--port 5173`)。
|
||||
- 需要清理缓存后重试:
|
||||
```sh
|
||||
npm run docs:dev-clean
|
||||
```
|
||||
- 更换端口示例(以 8080 为例):
|
||||
```sh
|
||||
npx vuepress dev docs --port 8080 --host localhost
|
||||
```
|
||||
|
||||
## 使用
|
||||
|
||||
|
||||
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
|
||||
@@ -1,25 +1,36 @@
|
||||
import { defineUserConfig } from 'vuepress'
|
||||
import { plumeTheme } from 'vuepress-theme-plume'
|
||||
import { viteBundler } from '@vuepress/bundler-vite'
|
||||
import { commentPlugin } from '@vuepress/plugin-comment'
|
||||
import { umamiAnalyticsPlugin } from '@vuepress/plugin-umami-analytics'
|
||||
|
||||
export default defineUserConfig({
|
||||
base: '/',
|
||||
lang: 'zh-CN',
|
||||
title: '祀梦的花园',
|
||||
title: '仲夏夜之梦',
|
||||
description: '爱与回忆的小世界,记录生活中的每一份温暖与感动',
|
||||
|
||||
head: [
|
||||
// 配置站点图标
|
||||
['link', { rel: 'icon', type: 'image/png', href: 'https://theme-plume.vuejs.press/favicon-32x32.png' }],
|
||||
],
|
||||
|
||||
bundler: viteBundler(),
|
||||
shouldPrefetch: false, // 站点较大,页面数量较多时,不建议启用
|
||||
shouldPrefetch: false,
|
||||
|
||||
theme: plumeTheme({
|
||||
/* 站点域名,启动 SEO 优化 */
|
||||
hostname: 'https://notes.simengweb.com',
|
||||
/* 博客文章页面链接前缀 */
|
||||
article: '/article/',
|
||||
|
||||
/* 启用数学公式支持和Mermaid图表 */
|
||||
markdown: {
|
||||
math: {
|
||||
type: 'katex',
|
||||
},
|
||||
mermaid: true,
|
||||
demo: true,
|
||||
},
|
||||
/**
|
||||
* 编译缓存,加快编译速度
|
||||
*/
|
||||
@@ -28,10 +39,20 @@ export default defineUserConfig({
|
||||
/* 本地搜索, 默认启用 */
|
||||
search: { provider: 'local' },
|
||||
|
||||
/**
|
||||
* 博客相关配置
|
||||
*/
|
||||
blog: {
|
||||
postCover: {
|
||||
layout: 'left',
|
||||
width: 300,
|
||||
compact: true
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 文章贡献者配置
|
||||
*/
|
||||
// 修改contributors配置
|
||||
contributors: {
|
||||
mode: 'inline',
|
||||
info: [
|
||||
@@ -49,6 +70,25 @@ export default defineUserConfig({
|
||||
*/
|
||||
plugins: {
|
||||
git: true
|
||||
},
|
||||
|
||||
codeHighlighter: {
|
||||
lineNumbers: true,
|
||||
}
|
||||
}),
|
||||
|
||||
plugins: [
|
||||
commentPlugin({
|
||||
provider: 'Waline',
|
||||
serverURL: 'https://vercel.simengweb.com',
|
||||
meta: ['nick'],
|
||||
requiredMeta: ['nick']
|
||||
}),
|
||||
umamiAnalyticsPlugin({
|
||||
id: 'a4f0ca65-2da6-4e6b-a01b-f3b3157d05a3',
|
||||
link: 'https://umami.simengweb.com/script.js',
|
||||
domains: ['notes.simengweb.com'],
|
||||
cache: true
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
@@ -9,6 +9,15 @@ export default defineNavbarConfig([
|
||||
text: '博客',
|
||||
link: '/blog/',
|
||||
},
|
||||
{
|
||||
text: '学科知识',
|
||||
items: [
|
||||
{
|
||||
text: '英语学习笔记',
|
||||
link: '/subject/english/',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: '编程笔记',
|
||||
items: [
|
||||
@@ -24,8 +33,21 @@ export default defineNavbarConfig([
|
||||
text: 'Solidity',
|
||||
link: '/programming/solidity/',
|
||||
},
|
||||
{
|
||||
text: 'Web 开发',
|
||||
link: '/programming/web/',
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
text:"技术理论",
|
||||
items:[
|
||||
{
|
||||
text: '密码学基础',
|
||||
link: '/theory/cryptography/',
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
text: '运维',
|
||||
items: [
|
||||
|
||||
@@ -27,6 +27,53 @@ const cPlusPlus = defineNoteConfig({
|
||||
}
|
||||
]
|
||||
})
|
||||
const english = defineNoteConfig({
|
||||
dir: 'subject',
|
||||
link: '/subject/english/',
|
||||
sidebar: [
|
||||
{ text: "英语学习笔记", link: "/subject/english/" },
|
||||
{
|
||||
text: "学习环境与工具", prefix: "/basis", items: [
|
||||
{ text: "英语环境配置", link: "/subject/english/basis/" }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "词汇与记忆", prefix: "/vocabulary", items: [
|
||||
{ text: "词汇学习与记忆法", link: "/subject/english/vocabulary/" }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "语法与句法", prefix: "/grammar", items: [
|
||||
{ text: "核心语法与句型", link: "/subject/english/grammar/" }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "听力与口语", prefix: "/listening-speaking", items: [
|
||||
{ text: "听力口语训练", link: "/subject/english/listening-speaking/" }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "阅读与写作", prefix: "/reading-writing", items: [
|
||||
{ text: "阅读提升", link: "/subject/english/reading-writing/" }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "写译", prefix: "/writing-translation", items: [
|
||||
{ text: "写作与翻译指南", link: "/subject/english/writing-translation/" }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "考试与备考", prefix: "/exam", items: [
|
||||
{ text: "英语四级 (CET-4) 备考指南", link: "/subject/english/exam/cet-4/" }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "资源与工具", prefix: "/resources", items: [
|
||||
{ text: "学习资源与工具", link: "/subject/english/resources/" }
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
const solidity = defineNoteConfig({
|
||||
dir: 'programming',
|
||||
link: '/programming/solidity/',
|
||||
@@ -35,23 +82,50 @@ const solidity = defineNoteConfig({
|
||||
{
|
||||
text: "基础语法", prefix: "/basic-syntax", items: [
|
||||
{ text: "Solidity 基础语法与数据类型", link: "/programming/solidity/basic-syntax/" }
|
||||
]
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "项目实例", prefix: "/basic-syntax", items: [
|
||||
{ text: "Solidity 代码实例", link: "/programming/solidity/analysis/case-analysis/" }
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "杂项", prefix: "/other", items: [
|
||||
{ text: "Hardhat 相关知识", link: "/programming/solidity/other/hardhat/" },
|
||||
{ text: "一些没分类的小知识", link: "/programming/solidity/other/miscellaneous/" }
|
||||
],
|
||||
}
|
||||
]
|
||||
})
|
||||
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({
|
||||
dir: 'ops',
|
||||
link: '/ops/blockchain',
|
||||
sidebar: [
|
||||
{ text: "区块链运维指南", link: "/ops/blockchain/" },
|
||||
{
|
||||
text: "区块链理论基础", items: [
|
||||
text: "区块链理论基础", prefix: "/theory", items: [
|
||||
{ text: "区块链的基本原理", link: "/ops/blockchain/theory/basic-principles/" },
|
||||
{ text: "FISCO-BCOS 节点类型", link: "/ops/blockchain/theory/fisco-bcos-node-type/" }
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "区块链运维", items: [
|
||||
{ text: "区块链网络部署指南", link: "/ops/blockchain/deployment/" }
|
||||
{ text: "区块链产品设计和基本部署", link: "/ops/blockchain/practice/basic-deployment/" },
|
||||
{ text: "区块链网络部署与管理", link: "/ops/blockchain/practice/node-deployment/" },
|
||||
{ text: "Console 控制台操作", link: "/ops/blockchain/practice/console-operator/" }
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -68,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
|
||||
*/
|
||||
export default defineNotesConfig({
|
||||
dir: 'notes',
|
||||
link: '/',
|
||||
notes: [LeetCode, cPlusPlus, solidity, blockchain, linux],
|
||||
notes: [LeetCode, english, cPlusPlus, solidity, blockchain, linux, cryptography, web],
|
||||
})
|
||||
|
||||
@@ -3,7 +3,7 @@ import navbar from './navbar'
|
||||
import notes from './notes'
|
||||
|
||||
export default defineThemeConfig({
|
||||
logo: 'https://theme-plume.vuejs.press/plume.png',
|
||||
logo: '/plume.svg',
|
||||
|
||||
appearance: true, // 深色模式
|
||||
|
||||
@@ -15,7 +15,7 @@ export default defineThemeConfig({
|
||||
* @see https://theme-plume.vuejs.press/config/basic/#profile
|
||||
*/
|
||||
profile: {
|
||||
avatar: 'https://theme-plume.vuejs.press/plume.png',
|
||||
avatar: 'https://image.simengweb.com/elysia/header.jpg',
|
||||
name: 'SiMengWebSite Notes',
|
||||
description: '祀梦的笔记网站',
|
||||
},
|
||||
|
||||
@@ -1,8 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 72 72">
|
||||
<path fill="#5086a1" d="M42.334 49.147a29.945 29.945 0 0 1-19.338-8.151c-8.014-7.365-8.378-18.076-8.533-22.649l-.022-.627a2.904 2.904 0 0 1 3.457-2.951c17.005 3.355 21.695 16.324 22.056 17.4a49.543 49.543 0 0 1 3.574 15.922a1 1 0 0 1-.967 1.052c-.029.001-.106.004-.227.004" />
|
||||
<path fill="#8cccd5" d="M44.436 55.316c-11.646 0-17.376-6.974-17.653-7.354a1 1 0 0 1 .262-1.424a11.103 11.103 0 0 1 12.774-1.574c-1.465-9.078 1.877-13.568 2.031-13.77a.998.998 0 0 1 .75-.39a.97.97 0 0 1 .78.325c8.944 9.771 8.793 16.532 7.908 19.691c-.034.14-1.062 4.092-4.772 4.406c-.711.062-1.405.09-2.08.09" />
|
||||
<g fill="none" stroke="#333" stroke-linecap="round" stroke-linejoin="round" stroke-width="1">
|
||||
<path d="M55.184 57.69S34.96 45.877 23.097 24.206m22.131 30.096c-11.93.46-17.628-6.88-17.628-6.88" />
|
||||
<path d="M40.528 42.483c-.56-7.195 2.116-10.679 2.116-10.679c8.834 9.654 8.406 16.162 7.681 18.747m-13.311-3.129a30.15 30.15 0 0 1-13.341-7.162c-8.072-7.419-8.067-18.241-8.232-22.577a1.903 1.903 0 0 1 2.264-1.932C34.694 19.103 39.02 32.528 39.02 32.528" />
|
||||
</g>
|
||||
</svg>
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1759225877144" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1685" width="180" height="180" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M480.54625 437.511684l44.454975 31.121042L136.269726 1023.769663l-44.429382-31.121041z" fill="#7AEDE5" p-id="1686"></path><path d="M96.370298 986.352753l75.499238-13.30834 44.019894-62.958687-75.499237 13.308341-44.019895 62.958686zM174.172902 875.279298l75.499238-13.30834 44.019895-62.702757-75.499238 13.30834L174.172902 875.279298zM251.975507 764.205843l75.499237-13.30834 44.019895-62.702757-75.499238 13.308341-44.019894 62.702756zM329.778111 653.132389l75.499238-13.308341 43.763965-62.702756-75.499238 13.30834-43.763965 62.702757zM407.324786 542.058934l75.499237-13.30834 42.228388-60.143461-2.559297-1.791507-71.148434 12.540551-44.019894 62.702757z" fill="#44DCDF" p-id="1687"></path><path d="M864.159156 209.606358a184.013396 184.013396 0 0 0-179.150733-17.147284 185.293044 185.293044 0 0 0-76.778886-162.259379 151.254405 151.254405 0 0 0-217.028317 39.413161c-37.365724 54.768939-55.536727 131.547824-27.896329 230.336658a695.616705 695.616705 0 0 0 104.931144 204.743695 688.194746 688.194746 0 0 0 227.265502 28.920047 266.166804 266.166804 0 0 0 206.279273-104.675214 150.998475 150.998475 0 0 0-37.621654-219.331684z" fill="#f7adaf" p-id="1688"></path><path d="M925.326335 378.263977a147.67139 147.67139 0 0 0-61.167179-168.657619 184.013396 184.013396 0 0 0-179.150733-17.147284 185.293044 185.293044 0 0 0-76.778886-162.259379 151.254405 151.254405 0 0 0-217.028317 39.413161c-37.365724 54.768939-55.536727 131.547824-27.896329 230.336658a440.198945 440.198945 0 0 0 14.843918 43.763965l7.677889 5.886381c186.316763 129.756317 412.046687 137.946065 539.499637 28.664117z" fill="#f9babc" p-id="1689"></path><path d="M479.710939 66.563528m-10.422459 14.884814a18.171003 18.171003 0 1 0 20.844918-29.769628 18.171003 18.171003 0 1 0-20.844918 29.769628Z" fill="#FFFFFF" p-id="1690"></path><path d="M423.448352 97.253255c15.611707-15.611707 30.711554-10.493114 31.735273 0s-17.403214 15.867636-36.342006 60.399391a764.717703 764.717703 0 0 0-23.033666 81.129689c-5.374522 6.65417-10.493114-41.716528-1.535578-81.897478a131.547824 131.547824 0 0 1 29.175977-59.631602z" fill="#FFFFFF" p-id="1691"></path><path d="M428.566944 597.083802a321.703532 321.703532 0 0 1 98.021044 0c27.12854 6.65417 41.204669 24.057384 36.342006 47.09105s-29.687836 29.687836-41.972457 48.882557c-18.426933 28.408188-13.30834 37.621654-27.12854 55.536728a34.038639 34.038639 0 0 1-54.768939-2.303367 463.232611 463.232611 0 0 1-57.072305-102.371848zM392.992727 572.258629A320.935743 320.935743 0 0 0 358.442228 480.379896c-15.867636-23.289595-36.853865-30.711554-57.072305-18.171003s-17.659144 38.133513-31.223413 56.304516c-20.47437 25.592962-30.967484 25.592962-43.252106 44.531754a34.294569 34.294569 0 0 0 20.986229 51.185923 465.791907 465.791907 0 0 0 116.192047 18.426933z" fill="#f7adaf" p-id="1692"></path><path d="M388.130064 568.931544c10.237185-7.166029 35.830147 7.933818 41.204669 20.474369s-10.237185 25.592962-16.123566 36.597936-7.166029 22.521807-19.194722 27.896328a41.460598 41.460598 0 0 1-43.763964-22.777736c-4.862663-11.516833 11.004974-25.592962 22.009947-38.901302 5.886381-6.9101 6.65417-16.891355 15.867636-23.289595z" fill="#fbd2d3" p-id="1693"></path></svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 3.4 KiB |
@@ -7,16 +7,12 @@ config:
|
||||
full: true
|
||||
background: tint-plate
|
||||
hero:
|
||||
name: 祀梦的花园
|
||||
tagline: 爱与回忆的小世界
|
||||
name: 仲夏夜之梦
|
||||
tagline: 祀梦和小小夏的花园
|
||||
text: 在这里,每一个文字都承载着温暖与美好 🌸
|
||||
actions:
|
||||
-
|
||||
theme: brand
|
||||
text: 博客
|
||||
link: /blog/
|
||||
-
|
||||
theme: alt
|
||||
text: 探索笔记 →
|
||||
link: /notes/
|
||||
---
|
||||
|
||||
@@ -9,7 +9,7 @@ permalink: /about/
|
||||
|
||||
# 👋 这里是祀梦的小窝!
|
||||
|
||||
泥嚎~ 欢迎来到祀梦的个人博客,这是我在这个小站发布的第一篇文章哦~ (✧ω✧)
|
||||
嗨~ 欢迎来到祀梦的个人博客,这是我在这个小站发布的第一篇文章哦~ (✧ω✧)
|
||||
|
||||
## 关于站长我呀~ 🌸
|
||||
|
||||
@@ -31,7 +31,7 @@ permalink: /about/
|
||||
|
||||
如果您在网页访问过程中遇到什么问题,或者想要交个朋友的话,欢迎随时来找我玩哦~
|
||||
- 邮箱:meng_si@proton.me
|
||||
- B站:66ccff色的薰依草
|
||||
- B站:[66ccff色的薰依草](https://space.bilibili.com/361714249)
|
||||
|
||||
## 网站的成长记录~ 📝
|
||||
|
||||
|
||||
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 元,让荷包和模型一起“稳稳幸福”吧!
|
||||
149
docs/blog/competition/BRICS2025-ST-132.md
Normal file
149
docs/blog/competition/BRICS2025-ST-132.md
Normal file
@@ -0,0 +1,149 @@
|
||||
---
|
||||
title: 2025 一带一路金砖 - 区块链应用开发与运维 样题详解
|
||||
createTime: 2025/09/30 19:57:14
|
||||
permalink: /article/2025-BR-BRICS-BC-App-Develop-Op-Sample-Q&A/
|
||||
password: simeng
|
||||
---
|
||||
|
||||
## 第一部分:区块链平台运维
|
||||
### 第1题:完成 FISCO BCOS 区块链系统部署并验证
|
||||
**【要求】**
|
||||
|
||||
登录 Linux 服务器,完成节点部署、启动、将过程结果截图,保存至做答题并点击提交。
|
||||
|
||||
**【任务】**
|
||||
|
||||
登录 Linux 服务器,进入指定操作目录(/root/tools)基于开发部署工具 build_chain.sh 脚本在本地搭建一条 4 节点的 FISCO BCOS 链。起始端口号为:30300,20200,8545。将节点 2 的端口号改为 30500,20400,8675。确保搭建的区块链系统能正常运行,并将执行的命令和完整的命令执行结果截图保存至作答区并点击提交。具体任务如下:
|
||||
|
||||
**【参考答案】**
|
||||
|
||||
使用 build_chain.sh 脚本搭建 FISCO BCOS 链:
|
||||
|
||||
默认的 -v 会从网络中下载 FISCO BCOS,这里本地已经有了,比赛的时候肯定是断网的,这里直接调用本地的即可
|
||||
```shell
|
||||
bash build_chain.sh -l "127.0.0.1:4" -p 30300,20200,8545 -e ./fisco-bcos
|
||||
```
|
||||

|
||||
在创建完成之后,当前目录会出现一个 nodes 文件夹,这里面就是我们的每个节点的具体配置信息等等
|
||||
|
||||
这里推荐下载一个 tree 用来查看目录结构
|
||||
```shell
|
||||
apt install tree
|
||||
tree nodes
|
||||
```
|
||||
目录结构应该大概如下:
|
||||
```
|
||||
nodes
|
||||
├── 127.0.0.1
|
||||
│ ├── node0
|
||||
│ │ ├── ...
|
||||
│ ├── node1
|
||||
│ │ ├── ...
|
||||
│ ├── node2
|
||||
│ │ ├── ...
|
||||
│ ├── node3
|
||||
│ │ ├── ...
|
||||
```
|
||||
每个 node 文件夹都包含 `conf/`(配置文件),`log/`(日志文件),`fisco-bcos/`(二进制副本)
|
||||
|
||||
修改节点2的端口,根据要求修改为 30500,20400,8675
|
||||
|
||||
编辑配置文件:`vim nodes/127.0.0.1/node2/config.ini`
|
||||
|
||||
```bash
|
||||
[rpc]
|
||||
channel_listen_ip=0.0.0.0
|
||||
channel_listen_port=20202 # [!code --]
|
||||
channel_listen_port=20400 # [!code ++]
|
||||
jsonrpc_listen_ip=127.0.0.1
|
||||
jsonrpc_listen_port=8547 # [!code --]
|
||||
jsonrpc_listen_port=8675 # [!code ++]
|
||||
disable_dynamic_group=false
|
||||
[p2p]
|
||||
listen_ip=0.0.0.0
|
||||
listen_port=30302 # [!code --]
|
||||
listen_port=30500 # [!code ++]
|
||||
; nodes to connect
|
||||
node.0=127.0.0.1:30300
|
||||
node.1=127.0.0.1:30301
|
||||
node.2=127.0.0.1:30302 # [!code --]
|
||||
node.2=127.0.0.1:30500 # [!code ++]
|
||||
node.3=127.0.0.1:30303
|
||||
```
|
||||
不光节点2的 \[p2p\] 的 `node.2` 需要修改,其他几个节点的都需要进行修改
|
||||
|
||||
切换到 `nodes/127.0.0.1/` 目录下,通过 `bash start_all.sh` 启动所有节点
|
||||
|
||||

|
||||
|
||||
验证端口是否生效:`ss -tuln | grep -E '30500|20400|8675'`
|
||||
|
||||
预期输出如下:
|
||||
|
||||
```bash
|
||||
tcp LISTEN 0 4096 127.0.0.1:8675 0.0.0.0:*
|
||||
tcp LISTEN 0 4096 0.0.0.0:30500 0.0.0.0:*
|
||||
tcp LISTEN 0 4096 0.0.0.0:20400 0.0.0.0:*
|
||||
```
|
||||
|
||||
|
||||
主要参考文章如下:
|
||||
|
||||
1. [搭建第一个区块链网络](https://fisco-doc.readthedocs.io/zh/latest/docs/installation.html)
|
||||
2. [开发部署工具(build_chain.sh)](https://fisco-bcos-documentation.readthedocs.io/zh-cn/latest/docs/manual/build_chain.html)
|
||||
|
||||
### 第2题:按要求完成WeBASE-Node-Manager的安装与部署
|
||||
**【要求】**
|
||||
|
||||
登录 Linux 服务器,部署节点管理平台,并将部署、启动、应用过程结果截图,保存至作答区并点击提交。
|
||||
|
||||
**【任务】**
|
||||
|
||||
登录 linux 服务器,进入指定操作目录(/root/tools/webase)中完成区块链一体化管理平台的配置部署,并检查是否安装成功,具体操作任务如下:
|
||||
1. 进入 WeBASE-Node-Manager 目录,完成数据库初始化操作;
|
||||
2. 修改 application.yml 配置文件,进行 WeBASE-Node-Manager 的服务配置,包括数据库名称,数据库用户,数据库密码等;
|
||||
3. 使用命令启动 WeBASE-Node-Manager 管理平台服务,并检查节点管理是否正常启动;
|
||||
4. 使用 swagger 对节点管理服务的 API 接口测试。
|
||||
|
||||
**【参考答案】**
|
||||
|
||||
切换到 WeBASE-Front 目录下,将 `dist/conf_template` 配置文件目录复制一份作为配置文件,命名为 `dist/conf`
|
||||
```bash
|
||||
# 当前工作目录为:/home/simeng/blockchain/WeBASE-Front
|
||||
cp -r dist/conf_template dist/conf
|
||||
```
|
||||
|
||||
将节点所在目录 `nodes/{$ip}/sdk` 下的所有文件拷贝到当前的 `dist/conf` 目录下
|
||||
```bash
|
||||
cp ../nodes/127.0.0.1/sdk/* ./dist/conf/
|
||||
```
|
||||
|
||||
编辑配置文件 : `vim dist/conf/application.yml`
|
||||
```bash
|
||||
|
||||
```
|
||||
|
||||
配置环境变量 JAVA_HOME
|
||||
编辑配置文件:`~/.bashrc`,添加如下内容
|
||||
```bash
|
||||
export JAVA_HOME="/usr/lib/jvm/java-1.8.0-openjdk-amd64"
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
```
|
||||
刷新环境变量
|
||||
```bash
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
切换到 `dist` 目录下,拉取 Solidity 开发工具 v0.8.11.js(这一步可能会很慢,建议直接把 v0.8.11.js 下载到本地,然后直接放到对应目录,WSL2 的机器是直接挂载在 Windows 上的,Windows 可以直接操作)
|
||||
```bash
|
||||
wget https://github.com/WeBankBlockchain/WeBASELargeFiles/releases/download/v3.0.0/v0.8.11.js -O static/static/js/v0.8.11.js
|
||||
```
|
||||
|
||||
运行 `bash start.sh` 启动 WeBASE-Node-Manager 管理平台服务
|
||||
```bash
|
||||
# 当前工作目录为:/home/simeng/blockchain/WeBASE-Front/dist
|
||||
bash start.sh
|
||||
```
|
||||
|
||||
由于 localhostForwarding 机制(具体参考:[配置WSL2资源](https://notes.simengweb.com/article/operate-wsl2/#%E7%BD%91%E7%BB%9C%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE)),我们可以直接通过localhost来访问WSL2容器的端口的服务
|
||||
访问:[http://localhost:5002/WeBASE-Front](http://localhost:5002/WeBASE-Front)
|
||||
149
docs/blog/technology/Deploying_WSL2_on_Windows_10.md
Normal file
149
docs/blog/technology/Deploying_WSL2_on_Windows_10.md
Normal file
@@ -0,0 +1,149 @@
|
||||
---
|
||||
title: 在 Windows10 上部署 WSL2 并启动 ubuntu 虚拟机
|
||||
createTime: 2025/09/29 07:13:17
|
||||
cover: https://image.simengweb.com/elysia_cover_image/1pK7sI441p7x25YV.jpg
|
||||
coverStyle:
|
||||
layout: right
|
||||
permalink: /article/deploying-wsl2-on-windows-10/
|
||||
---
|
||||
|
||||
嗨呀~让我们在 Windows10 专业版上部署 WSL2 并启动 ubuntu 20.04 虚拟机吧~
|
||||
|
||||
最好使用 Windows10 专业版,并且在物理机上部署呢,在虚拟机上部署的话可能会有小麻烦,所以不太推荐啦~
|
||||
<!-- more -->
|
||||
|
||||
## Windows10 镜像
|
||||
大家好呀~今天要教大家如何在Windows10上部署WSL2并启动ubuntu虚拟机哦~
|
||||
|
||||
首先呢,我们需要准备一个Windows10的镜像文件~虽然Microsoft官方有提供,不过很容易下载失败呢,所以建议大家去[MSDN](https://msdn.itellyou.cn/)下载会更稳定哦~
|
||||
|
||||
在MSDN官网找到「操作系统」→「Window10」→「Windows 10 (Multiple Editions) (x64)」这个版本,它包含了专业版呢~要注意哦,WSL2只支持专业版、企业版或教育版,不支持家庭版呢,所以建议大家直接安装专业版会更方便~
|
||||
|
||||
## 启用WSL2和虚拟机平台
|
||||
接下来,我们需要启用WSL2和虚拟机平台的功能哦~首先以管理员身份打开PowerShell,然后依次运行下面的命令:
|
||||
```powershell
|
||||
# 启用 WSL 功能
|
||||
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
|
||||
|
||||
# 启用虚拟机平台(WSL2 必需)
|
||||
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
|
||||
```
|
||||
运行完成后,记得要重启电脑哦~重启之后,我们还要把WSL2设置为默认版本呢:
|
||||
```powershell
|
||||
# 设置 WSL2 为默认版本
|
||||
wsl --set-default-version 2
|
||||
```
|
||||
|
||||
## 在 WSL2 中安装 ubuntu 20.04 LTS 虚拟机
|
||||
现在到了安装Ubuntu虚拟机的环节啦~还是以管理员身份打开PowerShell,然后依次运行这些命令:
|
||||
```powershell
|
||||
# 查看可用的 Ubuntu 版本
|
||||
wsl --list --online
|
||||
|
||||
# 安装 Ubuntu 20.04 虚拟机
|
||||
wsl --install -d Ubuntu-20.04
|
||||
```
|
||||
安装过程大概是这样的哦~让我们一起来看看:
|
||||
```powershell :collapsed-lines
|
||||
wsl: 使用旧分发注册。请考虑改用基于 tar 的分发。
|
||||
正在下载: Ubuntu 20.04 LTS
|
||||
Ubuntu 20.04 LTS 已下载。
|
||||
已成功安装分发。可以通过 “wsl.exe -d Ubuntu 20.04 LTS” 启动它
|
||||
正在启动 Ubuntu 20.04 LTS...
|
||||
Installing, this may take a few minutes...
|
||||
Please create a default UNIX user account. The username does not need to match your Windows username.
|
||||
For more information visit: https://aka.ms/wslusers
|
||||
Enter new UNIX username: simeng
|
||||
New password:
|
||||
Retype new password:
|
||||
passwd: password updated successfully
|
||||
操作成功完成。
|
||||
wsl: Failed to start the systemd user session for 'root'. See journalctl for more details.
|
||||
Installation successful!
|
||||
wsl: Failed to start the systemd user session for 'simeng'. See journalctl for more details.
|
||||
To run a command as administrator (user "root"), use "sudo <command>".
|
||||
See "man sudo_root" for details.
|
||||
|
||||
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 6.6.87.2-microsoft-standard-WSL2 x86_64)
|
||||
|
||||
* Documentation: https://help.ubuntu.com
|
||||
* Management: https://landscape.canonical.com
|
||||
* Support: https://ubuntu.com/advantage
|
||||
|
||||
System information as of Tue Sep 30 14:27:51 CST 2025
|
||||
|
||||
System load: 0.48 Processes: 74
|
||||
Usage of /: 0.1% of 1006.85GB Users logged in: 1
|
||||
Memory usage: 7% IPv4 address for eth0: 172.31.237.99
|
||||
Swap usage: 0%
|
||||
|
||||
|
||||
Expanded Security Maintenance for Applications is not enabled.
|
||||
|
||||
0 updates can be applied immediately.
|
||||
|
||||
Enable ESM Apps to receive additional future security updates.
|
||||
See https://ubuntu.com/esm or run: sudo pro status
|
||||
|
||||
|
||||
The list of available updates is more than a week old.
|
||||
To check for new updates run: sudo apt update
|
||||
|
||||
|
||||
This message is shown once a day. To disable it please create the
|
||||
/home/simeng/.hushlogin file.
|
||||
simeng@localhost:~$
|
||||
```
|
||||
这样我们就成功安装好Ubuntu虚拟机啦,可以开始使用了哦~
|
||||
### 安装过程中可能会出现的错误
|
||||
|
||||
在安装过程中,可能会遇到一些小问题呢~不过不用担心,已经帮大家准备好了解决方案哦~
|
||||
|
||||
#### 错误码 0x800701bc 缺少更新包
|
||||
如果看到这样的错误信息:
|
||||
```txt
|
||||
Installing, this may take a few minutes...
|
||||
WslRegisterDistribution failed with error: 0x800701bc
|
||||
Error: 0x800701bc WSL 2 ?????????????????? https://aka.ms/wsl2kernel
|
||||
|
||||
Press any key to continue...
|
||||
```
|
||||
这说明系统缺少WSL2所需的Linux内核更新包哦~这时候我们可以打开微软官网的[下载 Linux 内核更新包](https://learn.microsoft.com/zh-cn/windows/wsl/install-manual#step-4---download-the-linux-kernel-update-package)页面,下载最新的包安装就可以解决啦~
|
||||
|
||||
#### 错误码 0x80370102 虚拟化技术没有开启
|
||||
如果遇到这个错误,可能是因为虚拟化技术没有开启哦~如果是在真实机上操作的话,需要进入BIOS开启虚拟化技术呢~开启之后,可以在任务管理器 -> 性能 -> CPU 的详情页面中,看到下方的虚拟化状态显示为「已启用」哦~
|
||||
|
||||

|
||||
|
||||
如果是在虚拟机中操作的话,就需要启用嵌套虚拟化技术啦~以VMware为例:
|
||||
|
||||
先关闭虚拟机,然后找到虚拟机的.vmx配置文件(通常在虚拟机目录下),在文件末尾添加一行:`vhv.enable = "TRUE"`
|
||||
|
||||
保存之后再启动虚拟机就可以啦~如果还是失败的话,建议尝试换用WSL1,或者使用Hyper-V来部署Windows10虚拟机哦~
|
||||
|
||||
## 通过 WSL2 操作 ubuntu 20.04 LTS 虚拟机
|
||||
安装完成后,我们该如何操作Ubuntu虚拟机呢?很简单哦~以管理员身份打开PowerShell,然后运行这个命令查看已安装的虚拟机:
|
||||
```powershell
|
||||
# 查看已安装的虚拟机
|
||||
wsl -l -v
|
||||
```
|
||||
如果前面的步骤都正确的话,这里应该可以看到一个Ubuntu-20.04的虚拟机啦~
|
||||
|
||||
另外,在文件资源管理器中,会多出一个Linux文件夹,里面有一个Ubuntu-20.04文件夹,这就是虚拟机的根目录哦~
|
||||
|
||||
想要启动并进入Ubuntu虚拟机的话,可以运行这个命令:
|
||||
```powershell
|
||||
wsl -d Ubuntu-20.04
|
||||
```
|
||||
|
||||
如果直接退出终端或者关闭窗口,虚拟机实例就会进入挂起状态,下次需要重新启动才能继续使用哦~当然,也可以通过指令强制终止虚拟机:
|
||||
```powershell
|
||||
wsl --terminate Ubuntu-20.04
|
||||
```
|
||||
|
||||
## 通过 VS Code 开发
|
||||
接下来,我们还可以通过VS Code来进行开发哦~不过需要先安装一些扩展呢:'Remote - SSH'和'WSL'
|
||||
|
||||
安装好扩展后,在VS Code左侧打开远程资源管理器,就可以看到Ubuntu20.04虚拟机啦~直接点击连接就可以了哦~不过第一次连接可能需要启动一下虚拟机,会有点慢呢,耐心等待一下吧~
|
||||

|
||||
连接成功之后,就可以愉快地进行开发啦~是不是很简单呢~
|
||||
120
docs/blog/technology/Operate_WSL2.md
Normal file
120
docs/blog/technology/Operate_WSL2.md
Normal file
@@ -0,0 +1,120 @@
|
||||
---
|
||||
title: WSL2 核心操作指南
|
||||
createTime: 2025/09/30 16:08:32
|
||||
cover: https://image.simengweb.com/elysia_cover_image/2MEiWEhvsx8OtKeJ.png
|
||||
permalink: /article/operate-wsl2/
|
||||
---
|
||||
这篇文章主要讲WSL2虚拟机核心操作哦~它基于轻量级Hyper-V运行,像贴心小精灵默默工作~还能用命令行精细控制!接下来讲启动/关闭、实例管理、资源配置、网络操作、备份迁移这五大操作,是不是很期待呢~♪
|
||||
|
||||
<!-- more -->
|
||||
|
||||
## 启动/关闭 WSL2 虚拟机
|
||||
WSL2的虚拟机平时是由Windows自动管理的呢,不过我们也可以通过命令手动控制它的生命周期哦~
|
||||
```
|
||||
# 启动指定的发行版
|
||||
wsl -d Ubuntu-20.04
|
||||
|
||||
# 关闭指定的发行版
|
||||
wsl --terminate Ubuntu-20.04
|
||||
```
|
||||
如果想要完全关闭WSL2的所有虚拟机,也是可以的哦~
|
||||
|
||||
使用这个命令后,所有的发行版都会被强制终止,内存、网络、文件句柄都会被全部释放呢~
|
||||
```
|
||||
wsl --shutdown
|
||||
```
|
||||
|
||||
## 管理正在运行的 WSL 实例
|
||||
想知道当前有哪些WSL实例在运行吗?很简单哦~使用下面这个命令就可以查看啦:
|
||||
```
|
||||
wsl -l -v
|
||||
```
|
||||
输出结果大概是这个样子的哦~
|
||||
```text
|
||||
NAME STATE VERSION
|
||||
* Ubuntu Running 2
|
||||
docker-desktop Running 2
|
||||
Ubuntu-20.04 Stopped 2
|
||||
```
|
||||
看到那个带星号(*)的了吗?那就是当前的默认系统哦~如果想要设置新的默认发行版,可以使用这个命令:
|
||||
```
|
||||
wsl --set-default Ubuntu-20.04
|
||||
```
|
||||
|
||||
嘿嘿~接下来讲讲怎么删除一个 WSL 实例哦~如果想和某个WSL实例说拜拜,就可以用下面这个命令哒~
|
||||
```
|
||||
wsl --unregister Ubuntu-20.04
|
||||
```
|
||||
注意,删除后无法恢复哦~请谨慎操作~
|
||||
|
||||
## 配置 WSL2 资源
|
||||
WSL2的资源也是可以自定义配置的哦~我们可以通过编辑`%USERPROFILE%\.wslconfig`文件来设置内存、CPU核心数等参数呢~
|
||||
```
|
||||
[wsl2]
|
||||
# 内存限制(默认:80% 物理内存)
|
||||
memory=4GB
|
||||
|
||||
# CPU 核心数限制(默认:全部核心)
|
||||
processors=2
|
||||
|
||||
# 交换空间大小(默认:25% 内存)
|
||||
swap=2GB
|
||||
|
||||
# 是否启用 localhost 端口转发(默认 true)
|
||||
localhostForwarding=true
|
||||
```
|
||||
要注意哦~修改完配置后,必须重启WSL2虚拟机才能让这些设置生效呢~
|
||||
## 网络相关配置
|
||||
WSL2使用的是虚拟NAT网络哦,它和Windows主机是相互隔离的,但又可以互相通信呢~是不是很神奇~
|
||||
|
||||
| 方向 | 访问方式 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| Windows -> WSL2 | localhost:port | 自动端口转发(需要`localhostForwarding=true`) |
|
||||
| WSL2 -> Windows | `host.docker.internal` 或 `$(cat /etc/resolv.conf \| grep nameserver \| awk '{print $2}')` | 获取主机的IP地址 |
|
||||
| 外部机器 -> WSL2 | 默认不可达 | 需要手动端口转发或使用 Windows 防火墙规则 |
|
||||
|
||||
想知道WSL2的IP地址吗?可以用这个命令查看哦~(不过要注意,每次启动WSL2后,IP地址可能会变呢~)
|
||||
|
||||
注意哦~这个命令需要进入到WSL2虚拟机内部执行才行呢~
|
||||
```
|
||||
hostname -I
|
||||
```
|
||||
|
||||
如果需要访问WSL2中的服务,多亏了`localhostForwarding`的配置,我们直接访问[localhost:port](http://localhost:port)就可以啦~超方便的~
|
||||
|
||||
如果需要手动设置端口转发,可以在Powershell中添加防火墙规则和端口转发哦~不过要记得以管理员方式打开Powershell呢~
|
||||
```
|
||||
# 获取 WSL2 当前IP地址
|
||||
$wslIp = (wsl hostname -I).Trim()
|
||||
|
||||
$wslIp
|
||||
|
||||
# 添加端口转发(以 8000 端口为样例)
|
||||
netsh interface portproxy add v4tov4 listenport=8000 listenaddress=0.0.0.0 connectport=8000 connectaddress=$wslIp
|
||||
|
||||
# 开放 Windows 防火墙
|
||||
New-NetFirewallRule -DisplayName "WSL2 Port 8000" -Direction Inbound -LocalPort 8000 -Protocol TCP -Action Allow
|
||||
|
||||
# 撤销端口转发
|
||||
netsh interface portproxy delete v4tov4 listenport=8000 listenaddress=0.0.0.0
|
||||
|
||||
# 撤销开放的防火墙规则
|
||||
Remove-NetFirewallRule -DisplayName "WSL2 Port 8000"
|
||||
```
|
||||
|
||||
## 备份和迁移
|
||||
WSL2发行版也是可以备份和迁移的哦~我们可以把整个发行版导出成tar文件,这样就可以用于备份、迁移或者分享给其他小伙伴啦~
|
||||
```
|
||||
# 导出指定发行版到 tar 文件
|
||||
wsl --export <发行版名称> <输出文件路径.tar>
|
||||
wsl --export Ubuntu-20.04 D:\backups\ubuntu-2004.tar
|
||||
|
||||
# 导入 tar 文件为新的发行版
|
||||
wsl --import <新发行版名称> <安装目录> <tar 文件路径> [选项]
|
||||
wsl --import Ubuntu-Backup C:\wsl\Ubuntu-Backup D:\backups\ubuntu-2004.tar --version 2
|
||||
```
|
||||
要注意哦~导入完成后,默认用户会变成root呢~如果想要设置回原来的用户,可以使用这个命令:
|
||||
```
|
||||
ubuntu2004.exe config --default-user username
|
||||
```
|
||||
悄悄告诉大家一个小秘密~WSL2是可以同时存在多个同源发行版的哦~这样我们就可以在不同的环境中进行不同的实验啦~是不是很方便呢~
|
||||
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 进行时间同步,同时为其他服务器提供时间服务。
|
||||
## 第一部分
|
||||
## 第一部分
|
||||
## 第一部分
|
||||
@@ -1,25 +1,27 @@
|
||||
---
|
||||
title: 通过 EdgeOne Pages 搭建图床
|
||||
createTime: 2025/09/29 02:28:17
|
||||
cover: https://image.simengweb.com/elysia_cover_image/0lQviAbmMCVGN0Y6.png
|
||||
permalink: /article/8gihio2v/
|
||||
---
|
||||
|
||||
EdgeOne Pages 是微软提供的一个静态网站托管服务,拥有一定的免费额度,基本上够用。
|
||||
各位~今天要给大家介绍一个超棒的图床搭建方法哦!EdgeOne Pages 是腾讯云提供的静态网站托管服务,而且还有免费额度可以使用呢,对于日常需求来说完全足够啦~
|
||||
|
||||
<!-- more -->
|
||||
|
||||
## 创建一个 Git 项目
|
||||
|
||||
这里首先要在 Gitee 上要搭建一个项目,用来存储网站中会用到的一些图片。
|
||||
Github 或 CNB 也可以,都支持的,这里的项目的目录就是到时候的访问目录。
|
||||
第一步呢,我们需要先在 Gitee 上创建一个项目,专门用来存放网站里要用的各种图片。当然啦,如果你习惯用 Github 或者 CNB 也没问题,这些平台都是支持的哦~而且要记住,项目的目录结构就是以后图片的访问路径呢~
|
||||
|
||||
## EdgeOne Page 中导入项目
|
||||
先打开 EdgeOne Page 的[控制台](https://console.cloud.tencent.com/edgeone/pages),这里可以导入 Github、Gitee 和 CNB 的项目。
|
||||
接下来打开 EdgeOne Page 的[控制台](https://console.cloud.tencent.com/edgeone/pages),这里可以导入 Github、Gitee 和 CNB 的项目哦~
|
||||
|
||||
然后点击导入项目,选择 Gitee 项目,选择对应的项目,然后直接开始部署就行。
|
||||
点击「导入项目」,选择 Gitee 项目,找到刚才创建的那个项目,然后就可以直接开始部署啦~
|
||||
|
||||
大概一分钟左右,部署完成之后,可以在项目概览中点击预览,可以预览一下资源的访问。
|
||||
等待大概一分钟左右,部署完成后,在项目概览页面点击预览按钮,就可以先看看资源能不能正常访问啦~
|
||||
|
||||
## 配置域名
|
||||
|
||||
临时链接可以正常访问的话,可以在项目总揽中点击自定义域名去配置我们的域名。
|
||||
如果临时链接可以正常访问的话,我们就可以配置自己的域名啦~在项目概览页面点击「自定义域名」就可以进入配置界面哦~
|
||||
|
||||
项目概览中可以添加自定义域名,输入域名即可,腾讯云有50个免费证书的额度,而且到期之后会自动释放额度,这里可以放心的点使用免费证书
|
||||
在那里输入你想要使用的域名,腾讯云可是提供了50个免费证书的额度呢!而且证书到期后还会自动释放额度,所以完全不用担心证书不够用的问题,可以放心大胆地点击「使用免费证书」按钮哦~
|
||||
@@ -22,4 +22,9 @@ list:
|
||||
link: https://www.ajohn.top/
|
||||
avatar: https://github.com/zzyAJohn.png
|
||||
desc: 我希望正在读这句话的人永远开心
|
||||
-
|
||||
name: 小小夏
|
||||
link: https://notes.simengweb.com
|
||||
avatar: https://image.simengweb.com/images/xxx.jpg
|
||||
desc: Kawasaki天下第一!
|
||||
---
|
||||
|
||||
@@ -4,4 +4,25 @@ createTime: 2025/09/28 07:54:17
|
||||
permalink: /ops/blockchain/
|
||||
---
|
||||
|
||||
## 区块链运维
|
||||
## 区块链简介
|
||||
区块链就像是一本神奇的共享账本哦~它由许许多多的"区块"连接而成,每个区块里都记录着各种交易信息~最特别的是,这本账本不是由某一个人或组织保管的,而是由网络里的所有人一起维护呢~
|
||||
|
||||
想象一下,当有新的交易发生时,网络里的每个人都会收到一份拷贝,大家一起验证这份交易的真实性,然后把它添加到账本里~这样一来,就没有人能够偷偷篡改账本啦~是不是很神奇呢~♪
|
||||
|
||||
区块链还有一个超棒的特点哦~它不需要中间人的帮忙,就能让互不相识的人们安全地进行交易~就像魔法一样,让信任在数字世界里自然生长~
|
||||
|
||||
## 区块链的理论基础
|
||||
|
||||
呜呜~在网上找关于完整区块链原理的资料好难呀,现在就只看到一些比较基础的课程和书籍呢。
|
||||
|
||||
嘿嘿,在B站的话,发现有一个课程超棒哒,就是肖臻老师的[《区块链技术与应用》](https://www.bilibili.com/video/BV1Vt411X7JF/)呢!
|
||||
|
||||
在Youtube上也可以去看看[Binance Academy](https://www.youtube.com/@BinanceAcademy)的视频哟,感觉也很不错哒!
|
||||
|
||||
至于书籍嘛,目前还没找到特别好的,不过没关系,会继续努力找找哒!如果有好的课程的话,可以评论留言分享一下哦~
|
||||
|
||||
## 区块链的运维实践
|
||||
|
||||
嘿嘿~区块链的搭建呀,主要就是通过 [FISCO BCOS](https://fisco-bcos-documentation.readthedocs.io/zh-cn/latest/docs/introduction.html) 来实现哒!
|
||||
|
||||
它呢,是一个开源的、基于Java的区块链平台哟~还支持智能合约的部署和执行呢,超厉害的!
|
||||
|
||||
@@ -1,226 +0,0 @@
|
||||
---
|
||||
title: 区块链网络部署指南~(≧∇≦)ノ
|
||||
description: 详细介绍区块链网络的搭建和部署过程
|
||||
createTime: 2025/09/28 20:15:00
|
||||
permalink: /ops/blockchain/deployment/
|
||||
---
|
||||
|
||||
# 区块链网络部署指南~(≧∇≦)ノ
|
||||
|
||||
嗨~今天我们要一起学习如何搭建和部署一个区块链网络哦!是不是听起来很厉害呢?其实只要按照步骤一步步来,你也可以成为区块链部署小能手的~(๑˘ᴗ˘๑)
|
||||
|
||||
## 准备工作 🏗️
|
||||
|
||||
在开始部署之前,让我们先准备好所需的环境和工具吧:
|
||||
|
||||
```bash
|
||||
# 更新系统包
|
||||
sudo apt update && sudo apt upgrade -y
|
||||
|
||||
# 安装必要的依赖
|
||||
sudo apt install -y git curl wget docker.io docker-compose
|
||||
|
||||
# 启动Docker服务并设置开机自启
|
||||
sudo systemctl start docker
|
||||
sudo systemctl enable docker
|
||||
|
||||
# 添加当前用户到docker组,避免每次使用sudo
|
||||
# 注意:添加后需要重新登录才能生效哦~
|
||||
sudo usermod -aG docker $USER
|
||||
```
|
||||
|
||||
## 选择区块链平台 🌈
|
||||
|
||||
市面上有很多不同的区块链平台,我们可以根据项目需求来选择:
|
||||
|
||||
- **以太坊**:最流行的智能合约平台,适合开发DApp
|
||||
- **Hyperledger Fabric**:企业级联盟链解决方案
|
||||
- **Polygon**:以太坊的Layer 2扩展解决方案
|
||||
- **BSC**:币安智能链,高性能的智能合约平台
|
||||
|
||||
今天我们将以以太坊私有链为例来演示部署过程哦~
|
||||
|
||||
## 部署以太坊私有链 🔗
|
||||
|
||||
### 1. 安装Geth客户端
|
||||
|
||||
Geth是以太坊的官方Go语言客户端,我们需要先安装它:
|
||||
|
||||
```bash
|
||||
# 下载Geth安装包
|
||||
wget https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.13.10-7a0c19f6.tar.gz
|
||||
|
||||
# 解压安装包
|
||||
tar -xvf geth-linux-amd64-1.13.10-7a0c19f6.tar.gz
|
||||
|
||||
# 移动geth可执行文件到系统路径
|
||||
sudo mv geth-linux-amd64-1.13.10-7a0c19f6/geth /usr/local/bin/
|
||||
|
||||
# 验证安装是否成功
|
||||
geth version
|
||||
```
|
||||
|
||||
### 2. 创建创世区块配置文件
|
||||
|
||||
创世区块是区块链的第一个区块,我们需要创建一个配置文件来定义它的参数:
|
||||
|
||||
```bash
|
||||
# 创建一个名为genesis.json的文件
|
||||
nano genesis.json
|
||||
```
|
||||
|
||||
将以下内容复制到文件中:
|
||||
|
||||
```json
|
||||
{
|
||||
"config": {
|
||||
"chainId": 12345,
|
||||
"homesteadBlock": 0,
|
||||
"eip150Block": 0,
|
||||
"eip155Block": 0,
|
||||
"eip158Block": 0,
|
||||
"byzantiumBlock": 0,
|
||||
"constantinopleBlock": 0,
|
||||
"petersburgBlock": 0,
|
||||
"istanbulBlock": 0,
|
||||
"berlinBlock": 0,
|
||||
"londonBlock": 0,
|
||||
"arrowGlacierBlock": 0,
|
||||
"grayGlacierBlock": 0,
|
||||
"mergeForkIdTransition": 0,
|
||||
"terminalTotalDifficulty": 0,
|
||||
"terminalTotalDifficultyPassed": true,
|
||||
"shanghaiTime": 0,
|
||||
"cancunTime": 0
|
||||
},
|
||||
"difficulty": "0x400",
|
||||
"gasLimit": "0x1000000",
|
||||
"alloc": {
|
||||
"0x71C7656EC7ab88b098defB751B7401B5f6d8976F": {
|
||||
"balance": "0x100000000000000000000000000000000"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 初始化区块链
|
||||
|
||||
现在我们可以使用创世区块配置文件来初始化我们的私有链了:
|
||||
|
||||
```bash
|
||||
# 创建一个目录来存储区块链数据
|
||||
mkdir -p ~/ethereum-private-chain/data
|
||||
|
||||
# 使用genesis.json初始化区块链
|
||||
geth --datadir ~/ethereum-private-chain/data init genesis.json
|
||||
```
|
||||
|
||||
### 4. 启动区块链节点
|
||||
|
||||
初始化完成后,我们可以启动我们的区块链节点了:
|
||||
|
||||
```bash
|
||||
# 启动区块链节点
|
||||
# --networkid 要与创世区块配置中的chainId一致
|
||||
# --nodiscover 禁用节点发现机制,只允许手动添加节点
|
||||
# --http 启用HTTP-RPC接口
|
||||
# --http.addr 设置HTTP-RPC接口监听地址
|
||||
# --http.api 启用的API模块
|
||||
geth --datadir ~/ethereum-private-chain/data --networkid 12345 --nodiscover --http --http.addr "0.0.0.0" --http.api "eth,net,web3,personal,miner" console
|
||||
```
|
||||
|
||||
### 5. 开始挖矿
|
||||
|
||||
在Geth控制台中,我们可以开始挖矿来生成新区块:
|
||||
|
||||
```javascript
|
||||
// 设置挖矿账户
|
||||
miner.setEtherbase(eth.accounts[0])
|
||||
|
||||
// 开始挖矿
|
||||
miner.start(1)
|
||||
|
||||
// 查看挖矿状态
|
||||
eth.blockNumber
|
||||
|
||||
// 查看账户余额
|
||||
eth.getBalance(eth.accounts[0])
|
||||
|
||||
// 停止挖矿
|
||||
// miner.stop()
|
||||
```
|
||||
|
||||
### 6. 添加其他节点(可选)
|
||||
|
||||
如果需要搭建多节点的区块链网络,我们可以将其他节点连接到我们的主节点:
|
||||
|
||||
```javascript
|
||||
// 在主节点上获取节点信息
|
||||
admin.nodeInfo.enode
|
||||
|
||||
// 在其他节点的Geth控制台中添加主节点
|
||||
admin.addPeer("enode://主节点的enode信息@主节点IP:30303")
|
||||
|
||||
// 查看已连接的节点
|
||||
admin.peers
|
||||
```
|
||||
|
||||
## 部署智能合约 🚀
|
||||
|
||||
区块链网络搭建完成后,我们可以部署一个简单的智能合约来测试它:
|
||||
|
||||
```javascript
|
||||
// 在Geth控制台中编写一个简单的智能合约
|
||||
var helloWorldContract = eth.contract([
|
||||
{"constant":true,"inputs":[],"name":"greeting","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},
|
||||
{"constant":false,"inputs":[{"name":"_greeting","type":"string"}],"name":"setGreeting","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},
|
||||
{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}
|
||||
]);
|
||||
|
||||
// 编译合约代码
|
||||
var helloWorldCompiled = eth.compile.solidity('pragma solidity ^0.8.0; contract HelloWorld { string public greeting; constructor() { greeting = "Hello, Blockchain!"; } function setGreeting(string memory _greeting) public { greeting = _greeting; } }');
|
||||
|
||||
// 部署合约
|
||||
var helloWorld = helloWorldContract.new({
|
||||
from: eth.accounts[0],
|
||||
data: helloWorldCompiled.HelloWorld.code,
|
||||
gas: 1000000
|
||||
});
|
||||
|
||||
// 查看合约地址
|
||||
helloWorld.address
|
||||
|
||||
// 调用合约函数
|
||||
helloWorld.greeting.call()
|
||||
helloWorld.setGreeting("Hello, Ethereum!", {from: eth.accounts[0]})
|
||||
helloWorld.greeting.call()
|
||||
```
|
||||
|
||||
## 监控与维护 📊
|
||||
|
||||
区块链网络部署完成后,我们需要定期进行监控和维护:
|
||||
|
||||
- **节点状态监控**:检查节点是否正常运行,区块高度是否在增长
|
||||
- **网络连接监控**:监控节点之间的连接状态
|
||||
- **资源使用监控**:监控服务器的CPU、内存、磁盘和网络使用情况
|
||||
- **日志分析**:定期查看区块链节点的日志,及时发现和解决问题
|
||||
|
||||
## 安全注意事项 🔒
|
||||
|
||||
在部署区块链网络时,安全是非常重要的:
|
||||
|
||||
- 不要在生产环境中使用默认的配置参数
|
||||
- 定期更新节点软件到最新版本
|
||||
- 使用防火墙限制对节点的访问
|
||||
- 妥善保管私钥和密码
|
||||
- 考虑使用多重签名机制来保护重要操作
|
||||
|
||||
## 小练习 🏋️♀️
|
||||
|
||||
现在轮到你自己动手实践了!试着按照上面的步骤部署一个以太坊私有链,然后创建一个简单的智能合约并部署到链上吧~相信自己,你一定可以做到的!(๑•̀ㅂ•́)و✧
|
||||
|
||||
## 写在最后~💌
|
||||
|
||||
今天我们学习了如何部署一个区块链网络,从准备环境到部署智能合约,每一步都很重要哦~虽然看起来步骤很多,但只要耐心地一步步来,你一定能成功的!如果你在部署过程中遇到了问题,不要灰心,可以查阅相关文档或者向社区寻求帮助。
|
||||
|
||||
希望这篇指南能对你有所帮助,让我们一起在区块链的世界里快乐地探索吧!(づ ̄ 3 ̄)づ
|
||||
70
docs/notes/ops/blockchain/practice/basic-deployment.md
Normal file
70
docs/notes/ops/blockchain/practice/basic-deployment.md
Normal file
@@ -0,0 +1,70 @@
|
||||
---
|
||||
title: 区块链产品设计和基础部署
|
||||
description: 详细介绍区块链产品设计和基础部署
|
||||
createTime: 2025/09/28 20:15:00
|
||||
permalink: /ops/blockchain/practice/basic-deployment/
|
||||
---
|
||||
|
||||
## 区块链产品方案设计
|
||||
|
||||
### 区块链产品需求分析
|
||||
|
||||
区块链产品分析主要是以下几个步骤:
|
||||
|
||||
1. 明确业务需求
|
||||
|
||||
围绕指定业务分析区块链落地解决的痛点,提出围绕业务的功能概述。
|
||||
|
||||
2. 搜集业务相关信息
|
||||
|
||||
针对设计功能,分析收集数据的方向、类型和具体维度
|
||||
|
||||
3. 分析搜集数据
|
||||
|
||||
借助数据分析工具整合收集数据,并能根据收集数据得出初步结论
|
||||
|
||||
能够保证收集数据的准确性和安全性
|
||||
|
||||
4. 确定应用需求
|
||||
|
||||
根据业务需求和收集数据,细化产品具体功能需求
|
||||
|
||||
5. 落地区块链平台
|
||||
|
||||
形成具体平台的设计需求报告
|
||||
|
||||
形成平台验收的准则
|
||||
|
||||
### 区块链平台设计方案
|
||||
|
||||
区块链平台包括:区块链底层平台、智能合约层、业务层、应用层和用户层
|
||||
|
||||

|
||||
|
||||
### 业务功能模块设计
|
||||
|
||||
业务功能模块设计包括三层:功能平台、功能模块、详细功能
|
||||
|
||||

|
||||
|
||||
### 业务流程图
|
||||
|
||||
关于业务流程图的一些常见符号:
|
||||
|
||||

|
||||
|
||||
有一些好用的在线绘制流程图的网站:
|
||||
|
||||
1. [Draw.io](https://app.diagrams.net/)
|
||||
|
||||
### ER 图设计
|
||||
|
||||
E-R 图(实体-关系图)是数据库设计中常用的一种工具,E 是实体,拥有一组属性,R 是关系,用于找到实体之间的联系。
|
||||
|
||||
实体与实体之间的关系,可能是一对一(1:1),一对多(1:n),多对多(m:n)
|
||||
|
||||
实体:通常用矩形表示,代表系统中的一个对象或概念,如"学生","课程","老师"
|
||||
|
||||
属性:通常用椭圆形表示,表示实体的特征,如"学生"的"姓名","班级"
|
||||
|
||||
关系:用菱形表示,用于不同实体间的联系,如"课程"和"学生"之间的"选修"关系
|
||||
59
docs/notes/ops/blockchain/practice/console-operator.md
Normal file
59
docs/notes/ops/blockchain/practice/console-operator.md
Normal file
@@ -0,0 +1,59 @@
|
||||
---
|
||||
title: Console 控制台操作
|
||||
createTime: 2025/10/03 02:55:49
|
||||
permalink: /ops/blockchain/practice/console-operator/
|
||||
---
|
||||
|
||||
## Console 控制台是什么?
|
||||
Console 是 FISCO BCOS 官方提供的一个交互式命令行工具,用于直接与区块链节点交互。
|
||||
主要功能包括:
|
||||
- 查询区块链状态(如区块链高度、节点列表、群组信息)
|
||||
- 部署和调用智能合约(支持 Solidity)
|
||||
- 管理节点(如查看节点共识状态、动态添加节点)
|
||||
- 调试交易和查看回执
|
||||
|
||||
## 部署 Console 控制台
|
||||
获取下载脚本:`wget https://gitee.com/FISCO-BCOS/console/releases/download/v2.8.0/console.tar.gz`
|
||||
解压控制台安装包:`tar -zxf console.tar.gz console/`
|
||||
|
||||
复制配置文件:`cp conf/config-example.toml conf/config.toml`
|
||||
编辑配置文件:`vim conf/config.toml`
|
||||
```bash
|
||||
# enSslKey = "conf/gm/gmensdk.key" # GM ssl cert file path
|
||||
# default load the GM SSL encryption privateKey from ${certPath}/gm/gmensdk.key
|
||||
|
||||
[network]
|
||||
# 请确保这里的连接地址都有节点
|
||||
peers=["127.0.0.1:20200", "127.0.0.1:20201"] # The peer list to connect [!code warning]
|
||||
|
||||
# Configure a private topic as a topic message sender.
|
||||
|
||||
```
|
||||
|
||||
复制节点证书到 Console 的配置目录下
|
||||
```bash
|
||||
cp -r ../nodes/127.0.0.1/sdk/* conf/
|
||||
```
|
||||
|
||||
通过 `bash start.sh` 就可以启动 Console 控制台啦!
|
||||

|
||||
|
||||
## 常用控制台命令
|
||||
|
||||
这里的区块链的搭建是根据前一篇文章中的多机构多群组多节点的关系
|
||||
|
||||
### 合约相关命令
|
||||
### 其他命令
|
||||
- 查询区块高度:`getBlockNumber`
|
||||
```bash title='output_example'
|
||||
[group:1]> getBlockNumber
|
||||
0
|
||||
```
|
||||
- 查看共识节点列表:`getSealerList`
|
||||
```bash title='output_example'
|
||||
[group:1]> getSealerList
|
||||
[
|
||||
d036a22f16909cba4c8521cd3c31db3be381e673c9749e3fd2848ab25eca134ef917cb9306f41893295c535078bce77bdc241eba3f92549a73efe4699d3c0df8,
|
||||
f0535616759000b473a285d60814bc2c5927a9cb897644da46890de71e59df590cd6fe1b226a95e19a566b6fc127fd85032de0d9fdd3d529e5e50cd96ad51f28
|
||||
]
|
||||
```
|
||||
122
docs/notes/ops/blockchain/practice/node-deployment.md
Normal file
122
docs/notes/ops/blockchain/practice/node-deployment.md
Normal file
@@ -0,0 +1,122 @@
|
||||
---
|
||||
title: 区块链网络部署与管理
|
||||
createTime: 2025/10/02 04:13:08
|
||||
permalink: /ops/blockchain/practice/node-deployment/
|
||||
---
|
||||
|
||||
## FISCO BCOS 简介
|
||||
|
||||
嘿呀~FISCO BCOS 可是金链盟开源工作组超用心牵头打造的企业级金融区块链底层平台哟!它就像一个超级厉害的小能手,有着高性能、高可用、安全可控这些超棒的特点呢。还支持多群组架构喔,能轻轻松松满足不同业务场景下的数据隔离和隐私保护需求,简直太赞啦!
|
||||
|
||||
而且呢,FISCO BCOS 还准备了好多丰富的开发工具和组件,就像给开发者们准备了一个魔法百宝箱,帮助大家能快速搭建区块链应用。现在在金融、政务、供应链这些好多好多领域都能看到它活跃的身影,应用可广泛啦!
|
||||
|
||||
## FISCO BCOS 网络部署
|
||||
|
||||
FICSO BCOS 提供了一个 build_chain.sh 来部署区块链,下面的步骤都是通过这个脚本来部署的区块链网络
|
||||
```
|
||||
# 可以通过这个指令下载脚本并赋予执行权限
|
||||
curl -#LO https://github.com/FISCO-BCOS/FISCO-BCOS/releases/download/v2.11.0/build_chain.sh && chmod u+x build_chain.sh
|
||||
```
|
||||
|
||||
### 部署单群组4节点联盟链
|
||||
这里要确保机器的30300-30303,20200-20203,8545-8548端口都没有被占用
|
||||
|
||||
```
|
||||
# 部署单群组4节点联盟链
|
||||
bash build_chain.sh -l 127.0.0.1:4 -p 30300,20200,8545 -e ./fisco-bcos
|
||||
```
|
||||
|
||||
如果是国密版本,执行下面的命令
|
||||
```
|
||||
# 部署单群组4节点联盟链(国密版本)
|
||||
bash build_chain.sh -l 127.0.0.1:4 -p 30300,20200,8545 -g -G -e ./fisco-bcos
|
||||
```
|
||||
|
||||
参数解析:
|
||||
- -l:指定节点的IP地址和节点数
|
||||
- -p:指定节点的端口号
|
||||
- -g 和 -G:使用国密sm算法
|
||||
- -e:使用指定的 fisco-bcos 文件
|
||||
|
||||
默认情况下脚本会去 github 上下载 fisco-bcos 二进制文件,这一步在国内很有可能失败,建议提前下载好,然后直接使用本地的
|
||||
|
||||
部署完成之后就可以启动节点了
|
||||
|
||||
```
|
||||
bash nodes/127.0.0.1/start_all.sh
|
||||
```
|
||||
|
||||
检查节点进程是否存在
|
||||
```
|
||||
ps -ef | grep fisco-bcos
|
||||
```
|
||||
|
||||
检查节点之间是否互相链接了
|
||||
```
|
||||
# 这里是检查 node0 的日志文件
|
||||
tail -f nodes/127.0.0.1/node0/log/log* | grep connected
|
||||
```
|
||||
输出样例如下:
|
||||
```
|
||||
info|2025-10-02 17:06:40.006979|[P2P][Service] heartBeat,connected count=3
|
||||
...
|
||||
```
|
||||
这里可以看到 count=3,说明 node0 已经链接了另外的三个节点
|
||||
|
||||
检查节点之间是否存在共识
|
||||
```
|
||||
# 这里是检查 node0 的日志文件
|
||||
tail -f nodes/127.0.0.1/node0/log/log* | grep +++
|
||||
```
|
||||
输出样例如下:
|
||||
```
|
||||
info|2025-10-02 17:08:29.795822|[g:1][CONSENSUS][SEALER]++++++++++++++++ Generating seal on,blkNum=1,tx=0,nodeIdx=0,hash=5b5f44f4...
|
||||
info|2025-10-02 17:08:33.807504|[g:1][CONSENSUS][SEALER]++++++++++++++++ Generating seal on,blkNum=1,tx=0,nodeIdx=0,hash=50fec464...
|
||||
...
|
||||
```
|
||||
不断输出带有 `++++Generating seal` 的日志,说明共识正常
|
||||
|
||||
检查群组之间的共识
|
||||
```bash
|
||||
tail -f nodes/127.0.0.1/node0/log/log* | grep 'g:1.*+++'
|
||||
```
|
||||
输出样例如下:
|
||||
```bash
|
||||
info|2025-10-02 17:59:59.194525|[g:1][CONSENSUS][SEALER]++++++++++++++++ Generating seal on,blkNum=1,tx=0,nodeIdx=1,hash=fdb2da54...
|
||||
info|2025-10-02 18:59:59.225102|[g:1][CONSENSUS][SEALER]++++++++++++++++ Generating seal on,blkNum=1,tx=0,nodeIdx=1,hash=b7d87997...
|
||||
info|2025-10-02 19:59:59.327677|[g:1][CONSENSUS][SEALER]++++++++++++++++ Generating seal on,blkNum=1,tx=0,nodeIdx=1,hash=38dea43f...
|
||||
info|2025-10-02 20:59:59.462059|[g:1][CONSENSUS][SEALER]++++++++++++++++ Generating seal on,blkNum=1,tx=0,nodeIdx=1,hash=cb0e89fa...
|
||||
info|2025-10-02 21:59:59.284218|[g:1][CONSENSUS][SEALER]++++++++++++++++ Generating seal on,blkNum=1,tx=0,nodeIdx=1,hash=721e8904...
|
||||
```
|
||||
|
||||
### 部署多机构多群组多节点
|
||||
|
||||
在很多时候,我们需要部署多机构多群组多节点的联盟链,来满足不同业务场景下的需求。
|
||||
|
||||
现在有需求如下:
|
||||
|
||||
|IP|节点数|所属机构|所属群组|P2P端口|Channel端口|RPC端口|
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| 127.0.0.1 | 2 | agencyA | 1,2 | 30300 | 20200 | 8545 |
|
||||
| 127.0.0.2 | 2 | agencyB | 2,3 | 30400 | 20300 | 8645 |
|
||||
| 127.0.0.3 | 2 | agencyC | 3 | 30500 | 20400 | 8745 |
|
||||
| 127.0.0.4 | 2 | agencyD | 4 | 30600 | 20500 | 8845 |
|
||||
|
||||
这种时候建议直接编辑配置文件,参考样例如下:
|
||||
```bash title='ipconf'
|
||||
127.0.0.1:2 agencyA 1,2 30300,20200,8545
|
||||
127.0.0.1:2 agencyB 2,3 30400,20300,8645
|
||||
127.0.0.1:2 agencyC 3 30500,20400,8745
|
||||
127.0.0.1:2 agencyD 4 30600,20500,8845
|
||||
```
|
||||
|
||||
通过配置文件部署多机构多群组多节点联盟链
|
||||
```
|
||||
bash build_chain.sh -f ipconf -p 30300,20200,8545 -e ./fisco-bcos
|
||||
```
|
||||
这里查看一下输出信息,应当如下图所示:
|
||||

|
||||
|
||||
## 参考文章
|
||||
- [搭建第一个区块链网络](https://fisco-bcos-documentation.readthedocs.io/zh-cn/latest/docs/installation.html)
|
||||
- [开发部署工具](https://fisco-bcos-documentation.readthedocs.io/zh-cn/release-2.7.0/docs/manual/build_chain.html)
|
||||
@@ -4,12 +4,3 @@ createTime: 2025/09/28 12:39:11
|
||||
permalink: /ops/blockchain/theory/basic-principles/
|
||||
---
|
||||
|
||||
## 学习资料和课程推荐
|
||||
关于完整的区块链原理的资料,我目前在网上很少看到,只有一些比较基础的课程和书籍。
|
||||
|
||||
目前在B站的话我只找到一个课程是比较推荐的,肖臻老师的[《区块链技术与应用》](https://www.bilibili.com/video/BV1Vt411X7JF/)
|
||||
|
||||
在Youtube上的话,可以看一看[Binance Academy](https://www.youtube.com/@BinanceAcademy)的视频,也不错。
|
||||
|
||||
至于书籍的话,我目前还没有看到特别好的,等我再找找吧。
|
||||
|
||||
|
||||
342
docs/notes/ops/blockchain/theory/fisco-bcos-node-type.md
Normal file
342
docs/notes/ops/blockchain/theory/fisco-bcos-node-type.md
Normal file
@@ -0,0 +1,342 @@
|
||||
---
|
||||
title: 区块链的节点
|
||||
createTime: 2025/10/05 13:07:05
|
||||
permalink: /ops/blockchain/theory/fisco-bcos-node-type/
|
||||
---
|
||||
|
||||
## 节点的基础概念
|
||||
|
||||
FISCO BCOS 引入了[游离节点、观察者节点和共识节点](https://fisco-bcos-documentation.readthedocs.io/zh-cn/latest/docs/design/security_control/node_management.html#id6),这三种节点类型可以通过控制台互相转换。
|
||||
|
||||
组员:
|
||||
- 共识节点:参与共识的节点,拥有群组的所有数据(搭链时默认都生成共识节点)。
|
||||
- 观察者节点:不参与共识,但能实时同步链上数据的节点。
|
||||
|
||||
非组员:
|
||||
- 游离节点:已启动,等待加入群组的节点。处在一种暂时的节点状态,不能获取链上的数据。
|
||||
|
||||
## 节点配置文件详解
|
||||
|
||||
节点搭建完成之后会有`config.ini`、`conf/group.%group_id.genesis`、`conf/group.%group_id.ini`、`node.nodeid` 等配置文件
|
||||
|
||||
::: code-tabs
|
||||
@tab config.ini
|
||||
```bash
|
||||
# RPC (Remote Proceduce Call 远程过程调用)
|
||||
# 用于配置节点对外提供的 RPC 服务,包括 JSON-RPC ( 用于 Web3.js,控制台等 )和 Channel 通信( 用于 SDK,Java 应用等 )
|
||||
[rpc]
|
||||
# 允许外部访问
|
||||
channel_listen_ip=0.0.0.0
|
||||
channel_listen_port=20200
|
||||
# 只允许内部访问
|
||||
jsonrpc_listen_ip=127.0.0.1
|
||||
jsonrpc_listen_port=8545
|
||||
|
||||
# P2P (Peer-to-Peer 点对点通信)
|
||||
# 用于配置节点之间的 P2P 通信
|
||||
[p2p]
|
||||
listen_ip=0.0.0.0
|
||||
listen_port=30300
|
||||
; nodes to connect
|
||||
node.0=127.0.0.1:30300
|
||||
node.1=127.0.0.1:30301
|
||||
node.2=127.0.0.1:30400
|
||||
node.3=127.0.0.1:30401
|
||||
node.4=127.0.0.1:30500
|
||||
node.5=127.0.0.1:30501
|
||||
node.6=127.0.0.1:30600
|
||||
node.7=127.0.0.1:30601
|
||||
|
||||
# 证书的黑白名单控制
|
||||
[certificate_blacklist]
|
||||
; crl.0 should be nodeid, nodeid's length is 128
|
||||
;crl.0=
|
||||
|
||||
[certificate_whitelist]
|
||||
; cal.0 should be nodeid, nodeid's length is 128
|
||||
;cal.0=
|
||||
|
||||
# 群组的配置目录和数据目录
|
||||
# 启动的时候会自动加载 group_config_path 下的所有群组
|
||||
[group]
|
||||
group_data_path=data/
|
||||
group_config_path=conf/
|
||||
|
||||
# 配置网络安全
|
||||
[network_security]
|
||||
; directory the certificates located in
|
||||
# 网络部分的配置文件目录
|
||||
data_path=conf/
|
||||
; the node private key file
|
||||
# 节点的私钥文件
|
||||
key=node.key
|
||||
; the node certificate file
|
||||
# 节点的证书文件
|
||||
cert=node.crt
|
||||
; the ca certificate file
|
||||
# CA 的证书文件
|
||||
ca_cert=ca.crt
|
||||
|
||||
# 配置加密存储
|
||||
# 用于对接 KMS ,实现落盘数据加密
|
||||
# 具体的可以查看参考文献中的第2篇文章,落盘加密
|
||||
[storage_security]
|
||||
enable=false
|
||||
key_manager_ip=
|
||||
key_manager_port=
|
||||
cipher_data_key=
|
||||
|
||||
# 链的基本信息
|
||||
[chain]
|
||||
# 链的 ID ,不同链ID的节点无法通信
|
||||
id=1
|
||||
; use SM crypto or not, should nerver be changed
|
||||
# 是否启动国密算法,这一步在创建的时候就应该规划好
|
||||
# 一旦设定,不可更改,否则无法和其他节点通信
|
||||
sm_crypto=false
|
||||
# cannel 是否启用国密,需和 SDK 一致
|
||||
sm_crypto_channel=false
|
||||
|
||||
# 兼容性配置
|
||||
[compatibility]
|
||||
; supported_version should nerver be changed
|
||||
# 指定节点兼容的 FISCO BCOS 的版本
|
||||
# 默认值即可,不应手动修改
|
||||
supported_version=2.8.0
|
||||
|
||||
# 日志配置
|
||||
[log]
|
||||
# 启用配置
|
||||
enable=true
|
||||
# 日志配置目录
|
||||
log_path=./log
|
||||
; enable/disable the statistics function
|
||||
# 是否启用统计功能
|
||||
enable_statistic=false
|
||||
; network statistics interval, unit is second, default is 60s
|
||||
# 统计信息刷新间隔(单位:秒)
|
||||
stat_flush_interval=60
|
||||
; info debug trace
|
||||
# 日志级别,可选值(trace < debug < info < warning < error)
|
||||
level=info
|
||||
; MB
|
||||
# 单个日志文件最大大小(单位:MB)
|
||||
max_log_file_size=200
|
||||
# 是否实时刷盘
|
||||
flush=true
|
||||
|
||||
# 流量控制
|
||||
[flow_control]
|
||||
; restrict QPS of the node
|
||||
# 限制 QPS 每秒请求数,防止 DDOS
|
||||
;limit_req=1000
|
||||
; restrict the outgoing bandwidth of the node
|
||||
; Mb, can be a decimal
|
||||
; when the outgoing bandwidth exceeds the limit, the block synchronization operation will not proceed
|
||||
# 限制节点出带宽(单位Mbps)
|
||||
# 超出之后会暂停区块同步,避免网络拥塞
|
||||
;outgoing_bandwidth_limit=2
|
||||
```
|
||||
@tab group.1.genesis
|
||||
```bash
|
||||
# 共识机制配置
|
||||
[consensus]
|
||||
; consensus algorithm now support PBFT(consensus_type=pbft), Raft(consensus_type=raft)
|
||||
; rpbft(consensus_type=rpbft)
|
||||
# 共识算法
|
||||
consensus_type=pbft
|
||||
; the max number of transactions of a block
|
||||
# 每个区块的最大打包量,超出的部分会留在交易池,等待下一次打包
|
||||
max_trans_num=1000
|
||||
; in seconds, block consensus timeout, at least 3s
|
||||
# 共识算法的超时时间
|
||||
consensus_timeout=3
|
||||
; rpbft related configuration
|
||||
; the working sealers num of each consensus epoch
|
||||
# 仅在 rpbft 的时候生效,每轮共识 epoch 中参与打包的共识节点数。
|
||||
epoch_sealer_num=2
|
||||
; the number of generated blocks each epoch
|
||||
# 仅在 rpbft 的时候生效,每轮 epoch 持续的区块数。
|
||||
epoch_block_num=1000
|
||||
; the node id of consensusers
|
||||
# 群组中共识节点的列表
|
||||
node.0=f0535616759000b473a285d60814bc2c5927a9cb897644da46890de71e59df590cd6fe1b226a95e19a566b6fc127fd85032de0d9fdd3d529e5e50cd96ad51f28
|
||||
node.1=d036a22f16909cba4c8521cd3c31db3be381e673c9749e3fd2848ab25eca134ef917cb9306f41893295c535078bce77bdc241eba3f92549a73efe4699d3c0df8
|
||||
|
||||
# 存储区块链的状态信息
|
||||
# 支持 storage state 和 MPT state
|
||||
# storage state 效率高
|
||||
# MPT state 效率低,但是包含完整的历史信息
|
||||
[state]
|
||||
type=storage
|
||||
# transaction (交易)相关配置
|
||||
# gas 是一种计算智能合约执行过程中消耗的计算和存储资源,包括交易的gas的最大值的限制和区块的gas最大值的限制
|
||||
# 如果交易或区块执行消耗的 gas 超过限制,则会丢弃交易区块
|
||||
# FISCO BCOS 是联盟链,简化了 gas 的设计,仅保留交易最大 gas 限制,区块最大 gas 是通过共识配置的
|
||||
[tx]
|
||||
; transaction gas limit
|
||||
gas_limit=300000000
|
||||
# 群组的配置
|
||||
[group]
|
||||
# 群组 ID
|
||||
id=1
|
||||
# 群组的创世区块的时间戳(ms)
|
||||
timestamp=1759397321000
|
||||
|
||||
# 群组的 EVM 配置
|
||||
# 是否开启 free storage
|
||||
# 这里具体的内容,可以查看参考文献中的第4篇文章,【教程】如何修改FISCO-BCOS内的EVM的gas...
|
||||
[evm]
|
||||
enable_free_storage=false
|
||||
```
|
||||
@tab group.1.ini
|
||||
```bash
|
||||
# 共识运行参数(PBFT 优化)
|
||||
[consensus]
|
||||
; the ttl for broadcasting pbft message
|
||||
# PBFT 消息在网络中最多转发 2 跳
|
||||
ttl=2
|
||||
; min block generation time(ms)
|
||||
# 最小出块时间 500ms
|
||||
min_block_generation_time=500
|
||||
# 动态调整区块大小 genesis 中的 max_trans_num
|
||||
enable_dynamic_block_size=true
|
||||
# 优化 TLL 转发逻辑,提升 PBFT 在大规模网络中的效率
|
||||
enable_ttl_optimization=true
|
||||
# Prepare 消息中只包含交易哈希,减少网络传输量
|
||||
# 大幅提示大区块场景下的共识效率
|
||||
enable_prepare_with_txsHash=true
|
||||
; The following is the relevant configuration of rpbft
|
||||
; set true to enable broadcast prepare request by tree
|
||||
# 使用树状拓扑广播 Prepare 广播(而非全网广播)
|
||||
# 适合节点多的场景
|
||||
# 仅在 rpbft 或优化版 PBFT 中有效
|
||||
broadcast_prepare_by_tree=true
|
||||
; percent of nodes that broadcast prepare status to, must be between 25 and 100
|
||||
# 广播 Prepare 状态给33%的节点,必须在 25%~100% 之间
|
||||
prepare_status_broadcast_percent=33
|
||||
; max wait time before request missed transactions, ms, must be between 5ms and 1000ms
|
||||
# 请求缺失交易前,最多等待 100ms(收集更多交易)
|
||||
# 范围 5 ~ 1000ms
|
||||
max_request_missedTxs_waitTime=100
|
||||
; maximum wait time before requesting a prepare, ms, must be between 10ms and 1000ms
|
||||
# 请求缺失 Prepare 消息前,最多等待 100ms
|
||||
# 范围 10ms ~ 1000ms
|
||||
max_request_prepare_waitTime=100
|
||||
|
||||
[storage]
|
||||
; storage db type, rocksdb / mysql / scalable, rocksdb is recommended
|
||||
# 存储引擎
|
||||
# 推荐使用 rocksdb (高性能,嵌入式 KV 数据库)
|
||||
# 支持 mysql ( 不推荐,性能差 ) , scalable (分布式存储,实验性)
|
||||
type=rocksdb
|
||||
; set true to turn on binary log
|
||||
# 开启二进制日志,默认关闭,开启会增加IO
|
||||
binary_log=false
|
||||
; scroll_threshold=scroll_threshold_multiple*1000, only for scalable
|
||||
# 仅在 scalable 存储引擎下生效
|
||||
scroll_threshold_multiple=2
|
||||
; set fasle to disable CachedStorage
|
||||
# 启用缓存层(非常推荐)
|
||||
cached_storage=true
|
||||
; max cache memeory, MB
|
||||
# 缓存最大内容,32MB
|
||||
max_capacity=32
|
||||
# 允许节点最多超前同步10个区块
|
||||
max_forward_block=10
|
||||
; only for external, deprecated in v2.3.0
|
||||
# 最大重试次数,默认 60 次
|
||||
max_retry=60
|
||||
topic=DB
|
||||
; only for mysql
|
||||
db_ip=127.0.0.1
|
||||
db_port=3306
|
||||
db_username=
|
||||
db_passwd=
|
||||
db_name=
|
||||
# 交易池
|
||||
[tx_pool]
|
||||
# 交易池最大容量,默认 150000
|
||||
limit=150000
|
||||
; transaction pool memory size limit, MB
|
||||
# 交易池最大内存占用:512 MB
|
||||
memory_limit=512
|
||||
; number of threads responsible for transaction notification,
|
||||
; default is 2, not recommended for more than 8
|
||||
# 用于通知 SDK 交易上链结果的线程数
|
||||
notify_worker_num=2
|
||||
# 区块同步优化
|
||||
[sync]
|
||||
; max memory size used for block sync, must >= 32MB
|
||||
# 区块同步最大内存:512MB,必须大于等于 32 MB
|
||||
max_block_sync_memory_size=512
|
||||
# 同步空闲时,等待 200ms 再检查新块
|
||||
idle_wait_ms=200
|
||||
; send block status by tree-topology, only supported when use pbft
|
||||
# 使用树状拓扑同步区块
|
||||
# 可以大幅度降低网络带宽
|
||||
# 仅在 PBFT 下支持
|
||||
sync_block_by_tree=true
|
||||
; send transaction by tree-topology, only supported when use pbft
|
||||
; recommend to use when deploy many consensus nodes
|
||||
# 交易广播也使用树状拓扑
|
||||
send_txs_by_tree=true
|
||||
; must between 1000 to 3000
|
||||
; only enabled when sync_by_tree is true
|
||||
# Gossip 协议心跳间隔
|
||||
gossip_interval_ms=1000
|
||||
# 每个节点维护 3 个gossip邻居
|
||||
gossip_peers_number=3
|
||||
; max number of nodes that broadcast txs status to, recommended less than 5
|
||||
# 交易状态最多广播给5个节点
|
||||
txs_max_gossip_peers_num=5
|
||||
|
||||
# 群组级的流量控制
|
||||
[flow_control]
|
||||
; restrict QPS of the group
|
||||
# 限制群组的 QPS 为 1000
|
||||
;limit_req=1000
|
||||
; restrict the outgoing bandwidth of the group
|
||||
; Mb, can be a decimal
|
||||
; when the outgoing bandwidth exceeds the limit, the block synchronization operation will not proceed
|
||||
# 限制群组的出链带宽为 2Mbps/s
|
||||
;outgoing_bandwidth_limit=2
|
||||
|
||||
# SDK 连接白名单
|
||||
[sdk_allowlist]
|
||||
; When sdk_allowlist is empty, all SDKs can connect to this node
|
||||
; when sdk_allowlist is not empty, only the SDK in the allowlist can connect to this node
|
||||
; public_key.0 should be nodeid, nodeid's length is 128
|
||||
;public_key.0=
|
||||
```
|
||||
@tab node.nodeid
|
||||
```bash
|
||||
# 节点的 ID
|
||||
f0535616759000b473a285d60814bc2c5927a9cb897644da46890de71e59df590cd6fe1b226a95e19a566b6fc127fd85032de0d9fdd3d529e5e50cd96ad51f28
|
||||
```
|
||||
:::
|
||||
|
||||
## 节点操作命令
|
||||
|
||||
- `addSealer`:将节点转换为共识节点。
|
||||
- `addObserver`:将节点转换为观察节点。
|
||||
- `removeNode`:将节点设置为游离节点。
|
||||
|
||||
- `getSealerList`:查询当前的共识节点的列表
|
||||
- `getObserverList`:查询当前的观察者节点的列表·
|
||||
- `getNodeList`:查询当前的所有节点的列表
|
||||
|
||||
操作节点的时候是通过节点ID进行操作的,节点ID可以在节点目录的`conf/node.nodeid`中获取
|
||||
|
||||
请确保节点加入的区块链所有节点共识正常:正常的节点会输出`+++`日志
|
||||
|
||||
|
||||
## 参考文章:
|
||||
|
||||
1. [组员节点管理](https://fisco-bcos-documentation.readthedocs.io/zh-cn/latest/docs/manual/node_management.html)
|
||||
|
||||
2. [落盘加密](https://fisco-bcos-documentation.readthedocs.io/zh-cn/latest/docs/design/features/storage_security.html)
|
||||
|
||||
3. [【全网首发】FISCO-BCOS从底层讲起链从配置文件开始解析...](https://blog.csdn.net/LforikQ/article/details/130920092)
|
||||
|
||||
4. [【教程】如何修改FISCO-BCOS内的EVM的gas值,让区块链预防DOS攻击...](https://blog.csdn.net/qq_57309855/article/details/126334115)
|
||||
@@ -7,3 +7,15 @@ permalink: /programming/solidity/
|
||||
|
||||
## Solidity 智能合约概述
|
||||
|
||||
Solidity 是一种用于编写智能合约的静态类型编程语言,它运行在以太坊虚拟机(EVM)上。
|
||||
|
||||
## 推荐的资料
|
||||
推荐的编辑器
|
||||
|
||||
Remix IDE:[https://remix.ethereum.org/](https://remix.ethereum.org/)
|
||||
|
||||
有在线版本,也可以下载之后使用,而且可以通过 Docker 部署,很方便
|
||||
|
||||
Solidity 学习资料:
|
||||
- [Solidity 官方文档](https://docs.soliditylang.org/zh-cn/latest/index.html)
|
||||
- [cryptozombies](https://cryptozombies.io/zh/course)
|
||||
|
||||
@@ -6,180 +6,83 @@ permalink: /programming/solidity/basic-syntax/
|
||||
|
||||
# Solidity 基础语法与数据类型~(≧∇≦)ノ
|
||||
|
||||
嗨~欢迎来到 Solidity 基础语法的学习时间!今天我们要一起探索 Solidity 这门神奇语言的基本结构和数据类型哦~准备好了吗?Let's go!(๑>◡<๑)
|
||||
## Solidity 文件基础框架
|
||||
|
||||
## 智能合约的基本结构 🏗️
|
||||
Solidity 文件的基础框架通常包含以下几个部分:
|
||||
|
||||
让我们先来看一个最简单的 Solidity 智能合约是什么样子的吧:
|
||||
1. **SPDX 许可证标识符 (SPDX License Identifier)**:为了避免法律问题和明确智能合约的开源许可证,建议在合约的开头添加 SPDX 许可证标识符。
|
||||
2. **Solidity 版本声明 (Pragma)**:这会告诉编译器您希望使用哪个版本的 Solidity 来编译您的代码。
|
||||
3. **ABI编码编译指示**:通过`pragma abicoder v1`或`pragma abicoder v2`来指定ABI编码版本。
|
||||
4. **合约定义 (Contract Definition)**:这是您编写智能合约代码的主体部分。
|
||||
|
||||
下面是一个基础的 Solidity 文件框架示例,您可以直接使用:
|
||||
|
||||
```solidity
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
pragma solidity ^0.8.20;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract HelloWorld {
|
||||
// 状态变量
|
||||
string public greeting = "Hello, World!";
|
||||
|
||||
// 函数
|
||||
function setGreeting(string memory _greeting) public {
|
||||
greeting = _greeting;
|
||||
}
|
||||
|
||||
function getGreeting() public view returns (string memory) {
|
||||
return greeting;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
是不是看起来有点像其他编程语言呀?让我们来一点一点地了解它吧~
|
||||
|
||||
## 版本声明和许可证 📜
|
||||
|
||||
在 Solidity 合约的最开始,我们需要添加两行重要的声明:
|
||||
|
||||
```solidity
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.0;
|
||||
```
|
||||
|
||||
- **许可证声明**:告诉别人你的代码使用什么许可证,可以自由使用吗?
|
||||
- **版本声明**:指定合约使用的 Solidity 编译器版本,`^0.8.0` 表示可以使用 0.8.0 及以上的版本哦~
|
||||
|
||||
## 数据类型 🌈
|
||||
|
||||
Solidity 有很多有趣的数据类型,让我们来认识一下它们吧~
|
||||
|
||||
### 值类型
|
||||
|
||||
这些类型在赋值时会直接复制值哦~
|
||||
|
||||
#### 布尔型 (Boolean)
|
||||
|
||||
```solidity
|
||||
bool public isActive = true;
|
||||
bool public isPaused = false;
|
||||
```
|
||||
|
||||
布尔型只有两个值:`true` 和 `false`,就像开关一样简单!(๑˘ᴗ˘๑)
|
||||
|
||||
#### 整型 (Integer)
|
||||
|
||||
```solidity
|
||||
int public negativeNumber = -42;
|
||||
uint public positiveNumber = 42;
|
||||
|
||||
// 你还可以指定位数哦~
|
||||
uint8 public smallNumber = 255; // 0-255
|
||||
uint256 public bigNumber = 1000000000000000000; // 这是 1 以太币的 wei 值哦~
|
||||
```
|
||||
|
||||
整型分为有符号(`int`)和无符号(`uint`)两种,可以存储正数和负数呢~
|
||||
|
||||
#### 地址型 (Address)
|
||||
|
||||
```solidity
|
||||
address public owner = 0x71C7656EC7ab88b098defB751B7401B5f6d8976F;
|
||||
|
||||
// 可以转账的地址类型
|
||||
address payable public recipient = payable(0x71C7656EC7ab88b098defB751B7401B5f6d8976F);
|
||||
```
|
||||
|
||||
地址类型非常特别,它用于存储以太坊账户的地址,就像是账户的身份证号码一样~`address payable` 还可以接收以太币转账呢!
|
||||
|
||||
### 引用类型
|
||||
|
||||
这些类型在赋值时只会传递引用,而不是复制整个值哦~
|
||||
|
||||
#### 字符串 (String)
|
||||
|
||||
```solidity
|
||||
string public message = "Hello, Solidity!";
|
||||
string public name = "祀梦";
|
||||
```
|
||||
|
||||
字符串用于存储文本数据,就像你平时写的便签一样~
|
||||
|
||||
#### 数组 (Array)
|
||||
|
||||
```solidity
|
||||
// 固定大小的数组
|
||||
uint[5] public fixedArray = [1, 2, 3, 4, 5];
|
||||
|
||||
// 动态大小的数组
|
||||
uint[] public dynamicArray;
|
||||
|
||||
// 你还可以在函数中这样使用哦~
|
||||
function addNumber(uint _number) public {
|
||||
dynamicArray.push(_number);
|
||||
}
|
||||
```
|
||||
|
||||
数组就像是一个收纳盒,可以按顺序存放多个相同类型的数据呢~
|
||||
|
||||
#### 映射 (Mapping)
|
||||
|
||||
```solidity
|
||||
// 映射:地址 => 余额
|
||||
mapping(address => uint) public balances;
|
||||
|
||||
// 使用方式
|
||||
function deposit() public payable {
|
||||
balances[msg.sender] += msg.value;
|
||||
}
|
||||
```
|
||||
|
||||
映射是 Solidity 中非常强大的数据结构,就像是一个魔法字典,可以通过键快速找到对应的值~
|
||||
|
||||
## 变量作用域 🔍
|
||||
|
||||
在 Solidity 中,变量有不同的作用域哦:
|
||||
|
||||
### 状态变量
|
||||
|
||||
```solidity
|
||||
contract MyContract {
|
||||
// 状态变量:存储在区块链上的
|
||||
uint public myStateVariable = 42;
|
||||
// 在这里编写您的合约代码
|
||||
}
|
||||
```
|
||||
|
||||
状态变量是存储在区块链上的,所有合约函数都可以访问它们,就像是合约的公共记忆一样~
|
||||
## Solidity 基础数据类型
|
||||
|
||||
### 局部变量
|
||||
- 布尔类型(bool):值为 `true` 和 `false`
|
||||
- 运算符:`!`(逻辑非)、`&&`(逻辑与)、`||`(逻辑或)、`==`(等于)、`!=`(不等于)
|
||||
- 整形(int/uint):
|
||||
- 有符号整数(int):可以表示负数和零。
|
||||
- 无符号整数(uint):只能表示非负数。
|
||||
- 整数类型可以是8位、16位、32位、64位或256位。(只要是八的倍数都可以)
|
||||
- 例如:`int8`、`uint256`等。
|
||||
- 运算符:
|
||||
- 比较运算符:`<=`,`<`,`>=`,`>`
|
||||
- 位运算符:`&`(按位与)、`|`(按位或)、`^`(按位异或)、`~`(按位取反)
|
||||
- 移位运算符:`<<`(左移)、`>>`(右移)
|
||||
- 算数运算符:`+`(加法)、`-`(减法)、`*`(乘法)、`/`(除法)、`%`(取余)
|
||||
- 对于一个整数类型`X`,可以使用`type(X).min`和`type(X).max`来获取其最小值和最大值。
|
||||
|
||||
|
||||
|
||||
## Solidity 基础语法结构
|
||||
|
||||
## Solidity 基础操作
|
||||
|
||||
### 导入其他源文件
|
||||
|
||||
Solidity 支持导入其他源文件,使用`import`语句。例如:
|
||||
|
||||
```solidity
|
||||
function myFunction() public {
|
||||
// 局部变量:只在函数内部可见
|
||||
uint myLocalVariable = 100;
|
||||
}
|
||||
import "filename.sol";
|
||||
```
|
||||
|
||||
局部变量只在定义它们的函数内部可见,函数执行结束后就会消失哦~
|
||||
这将导入`filename.sol`文件中的合约代码。
|
||||
|
||||
### 全局变量
|
||||
还可以创建一个新的全局符号
|
||||
|
||||
```solidity
|
||||
function getSender() public view returns (address) {
|
||||
// msg.sender 是一个全局变量,包含当前调用者的地址
|
||||
return msg.sender;
|
||||
}
|
||||
import * as NewName from "filename.sol"
|
||||
```
|
||||
|
||||
全局变量是 Solidity 内置的特殊变量,可以在任何地方使用,它们提供了关于区块链和交易的重要信息呢~
|
||||
这将创建一个新的全局符号`NewName`,您可以在合约中使用它来引用`filename.sol`文件中的合约,例如`NewName.ContractName`。
|
||||
|
||||
## 小练习 🏋️♀️
|
||||
还可以在导入的同时重命名符号:`import {symbol1 as alias, symbol2} from "filename";`
|
||||
|
||||
现在让我们来做一个小练习吧!试着编写一个简单的计数器合约,包含以下功能:
|
||||
### 注释
|
||||
|
||||
1. 一个状态变量来存储计数值
|
||||
2. 一个函数来增加计数
|
||||
3. 一个函数来减少计数
|
||||
4. 一个函数来获取当前计数值
|
||||
Solidity 支持两种类型的注释:
|
||||
|
||||
你可以做到吗?相信自己,你一定可以的!(๑•̀ㅂ•́)و✧
|
||||
1. **行注释**:使用`//`来注释单行代码。
|
||||
2. **块注释**:使用`/*`和`*/`来注释多行代码。
|
||||
|
||||
## 写在最后~💌
|
||||
例如:
|
||||
|
||||
今天我们学习了 Solidity 的基础语法和数据类型,这些都是构建智能合约的基石哦~虽然一开始可能会觉得有点复杂,但只要多练习,你一定会越来越熟练的!下节课我们将学习 Solidity 的函数和修饰器,敬请期待吧~
|
||||
```solidity
|
||||
// 这是一个行注释
|
||||
|
||||
如果有任何问题,欢迎随时提问哦~让我们一起在区块链的世界里快乐地探索吧!(づ ̄ 3 ̄)づ
|
||||
/*
|
||||
这是一个
|
||||
块注释
|
||||
*/
|
||||
```
|
||||
922
docs/notes/programming/solidity/case-analysis.md
Normal file
922
docs/notes/programming/solidity/case-analysis.md
Normal file
@@ -0,0 +1,922 @@
|
||||
---
|
||||
title: 十份代码实例
|
||||
createTime: 2025/10/10 11:07:11
|
||||
permalink: /programming/solidity/analysis/case-analysis/
|
||||
password: simeng
|
||||
---
|
||||
|
||||
## 题目一
|
||||
|
||||
原题:
|
||||
|
||||
1.食品信息(FoodInfoItem)的接口编码
|
||||
|
||||
(1)编写食品信息实体的接口,完成可溯源食品信息初始化,实现可追溯的原始生产商食品信息上链功能
|
||||
|
||||
(2)编写分销商食品上链信息接口,根据食品溯源智能合约地址获取分销商上链食品的信息
|
||||
|
||||
(3)编写超市进行食品上链信息的接口,根据食品溯源智能合约地址获取超市上链食品信息。
|
||||
|
||||
2.食品溯源(Trace)的接口编码
|
||||
|
||||
(1)编写食品溯源智能合约生产商Producer添加食品接口,必须生产商才能添加可溯源的食品,实现溯源功能
|
||||
|
||||
(2)编写食品溯源智能合约分销商Distributor添加食品接口,必须分销商才能添加可溯源的食品,实现溯源功能
|
||||
|
||||
(3)编写食品溯源智能合约超市Retailer添加食品接口,必须超市才能添加可溯源的食品,实现溯源功能
|
||||
|
||||
3.角色(Role)管理的接口编码
|
||||
|
||||
(1)编写食品溯源增加角色接口,必须是未增加的角色才能被添加,实现添加角色的功能
|
||||
|
||||
(2)编写食品溯源移除角色接口,必须是已增加的角色才能被移除,实现移除角色的功能
|
||||
|
||||
(3)编写食品溯源角色授权接口,必须是授权的角色地址,实现角色权限管理功能
|
||||
|
||||
::: code-tabs
|
||||
@tab Distributor.sol
|
||||
```solidity
|
||||
pragma solidity ^0.4.25;
|
||||
|
||||
import "./Roles.sol";
|
||||
|
||||
//中间商角色
|
||||
contract Distributor {
|
||||
using Roles for Roles.Role;
|
||||
|
||||
event DistributorAdded(address indexed account);
|
||||
event DistributorRemoved(address indexed account);
|
||||
|
||||
Roles.Role private _distributors;
|
||||
|
||||
constructor (address distributor ) public {
|
||||
_addDistributor(distributor);
|
||||
}
|
||||
|
||||
modifier onlyDistributor() {
|
||||
require(isDistributor(msg.sender), "DistributorRole: caller does not have the Distributor role");
|
||||
_;
|
||||
}
|
||||
|
||||
function isDistributor(address account) public view returns (bool) {
|
||||
return _distributors.has(account);
|
||||
}
|
||||
|
||||
function addDistributor(address account) public onlyDistributor {
|
||||
_addDistributor(account);
|
||||
}
|
||||
|
||||
function renounceDistributor() public {
|
||||
_removeDistributor(msg.sender);
|
||||
}
|
||||
|
||||
function _addDistributor(address account) internal {
|
||||
_distributors.add(account);
|
||||
emit DistributorAdded(account);
|
||||
}
|
||||
|
||||
function _removeDistributor(address account) internal {
|
||||
_distributors.remove(account);
|
||||
emit DistributorRemoved(account);
|
||||
}
|
||||
}
|
||||
```
|
||||
@tab FoodInfoItem.sol
|
||||
```solidity
|
||||
pragma solidity >=0.4.22 <0.5.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
//食品信息管理合约
|
||||
// 1. 保存食品基本信息:时间戳(流转过程中),用户名(流转过程中),用户地址信息(流转过程中),食品质量(流转过程中),食物名称,当前用户名称,质量,状态.
|
||||
// 2. 对食品基本信息进行初始化
|
||||
// 3. 实现两个方法:中间商添加食品信息;超市添加食品信息
|
||||
// 4. 实现显示食品信息的方法
|
||||
|
||||
contract FoodInfoItem{
|
||||
uint[] _timestamp;//①保存食品流转过程中各个阶段的时间戳
|
||||
string[] _traceName;//②保存食品流转过程各个阶段的用户名
|
||||
address[] _traceAddress;//③保存食品流转过程各个阶段的用户地址信息(和用户一一对应)
|
||||
uint8[] _traceQuality;//④保存食品流转过程中各个阶段的质量
|
||||
string _name;//⑤食品名称
|
||||
string _currentTraceName;//⑥当前用户名称
|
||||
uint8 _quality;//⑦质量(0=优质 1=合格 2=不合格)
|
||||
uint8 _status;//⑧状态(0:生产 1:分销 2:出售)
|
||||
address _owner;//⑨初始化owner
|
||||
|
||||
constructor (string name, string traceName, uint8 quality, address producer) public {
|
||||
_timestamp.push(now);
|
||||
_traceName.push(traceName);
|
||||
_traceAddress.push(producer);
|
||||
_traceQuality.push(quality);
|
||||
_name = name;
|
||||
_currentTraceName = traceName;
|
||||
_quality = quality;
|
||||
_status = 0;
|
||||
_owner = msg.sender;
|
||||
}
|
||||
|
||||
function addTraceInfoByDistributor(string traceName,address distributor, uint8 quality) public returns(bool) {
|
||||
require(_status == 0 , "status must be producing");
|
||||
require(_owner == msg.sender,"only trace contract can invoke")
|
||||
//②
|
||||
_timestamp.push(now);
|
||||
_traceName.push(traceName);
|
||||
_currentTraceName = traceName;
|
||||
_traceAddress.push(distributor);
|
||||
_quality = quality;
|
||||
//③
|
||||
//④
|
||||
_traceQuality.push(_quality);
|
||||
_status = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
function addTraceInfoByRetailer(string traceName,address retailer, uint8 quality) public returns(bool) {
|
||||
require(_status == 1 , "status must be distributing");
|
||||
require(_owner == msg.sender,"only trace contract can invoke")
|
||||
//②
|
||||
_timestamp.push(now);
|
||||
_traceName.push(traceName);
|
||||
_currentTraceName = traceName;
|
||||
_traceAddress.push(retailer);
|
||||
_quality = quality;
|
||||
//③
|
||||
//④
|
||||
_traceQuality.push(_quality);
|
||||
_status = 2;
|
||||
return true;
|
||||
}
|
||||
function getTraceInfo() public constant returns(uint[], string[], address[], uint8[]) {
|
||||
return(_timestamp, _traceName, _traceAddress, _traceQuality);
|
||||
}
|
||||
|
||||
function getFood() public constant returns(uint, string, string, string, address, uint8) {
|
||||
return(_timestamp[0], _traceName[0], _name, _currentTraceName, _traceAddress[0], _quality);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
@tab Producer.sol
|
||||
```solidity
|
||||
pragma solidity ^0.4.25;
|
||||
|
||||
import "./Roles.sol";
|
||||
|
||||
//生产者角色
|
||||
contract Producer {
|
||||
using Roles for Roles.Role;
|
||||
|
||||
event ProducerAdded(address indexed account);
|
||||
event ProducerRemoved(address indexed account);
|
||||
|
||||
Roles.Role private _producers;
|
||||
|
||||
constructor (address producer) public {
|
||||
_addProducer(producer);
|
||||
}
|
||||
|
||||
modifier onlyProducer() {
|
||||
require(isProducer(msg.sender), "ProducerRole: caller does not have the Producer role");
|
||||
_;
|
||||
}
|
||||
|
||||
function isProducer(address account) public view returns (bool) {
|
||||
return _producers.has(account);
|
||||
}
|
||||
|
||||
function addProducer(address account) public onlyProducer {
|
||||
_addProducer(account);
|
||||
}
|
||||
|
||||
function renounceProducer() public {
|
||||
_removeProducer(msg.sender);
|
||||
}
|
||||
|
||||
function _addProducer(address account) internal {
|
||||
_producers.add(account);
|
||||
emit ProducerAdded(account);
|
||||
}
|
||||
|
||||
function _removeProducer(address account) internal {
|
||||
_producers.remove(account);
|
||||
emit ProducerRemoved(account);
|
||||
}
|
||||
}
|
||||
```
|
||||
@tab Retailer.sol
|
||||
```solidity
|
||||
pragma solidity ^0.4.25;
|
||||
|
||||
import "./Roles.sol";
|
||||
|
||||
//零售商角色(超市)
|
||||
contract Retailer {
|
||||
using Roles for Roles.Role;
|
||||
|
||||
event RetailerAdded(address indexed account);
|
||||
event RetailerRemoved(address indexed account);
|
||||
|
||||
Roles.Role private _retailers;
|
||||
|
||||
constructor (address retailer) public {
|
||||
_addRetailer(retailer);
|
||||
}
|
||||
|
||||
modifier onlyRetailer() {
|
||||
require(isRetailer(msg.sender), "RetailerRole: caller does not have the Retailer role");
|
||||
_;
|
||||
}
|
||||
|
||||
function isRetailer(address account) public view returns (bool) {
|
||||
return _retailers.has(account);
|
||||
}
|
||||
|
||||
function addRetailer(address account) public onlyRetailer {
|
||||
_addRetailer(account);
|
||||
}
|
||||
|
||||
function renounceRetailer() public {
|
||||
_removeRetailer(msg.sender);
|
||||
}
|
||||
|
||||
function _addRetailer(address account) internal {
|
||||
_retailers.add(account);
|
||||
emit RetailerAdded(account);
|
||||
}
|
||||
|
||||
function _removeRetailer(address account) internal {
|
||||
_retailers.remove(account);
|
||||
emit RetailerRemoved(account);
|
||||
}
|
||||
}
|
||||
```
|
||||
@tab Roles.sol
|
||||
```solidity
|
||||
pragma solidity ^0.4.25;
|
||||
//角色库(管理所有角色地址)
|
||||
// 1. 实现增加角色地址
|
||||
// 2. 移除角色地址
|
||||
// 3. 判断角色地址是否被授权
|
||||
library Roles {
|
||||
struct Role {
|
||||
mapping (address => bool) bearer;
|
||||
}
|
||||
function add(Role storage role, address account) internal {
|
||||
require(!has(role, account), "Roles: account already has role");
|
||||
role.bearer[account] = true;
|
||||
}
|
||||
function remove(Role storage role, address account) internal {
|
||||
require(has(role, account), "Roles: account does not have role");
|
||||
role.bearer[account] = false;
|
||||
}
|
||||
function has(Role storage role, address account) internal returns (bool) {
|
||||
require(account != address(0), "Roles: account is the zero address");
|
||||
return role.bearer[account];
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
@tab Trace.sol
|
||||
```solidity
|
||||
pragma solidity >=0.4.22 <0.7.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
import "./FoodInfoItem.sol";
|
||||
import "./Distributor.sol";
|
||||
import "./Producer.sol";
|
||||
import "./Retailer.sol";
|
||||
|
||||
//食品溯源合约(负责具体食品溯源信息的生成)
|
||||
// 1.实现生产食品的方法(新建食品信息)
|
||||
// 2.实现食品分销过程中增加溯源信息的接口
|
||||
// 3.实现食品出售过程中增加溯源信息的接口
|
||||
// 4.实现获取食品溯源信息接口
|
||||
|
||||
contract Trace is Producer, Distributor, Retailer{
|
||||
|
||||
mapping (uint256 => address) foods;//食品溯源id到具体食品溯源合约的映射表
|
||||
uint[] foodList;
|
||||
|
||||
//构造函数
|
||||
constructor(address producer, address distributor, address retailer)
|
||||
public Producer(producer)
|
||||
Distributor(distributor)
|
||||
Retailer(retailer){
|
||||
|
||||
}
|
||||
//生成食品溯源信息接口
|
||||
//只有Producer能调用
|
||||
//name 食品名称
|
||||
//traceNumber 食品溯源id
|
||||
//traceName 当前用户名称
|
||||
//quality 当前食品质量
|
||||
function newFood(string name,uint256 traceNumber, string traceName, uint8 quality)
|
||||
public onlyProducer returns(uint)
|
||||
{
|
||||
require(foods[traceNumber] == address(0),"traceName already exist");//④
|
||||
FoodInfoItem food = new FoodInfoItem(name,traceName,quality,msg.sender);//⑤
|
||||
foods[traceNumber] = food;//⑥
|
||||
foodList.push(traceNumber);//⑦
|
||||
retur food;//⑧
|
||||
}
|
||||
|
||||
//食品分销过程中增加溯源信息的接口
|
||||
//只有Distributor能调用
|
||||
//traceNumber 食品溯源id
|
||||
//traceName 当前用户名称
|
||||
//quality 当前食品质量
|
||||
function addTraceInfoByDistributor(uint256 traceNumber,string traceName, uint8 quality)
|
||||
public onlyRetailer returns(bool) {
|
||||
require(foods[traceNumber] != address(0),"traceNumber does not exist");
|
||||
//③
|
||||
return FoodInfoItem(foods[traceNumber]).addTraceInfoByDistributor(traceName,msg.sender, quality);
|
||||
}
|
||||
|
||||
//食品出售过程中增加溯源信息的接口
|
||||
//只有Retailer能调用
|
||||
//traceNumber 食品溯源id
|
||||
//traceName 当前用户名称
|
||||
//quality 当前食品质量
|
||||
function addTraceInfoByRetailer(uint256 traceNumber,string traceName, uint8 quality)
|
||||
public onlyRetailer returns(bool) {
|
||||
require(foods[traceNumber != address(0)], "traceNumber does not exist");
|
||||
return FoodInfoItem(foods[traceNumber]).addTraceInfoByRetailer(traceName,msg.sender, quality);
|
||||
}
|
||||
|
||||
//获取食品溯源信息接口
|
||||
//string[] 保存食品流转过程中各个阶段的相关信息
|
||||
//address[] 保存食品流转过程各个阶段的用户地址信息(和用户一一对应)
|
||||
//uint8[] 保存食品流转过程中各个阶段的状态变化
|
||||
function getTraceInfo(uint256 traceNumber) public constant returns(uint[], string[], address[], uint8[]) {
|
||||
require(foods[traceNumber] != address(0), "traceNumber does not exist");
|
||||
return FoodInfoItem(foods[traceNumber]).getTraceInfo();
|
||||
}
|
||||
|
||||
function getFood(uint256 traceNumber) public constant returns(uint, string, string, string, address, uint8) {
|
||||
require(foods[traceNumber] != address(0), "traceNumber does not exist");
|
||||
return FoodInfoItem(foods[traceNumber]).getFood();
|
||||
}
|
||||
|
||||
function getAllFood() public constant returns (uint[]) {
|
||||
return foodList;
|
||||
}
|
||||
}
|
||||
```
|
||||
:::
|
||||
## 题目二
|
||||
|
||||
题目:
|
||||
|
||||
1.供应链金融实体信息编码(6分)
|
||||
|
||||
(1)编写供应链金融智能合约的实体接口,完成实体通用数据的初始化,实现企业和票据实体信息上链的功能;(2分)
|
||||
|
||||
(2)编写企业上链信息接口,实现供应链金融的企业信息上链;(2分)
|
||||
|
||||
(3)基于给定的智能合约代码以及注释,完成银行向企业交易的接口函数;(2分)
|
||||
|
||||
2.供应链金融公司与公司接口编码(6分)
|
||||
|
||||
(1)编写公司与公司之间进行交易的历史存证上链接口,实现公司与公司之间的交易功能;(2分)
|
||||
|
||||
(2)编写创建存证的接口,实现创建存证的功能;(2分)
|
||||
|
||||
(3)编写交易金额数量变化的接口,实现凭证交易双方资金的变化功能;(2分)
|
||||
|
||||
3.供应链金融公司与银行交易的接口编码(4分)
|
||||
|
||||
(1)编写公司与银行之间进行交易的历史存证上链接口,实现公司与银行之间的交易功能;(2分)
|
||||
|
||||
(2)编写创建存证的接口,实现创建存证的功能;(1分)
|
||||
|
||||
(3)编写交易金额数量变化的接口,实现凭证交易双方资金的变化功能;(1分)
|
||||
|
||||
::: code-tabs
|
||||
@tab xxx.sol
|
||||
```solidity
|
||||
```
|
||||
@tab xxx.sol
|
||||
```solidity
|
||||
```
|
||||
@tab xxx.sol
|
||||
```solidity
|
||||
```
|
||||
:::
|
||||
## 题目三
|
||||
|
||||
题目:
|
||||
|
||||
子任务2-2-1:太阳能板管理接口编码
|
||||
|
||||
1. 根据文档要求,编写太阳能板新增接口功能,必须将新增太阳能板数据存入指定表中,在存储完成后需触发后事件并返回存储与否的标识;
|
||||
|
||||
2. 根据文档要求,编写太阳能板修改接口,必须通过指定表修改完成数据更新,在完成更新后需触发事件并返回更新与否的标识。
|
||||
|
||||
子任务2-2-2:能源管理接口编码
|
||||
|
||||
1. 根据文档要求,编写能源新增接口功能,必须将新增能源数据存入指定表中,在存储完成后需触发后事件并返回存储与否的标识;
|
||||
|
||||
2. 根据文档要求,编写能源修改接口,必须通过指定表修改完成数据更新,在完成更新后需触发事件并返回更新与否的标识。
|
||||
|
||||
子任务2-2-3:合约部署和调用
|
||||
|
||||
1. 解决代码错误和警告,正确编译并部署合约,成功获取部署的合约地址和ABI;
|
||||
|
||||
2. 调用太阳能板查询合约接口,完整验证业务流程;
|
||||
|
||||
3. 调用能源查询合约接口,完整验证业务流程。
|
||||
|
||||
::: code-tabs
|
||||
@tab xxx.sol
|
||||
```solidity
|
||||
```
|
||||
@tab xxx.sol
|
||||
```solidity
|
||||
```
|
||||
@tab xxx.sol
|
||||
```solidity
|
||||
```
|
||||
:::
|
||||
## 题目四
|
||||
|
||||
原题:
|
||||
|
||||
1.编写原材料接口newMaterial,初始化原材料信息,返回合约地址,并实现原材料信息上链功能。
|
||||
|
||||
2.编写获取存原材料接口getMaterial,根据合约地址获取原材料信息
|
||||
|
||||
3.编写食品物流上链接口addLogistic,实现食品物流信息上链功能
|
||||
|
||||
4.编写获取食品物流信息的接口getLogistics,根据食品产品编号获取物流信息
|
||||
|
||||
::: code-tabs
|
||||
@tab Logistics.sol
|
||||
```solidity
|
||||
pragma solidity 0.6.10;
|
||||
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract Logistics {
|
||||
|
||||
struct LogisticsData {
|
||||
address cargo; //货物合约地址
|
||||
address orgin; //货物上级合约地址
|
||||
address destination; //货物下级合约地址
|
||||
string memo; //备注信息
|
||||
uint createdAt; //创建时间
|
||||
uint queryCount; //已查询次数
|
||||
}
|
||||
|
||||
LogisticsData[] private _logisticsData; //全部物流信息数组
|
||||
|
||||
uint public recordCount;//所有记录条数
|
||||
uint public queryCount;//所有查询次数
|
||||
|
||||
//可自行添加形参和返回值
|
||||
function addLogistics(address _cargo,address _orgin,【请补充】) public {
|
||||
//TODO:”请补充缺失代码
|
||||
}
|
||||
|
||||
//可自行添加形参和返回值
|
||||
function getLogisticsInfo(address _cargo) public returns(LogisticsData[] memory _cargoLogisticsData) {
|
||||
|
||||
//TODO:”请补充缺失代码
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
@tab Material.sol
|
||||
```solidity
|
||||
pragma solidity 0.6.10;
|
||||
|
||||
contract Material {
|
||||
struct Material {
|
||||
address owner;
|
||||
string name;
|
||||
string id;
|
||||
string memo;
|
||||
uint createdAt;
|
||||
bool exist;
|
||||
}
|
||||
|
||||
mapping(string => Material) public materials;
|
||||
//可自行添加形参和返回值
|
||||
function newMaterial(string memory _name,string memory _id,【请补充】) public {
|
||||
|
||||
//TODO:”请补充缺失代码
|
||||
}
|
||||
|
||||
|
||||
//可自行添加形参和返回值
|
||||
function getMaterial(string memory id) public view returns(【请补充】) {
|
||||
|
||||
//TODO:”请补充缺失代码
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
参考答案:
|
||||
|
||||
::: code-tabs
|
||||
@tab Logistics.sol
|
||||
```solidity
|
||||
pragma solidity 0.6.10;
|
||||
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract Logistics {
|
||||
|
||||
struct LogisticsData {
|
||||
address cargo; //货物合约地址
|
||||
address orgin; //货物上级合约地址
|
||||
address destination; //货物下级合约地址
|
||||
string memo; //备注信息
|
||||
uint createdAt; //创建时间
|
||||
uint queryCount; //已查询次数
|
||||
}
|
||||
|
||||
LogisticsData[] private _logisticsData; //全部物流信息数组
|
||||
|
||||
uint public recordCount;//所有记录条数
|
||||
uint public queryCount;//所有查询次数
|
||||
|
||||
//可自行添加形参和返回值
|
||||
function addLogistics(address _cargo,address _orgin,【请补充】) public {
|
||||
//TODO:”请补充缺失代码
|
||||
}
|
||||
|
||||
//可自行添加形参和返回值
|
||||
function getLogisticsInfo(address _cargo) public returns(LogisticsData[] memory _cargoLogisticsData) {
|
||||
|
||||
//TODO:”请补充缺失代码
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
@tab Material.sol
|
||||
```solidity
|
||||
pragma solidity 0.6.10;
|
||||
|
||||
contract Material {
|
||||
struct Material {
|
||||
address owner;
|
||||
string name;
|
||||
string id;
|
||||
string memo;
|
||||
uint createdAt;
|
||||
bool exist;
|
||||
}
|
||||
|
||||
mapping(string => Material) public materials;
|
||||
//可自行添加形参和返回值
|
||||
function newMaterial(string memory _name,string memory _id,【请补充】) public {
|
||||
|
||||
//TODO:”请补充缺失代码
|
||||
}
|
||||
|
||||
|
||||
//可自行添加形参和返回值
|
||||
function getMaterial(string memory id) public view returns(【请补充】) {
|
||||
|
||||
//TODO:”请补充缺失代码
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
## 题目五
|
||||
|
||||
题目:
|
||||
|
||||
1.个人签章信息接口编码
|
||||
|
||||
(1)编写个人签章智能合约的实体接口,完成实体通用数据的初始化,实现签章和用户实体信息上链的功能
|
||||
|
||||
(2)编写签章信息上链的接口,实现Seal合约的构造函数;
|
||||
|
||||
(3)基于给定的智能合约代码以及注释,完成ElectronicSeal合约判断多人签章文件编号是否存在的函数。
|
||||
|
||||
2.电子印章接口编码
|
||||
|
||||
(1)基于给定的智能合约代码以及注释,完成ElectronicSeal合约获取多人签章信息函数;
|
||||
|
||||
(2)基于给定的智能合约代码以及注释,完成ElectronicSeal合约多人签章函数。
|
||||
|
||||
::: code-tabs
|
||||
@tab xxx.sol
|
||||
```solidity
|
||||
```
|
||||
:::
|
||||
## 题目六
|
||||
|
||||
题目:
|
||||
|
||||
1.食品信息(Food)、成员信息(Member)、生产订单信息(Productions)的结构体功能编码(6分)
|
||||
|
||||
(1)编写食品信息实体功能。(2分)
|
||||
|
||||
(2)完善智能合约中用户结构体内容(2分)
|
||||
|
||||
(3)编写生产订单(Productions)结构体信息。(2分)
|
||||
|
||||
2.食品溯源(Trace)的接口编码(6分)
|
||||
|
||||
(1)根据食品信息结构体,完成食品信息添加相应功能(2分)
|
||||
|
||||
(2)编写食品溯源收购商创建收购订单功能。
|
||||
|
||||
(3)编写食品溯源创建运输订单功能。
|
||||
|
||||
3.角色(Role)管理的接口编码(4分)
|
||||
|
||||
(1)编写食品溯源增加角色接口,实现添加角色的功能。(1分)
|
||||
|
||||
(2)编写食品溯源获取角色功能。(1分)
|
||||
|
||||
(3)编写食品溯源修改角色功能。(2分)
|
||||
|
||||
::: code-tabs
|
||||
@tab xxx.sol
|
||||
```
|
||||
```
|
||||
:::
|
||||
## 题目七
|
||||
|
||||
原题:
|
||||
**子任务2-2-1:航班延误保险购买合约编码(5分)**
|
||||
|
||||
(1)编写航班保险购买上链接口,完成只有购买机票的用户可以购买保险、必须缴纳正确的保费金额、购买保险的时间不能超过购买机票后的0.5小时的功能,符合条件则用户可以购买保险,将用户购买保险状态上链;(3分)
|
||||
|
||||
(2)编写退保接口,完成保险公司预存赔偿金后,用户无法退保,反之用户可退保的功能,将用户退保状态上链,并退还用户保费功能。(2分)
|
||||
|
||||
**子任务2-2-2:航班信息存证上链合约编码**
|
||||
|
||||
(1)编写获取航班信息接口,实现依据航班号获得航班号对应的计划起飞时间、实际起飞时间、到达时间、是否延误状态的功能;
|
||||
|
||||
(2)编写判断航班是否延误接口,实现依据航班号获得航班号对应的航班是否延误,得到航班是否延误的结果功能。
|
||||
|
||||
**子任务2-2-3:航班延误险理赔合约编码**
|
||||
|
||||
(1)编写客户理赔接口,实现如果航班延误超过4小时,将赔偿金赔偿给乘客的功能;
|
||||
|
||||
(2)编写保险公司收取保费接口,实现如果航班没有延误或者延误时间少于4小时,将保费转账给保险公司,并退还赔偿金的功能。
|
||||
|
||||
::: code-tabs
|
||||
@tab Claims.sol
|
||||
```solidity
|
||||
pragma solidity ^0.6.10;
|
||||
|
||||
import "./FlightDelayInsurance.sol";
|
||||
|
||||
contract Claims is FlightDelayInsurance{
|
||||
|
||||
// 定义航班信息结构体
|
||||
struct Flight {
|
||||
uint256 departureTime; // 航班出发时间
|
||||
uint256 delayTime; // 航班延误时间
|
||||
bool isDelayed; // 航班是否延误
|
||||
bool isInsured; // 航班是否购买保险
|
||||
}
|
||||
|
||||
// 定义保险公司地址
|
||||
address public insuranceCompany;
|
||||
|
||||
// 定义航班信息映射
|
||||
mapping(bytes32 => Flight) public flights;
|
||||
|
||||
// 定义购买保险事件
|
||||
event BuyInsurance(bytes32 flightKey, address passenger, uint256 premium);
|
||||
|
||||
// 定义航班延误事件
|
||||
event FlightDelay(bytes32 flightKey, uint256 delayTime);
|
||||
|
||||
// 定义理赔事件
|
||||
event Claim(bytes32 flightKey, address passenger, uint256 amount);
|
||||
|
||||
// 定义保险公司预存的赔偿金
|
||||
uint256 public compensationNew;
|
||||
|
||||
// 构造函数,初始化保险公司地址和赔偿金
|
||||
constructor() FlightDelayInsurance(platformS,airlineV,insuranceCompanyC,premium,compensation) public {
|
||||
insuranceCompany = msg.sender;
|
||||
compensationNew = compensation;
|
||||
}
|
||||
|
||||
// 更新航班信息函数
|
||||
function updateFlight(bytes32 flightKey, uint256 departureTime, uint256 delayTime, bool isDelayed) payable public {
|
||||
// 判断调用者是否为保险公司
|
||||
require(msg.sender == insuranceCompany, "Only insurance company can update flight information");
|
||||
// 更新航班信息
|
||||
flights[flightKey].departureTime = departureTime;
|
||||
flights[flightKey].isDelayed = isDelayed;
|
||||
|
||||
/*********** 客户理赔接口 **********/
|
||||
//任务2-2-3,请编写合约代码
|
||||
|
||||
|
||||
|
||||
/********** 客户理赔接口 ***********/
|
||||
|
||||
/*********** 保险公司收取保费接口开发 **********/
|
||||
//任务2-2-3,请编写合约代码
|
||||
|
||||
|
||||
|
||||
|
||||
/********** 保险公司收取保费接口开发 ***********/
|
||||
// 触发航班延误事件
|
||||
emit FlightDelay(flightKey, delayTime);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
@tab FlightDelayInsurance.sol
|
||||
```solidity
|
||||
pragma solidity ^0.6.10;
|
||||
|
||||
contract FlightDelayInsurance {
|
||||
address public platformS; // 平台S的地址
|
||||
address public airlineV; // 航空公司V的地址
|
||||
address public insuranceCompanyC; // 保险公司C的地址
|
||||
uint public premium; // 保险费
|
||||
uint public compensation; // 赔偿金额
|
||||
uint public purchaseTime; // 购买保险的时间
|
||||
uint public depositTime; // 存入赔偿金额的时间
|
||||
bool public purchased; // 是否购买了保险
|
||||
bool public deposited; // 是否存入了赔偿金额
|
||||
mapping(address => bool) public insured; // 已退保的用户
|
||||
mapping(address => bool) public policy; // 已生成保单的用户
|
||||
mapping(address => bool) public purchasedTicket; // 已购买机票的用户
|
||||
|
||||
constructor(address _platformS, address _airlineV, address _insuranceCompanyC, uint _premium, uint _compensation) public {
|
||||
platformS = _platformS; // 初始化平台S的地址
|
||||
airlineV = _airlineV; // 初始化航空公司V的地址
|
||||
insuranceCompanyC = _insuranceCompanyC; // 初始化保险公司C的地址
|
||||
premium = _premium; // 初始化保险费
|
||||
compensation = _compensation; // 初始化赔偿金额
|
||||
}
|
||||
|
||||
function purchaseTicket() public {
|
||||
require(!purchasedTicket[msg.sender], "Ticket has already been purchased"); // 该用户已购买机票
|
||||
purchasedTicket[msg.sender] = true; // 标记该用户已购买机票
|
||||
purchaseTime = block.timestamp;
|
||||
}
|
||||
/*********** 航班保险购买上链接口开发 **********/
|
||||
//任务2-2-1,请编写合约代码
|
||||
|
||||
|
||||
|
||||
|
||||
/********** 航班保险购买上链接口开发 ***********/
|
||||
function depositCompensation() public payable {
|
||||
require(msg.sender == insuranceCompanyC, "Only insurance company C can deposit compensation"); // 只有保险公司C可以存入赔偿金额
|
||||
require(msg.value == compensation, "Compensation amount is incorrect"); // 赔偿金额不正确
|
||||
require(block.timestamp < depositTime + 2 hours, "Deposit time has expired"); // 存入赔偿金额的时间已过期
|
||||
deposited = true; // 标记已存入赔偿金额
|
||||
}
|
||||
|
||||
/*********** 退保接口开发 **********/
|
||||
//任务2-2-1,请编写合约代码
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/********** 退保接口开发 ***********/
|
||||
|
||||
function generatePolicy() public {
|
||||
require(deposited, "Compensation has not been deposited"); // 赔偿金额未存入,无法生成保单
|
||||
require(msg.sender == platformS, "Only platform S can generate policy"); // 只有平台S可以生成保单
|
||||
require(!policy[msg.sender], "Policy has already been generated"); // 该用户已生成保单
|
||||
policy[msg.sender] = true; // 标记该用户已生成保单
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
@tab FlightManagement.sol
|
||||
```solidity
|
||||
pragma solidity ^0.6.10;
|
||||
|
||||
contract FlightManagement {
|
||||
|
||||
// 航班结构体
|
||||
struct Flight {
|
||||
string flightNumber; // 航班号
|
||||
uint256 scheduledDepartureTime; // 计划起飞时间
|
||||
uint256 actualDepartureTime; // 实际起飞时间
|
||||
uint256 arrivalTime; // 到达时间
|
||||
bool delayed; // 是否延误
|
||||
}
|
||||
|
||||
// 航班号到航班信息的映射
|
||||
mapping(string => Flight) flights;
|
||||
|
||||
// 添加航班
|
||||
function addFlight(string memory _flightNumber, uint256 _scheduledDepartureTime, uint256 _arrivalTime) public {
|
||||
flights[_flightNumber] = Flight(_flightNumber, _scheduledDepartureTime, 0, _arrivalTime, false);
|
||||
}
|
||||
|
||||
// 更新实际起飞时间
|
||||
function updateActualDepartureTime(string memory _flightNumber, uint256 _actualDepartureTime) public {
|
||||
flights[_flightNumber].actualDepartureTime = _actualDepartureTime;
|
||||
}
|
||||
|
||||
/*********** 获取航班信息接口开发 **********/
|
||||
//任务2-2-2,请编写合约代码
|
||||
|
||||
|
||||
|
||||
|
||||
/********** 获取航班信息接口开发 ***********/
|
||||
|
||||
/*********** 编写判断航班是否延误接口开发 **********/
|
||||
//任务2-2-2,请编写合约代码
|
||||
|
||||
|
||||
|
||||
|
||||
/********** 编写判断航班是否延误接口开发 ***********/
|
||||
}
|
||||
|
||||
```
|
||||
:::
|
||||
## 题目八
|
||||
|
||||
题目:
|
||||
子任务2-2-1:信息管理合约编码
|
||||
1. 编写检索个人信息接口,完成患者通过身份证号检索其姓名、性别、年龄的功能;
|
||||
2. 编写信息管理接口,完成允许患者与医院和科室进行信息管理,通过身份证号检索到患者的个人信息,将预约信息显示给患者,并发送到患者的账户地址中的功能;
|
||||
子任务2-2-2:病历管理合约编码
|
||||
1. 编写新建病历接口,实现检索病人对应科室既往病历,授权医生查看,如果没有既往病历则创建一个新的病历功能;
|
||||
2. 编写结束就诊接口,实现检查病历是否已经填写,并结束病历咨询的功能。
|
||||
子任务2-2-3:病历查看合约编码
|
||||
根据需求用例文档在待补充源码中完成病历查看合约的编码,解决代码错误和警告,正确编译合约,功能调试正确,运行合约中的检查退款请求状态、自动批准退款请求接口功能。
|
||||
1.编写查看病人个人信息接口,实现获取指定病人个人信息功能;
|
||||
2.编写查看病人病情描述接口,实现获取指定病人病情描述功能。
|
||||
::: code-tabs
|
||||
@tab xxx.sol
|
||||
```
|
||||
```
|
||||
:::
|
||||
## 题目九
|
||||
|
||||
题目:
|
||||
|
||||
子任务2-2-1:合同管理合约编码
|
||||
|
||||
(1)编写房东签署合同接口,完成本合同位置只允许房东签署,通过合同中的信息生成租赁合同的链上哈希,触发协议签署合同的功能,其中合同中的信息包括房东链上账户、租客链上账户、租赁开始时间、租赁结束时间、月租金额、押金金额、交租时间;
|
||||
|
||||
(2)编写租金支付接口,完成只允许租客支付租金的规则,检查支付的租金金额是否正确,触发记录租金支付情况的功能。
|
||||
|
||||
子任务2-2-2:违约管理合约编码
|
||||
|
||||
(1)编写房东终止合同接口,实现房东终止合同判断,如果租客已经终止合同则合同无效,如果合同有效,对合同终止状态进行标记,将剩余押金退还给租客的功能;
|
||||
|
||||
(2)编写租客终止合同接口,实现租客终止合同判断,如果房东已经终止合同则合同无效,如果合同有效,对合同终止状态进行标记,将剩余押金退还给房东的功能。
|
||||
|
||||
子任务2-2-3:押金管理合约编码
|
||||
|
||||
根据需求用例文档在待补充源码中完成押金管理合约的编码,解决代码错误和警告,正确编译合约,功能调试正确,运行合约中的租客缴纳押金情况查询、房东收取押金情况查询接口功能。
|
||||
|
||||
(1)编写租客缴纳押金情况查询接口,实现查询租客是狗已缴纳押金功能;
|
||||
|
||||
(2)编写房东收取押金情况查询接口,实现房东是否已收到押金的功能。
|
||||
|
||||
::: code-tabs
|
||||
@tab xxx.sol
|
||||
```
|
||||
```
|
||||
:::
|
||||
## 题目十
|
||||
|
||||
题目:
|
||||
|
||||
子任务2-2-1:账户管理合约编码
|
||||
|
||||
根据需求用例文档在待补充源码中完成账户管理合约的编码,解决代码错误和警告,正确编译合约,功能调试正确。需要编写生成账户接口,完成从外部部门检索姓名、年龄、雇主、开始日期、工资、缴费基数,将人员信息进行综合存储功能。
|
||||
|
||||
子任务2-2-2:费用管理合约编码
|
||||
|
||||
根据需求用例文档在待补充源码中完成费用管理合约的编码,解决代码错误和警告,正确编译合约,功能调试正确,运行添加新职工账户、添加新雇主账户。
|
||||
|
||||
1.编写添加新职工账户接口,实现当账户不存在,只有管理员可以添加职工账户,职工新账户中账户余额为0,未被赞助的功能;
|
||||
|
||||
2.编写添加新雇主账户接口,实现当账户不存在,只有管理员可以添加雇主账户,雇主新账户中账户余额为0,已被赞助的功能;
|
||||
|
||||
子任务2-2-3:保险转移合约编码
|
||||
|
||||
根据需求用例文档在待补充源码中完成保险转移合约的编码,解决代码错误和警告,正确编译合约,功能调试正确,运行合约中的申请转移关系、接收账户转移接口。
|
||||
|
||||
1.编写申请转移关系接口,实现创建申请、添加到申请列表功能,其中创建申请需要设置申请人地址、原城市、目标城市、停缴状态、批准状态;
|
||||
|
||||
2.编写接收账户转移接口,实现获取账户,进行账户授权状态、接收状态、个人账户基金、统筹账户基金、养老保险账户的信息设置;
|
||||
|
||||
::: code-tabs
|
||||
@tab xxx.sol
|
||||
```
|
||||
```
|
||||
:::
|
||||
56
docs/notes/programming/solidity/other/hardhat.md
Normal file
56
docs/notes/programming/solidity/other/hardhat.md
Normal file
@@ -0,0 +1,56 @@
|
||||
---
|
||||
title: Hardhat 相关知识
|
||||
createTime: 2025/10/14 14:57:06
|
||||
permalink: /programming/solidity/other/hardhat/
|
||||
---
|
||||
|
||||
## HardHat2 部署
|
||||
### Node.js v16 安装
|
||||
HardHat2 需要 Node.js v16 及以上的版本
|
||||
这里给出的是通过 npm 来将旧版本升级到 Node.js v16 的,如果想要直接安装的话通过 `yum install nodejs` 或者 `apt install nodejs` 来即可。
|
||||
```bash
|
||||
npm config set registry https://registry.npmmirror.com
|
||||
sudo npm install -g n
|
||||
sudo n 16
|
||||
```
|
||||
安装完成之后可以查看版本,如果没有更新可以重新刷新一下环境(直接退出重连最简单)
|
||||
```bash
|
||||
node -v
|
||||
# v16.20.2
|
||||
npm -v
|
||||
# 6.14.15
|
||||
```
|
||||
### 安装 Hardhat2
|
||||
创建一个 hardhat2-project 目录,初始化 npm 项目,注意这里不要用 hardhat 作为项目名
|
||||
```bash
|
||||
mkdir ~/hardhat2-project
|
||||
cd ~/hardhat2-project
|
||||
npm init -y
|
||||
```
|
||||
安装 Hardhat 2
|
||||
```bash
|
||||
npm install --save-dev hardhat@^2.23.0
|
||||
```
|
||||
初始化 Hardhat2 项目
|
||||
```bash
|
||||
npx hardhat init
|
||||
```
|
||||
选择
|
||||
```bash
|
||||
✔ What do you want to do? · Create a JavaScript project
|
||||
✔ Hardhat project root: · /root/hardhat2-project
|
||||
✔ Do you want to add a .gitignore? (Y/n) · y
|
||||
✔ Help us improve Hardhat with anonymous crash reports & basic usage data? (Y/n) · y
|
||||
✔ Do you want to install this sample project's dependencies with npm (@nomicfoundation/hardhat-toolbox)? (Y/n) · y
|
||||
```
|
||||
## 使用 Hardhat2 编译测试合约
|
||||
在 hardhat2-project 目录下,执行以下命令来编译合约
|
||||
合约都会放在 `contracts` 目录下,这里我们选择了一个默认的合约,因此可以直接编译
|
||||
```bash
|
||||
# 测试编译
|
||||
npx hardhat compile
|
||||
# 运行测试
|
||||
npx hardhat test
|
||||
# 查看可用任务
|
||||
npx hardhat help
|
||||
```
|
||||
88
docs/notes/programming/solidity/other/miscellaneous.md
Normal file
88
docs/notes/programming/solidity/other/miscellaneous.md
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
title: 一些没分类的小知识
|
||||
createTime: 2025/10/12 15:34:38
|
||||
permalink: /programming/solidity/other/miscellaneous/
|
||||
---
|
||||
|
||||
## 关于 memory 和 storage 存储类型
|
||||
|
||||
- `storage`:合约的持久化状态数据,保存在链上状态。对 `storage` 的写入最昂贵,读取也比内存贵;修改会永久生效。
|
||||
- `memory`:函数调用期间的临时数据,函数返回后即释放。对 `memory` 的更改不会持久化。
|
||||
- (补充)`calldata`:外部函数参数的只读数据位置,零拷贝、不可修改,用于节省 gas。
|
||||
|
||||
### 生命周期与成本
|
||||
- `storage` 写入昂贵、读取较贵;适合保存需要长期存在的状态。
|
||||
- `memory` 在函数结束时释放,读取/写入相对便宜;适合临时计算与返回值。
|
||||
- 复杂引用类型(数组、`struct`、`mapping`、`string`、`bytes`)在函数参数或局部变量处通常必须显式标注数据位置。
|
||||
|
||||
### 默认与必须声明
|
||||
- 状态变量总是位于 `storage`(例如 `User[] public users;`)。
|
||||
- 外部函数(`external`)的复杂类型参数默认是 `calldata`;内部/公共函数需要显式标注 `memory` 或 `storage`。
|
||||
- 局部变量的复杂类型必须指定数据位置,否则编译报错。
|
||||
|
||||
### 拷贝与引用语义
|
||||
- 从 `storage` 读取到 `memory` 会“复制”数据;修改 `memory` 副本不影响原始 `storage`。
|
||||
- 使用 `storage` 局部变量可以得到对状态数据的“引用”,对其赋值会持久化。
|
||||
|
||||
```solidity
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
contract Users {
|
||||
struct User { string name; uint age; }
|
||||
User[] public users;
|
||||
|
||||
function add(string memory name, uint age) external {
|
||||
users.push(User(name, age)); // 写入 storage
|
||||
}
|
||||
|
||||
function updateName(uint i, string memory newName) external {
|
||||
User storage u = users[i]; // storage 引用(指向链上状态)
|
||||
u.name = newName; // 修改持久化生效
|
||||
}
|
||||
|
||||
function tryUpdate(uint i) external {
|
||||
User memory u = users[i]; // 从 storage 复制到 memory
|
||||
u.age = 99; // 仅修改副本,不会影响链上状态
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 在内部函数传递 storage 引用
|
||||
- 仅内部/私有函数可以接收 `storage` 引用参数,从而直接修改状态;外部函数参数不能是 `storage`。
|
||||
|
||||
```solidity
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
contract Users2 {
|
||||
struct User { string name; uint age; }
|
||||
User[] public users;
|
||||
|
||||
function _inc(User storage u) internal { u.age += 1; }
|
||||
|
||||
function birthday(uint i) external {
|
||||
_inc(users[i]); // 传递 storage 引用,持久化修改
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 动态 memory 数组与限制
|
||||
- 可在 `memory` 中构造动态数组:`new uint[](n)`;适合作为返回值或临时计算。
|
||||
- `mapping` 只能存在于 `storage`,不能在 `memory` 中创建或拷贝。
|
||||
|
||||
```solidity
|
||||
pragma solidity ^0.8.20;
|
||||
|
||||
contract Arrays {
|
||||
function make(uint n) external pure returns (uint[] memory a) {
|
||||
a = new uint[](n);
|
||||
for (uint i = 0; i < n; i++) a[i] = i;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 常见坑与实践建议
|
||||
- 给 `storage` 变量整体赋值会进行深拷贝或引用变更(依据类型),要明确拷贝成本与语义。
|
||||
- 修改 `memory` 副本不会持久化;要修改链上状态请使用 `storage` 引用。
|
||||
- 大型 `string/bytes/数组` 在 `memory↔storage` 间复制成本高,尽量减少不必要的复制。
|
||||
- 外部函数能用 `calldata` 的地方尽量使用(只读参数),节省 gas。
|
||||
|
||||
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 的强大功能和灵活性!
|
||||
22
docs/notes/subject/english/README.md
Normal file
22
docs/notes/subject/english/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
title: 英语学习笔记
|
||||
createTime: 2025/10/20 16:34:20
|
||||
permalink: /subject/english/
|
||||
---
|
||||
|
||||
# 英语学习笔记
|
||||
|
||||
这是一个英语学习笔记的总览页。下面是目录与分区入口:
|
||||
|
||||
## 目录
|
||||
- 学习环境与工具 → `/subject/english/basis/`
|
||||
- 词汇与记忆 → `/subject/english/vocabulary/`
|
||||
- 语法与句法 → `/subject/english/grammar/`
|
||||
- 听力与口语 → `/subject/english/listening-speaking/`
|
||||
- 阅读 → `/subject/english/reading-writing/`
|
||||
- 考试与备考(含四级) → `/subject/english/exam/cet-4/`
|
||||
- 学习资源与工具 → `/subject/english/resources/`
|
||||
- 写译 → `/subject/english/writing-translation/`
|
||||
|
||||
|
||||
你可以从以上入口进入对应的专题,随时扩展各章节内容。
|
||||
15
docs/notes/subject/english/basis/README.md
Normal file
15
docs/notes/subject/english/basis/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
title: 英语环境配置
|
||||
createTime: 2025/10/20 16:34:20
|
||||
permalink: /subject/english/basis/
|
||||
---
|
||||
|
||||
# 英语环境配置
|
||||
|
||||
这里是英语学习的入门环境配置示例模版:
|
||||
|
||||
- 推荐词典与工具
|
||||
- 输入法与语音资源
|
||||
- 常用学习网站与 App
|
||||
|
||||
你可以按需补充具体内容。
|
||||
42
docs/notes/subject/english/exam/cet-4.md
Normal file
42
docs/notes/subject/english/exam/cet-4.md
Normal file
@@ -0,0 +1,42 @@
|
||||
---
|
||||
title: 英语四级 (CET-4) 备考指南
|
||||
createTime: 2025/10/20 16:42:00
|
||||
permalink: /subject/english/exam/cet-4/
|
||||
---
|
||||
|
||||
# 英语四级 (CET-4) 备考指南
|
||||
|
||||
## 考试结构概览
|
||||
- 听力 (25%):新闻、长对话、讲座/采访
|
||||
- 阅读 (35%):仔细阅读、选词填空
|
||||
- 翻译 (15%):汉译英
|
||||
- 写作 (25%):应用文与观点写作
|
||||
|
||||
## 核心备考策略
|
||||
- 词汇:高频词与真题语块,使用 SRS 间隔重复
|
||||
- 语法:时态、非谓语、从句,针对写作与翻译的准确表达
|
||||
- 听力:精听 + 跟读(shadowing),积累场景表达
|
||||
- 阅读:结构化分析段落逻辑,题型定位与干扰项识别
|
||||
- 写作:模板+素材库+改写练习,关注连贯与准确
|
||||
|
||||
## 时间分配建议
|
||||
- 写作 30 分钟:审题→列纲→写作→快速校对
|
||||
- 阅读 40 分钟:定位→分析→作答→标记不确定
|
||||
- 听力 按机考节奏:提前熟悉说明与做题界面
|
||||
- 翻译 20 分钟:分句翻译→语法检查→润色
|
||||
|
||||
## 真题与模拟
|
||||
- 使用近 3-5 年真题按套训练;分析错因并归档到词汇/语法/方法类别
|
||||
- 每周至少一次全真模拟,记录分配与状态调整
|
||||
|
||||
## 考场技巧
|
||||
- 先易后难;不确定题目标记后回看
|
||||
- 注意题干限制词与语义线索(especially/only/not/except 等)
|
||||
- 写作与翻译建议使用简单准确句式,避免长难句错误
|
||||
|
||||
## 推荐资源
|
||||
- 真题:教育部考试中心官方题库与解析
|
||||
- 听力:BBC 6 Minute English、VOA Learning English
|
||||
- 写作:常用应用文格式与常见开头结尾句
|
||||
|
||||
> 后续我会补充各模块的详细练习清单与示例。
|
||||
84
docs/notes/subject/english/grammar/README.md
Normal file
84
docs/notes/subject/english/grammar/README.md
Normal file
@@ -0,0 +1,84 @@
|
||||
---
|
||||
title: 核心语法与句型
|
||||
createTime: 2025/10/20 16:40:00
|
||||
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.)
|
||||
|
||||
### 长难句拆解策略
|
||||
- 找谓语,定主干
|
||||
- 划从句,标连接词
|
||||
- 去插入,还省略
|
||||
- 调语序,还原文
|
||||
89
docs/notes/subject/english/listening-speaking/README.md
Normal file
89
docs/notes/subject/english/listening-speaking/README.md
Normal file
@@ -0,0 +1,89 @@
|
||||
---
|
||||
title: 听力口语训练
|
||||
createTime: 2025/10/20 16:40:00
|
||||
permalink: /subject/english/listening-speaking/
|
||||
---
|
||||
|
||||
# 听力口语训练
|
||||
|
||||
- 音素与连读弱读
|
||||
- 听力材料选择与精听泛听
|
||||
- 跟读与复述(shadowing & retelling)
|
||||
- 场景对话与表达
|
||||
|
||||
## 自然拼读法Phonics
|
||||
|
||||
Phonics自然拼音,或叫“英语自然拼读法”更容易理解。拼读什么?就是看到英文字母或字母的组合能自然地读出、读对它的发音。这里,首先要区分“读音”(Name)与“发音”(Sound)。A-Z的26个字母几乎大家都认识、都能念出来,而念出来的就是字母本身的“读音”;而自然发音指的是字母的“发音”。发音不同于读音。看到字母后,不管读音,找对发音。这就Phonics要学的。理论可以讲很多很深,但Phonics注重的是方法与实践。因此,知道怎么正确发音就行了。
|
||||
|
||||
下面给你放一个基本发音规则的表,虽然看不到完整版但是足够了也足够大致理解发音规律了
|
||||
|
||||
```
|
||||
https://wenku.so.com/tfd/b97611df865df13967a3b93a66d9e904?src=360ss&ocpc_id=139916&plan_id=2327941041&group_id=687803892&keyword=%E8%8B%B1%E8%AF%AD%E8%87%AA%E7%84%B6%E6%8B%BC%E8%AF%BB%E5%AD%97%E6%AF%8D%E7%BB%84%E5%90%88%E5%8F%91%E9%9F%B3&qhclickid=2ee0322320520786
|
||||
```
|
||||
|
||||
英文的26个字母,分为元音和辅音,其中元音只有5个,即a,e,i,o,u,其余字母均为辅音。
|
||||
|
||||
对于大多数辅音来说,它们的发音是一对一的,而有少数几个辅音字母,每个字母有两个或以上的发音。
|
||||
|
||||
### 二、有多个发音的辅音
|
||||
|
||||
#### c 字母
|
||||
c后面接a,o,u的时候,c的发音与字母k发音相同,叫做“hard c sound”:
|
||||
```
|
||||
cat, cap,call,coat,cup
|
||||
```
|
||||
|
||||
当字母c后面接e,i,或y的时候,通常c的发音与字母s发音相同,叫做“soft c sound” :
|
||||
```
|
||||
city, ice, rice, face, cell, cent, voice, pencil, juice
|
||||
```
|
||||
|
||||
有时在e或i前面,c会发/sh/音:
|
||||
```
|
||||
ocean, racial, social
|
||||
```
|
||||
|
||||
#### g 字母
|
||||
g后面接a,o,u的时候,所发的音叫做“hard g sound”:
|
||||
```
|
||||
girl, gas, get, give, go
|
||||
```
|
||||
|
||||
当字母g后面接e,i,或y的时候,有时g的发音与字母j的发音相同,叫做“soft g sound”
|
||||
```
|
||||
age, change, ginger, Egypt, gentle, giraffe, badge
|
||||
```
|
||||
|
||||
特例:forget, give, girl中的g发hard sound。
|
||||
|
||||
#### x 字母
|
||||
x在单词中间或结尾时发/ks/音:
|
||||
```
|
||||
box, next, fix, mix, tax
|
||||
```
|
||||
|
||||
x在单词中间时有时发/gz/音:
|
||||
```
|
||||
exit, exam, exact
|
||||
```
|
||||
|
||||
x在单词起始位置时发/z/音:
|
||||
```
|
||||
xylophone, xerox。
|
||||
```
|
||||
|
||||
#### y 字母
|
||||
y在单词起始位置时发音为辅音:
|
||||
```
|
||||
yes, you, yard, year, yell
|
||||
```
|
||||
|
||||
y在单词或音节中间或结尾时被当做元音;
|
||||
|
||||
y在结尾,单词只有一个音节时y发长/i/音,y在结尾,单词有两个或以上音节时y发长/e/音,y在单词或音节中间时,发短/i/音。
|
||||
|
||||
- 小测试:
|
||||
- my, cry, fly, sky, baby, happy
|
||||
- puppy, hurrygym, nymph
|
||||
|
||||
|
||||
11
docs/notes/subject/english/reading-writing/README.md
Normal file
11
docs/notes/subject/english/reading-writing/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
title: 阅读提升
|
||||
createTime: 2025/10/20 16:40:00
|
||||
permalink: /subject/english/reading-writing/
|
||||
---
|
||||
|
||||
# 阅读提升
|
||||
|
||||
- 阅读策略(略读、扫读、精读)
|
||||
- 篇章结构与逻辑(指代、连接、修饰)
|
||||
|
||||
50
docs/notes/subject/english/resources/README.md
Normal file
50
docs/notes/subject/english/resources/README.md
Normal file
@@ -0,0 +1,50 @@
|
||||
---
|
||||
title: 学习资源与工具
|
||||
createTime: 2025/10/20 16:40:00
|
||||
permalink: /subject/english/resources/
|
||||
---
|
||||
|
||||
# 学习资源与工具
|
||||
|
||||
- 词典与语法书:牛津、朗文、柯林斯
|
||||
- 学习 App:扇贝、欧路、Grammarly
|
||||
- 新闻来源:BBC、VOA、The Economist
|
||||
- 社区与练习:Reddit、StackExchange English、写作论坛
|
||||
|
||||
## 每日读物
|
||||
希望每天都能读一篇简单的小文章,将不会的单词标出,不理解的句子记下来。通过有道词典等工具查询后能够自己理解并通读。
|
||||
|
||||
### 下面是今日份读物推荐~
|
||||
|
||||
解析将稍后更新~
|
||||
|
||||
### 2025.10.27
|
||||
|
||||
```
|
||||
https://web.shanbay.com/reading/web-news/articles/umxci
|
||||
```
|
||||
|
||||
复制链接至浏览器后,点击APP内打开,点击短文,登陆注册后找到这篇文章可读性更强且自带单词查询功能
|
||||
|
||||
不过个人建议先盲读,尝试用自己认识的单词推理拼凑一篇文章吧~
|
||||
|
||||
#### Study Finds Minimal Link Between phone Use and Adult Well-Being
|
||||
|
||||
Despite previous findings, Oregon-led research has determined that smartphone use isn't necessarily related to the well-being of adults.
|
||||
|
||||
The study conducted by the University of Oregon and Google Research found that younger adults experience lower moods when using social media in one particular stance, but the link between mental health and digital surfing was "either weak or statistically insignificant" when assessing longer time periods.
|
||||
|
||||
According to UO, Nicholas Allen — a psychology professor and director of the Center for Digital Mental Health — led the team that conducted the study.For four weeks, researchers recorded the smartphone activity and daily moods of more than 10,000 participants who were at least 18 years of age.
|
||||
|
||||
The university noted that previous studies have included self-reported data, which scientists claimed aren't as reliable.
|
||||
|
||||
"Our findings challenge the popular assumption that smartphone use is inherently harmful to mental health and well-being," Allen said in a release."There's been a lot of public concern and policy discussion often based on small, self-reported studies.This large-scale, objective data suggests the relationship is far more nuanced and, in most cases, minimal — at least over this time frame."
|
||||
|
||||
The findings, which were published in the National Library of Medicine earlier this week, show that demographics like age and gender were more likely to negatively impact mental well-being than smartphone usage.Notably, researchers discovered that younger adults and women experienced lower moods despite how often they surfed social media.
|
||||
|
||||
"Smartphones are part of the context of our daily lives; they're not inherently good or bad.The key is understanding how people use them and how technology can be designed to support well-being rather than detract from it," Allen added.
|
||||
|
||||
|
||||
|
||||
|
||||
#### 将生词整理到纸或本子上吧~熟记这些单词和使用时的语境会在你意想不到的时候帮助到你哦!
|
||||
12
docs/notes/subject/english/vocabulary/README.md
Normal file
12
docs/notes/subject/english/vocabulary/README.md
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
title: 词汇学习与记忆法
|
||||
createTime: 2025/10/20 16:40:00
|
||||
permalink: /subject/english/vocabulary/
|
||||
---
|
||||
|
||||
# 词汇学习与记忆法
|
||||
|
||||
- 高频词与词根词缀
|
||||
- 主题词汇(校园、科技、社会等)
|
||||
- 间隔重复(SRS)与记忆曲线
|
||||
- 固定搭配与语块(collocations & chunks)
|
||||
11
docs/notes/subject/english/writing-translation/README.md
Normal file
11
docs/notes/subject/english/writing-translation/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
title: 写译
|
||||
createTime: 2025/10/22 10:26:07
|
||||
permalink: /subject/english/writing-translation/
|
||||
---
|
||||
|
||||
# 写译
|
||||
|
||||
- 写作模板与常用句式
|
||||
- 改写与润色(句式多样化、语法准确性)
|
||||
- 翻译(语法、词汇、上下文)
|
||||
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)
|
||||
1247
package-lock.json
generated
1247
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@@ -8,18 +8,24 @@
|
||||
"node": "^20.6.0 || >=22.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"docs:dev": "vuepress dev docs",
|
||||
"docs:dev-clean": "vuepress dev docs --clean-cache --clean-temp",
|
||||
"docs:dev": "vuepress dev docs --port 4567",
|
||||
"docs:dev-clean": "vuepress dev docs --clean-cache --clean-temp --port 4567",
|
||||
"docs:build": "vuepress build docs --clean-cache --clean-temp",
|
||||
"docs:preview": "http-server docs/.vuepress/dist",
|
||||
"vp-update": "npx vp-update"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vuepress/bundler-vite": "2.0.0-rc.24",
|
||||
"vuepress": "2.0.0-rc.24",
|
||||
"vuepress-theme-plume": "1.0.0-rc.164",
|
||||
"@vuepress/plugin-umami-analytics": "^2.0.0-rc.112",
|
||||
"artalk": "^2.9.1",
|
||||
"http-server": "^14.1.1",
|
||||
"typescript": "^5.9.2",
|
||||
"vue": "^3.5.21",
|
||||
"typescript": "^5.9.2"
|
||||
"vuepress": "2.0.0-rc.24",
|
||||
"vuepress-theme-plume": "1.0.0-rc.164"
|
||||
},
|
||||
"dependencies": {
|
||||
"@waline/client": "^3.6.0",
|
||||
"mermaid": "^11.12.1"
|
||||
}
|
||||
}
|
||||
59
start.bat
Normal file
59
start.bat
Normal file
@@ -0,0 +1,59 @@
|
||||
@echo off
|
||||
setlocal ENABLEDELAYEDEXPANSION
|
||||
|
||||
REM Usage:
|
||||
REM start.bat [host] [port]
|
||||
REM Examples:
|
||||
REM start.bat -> try 0.0.0.0:4567, fallback to localhost and 5173
|
||||
REM start.bat local 8080 -> localhost:8080
|
||||
REM start.bat lan 4567 -> 0.0.0.0:4567
|
||||
|
||||
set HOST=%~1
|
||||
if "%HOST%"=="" set HOST=0.0.0.0
|
||||
if /I "%HOST%"=="lan" set HOST=0.0.0.0
|
||||
if /I "%HOST%"=="local" set HOST=localhost
|
||||
|
||||
set PORT=%~2
|
||||
if "%PORT%"=="" set PORT=4567
|
||||
set FALLBACK_PORT=5173
|
||||
|
||||
echo [Start] VuePress dev on host %HOST% port %PORT%
|
||||
call npx vuepress@2.0.0-rc.24 dev docs --host %HOST% --port %PORT%
|
||||
if %ERRORLEVEL% EQU 0 goto success
|
||||
|
||||
REM Fallback 1: switch to localhost same port
|
||||
if NOT "%HOST%"=="localhost" (
|
||||
echo [Fallback] switch to localhost on same port %PORT%...
|
||||
call npx vuepress@2.0.0-rc.24 dev docs --host localhost --port %PORT%
|
||||
if %ERRORLEVEL% EQU 0 goto success
|
||||
)
|
||||
|
||||
REM Fallback 2: clean cache and use localhost on fallback port
|
||||
if NOT "%PORT%"=="%FALLBACK_PORT%" (
|
||||
echo [Fallback] clean cache and start on localhost:%FALLBACK_PORT%...
|
||||
call npx vuepress@2.0.0-rc.24 dev docs --clean-cache --clean-temp --host localhost --port %FALLBACK_PORT%
|
||||
if %ERRORLEVEL% EQU 0 (
|
||||
set HOST=localhost
|
||||
set PORT=%FALLBACK_PORT%
|
||||
goto success
|
||||
)
|
||||
)
|
||||
|
||||
REM Fallback 3: try another common port
|
||||
set ALT_PORT=8080
|
||||
if NOT "%PORT%"=="%ALT_PORT%" (
|
||||
echo [Fallback] try localhost:%ALT_PORT%...
|
||||
call npx vuepress@2.0.0-rc.24 dev docs --host localhost --port %ALT_PORT%
|
||||
if %ERRORLEVEL% EQU 0 (
|
||||
set HOST=localhost
|
||||
set PORT=%ALT_PORT%
|
||||
goto success
|
||||
)
|
||||
)
|
||||
|
||||
echo [Error] Failed to start dev server. Please check firewall or port usage.
|
||||
exit /b 1
|
||||
|
||||
:success
|
||||
echo [Ready] Open http://localhost:%PORT%/ (or http://%HOST%:%PORT%/ if accessible)
|
||||
exit /b 0
|
||||
Reference in New Issue
Block a user