Compare commits

42 Commits

Author SHA1 Message Date
祀梦 5dba6ac5b4 docs: 完善安装指南并增强启动脚本功能
- 扩展 README.md 中的安装说明,增加环境要求、详细步骤和常见问题排查
- 重写 start.bat 脚本,支持参数化配置并添加多重回退机制
- 优化开发服务器启动流程,提升不同环境下的兼容性
2025-10-22 16:26:29 +08:00
Kawaxxxsaki d7d342fd55 更新每日英语读物 2025-10-22 13:00:56 +08:00
Kawaxxxsaki b734f403b3 拆分阅读和写作模块 2025-10-22 11:13:21 +08:00
祀梦 086835d409 docs(solidity): 更新memory和storage存储类型的文档
补充关于Solidity中memory和storage存储类型的详细说明,包括生命周期、成本、默认行为、拷贝语义、内部函数引用传递、动态数组限制等内容。添加代码示例和最佳实践建议,帮助开发者更好地理解和使用不同存储类型。
2025-10-20 20:25:23 +08:00
祀梦 69312a780e feat(english): 添加英语学习笔记文档和导航配置
添加英语学习相关文档,包括基础配置、词汇、语法、听说读写等模块
更新导航栏和侧边栏配置以支持英语学习笔记
修改首页标题和描述以更符合内容定位
2025-10-20 19:55:15 +08:00
祀梦 b3b5198eac docs: 更新关于页面中的欢迎语
将欢迎语从"泥嚎~"改为更常见的"嗨~",使语气更加自然友好
2025-10-20 14:41:24 +08:00
祀梦 771fa51fb9 docs(solidity): 修正hardhat初始化命令的拼写错误
将`--init`改为正确的`init`命令
2025-10-17 23:32:49 +08:00
祀梦 90ed801658 Merge branch 'main' of https://gitea.simengweb.com/si-meng-spec/SiMengWebSite_Notes 2025-10-14 15:39:37 +08:00
祀梦 f0e768d66f 更新 2025-10-14 15:39:08 +08:00
祀梦 6a508cc8d4 更新文章 2025-10-14 15:38:57 +08:00
祀梦 6ac5000c86 更新文章 2025-10-11 23:48:28 +08:00
祀梦 df01754706 更新文章 2025-10-10 17:33:17 +08:00
祀梦 7e413866c2 文章更新 2025-10-10 10:54:35 +08:00
si-meng-spec 95dc8fecf9 更新文章 2025-10-05 17:43:04 +08:00
si-meng-spec 807e222e8a Merge branch 'main' of https://gitea.simengweb.com/simeng/SiMengWebSite_Notes 2025-10-05 17:39:34 +08:00
si-meng-spec ba6702c880 更新文章 2025-10-05 17:35:32 +08:00
si-meng-spec 5984402fb2 更新文章 2025-10-05 17:35:06 +08:00
si-meng-spec 9f28803260 更新文章 2025-10-02 12:08:11 -04:00
si-meng-spec e2c883233c 更新文章 2025-10-02 03:56:20 -04:00
si-meng-spec 564040b8c3 修改配置文件 2025-10-01 06:01:22 -04:00
si-meng-spec 44689736d5 配置 umami 2025-10-01 05:34:17 -04:00
si-meng-spec cb3747d38c 更新文章 2025-10-01 03:21:10 -04:00
si-meng-spec eeb0031bf5 修改文章内网 2025-09-30 07:49:12 -04:00
si-meng-spec 3130dcbbc3 修改网站图标 2025-09-30 07:48:55 -04:00
si-meng-spec 056e58c5bd 操作 WSL2 2025-09-30 05:04:16 -04:00
si-meng-spec 89a3f2182a 在 Windows10 上部署 WSL2 并安装 ubuntu 20.04 虚拟机 2025-09-30 03:20:17 -04:00
si-meng-spec 8eb832de6c 配置 Waline 评论 2025-09-29 08:39:59 -04:00
si-meng-spec d831135553 配置封面图,更新文章 2025-09-29 04:24:24 -04:00
si-meng-spec 7ac31a3984 文章更新 2025-09-29 03:24:19 -04:00
si-meng-spec 3bb7ee6796 创建 Linux 和 区块链 运维的样例 2025-09-28 08:03:21 -04:00
si-meng-spec 12fdf56539 创建 solidity 编程语言的样例 2025-09-28 07:37:34 -04:00
si-meng-spec 173a99a626 更新提交用户名 2025-09-24 00:02:33 -04:00
si-meng-spec 99a79b4af6 修改关于界面的位置,C++ 基础 2025-09-23 23:53:04 -04:00
si-meng-spec 1f02282ad6 更新贡献者名称 2025-09-22 10:00:45 -04:00
si-meng-spec 218c43abd9 更新介绍 2025-09-22 09:27:05 -04:00
si-meng-spec 48130b5d8f 关于 C++ 的初步笔记 2025-09-22 09:23:42 -04:00
si-meng-spec cc419e6541 关于 LeetCode 算法的初步笔记 2025-09-22 08:58:52 -04:00
si-meng-spec 7e9b7e6a2a 添加工具栏和友链 2025-09-22 08:08:44 -04:00
si-meng-spec d2513b2158 配置显示贡献者 2025-09-22 07:25:37 -04:00
si-meng-spec 38d8fccaa0 初始配置,第一篇文章 2025-09-22 07:15:29 -04:00
si-meng-spec 3029cc0fdf 初始化 2025-09-21 06:36:45 -04:00
root 6465c714e0 初始化项目:创建 VuePress Plume 网站 2025-09-21 06:30:20 -04:00
83 changed files with 2738 additions and 13434 deletions
@@ -1,31 +0,0 @@
---
description: 每次站点相关修改后须本地构建/启动并验证;Git 仅在被用户明确要求时提交
alwaysApply: true
---
# Agent 工作流:验证站点与 Git 提交
## 修改后必须自行验证(硬性要求)
凡改动 **VuePress / Plume 配置、`docs/` 下内容与主题相关代码** 等会影响站点展示或 dev/build 的行为时,**在本轮任务结束前必须**完成下列至少一项,并确认 **首页等主要页面非白屏**、**无控制台致命报错**(开发模式下可 F12 查看):
1. **推荐(与线上最接近)**:在项目根执行
`npm run docs:build`
然后执行
`npm run docs:verify`
(会检查 `docs/.vuepress/dist/index.html` 是否包含首页 hero 结构。)
2. **若重点验证热更新 / 开发体验**:执行
`npm run docs:dev-clean`
`--clean-cache --clean-temp` 可避免 **Vite 预构建缓存** 仍指向旧版 `@vuepress/helper`,从而触发 **`encodeSVG` 导出缺失、整站白屏**。)
在浏览器打开本地地址,确认首页 hero 与导航正常。
**白屏常见原因速记**`@vuepress/plugin-markdown-chart` 等依赖需要 `@vuepress/helper/client` 导出 `encodeSVG`;若 `docs/.vuepress/.cache` 里预打包了过旧的 helper,会出现 **仅 dev 白屏、build 正常**。处理:执行 **`npm run docs:clear-cache`** 后重启 dev,或 **`npm run docs:dev-clean`** / **`npm run docs:build`**(后两者会 clean)。项目已在 `config.ts` 的 Vite `optimizeDeps.include` 中强制包含 `@vuepress/helper/client`,以降低复发概率。
## Git 提交策略
- **禁止自作主张提交**:**仅当用户在本轮对话中明确说出要提交**(例如「提交一下」「帮我 commit」「推到 git」等)时,才执行 `git add` / `git commit` / `git push`。
- **未要求提交时**:改完代码、做完验证即可结束;**不要**替用户 commit。
- **用户若说不要提交**:同样不执行任何 git 写入操作。
**注意**:构建产物目录 **`docs/.vuepress/dist`**、缓存 **`.cache` / `.temp`** 已在 `.gitignore` 中,**不要**将编译输出提交进源码仓。
@@ -1,14 +0,0 @@
---
description: RAGFlow 检索 Plume 主题时必须使用 VuePress2-Plume 数据集,避免选错知识库
alwaysApply: true
---
# RAGFlow 与 Plume 文档
当任务涉及 **vuepress-theme-plume**、**Plume 主题**、**主题配置 / 博客 / 分类 / 标签 / 侧边栏** 等与 Plume 相关的问题,需要通过 **RAGFlow MCP**`ragflow_retrieval`)查官方文档时:
- **必须使用数据集****VuePress2-Plume**(名称)。
- 若接口需要 `dataset_ids`:当前知识库 ID 为 **`e57440b52aa711f1845c9627700ac9a4`**(与名称对应;若后台重建数据集请以维护者为准更新本条)。
- **禁止**在未确认数据集的情况下用其它知识库代替 Plume 文档检索,以免污染答案或引发环境异常。
与 Plume 无关的问题(例如通用 VuePress 2 核心、本项目业务逻辑)再按需选择其它数据集或不指定 `dataset_ids`。
@@ -1,17 +0,0 @@
---
description: 双仓库结构、本地构建与发布流程;启动时加载项目上下文
alwaysApply: true
---
# SiMengWebSite_Notes — 仓库与部署上下文
在开始涉及 **构建、发布、静态资源路径、`_publish`** 或 **多仓库** 的任务前,请先阅读仓库根目录的 **`PROJECT_BRIEF.local.md`**(若存在)。该文件为本地说明,不进入 Git,含完整背景与命令示例。
## 速记(无本地文件时的兜底)
- **源码仓**:仓库根目录 → 远程示例 `SiMengWebSite_Notes.git`;日常开发与提交 Markdown / VuePress 配置。
- **构建仓****`_publish/`** 内为 **独立 Git 仓库** → 远程示例 `build_notes_simengweb.git`**只提交** `npm run docs:build` 产出(`docs/.vuepress/dist` 的内容同步至此)。
- **原因**:业务服务器性能不足,**不在线上构建**;本地构建后推送构建仓,**服务器拉取更新**即可换页。
- **`_publish/`** 与 **`PROJECT_BRIEF.local.md`** 已被根目录 `.gitignore` 忽略,勿把构建产物或该简介误提交进源码仓。
若缺少 `PROJECT_BRIEF.local.md`,可向维护者索取模板或根据上述速记操作,避免在源码仓中提交 `dist` 或误改发布仓历史。
-3
View File
@@ -9,6 +9,3 @@
*.tff binary
*.woff binary
*.woff2 binary
*.mp4 binary
*.webm binary
*.mov binary
-12
View File
@@ -7,15 +7,3 @@ docs/.vuepress/dist
.trae/
.DS_Store
*.log
# Local project brief for agents (do not commit)
PROJECT_BRIEF.local.md
# Build and Publish output
_publish/
# Local resources storage (not uploaded)
resources/
# Ensure .gitkeep files are always tracked
!**/.gitkeep
-1
View File
@@ -1 +0,0 @@
legacy-peer-deps=true
-1
View File
@@ -1 +0,0 @@
WINDOWS11_RAGFLOW_DEPLOYMENT_AND_MCP_GUIDE.md
+16 -3
View File
@@ -1,9 +1,22 @@
import { defineClientConfig } from 'vuepress/client'
import RImg from './theme/components/RImg.vue'
import './theme/styles/custom.css'
// import RepoCard from 'vuepress-theme-plume/features/RepoCard.vue'
// import NpmBadge from 'vuepress-theme-plume/features/NpmBadge.vue'
// import NpmBadgeGroup from 'vuepress-theme-plume/features/NpmBadgeGroup.vue'
// import Swiper from 'vuepress-theme-plume/features/Swiper.vue'
// import CustomComponent from './theme/components/Custom.vue'
// import './theme/styles/custom.css'
export default defineClientConfig({
enhance({ app }) {
app.component('RImg', RImg)
// built-in components
// app.component('RepoCard', RepoCard)
// app.component('NpmBadge', NpmBadge)
// app.component('NpmBadgeGroup', NpmBadgeGroup)
// app.component('Swiper', Swiper) // you should install `swiper`
// your custom components
// app.component('CustomComponent', CustomComponent)
},
})
-272
View File
@@ -1,272 +0,0 @@
import { defineCollection, defineCollections } from 'vuepress-theme-plume'
/** 博客目录名 → 中文分类展示 */
const BLOG_CATEGORY_LABEL_ZH: Record<string, string> = {
blog: '博客',
competition: '竞赛',
technology: '技术',
website: '网站',
elysia: '爱莉希雅',
collect: '合集',
ai: 'AI',
}
export default defineCollections([
defineCollection({
type: 'post',
dir: 'blog',
title: '博客',
link: '/blog/',
linkPrefix: '/article/',
postCover: {
layout: 'left',
compact: true,
},
categoriesTransform: (categories) =>
categories.map((c) => ({
...c,
name: BLOG_CATEGORY_LABEL_ZH[c.name] ?? c.name,
})),
}),
defineCollection({
type: 'doc',
dir: 'notes/ai',
title: '模型',
linkPrefix: '/ai/',
sidebar: [
{ text: '模型', link: '/ai/' },
{
text: '基础概念',
collapsed: false,
items: [
{ text: 'MCP 与 Skills 详解', link: '/article/mcp-and-skills/' },
],
},
{
text: '部署与工具链',
collapsed: false,
items: [
{ text: 'RAGFlow 与 MCP', link: '/article/windows11-ragflow-deployment-mcp/' },
],
},
{
text: '模型与 API',
collapsed: false,
items: [{ text: '大模型 API 整合', link: '/article/free_model_api/' }],
},
],
}),
defineCollection({
type: 'doc',
dir: 'notes/subject/english',
title: '英语学习',
linkPrefix: '/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/' }],
},
],
}),
defineCollection({
type: 'doc',
dir: 'notes/subject/certification',
title: '系统分析师',
linkPrefix: '/subject/certification/',
sidebar: [
{ text: '系统分析师简介', link: '/subject/certification/' },
{
text: '第一篇 基础知识',
prefix: '/certification/sys-analyst',
items: [
{ text: '第一章 绪论', link: '/subject/certification/sys-analyst/' },
{ text: '第二章 数学与工程基础', link: '/subject/certification/sys-analyst/math/' },
],
},
{
text: '第二篇 关键技术',
prefix: '/certification/sys-analyst',
items: [
{ text: '第十章 系统规划与分析', link: '/subject/certification/sys-analyst/planning/' },
],
},
],
}),
defineCollection({
type: 'doc',
dir: 'notes/programming/solidity',
title: 'Solidity',
linkPrefix: '/programming/solidity/',
sidebar: [
{ text: 'Solidity 学习笔记', link: '/programming/solidity/' },
{
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/' },
],
},
],
}),
defineCollection({
type: 'doc',
dir: 'notes/theory/cryptography',
title: '密码学基础',
linkPrefix: '/theory/cryptography/',
sidebar: [
{ text: '密码学基础', link: '/theory/cryptography/' },
{
text: '古典加密算法',
prefix: '/theory',
items: [
{ text: '替换密码', link: '/theory/cryptography/substitution-ciphers/' },
{ text: '置换密码', link: '/theory/cryptography/permutation-encryption/' },
],
},
],
}),
defineCollection({
type: 'doc',
dir: 'notes/ops/blockchain',
title: '区块链运维',
linkPrefix: '/ops/blockchain/',
sidebar: [
{ text: '区块链运维指南', link: '/ops/blockchain/' },
{
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/practice/basic-deployment/' },
{ text: '区块链网络部署与管理', link: '/ops/blockchain/practice/node-deployment/' },
{ text: 'Console 控制台操作', link: '/ops/blockchain/practice/console-operator/' },
],
},
],
}),
defineCollection({
type: 'doc',
dir: 'notes/ops/linux',
title: 'Linux 运维',
linkPrefix: '/ops/linux/',
sidebar: [
{ text: 'Linux 运维笔记', link: '/ops/linux/' },
{
text: 'Linux 基础',
prefix: '/linux',
items: [{ text: 'Linux 基础命令详解', link: '/ops/linux/basic-commands/' }],
},
{
text: '其他',
prefix: '/linux',
items: [{ text: '一些零散的命令', link: '/ops/linux/other/' }],
},
],
}),
defineCollection({
type: 'doc',
dir: 'notes/ops/docker',
title: 'Docker',
linkPrefix: '/ops/docker/',
sidebar: [
{ text: 'Docker 运维笔记', link: '/ops/docker/' },
{
text: '数据库相关',
prefix: '/ops/docker/db/',
items: [
{ text: 'MongoDB 部署', link: '/ops/docker/db/mongodb/' },
{ text: 'Postgres 部署', link: '/ops/docker/db/postgres/' },
],
},
{
text: '其他服务',
prefix: '/ops/docker/other/',
items: [{ text: 'ETLCloud 部署', link: '/ops/docker/other/ETLCloud/' }],
},
],
}),
defineCollection({
type: 'doc',
dir: 'notes/programming/web',
title: 'Web 开发',
linkPrefix: '/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/' },
],
},
],
}),
])
+23 -42
View File
@@ -3,53 +3,25 @@ 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'
import { enrichBlogReadingTimePlugin } from './plugins/enrichBlogReadingTime'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
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({
viteOptions: {
resolve: {
alias: {
'@theme/Blog/VPPostItem.vue': path.resolve(__dirname, './theme/Blog/VPPostItem.vue'),
},
},
/**
* 强制预构建含 encodeSVG 的 client 入口,避免 docs/.vuepress/.cache/deps 里残留旧版
* @vuepress/helper 导致 dev 下「does not provide an export named encodeSVG」整页白屏。
*/
optimizeDeps: {
include: ['@vuepress/helper/client'],
},
},
}),
shouldPrefetch: false,
bundler: viteBundler(),
shouldPrefetch: false, // 站点较大,页面数量较多时,不建议启用
theme: plumeTheme({
/* 站点域名,启动 SEO 优化 */
hostname: 'https://www.simengweb.com',
/* 博客文章页面链接前缀 */
article: '/article/',
/* 启用数学公式支持和Mermaid图表 */
markdown: {
math: {
type: 'katex',
},
mermaid: true,
demo: true,
},
/**
* 编译缓存,加快编译速度
*/
@@ -57,14 +29,22 @@ export default defineUserConfig({
/* 本地搜索, 默认启用 */
search: { provider: 'local' },
footer: {
message: '愿每一份温柔都被世界珍藏 ✨',
copyright: '<a href="https://beian.miit.gov.cn/" target="_blank" aria-label="gongan filing address">沪ICP备2023010022号-1</a>©2025祀梦的个人博客'
/**
* 博客相关配置
*/
blog: {
postCover: {
layout: 'left',
width: 300,
compact: true
}
},
/**
* 文章贡献者配置
*/
// 修改contributors配置
contributors: {
mode: 'inline',
info: [
@@ -84,10 +64,12 @@ export default defineUserConfig({
git: true
},
/**
* 代码块配置
*/
codeHighlighter: {
lineNumbers: true,
lineNumbers: true,
}
}),
plugins: [
@@ -98,11 +80,10 @@ export default defineUserConfig({
requiredMeta: ['nick']
}),
umamiAnalyticsPlugin({
id: '2114ab32-5543-4be1-b5e8-c4f2c9269d0d',
id: 'a4f0ca65-2da6-4e6b-a01b-f3b3157d05a3',
link: 'https://umami.simengweb.com/script.js',
domains: ['www.simengweb.com'],
domains: ['notes.simengweb.com'],
cache: true
}),
enrichBlogReadingTimePlugin(),
],
})
+8 -25
View File
@@ -9,10 +9,6 @@ export default defineNavbarConfig([
text: '博客',
link: '/blog/',
},
{
text: '模型',
link: '/ai/',
},
{
text: '学科知识',
items: [
@@ -20,34 +16,25 @@ export default defineNavbarConfig([
text: '英语学习笔记',
link: '/subject/english/',
},
{
text: '系统分析师',
link: '/subject/certification/',
},
],
},
{
text: '编程笔记',
items: [
{
text: 'LeetCode',
link: '/programming/leetcode/',
},
{
text: 'C++',
link: '/programming/cplusplus/',
},
{
text: 'Solidity',
link: '/programming/solidity/',
},
{
text: 'Web 开发',
link: '/programming/web/',
}
],
},
{
text:"技术理论",
items:[
{
text: '密码学基础',
link: '/theory/cryptography/',
},
]
},
{
text: '运维',
items: [
@@ -59,10 +46,6 @@ export default defineNavbarConfig([
text: 'Linux 运维',
link: '/ops/linux/',
},
{
text: 'Docker 运维',
link: '/ops/docker/',
},
],
},
{
+139
View File
@@ -0,0 +1,139 @@
import { defineNoteConfig, defineNotesConfig } from 'vuepress-theme-plume'
/**
* 配置编程笔记
*/
const LeetCode = defineNoteConfig({
dir: 'programming',
link: '/programming/leetcode/',
sidebar: [
{ text: "LeetCode 指南", link: "/programming/leetcode/" },
{
text: "刷题题单", prefix: "/question_sheet", items: [
{ text: "LeetCode 入门题单~(≧∇≦)ノ", link: "/programming/leetcode/question_sheet/beginner/" }
]
}
]
})
const cPlusPlus = defineNoteConfig({
dir: 'programming',
link: '/programming/cplusplus/',
sidebar: [
{ text: "C++ 学习笔记", link: "/programming/cplusplus/" },
{
text: "基础配置与开发工具", prefix: "/basis", items: [
{ text: "C++ 环境配置", link: "/programming/cplusplus/basis/" }
]
}
]
})
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/',
sidebar: [
{ text: "Solidity 学习笔记", link: "/programming/solidity/" },
{
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 blockchain = defineNoteConfig({
dir: 'ops',
link: '/ops/blockchain',
sidebar: [
{ text: "区块链运维指南", link: "/ops/blockchain/" },
{
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/practice/basic-deployment/" },
{ text: "区块链网络部署与管理", link: "/ops/blockchain/practice/node-deployment/" },
{ text: "Console 控制台操作", link: "/ops/blockchain/practice/console-operator/" }
]
}
]
})
const linux = defineNoteConfig({
dir: 'ops',
link: '/ops/',
sidebar: [
{ text: "Linux 运维笔记", link: "/ops/linux/" },
{
text: "Linux 基础", prefix: "/linux", items: [
{ text: "Linux 基础命令详解", link: "/ops/linux/basic-commands/" }
]
}
]
})
/**
* 导出所有的 note
*/
export default defineNotesConfig({
dir: 'notes',
link: '/',
notes: [LeetCode, english, cPlusPlus, solidity, blockchain, linux],
})
@@ -1,61 +0,0 @@
import fs from 'node:fs'
import { pathToFileURL } from 'node:url'
import type { App, PluginFunction } from 'vuepress'
const HMR_TAIL = `if (import.meta.webpackHot) {
import.meta.webpackHot.accept()
if (__VUE_HMR_RUNTIME__.updateBlogPostData) {
__VUE_HMR_RUNTIME__.updateBlogPostData(blogPostData)
}
}
if (import.meta.hot) {
import.meta.hot.accept(({ blogPostData }) => {
__VUE_HMR_RUNTIME__.updateBlogPostData(blogPostData)
})
}
`
async function enrichBlogData(app: App): Promise<void> {
const tempFile = app.dir.temp('internal/blogData.js')
if (!fs.existsSync(tempFile)) return
let blogPostData: Record<string, unknown>[]
try {
const url = `${pathToFileURL(tempFile).href}?t=${Date.now()}`
const mod = await import(url) as { blogPostData: Record<string, unknown>[] }
blogPostData = mod.blogPostData.map(p => ({ ...p }))
}
catch {
return
}
const byPath = new Map<string, { minutes: number; words: number }>()
for (const page of app.pages) {
const rt = page.data.readingTime as { minutes: number; words: number } | undefined
if (rt && typeof rt.words === 'number') byPath.set(page.path, rt)
}
for (const post of blogPostData) {
const rt = byPath.get(post.path as string)
if (rt) post.readingTime = rt
}
await app.writeTemp(
'internal/blogData.js',
`export const blogPostData = ${JSON.stringify(blogPostData)}\n\n${HMR_TAIL}\n`,
)
}
/**
* 在主题写入 blogData 之后,把各页的 readingTime(字数、分钟)并入博客列表数据,
* 供自定义 VPPostItem 在 /blog/ 列表展示。
*/
export function enrichBlogReadingTimePlugin(): PluginFunction {
return () => ({
name: 'enrich-blog-reading-time',
onPrepared: async (app: App) => {
await enrichBlogData(app)
},
})
}
+2 -2
View File
@@ -1,6 +1,6 @@
import { defineThemeConfig } from 'vuepress-theme-plume'
import collections from './collections'
import navbar from './navbar'
import notes from './notes'
export default defineThemeConfig({
logo: '/plume.svg',
@@ -21,5 +21,5 @@ export default defineThemeConfig({
},
navbar,
collections,
notes,
})
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 629 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 384 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 933 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 600 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 614 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 509 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 492 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 676 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 592 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 658 KiB

-416
View File
@@ -1,416 +0,0 @@
<script lang="ts" setup>
import type { ReadingTime } from '@vuepress/plugin-reading-time/client'
import { getReadingTimeLocale, useReadingTimeLocaleConfig } from '@vuepress/plugin-reading-time/client'
import type { BlogPostCoverStyle, ThemeBlogPostItem } from 'vuepress-theme-plume/shared'
import VPLink from '@theme/VPLink.vue'
import { isMobile as _isMobile } from '@vuepress/helper/client'
import { computed, onMounted, ref } from 'vue'
import { withBase } from 'vuepress/client'
import { useData, useInternalLink, useTagColors } from 'vuepress-theme-plume/composables'
type PostItem = ThemeBlogPostItem & { readingTime?: ReadingTime }
const props = defineProps<{
post: PostItem
index: number
}>()
const isMobile = ref(false)
onMounted(() => {
isMobile.value = _isMobile(navigator.userAgent)
window.addEventListener('resize', () => {
isMobile.value = _isMobile(navigator.userAgent)
})
})
const { blog } = useData()
const colors = useTagColors()
const { categories: categoriesLink, tags: tagsLink } = useInternalLink()
const readingLocale = useReadingTimeLocaleConfig()
const createTime = computed(() => props.post.createTime?.split(/\s|T/)[0].replace(/\//g, '-'))
const categoryList = computed(() => props.post.categoryList ?? [])
const readingTimeText = computed(() => {
const rt = props.post.readingTime
const loc = readingLocale.value
if (!rt || !loc) return null
return getReadingTimeLocale(rt, loc)
})
const sticky = computed(() => {
if (typeof props.post.sticky === 'boolean') {
return props.post.sticky
}
else if (typeof props.post.sticky === 'number') {
return props.post.sticky >= 0
}
return false
})
const tags = computed(() => {
const tagTheme = blog.value.tagsTheme ?? 'colored'
return (props.post.tags ?? [])
.slice(0, 4)
.map(tag => ({
name: tag,
className: colors.value[tag] ? `vp-tag-${colors.value[tag]}` : `tag-${tagTheme}`,
}))
})
const cover = computed<BlogPostCoverStyle | null>(() => {
if (!props.post.cover)
return null
const opt = blog.value.postCover ?? 'right'
const options = typeof opt === 'string' ? { layout: opt } : opt
return { layout: 'right', ratio: '4:3', ...options, ...props.post.coverStyle }
})
const coverLayout = computed(() => {
if (isMobile.value)
return 'top'
const layout = cover.value?.layout ?? 'right'
const odd = (props.index + 1) % 2 === 1
if (layout === 'odd-left')
return odd ? 'left' : 'right'
if (layout === 'odd-right')
return odd ? 'right' : 'left'
return layout
})
const coverCompact = computed(() => {
if (props.post.excerpt || coverLayout.value === 'top')
return false
return cover.value?.compact ?? false
})
const coverStyles = computed(() => {
if (!cover.value)
return null
let ratio: number
if (typeof cover.value.ratio === 'number') {
ratio = cover.value.ratio
}
else {
const [w, h] = cover.value.ratio!.split(/[:/]/).map(Number)
ratio = h / w
}
if (coverLayout.value === 'left' || coverLayout.value === 'right') {
const w = cover.value.width ?? 240
return { width: `${w}px`, height: `${w * ratio}px` }
}
return { height: 0, paddingBottom: `${ratio * 100}%` }
})
</script>
<template>
<div
class="vp-blog-post-item" data-allow-mismatch
:class="{ 'has-cover': post.cover, [coverLayout]: cover, 'draft': post.draft }"
>
<div
v-if="post.cover" class="post-cover" data-allow-mismatch
:class="{ compact: coverCompact }" :style="coverStyles"
>
<img :src="withBase(post.cover)" :alt="post.title" loading="lazy">
</div>
<div class="blog-post-item-content">
<h3>
<span v-if="sticky" class="sticky">TOP</span>
<span v-if="post.draft" class="draft">DRAFT</span>
<span v-if="post.encrypt" class="icon-lock vpi-lock" />
<VPLink :href="post.path" :text="post.title" />
</h3>
<div class="post-meta">
<div v-if="categoryList.length" class="category-list">
<span class="icon vpi-folder" />
<template v-for="(cate, i) in categoryList" :key="i">
<VPLink :href="categoriesLink ? `${categoriesLink.link}?id=${cate.id}` : undefined">
{{ cate.name }}
</VPLink>
<span v-if="i !== categoryList.length - 1">/</span>
</template>
</div>
<div v-if="tags.length" class="tag-list">
<span class="icon vpi-tag" />
<template v-for="tag in tags" :key="tag.name">
<VPLink
class="tag"
:class="tag.className"
:href="tagsLink ? `${tagsLink.link}?tag=${tag.name}` : undefined"
>
{{ tag.name }}
</VPLink>
</template>
</div>
<div v-if="readingTimeText" class="reading-time">
<span class="icon vpi-books" />
<span>{{ readingTimeText.words }}</span>
<span>{{ readingTimeText.time }}</span>
</div>
<div v-if="createTime" class="create-time">
<span class="icon vpi-clock" />
<span>{{ createTime }}</span>
</div>
</div>
<div v-if="post.excerpt" class="vp-doc excerpt" v-html="post.excerpt" />
</div>
</div>
</template>
<style scoped>
.vp-blog-post-item {
padding: 16px;
margin: 0 -16px;
background-color: var(--vp-c-bg);
transition: background-color var(--vp-t-color);
}
.vp-blog-post-item.draft {
background-color: var(--vp-c-warning-soft);
}
.vp-blog-post-item.has-cover:where(.left, .right) {
display: flex;
gap: 20px;
}
@media (max-width: 419px) {
.vp-blog-post-item.has-cover:where(.left, .right) {
display: block;
gap: unset;
}
}
.vp-blog-post-item.has-cover.right {
flex-direction: row-reverse;
}
.post-cover {
position: relative;
align-self: center;
overflow: hidden;
border-radius: 8px;
}
.vp-blog-post-item.has-cover.left .post-cover.compact {
margin: -24px 0 -24px -20px;
}
.vp-blog-post-item.has-cover.right .post-cover.compact {
margin: -24px -20px -24px 0;
}
.vp-blog-post-item.has-cover.top .post-cover {
margin: -16px -16px 16px;
border-radius: 0;
}
@media (min-width: 419px) {
.vp-blog-post-item.has-cover.top .post-cover {
width: calc(100% + 40px);
margin: -24px -20px 24px;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}
}
.post-cover img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s;
transform: scale(1);
}
.vp-blog-post-item.has-cover:hover .post-cover img {
transform: scale(1.02);
}
.vp-blog-post-item.has-cover.left .post-cover.compact {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.vp-blog-post-item.has-cover.right .post-cover.compact {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.blog-post-item-content {
display: flex;
flex-direction: column;
gap: 8px;
}
.vp-blog-post-item.has-cover .blog-post-item-content {
flex: 1 2;
}
.blog-post-item-content .sticky,
.blog-post-item-content .draft {
display: inline-block;
padding: 3px 6px;
margin-right: 0.5rem;
font-size: 13px;
font-weight: 600;
line-height: 1;
color: var(--vp-c-text-2);
background-color: var(--vp-c-brand-soft);
border-radius: 4px;
transition: var(--vp-t-color);
transition-property: color, background-color;
}
.blog-post-item-content .draft {
color: var(--vp-c-warning-1);
background-color: var(--vp-c-warning-soft);
}
.blog-post-item-content .icon-lock {
width: 1em;
height: 1em;
margin-right: 8px;
margin-left: 3px;
color: var(--vp-c-text-3);
transition: var(--vp-t-color);
transition-property: color;
}
.blog-post-item-content h3 {
display: flex;
align-items: center;
margin: 0;
font-size: 18px;
font-weight: 600;
color: var(--vp-c-text-1);
transition: color var(--vp-t-color);
}
.blog-post-item-content h3 a {
color: inherit;
text-decoration: none;
}
.blog-post-item-content h3:hover {
color: var(--vp-c-brand-1);
}
.blog-post-item-content h3:hover .sticky {
color: var(--vp-c-text-2);
}
.blog-post-item-content .excerpt {
margin-top: 12px;
}
@media (min-width: 768px) {
.vp-blog-post-item {
padding: 24px 20px;
margin: 0;
border-radius: 8px;
box-shadow: var(--vp-shadow-1);
transition: var(--vp-t-color);
transition-property: background-color, color, box-shadow;
will-change: transform;
}
.vp-blog-post-item:hover {
box-shadow: var(--vp-shadow-2);
}
.blog-post-item-content .post-meta {
margin-bottom: 0;
}
}
.blog-post-item-content .post-meta {
display: flex;
flex-wrap: wrap;
gap: 16px;
align-items: center;
justify-content: flex-start;
font-size: 14px;
font-weight: 400;
color: var(--vp-c-text-2);
transition: color var(--vp-t-color);
}
.blog-post-item-content .post-meta > div {
display: flex;
align-items: center;
justify-content: flex-start;
}
.blog-post-item-content .post-meta .reading-time {
gap: 6px;
}
.blog-post-item-content .post-meta .tag-list {
display: flex;
align-items: center;
}
.blog-post-item-content .post-meta .tag-list .tag {
display: inline-block;
padding: 3px 5px;
margin-right: 6px;
font-size: 12px;
line-height: 1;
color: var(--vp-tag-color);
background-color: var(--vp-tag-bg);
border-radius: 3px;
transition: color var(--vp-t-color), background-color var(--vp-t-color);
}
.blog-post-item-content .post-meta .tag-list .tag:last-of-type {
margin-right: 0;
}
.blog-post-item-content .post-meta .icon {
width: 14px;
height: 14px;
margin-right: 0.3rem;
color: var(--vp-c-text-3);
transition: color var(--vp-t-color);
}
.blog-post-item-content .post-meta a {
font-weight: normal;
color: inherit;
text-decoration: none;
}
.excerpt.vp-doc :deep(p) {
margin: 0.5rem 0;
}
.excerpt.vp-doc :deep(p:first-of-type) {
margin-top: 0;
}
.excerpt.vp-doc :deep(p:last-of-type) {
margin-bottom: 0;
}
.excerpt.vp-doc :deep(p strong) {
color: var(--vp-c-text-2);
transition: color var(--vp-t-color);
}
.excerpt.vp-doc :deep(div[class*="language-"]) {
margin: 16px -16px;
}
@media (min-width: 496px) {
.excerpt.vp-doc :deep(div[class*="language-"]) {
margin: 16px 0;
}
}
</style>
@@ -0,0 +1,11 @@
<script setup lang="ts">
import { ref } from 'vue'
const message = ref('Hello World!')
</script>
<template>
<div class="my-custom-content">
{{ message }}
</div>
</template>
-27
View File
@@ -1,27 +0,0 @@
<template>
<img :src="imageSrc" :alt="alt" v-bind="$attrs" />
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
src: {
type: String,
required: true
},
alt: {
type: String,
default: ''
}
})
// 使用 Vite 的 import.meta.glob 或简单字符串拼接
// 由于别名在运行时不可直接动态拼接,我们这里使用一个更稳妥的方法
// 映射到我们配置好的别名
const imageSrc = computed(() => {
// 处理路径,确保指向别名
const path = props.src.startsWith('/') ? props.src.slice(1) : props.src
return new URL(`../../../resources/${path}`, import.meta.url).href
})
</script>
-28
View File
@@ -1,31 +1,3 @@
/**
* 博客:分类(中文展示名)与标签(英文)之间留出间距;分类路径本身前后略松一些
*/
.vp-blog-post-item .post-meta .category-list {
padding: 0.3em 0.65em;
margin-right: 0.75rem;
margin-left: 0.15rem;
border-radius: 4px;
}
.vp-blog-post-item .post-meta .category-list .icon {
margin-right: 0.45rem;
}
.vp-blog-post-item .post-meta .category-list a + span {
margin-inline: 0.2em;
}
/* 文章页面包屑:各级目录名前后略留白 */
.vp-breadcrumb ol {
gap: 6px 10px;
}
.vp-breadcrumb ol li .breadcrumb:not(.current) {
padding: 0.15em 0.5em;
border-radius: 4px;
}
:root {
/** 主题颜色 */
+2 -2
View File
@@ -7,8 +7,8 @@ config:
full: true
background: tint-plate
hero:
name: 仲夏夜之梦
tagline: 祀梦和小小夏的花园
name: 祀梦和小小夏的花园
tagline: 记录点滴,收藏时光
text: 在这里,每一个文字都承载着温暖与美好 🌸
actions:
-
+19 -42
View File
@@ -1,5 +1,5 @@
---
title: 关于祀梦与他的花园
title: 关于祀梦的花园
description: 这里是爱与回忆的小世界~
hideInBlogList: true
article: false
@@ -7,59 +7,36 @@ createTime: 2024/10/29 12:30:00
permalink: /about/
---
# 👋 嗨呀!这里是祀梦的小窝~
# 👋 这里是祀梦的小窝
欢迎来到我的数字花园!这里不仅是笔记的存放处,更是我思维流转、技术成长与生活感悟的小小交汇点。希望能在这里和你分享温暖与美好~ (๑>◡<๑)
嗨~ 欢迎来到祀梦的个人博客,这是我在这个小站发布的第一篇文章哦~ (✧ω✧)
## 🏗️ 正在努力构建的未来~
## 关于站长我呀~ 🌸
目前我是一名大三的学生,主修**信息安全**专业。虽然专业背景在“守”,但我对“建”有着更浓厚的兴趣呢!
我是祀梦,现在在上海某大专读书,是个可爱的男孩子~ 目前是信息安全专业的学生,但是超——级喜欢编程!(๑•̀ㅂ•́)و✧
- **职业坐标**:目前正全力投入**后端开发**的学习中,正在努力准备实习,期待能在真实的代码世界里磨砺自己,成为厉害的后端大牛!(๑•̀ㅂ•́)و✧
- **技术理念**:我崇尚简洁、高效的代码,同时也相信技术的最终目的是为了传递温暖和解决问题。
## 我的兴趣爱好~ 🌈
## 🪴 为什么会有这个“花园”?
我喜欢好多好多东西呀!编程、摄像、美食、旅游,还有画画~ 假期闲下来的时候,我会画一些自己喜欢的角色呢!(๑˘ᴗ˘๑)
你可能会发现这个站点的结构非常清晰(或者说,我在努力让它变得整齐一些~)。
## 技术方面~ 💻
2025 年末,我决定将原有的博客迁移到这个新家。原因很简单:**我需要一个更具结构化的空间来安放我的笔记**。从密码学理论到后端开发实战,从英语四级备考到算法练习,我希望知识能够像小植物一样,在合适的土壤里有序生长,方便自己翻阅,也能给路过的你一点点参考呀~ 🌸
技术方面,Python 是我最熟练的编程语言,Java 和 C 也懂一些,前后端开发和 Linux 运维我也会一点哦~ 虽然什么都感兴趣,什么都想学,但是总觉得自己不够聪明,学杂而不精呢... (╥ω╥)
## 🚀 个人项目展示~
## 为什么叫"祀梦" 🌙
除了这个笔记站,我还维护着以下这些心血之作:
这个名字的由来超有趣!初中的时候我很喜欢写小说,"祀梦"是我其中一本小书的主角名字~ 当时我的初中同学聊天的时候说这个名字很好听,我就一直沿用下来啦!(๑´ㅂ`๑)
- [**祀梦的个人博客**](https://blog.simengweb.com/):我的感性领地,记录着生活故事与长长的技术思考。
- [**算法练习平台**](https://algorithmplatform.simengweb.com/):为了提升算法能力而开发的小平台,欢迎来一起刷题呀!(≧∇≦)ノ
## 联系方式~ 📱
## 🛠️ 祀梦的小技能树~ (〃'▽'〃)
如果您在网页访问过程中遇到什么问题,或者想要交个朋友的话,欢迎随时来找我玩哦~
- 邮箱:meng_si@proton.me
- B站:[66ccff色的薰依草](https://space.bilibili.com/361714249)
虽然总觉得自己学得杂杂的,但每一项技能都是我用心收集的“宝藏”哦!
## 网站的成长记录~ 📝
- **常用的魔法咒语**Python (最熟练啦~), C++, Java, Solidity, JavaScript
- **探索过的奇幻领地**:后端开发、信息安全、区块链运维、Linux 系统管理 (。・ω・。)
- **随身携带的口袋工具**Docker, Git, WSL2, Hardhat
- 2025年9月21日:部署完网站
## 📸 生活的彩色一角
## 写在最后~ 💌
在代码之外,我的世界也是五颜六色的:
- **超棒的朋友**:首页提到的“小小夏”是我非常要好的朋友。我们共同守护着这个数字花园的宁静。
- **我的小爱好**:我热爱摄像、美食与旅游。假期闲下来的时候,也会拿起画笔,勾勒出心里的角色呢~ (๑˘ᴗ˘๑)
- **关于我呀**:一个喜欢美好事物、偶尔有点小社恐、但在技术面前总能保持好奇心的男孩子。
## 🕰️ 网站的成长足迹
- **2025-12-15**:完成结构化迁移,给笔记们找了个舒服的新家。
- **2025-09-21**:笔记站初次部署。
- **2024-10-29**:在这个小站写下了第一段关于花园的文字。
## 💌 找我玩呀~
如果你对我的项目感兴趣,或者只是想聊聊技术与生活,欢迎随时联系:
- **邮箱**[meng_si@proton.me](mailto:meng_si@proton.me)
- **B站**[66ccff色的薰依草](https://space.bilibili.com/361714249)
---
> “在每一个文字里,都承载着温暖与美好。” 🌸
很早之前我就总是喜欢写点东西,但是又不敢发到大的平台上,做一个属于自己的互联网小窝感觉真的超——级棒!希望大家能在这里找到有用的内容,也欢迎大家常来玩哦~ (づ ̄ 3 ̄)づ
View File
View File
@@ -1,266 +0,0 @@
---
title: 第十四届蓝桥杯大赛软件赛国赛 Python 研究生组(正在更新)
createTime: 2026/01/09 15:57:22
permalink: /archives/b1c77a1d-d402-4788-8049-fa3aeb12ebd0/
tags:
- contest
---
## 一、X 质数
### 题目
题目链接:0X质数 - 蓝桥云课
### 问题描述
对于一个含有 M 个数位的正整数 N ,任意选中其中 K 个不同的数位(0≤K<M),将这些选中的数位删除之后,余下的数位按照原来的顺序组成了一个新的数字 P 。如果至少存在一个 P 是质数,我们就称 N 是一个 X 质数。例如,对于整数 7869 ,我们可以删去 7 和 6 ,得到一个新的数字 89 ,由于 89 是一个质数,因此 7869 是一个 X 质数。又如,对于整数 77 ,可以删去一个 7 后变为质数 7 ,因此 77 也是一个 X 质数。
请问 1 (含)至 1000000(含)中一共有多少个不同的 X 质数。
### 解析
先通过埃氏筛,获取到范围内的所有质数。然后遍历每个数字的所有子串,查看是否满足 X 质数的定义,我们只要找到一个符合条件的子串即可退出循环,只要子串是质数或者 X 质数,我们都可以认定当前数字为 X 质数。
这里在寻找每个数的子串的时候,可以采用二进制的方式,详情查看:通过位运算快速生成所有的子序列|祀梦的个人博客
### 答案
```python
# import os
# import sys
# def is_prime(n):
# _nums = [True] * (n + 1)
# _nums[0] = _nums[1] = False
# for i in range(2, n):
# if _nums[i]:
# for j in range(i ** 2, n + 1, i):
# _nums[j] = False
# return _nums
# N = 1000000
# nums = is_prime(N)
# ans = 0
# for num in range(N + 1):
# digits = [int(n) for n in str(num)]
# length = len(str(num))
# for mask in range(1,1 << length):
# subseq = 0
# for i in range(length):
# if mask & ( 1 << i ):
# subseq = subseq * 10 + digits[i]
# if nums[subseq]:
# nums[num] = True
# ans += 1
# break
# print(ans) # 989457
print(989457)
```
## 二、顶板上的正方形
### 题目
题目链接:0钉板上的正方形 - 蓝桥云课
### 问题描述
小蓝有一个大小为 10×1010×10 钉板,如下图所示,上面等距分布着 10×1010×10 个钉槽(上下/左右相邻的钉槽之间的距离均相同)。其中有一些钉槽上面有钉子, 在图中用红色来进行标注,白色则表示此处没有钉子。小蓝喜欢用橡皮筋在钉 子上围出正方形图案,即选择钉板上的四个钉子,将其作为正方形的四个顶点, 从而把橡皮筋拉伸为一个正方形。
现在,小蓝想要知道在这个钉板上,可以围出多少种边长不同的正方 形?(相同边长的正方形均视作是同一种,不用考虑正方形的位置)。图中展示 了三种不同边长的正方形,其中蓝色线条表示橡皮筋。
### 解析
参考了评论区的大哥(马国良的个人主页 - 蓝桥云课)的思路,如下图所示
dr 为行之间的差距
dc 为列之间的差距
我们遍历 A 和 B,计算 C 和 D 的坐标,分别为 ( x2 + dr , y2 - dc )( x1 + dr , y1 - dc )
然后确保CD没有超过棋盘范围并且都有钉子即可
### 答案
```python
import os
import sys
from itertools import combinations
arr = [
[1, 1, 0, 1, 0, 1, 1, 1, 1, 1],
[1, 1, 1, 0, 0, 1, 1, 1, 1, 0],
[1, 1, 0, 0, 1, 0, 1, 1, 1, 1],
[1, 0, 1, 1, 0, 1, 1, 1, 1, 0],
[1, 0, 1, 0, 1, 1, 1, 1, 0, 0],
[1, 0, 0, 1, 0, 1, 0, 1, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 0, 1, 0, 1, 1, 1, 1],
[1, 0, 1, 0, 0, 1, 0, 1, 0, 0]
]
points = [(i, j) for i in range(10) for j in range(10) if arr[i][j]]
squares = set()
for (x1, y1), (x2, y2) in combinations(points, 2):
dx, dy = x1 - x2, y1 - y2
x3 = x2 + dy
y3 = y2 - dx
x4 = x1 + dy
y4 = y1 - dx
if all(0 <= coord < 10 for coord in [x3, y3, x4, y4]):
if arr[x3][y3] and arr[x4][y4]:
squares.add(dx*dx + dy*dy)
print(len(squares))
```
## 三、整数变换
### 题目
题目链接:0整数变换 - 蓝桥云课
### 问题描述
小蓝有一个整数 n。每分钟,小蓝的数都会发生变化,变为上一分钟的数减去上一分钟的数的各个数位和。
例如,如果小蓝开始时的数为 23,则下一分钟变为 23−(2+3)=18,再下一分钟变为 18−(1+8)=9,再下一分钟变为 9−9=0,共经过了 3 分钟变为 0。
给定一个正整数,请问这个数多少分钟后变为 0。
### 解析
这题直接暴力就过了。
Python3 跑出来只能通过 60% 的测试用例,用 PyPy3 就好了。
### 答案
```python
import os
import sys
num = int(input())
count = 0
while num != 0:
num -= sum(map(int,str(num)))
count += 1
print(count)
```
### 整数变换的第二种做法
### 答案
```python
import os
import sys
# 对 1000 以内的数进行预处理
# difference[i][j] 代表每次减去 sum_digits(i) + j 之后,剩余的值,可能为负数
# step[i][j] 记录最终结果
# 题目中数字的最大值范围为 10的9 次方,我们每一步多减去的 j 值代表的其实是前六位的和
# j 最大也就是 54( 前六位都是9 )
difference = [[0 for _ in range(55)] for _ in range(1000)]
step = [[0 for _ in range(55)] for _ in range(1000)]
# 这里要考虑一下边界情况,有可能后三位为 0 前六位还有
# 这个时候要减去前六位的值
# 并且步数需要加一步
difference[0] = [-num for num in range(55)]
step[0] = [0] + [1 for num in range(54)]
# 先计算出 0 ~ 999 以内的数的值
for i in range(1,1000):
# 遍历所有可能的 j 值
for j in range(55):
ans,num = 0,i
while num > 0:
num -= ( sum(map(int,str(num))) + j )
ans += 1
difference[i][j] = num
step[i][j] = ans
# 当 num 小于 1000 的时候直接返回
num = int(input())
if num < 1000:
print(step[num][0])
else:
ans = 0
while num:
if num < 1000:
ans += step[num][0]
break
# x 为前六位
# y 为后三位
x = num // 1000
y = num % 1000
# 直接加上步数,以及溢出的值即可
ans += step[y][sum(map(int,str(x)))]
num = x * 1000 + difference[y][sum(map(int,str(x)))]
print(ans)
```
## 四、火车运输
## 五、最大区间
### 题目
题目链接:0最大区间 - 蓝桥云课
### 问题描述
给定一个长度为 n 的序列 Ai​,求 L,R 使 (RL+1)⋅min(AL,AL+1,…,AR) 尽可能大,其中 min⁡ 表示最小值。
你只需要输出最大的值即可,不需要输出具体的 L,R。
### 解析
这道题要求给定字符串中的 (RL+1)⋅min(AL,AL+1,…,AR) 的最大值,每次计算区间内的最小值再扩展区间很麻烦,我们可以转换一下思路以当前元素为区间内的最小元素,视为右边界,然后不断向左边扩展,一直到小于当前元素的位置停下,就可以得到当前区间的结果。(这里为什么不用向右边扩展,因为如果存在这种情况的话,右边向左扩展的时候会包括这一段)我们可以采用单调递增栈来加快寻找的速度,0 是为了确保清空栈。
可以用下面这个例子 debug 一下程序查看运行过程。
n = 6
A = [1,2,3,2,3,2]
(感觉解释的还是不太够清楚,有啥问题可以直接评论)
### 答案
```python
import os
import sys
n = int(input())
A = list(map(int,input().split()))
A.append(0)
stack = []
ans = 0
for i in range(n+1):
while stack and A[i] <= A[stack[-1]]:
prev_i = stack.pop()
L = stack[-1] if stack else -1
ans = max( ( i - L - 1 ) * A[prev_i] ,ans)
stack.append(i)
print(ans)
```
## 六、等腰三角形
## 七、连续数组
## 八、质数排序
## 九、选段排序
## 十、最长同类子串
+149
View 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
```
![配置默认单机4节点](https://image.simengweb.com/blog/competition/BRICS2025-ST-132/20250930201715_253_27.png)
在创建完成之后,当前目录会出现一个 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` 启动所有节点
![启动所有节点](https://image.simengweb.com/blog/competition/BRICS2025-ST-132/20250930205309_254_27.png)
验证端口是否生效:`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)
File diff suppressed because it is too large Load Diff
-296
View File
@@ -1,296 +0,0 @@
---
title: 爱莉希雅语录
createTime: 2026/01/08 15:39:17
permalink: /archives/a5b3ea8e-7c3c-40a1-a737-26e911623da8/
tags:
- honkai-impact-3rd
---
嗨,亲爱的来访者♪ 欢迎来到这片收集了“真我”与“美丽”碎片的园圃。在这里,你会读到执拗花朵在暴雨中的坚持,也会听见逐火英桀们为文明奏响的最后颂歌。请怀着期待慢慢翻阅吧,愿这些如星光般的文字能陪你开启属于自己的闪耀旅程,毕竟……你本身就是这世间最瑰丽的馈赠呢♪
<!-- more -->
1. 执拗的花朵永远不会因暴雨而褪去颜色,你的决心也一定能在绝境中绽放真我。
2. 愿你前行的道路有群星闪耀。愿你留下的足迹有百花绽放。你即是上帝的馈赠,世界因你而瑰丽。
3. 悲剧并非终结,而是希望的起始。
4. 此后,将有群星闪耀,因为我如今来过。此后,将有百花绽放,因为我从未离去。
5. 告别过去,是为了走向未来
6. 我名为爱莉希雅……最初的律者,人之律者。
7. 某一日,祂从天坠落。人们抬头仰望,于是看见了星空。星月送来神的女儿,她愿成为人的伴侣。长风化作她的轺车,四海落成她的园圃。鸟雀衔来善的种子,百花编织爱的颂歌。她便是这样降生于世,行于大地,与人类一同长大,与世界一起发芽。
8. 亲爱的山雀,请将我的箭,我的花,与我的爱,带给那子然独行的旅人。然后,便让它开出永恒而无瑕的…人性之华吧。
9. 压力之下的选择才能揭示一个人的真我,也将决定他最终会成为怎样的人。
10. 即使未来不能改变,我也要自己决定到达那个结果的过程。
11. 这是段漫长的路途,你或许会停滞不前,甚至在很长一段时间里一无所获。但这未必是件坏事,并不是一定要做到了什么,达成了什么才算前进。空虚、迷茫、犹豫、自否,对于一个人的一生,这些过程同样拥有它们的意义——就像这里的十三个人曾经历的那样。
12. 天色暗了,接下来就是调皮捣蛋的时间了呢。
13. 白天的我也很可爱,晚上的我也很可爱,你更喜欢哪个我呢?
14. 说起粉色头发的可爱女孩,你第一个会想到谁?321回答!
15. 你好像有不少问题想问我呢,别心急,我们还有很多很多时间。
16. 你喜欢脚踩在落叶或是新雪上的感觉吗?我很喜欢哦。
17. 你比我想象中还可爱许多呢。是不是很在意我想象了什么?
18. 今天的任务都完成啦?真棒,夸夸你哦。
19. 嗨!今天天气真好,和我一样闪闪发光呢。
20. 嗨,早上好!一天的好心情,从见到你开始。
21. 嗨,早上好呀!看见我,有没有很开心呢?
22. 你该休息啦,约好了,我们明天再见哦。
23. 天冷了,小心别着凉哦。我?美少女怎么会冷呢。
24. 今天是我的生日哦。要一起庆祝吗?就我们两个人。
25. 哎呀,你也睡不着吗?那我们来聊聊天,好不好?
26. 有些事不用太在意,美丽的少女总有些小秘密,不是吗?
27. 这么晚了还不睡吗?是在想我,对不对?
28. 知道吗,今天是个很特别的日子。对啦,就是你的生日♪
29. 好啦,冷静一下♪
30. 以律者的标准,你的样子还真有些......别致呢♪
31. 哎呀,别生气嘛♪
32. 真是的......我会哭的哦......
33. 抱歉......得让你失望啦♪
34. 英桀们的谢幕,必须盛大而壮丽
35. 只是你我二人独处,显然有些寂寞了♪
36. 你说对不对?我的好·伊·甸♪
37. 你明明也很开心嘛♪
38. 英桀们也不过是心绪复杂,带有缺陷的普通人,就和当时的每个普通人一样。有自己的私心,也多半谈不上有什么大爱,但也会因为一时感动,或是心血来潮,去做一些冲动,又了不起的事。他们从来不是完美的英雄,只是因为在那个时间,出现在那里的是他们而已。
39. 我相信换做其他人,也一定会做出小异大同的选择,甚至做得更好也说不定?这就是[美丽]的永恒,我所相信的[真我]。十三个人生命的全部就是如此纷繁而又美妙的事物,意义在于在这个过程中我想要相信什么。那会决定在抵达终点时你能得到什么。
40. 你看,他们曾如此骄傲地活过,贯彻始终,以生命奏响了文明的颂歌,这是被称作英桀的人们的故事,是十三位逐火者未尽的旅途,但来访者,你们的道路仍将延续,不是吗,那就听凭心意前进吧,嘻,都说了要前进啦,沿着脚下的足迹,去见证这段逐火的征程,最后跨越逝者们的终幕,去创造我们所未能迎接的未来吧。
41. 要流传给后世的,绝不应该只有憎恨和使命。只有领略过这个时代的光辉和灿烂,未来的人们才能理解我们为之而战的意义。
42. 由英桀们来传承的,应当是身为英桀的荣耀,战斗的理由。是在这段逐火的旅途中,我们最终的灵魂所托。
43. 而后来的你们,将见证我们生命的足迹,灵魂的刻印,并在其中找到自己寻求的答案。
44. 但无论如何 我们的时代已经结束了,而我们也努力完成了各自的使命。
45. 不是被推搡,被裹挟着向前,也不是沿着被别人选定的道路行进。而是怀着这样的想法——我想要怎么做,我应该怎么做——去决定自己的命路,自己的刻印。
46. 以自我的意志,朝着自身所设下的目标,用自在的方式,竭尽全力活过“我”作为主角的一生。
47. 你看,我是这样的,大家也是这样的。我所知晓的那个时代,以及它所孕育出的这十三个人,都是如此。万千的轨迹交织、萦绕,由此诞下百花齐放的奇迹。这就是“美丽”的永恒,我所相信的“真我”。
48. 至此,我们的故事结束了。而从今以后,就是“你”的故事了。
49. 让无人传颂的歌谣,再度启唱。
50. 为历史尘封的故事,续写新章。
51. 高洁而纯真的灵魂,踏上旅途。
52. 愿掠集之兽爱佑其身,赐予「空梦」的自由。
53. 愿渡尘之羽爱佑其身,赐予「浮生」的坚忍。
54. 愿绘世之卷爱佑其身,赐予「繁星」的纯真。
55. 愿噬界之蛇爱佑其身,赐予「无限」的渴求。
56. 愿黎明之哨爱佑其身,赐予「旭光」的意志。
57. 愿寸断之刃爱佑其身,赐予「刹那」的决绝。
58. 愿善法之瞳爱佑其身,赐予「天慧」的智识。
59. 愿坏劫之焱爱佑其身,赐予「鏖灭」的赤诚。
60. 愿愚戏之匣爱佑其身,赐予「螺旋」的奇迹。
61. 愿璀耀之歌爱佑其身,赐予「黄金」的光辉。
62. 愿深罪之槛爱佑其身,赐予「戒律」的慈爱。
63. 愿无烬之剑爱佑其身,赐予「救世」的理想。
64. 愿无瑕之人爱佑其身,赐予「真我」的回归。
65. 我们于此赞颂,始源之律者的诞生
66. 我这支歌将抚摸你的前额,犹如那祝福的亲吻
67. 当你独自一人时,它会坐在身旁与你耳语
68. 当你陷入人群时,它又会保护你远离喧嚣。
69. 我的歌将成为你梦想的羽翼,它将载着你的心到那未知的边缘
70. 当黑夜遮蔽了你的路时,它又成为了照耀在你头顶的忠实星光
71. 于是,「始源」的故事迎来落幕
72. 于是,「始源」的故事迎来伊始
73. 以我为终……
74. 以我……为始。
75. 而今,终焉之时将至。而今,归去之时已至。就此告别吧,美丽的世界。
76. 不想前进的时候,就暂且停下脚步吧,我们永远都在这里,和当初一模一样,毕竟,美丽的女孩子什么都能做到嘛!
77. 游云拂风,花染湛空,与你并肩漫步在午后街头,携手美好此刻,共赏岁月温柔。
78. 经常会和别的女孩子谈论你哦。内容……是不是很想知道呀~
79. 有些事不用太在意,美丽的少女总有些小秘密,不是吗?
80. 这里有好多和我一样漂亮的女孩子呀,是天堂吗?
81. 你会不会嫌我话多呢?可我就是有好多话想对你说呀。
82. 不许叫错我的名字噢,不然……我会有小情绪的。
83. 如此绚丽的花朵,不该在绽放之前就枯萎。我会赠予你璀聚的祝福,而你的灵魂,也将会绽放更耀眼的光辉。
84. 嗨,想我了吗?
85. 不论何时何地,爱莉希雅都会回应你的期待
86. 嗨,我又来啦。多夸夸我好吗?我会很开心的~♪
87. 你好!新的一天,从一场美妙的邂逅开始。
88. 终于轮到我啦,这段时间我可是一直都在构思与你见面的开场白呢。
89. 你可以更光明正大的看向我噢,毕竟我也直在看着你嘛。来,让我们更深入地了解彼此吧?
90. 唉,要做的事好多~但焦虑可是女孩子的大敌,保持优雅得体,从容愉快地前进吧。
91. 别看我这样,其实我也是很忙的。不过,我的日程上永远有为你预留的时间。
92. 唉,时间真是个讨厌的东西,你不觉得吗?如果不是时间紧迫,我还想留下更多值得纪念的话语。
93. 有没有觉得我的话要比别人多一点?多就对啦,我可是有在很认真地准备这件事的。
94. 哇,你看那朵白白软软的云,是不是有点像我呢?
95. 可爱的少女心可是无所不能的噢~♪
96. 好啦可以啦,再说下去我就要哭了噢~♪
97. 这束鲜花,要心怀感激的收下哦~♪
98. 要好好看着我哦~♪
99. 这身衣服是伊甸做的噢,喜欢吗,还是说,喜欢的是我呢~♪
100. 别动噢,借你的眼睛照照镜子……好啦,我看起来怎么样?
101. 嗯~和女孩子独处时,可要好好看向对方的眼晴噢~♪
102. 有空多来陪陪我好吗,你一定不忍心让可爱的我孤独寂寞吧。
103. 这可是你选的衣服,要好好看着,不许移开视线噢。
104. 加点浪漫的气氛,如何?
105. 哇谢谢!我就知道你对我最好啦!
106. 爱莉希雅的贴心提示!你可以尽情的依赖爱莉希雅,而她,也会以全部的身心回应你!
107. 爱莉希雅的贴心提示!如果见到凯文在大厅里,多穿点衣服,他很冷的,各种意义上呢。
108. 在热情似火这件事上,我可不会输给千劫哦。
109. 这一次有你想要的东西吗?没有的话,我就可以再见你一面了。
110. 你应该不会嫌我话多吧?还是说,你更喜欢伊甸那种优雅文静的类型?
111. 如你所见,与那个凯文齐名的第二领袖,竟是一位如花朵般娇羞的少女也就是我啦。
112. 爱莉希雅的贴心提示!和樱说话时,别盯着耳朵看太久,她和我不一样,会害羞。
113. 想了想我毕竟算半个文职,说“武”也不太合适。那就去掉一个字,叫“女神”吧!你觉得呢?
114. 你说,我要是把头发留的和樱那么长,会不会更好看呀?嗯?
115. 你战斗的样子如此绚丽,就如同漫天的飞花一般。让我再为其添点色彩吧。
116. 这里埋藏着太多的历史、太多的秘密。但别担心,无论路有多长,我始终都会在你身边。
117. 如果我也成为律者,会是什么样子呢?头发会再变多些吗?还是说……裙摆会突然变长?
118. 说起来,为什么只有我的刻印是金色的伊甸不会生气吧?算啦,她那么好,一定不会生气的。
119. 咦,到我了吗?哎呀真可惜,这次的开场白我还没想好呢,原谅我吧,下次一定给你个惊喜。
120. 仔细想想,我是女孩子,战力比肩凯文,又有如神明般的聪慧与美貌。这么说来,我不也是“女武神”吗?
121. 爱莉希雅的贴心提示!如果遇到千劫,千万别问他有关面具的事哦。
122. 唉,不知道你见没见到这里的男孩们,他们都内向得很,还是我比较放得开吧?
123. 爱莉希雅的贴心提示!伊甸就像是天使一样——温柔,美丽,又总会予人以天使般的馈赠。
124. 这真是个神奇的地方,不是吗?它让我们的灵魂跨越时空于此相遇,多么浪漫呀。
125. 悄悄告诉你哦,我一共准备了40种不同的开场白。
126. 咦,你在看哪?哦......很在意这对耳朵?它们很漂亮对吗,我也这么觉得。
127. 你一定也在期待和我相遇吧?我知道,因为我的刻印总是很实用嘛。
128. 我的抉择与你的抉择,二者相遇会诞下怎样的奇迹,我想见证这一刻的到来。
129. 爱莉希雅的贴心提示!如果你不想听苏说话了,悄悄走开也行,他看不见。
130. 有我的刻印,你绝对不会输。输了也没关系,我会先一步去大厅等你回来。
131. 不要被三次元的女人骗了呀。
132. 英桀第二位,爱莉希雅,如你所见是一位像花朵般可爱的美丽少女。
133. 我们会留在过去,而你将走向未来。
134. 毕竟我向来不习惯太严肃的场合,也不喜欢过于拘谨的人际关系。
135. 再打下去我会哭的哦
136. 怎么样?喜欢我的记忆吗?有没有一种在和美丽的少女并肩作战的感觉?
137. 猜猜我为你带来了什么,金色的、闪闪发光的刻印,没有人能拒绝它,不是吗?
138. 见好就收哦!
139. 但我永远都会在这里,为你点亮前行的灯火。
140. 纵使知道文明已经覆灭,却依旧选择穷尽一切抗争到最后,只是为了将自己骄傲活过的样子永远铭刻在历史之中。
141. 悲伤不会凭空消失,但温暖的感情也会永远在心底珍藏。
142. 无论过去还是现在,可爱的少女心是无所不能的——只有这一点,无论如何都不会改变。
143. 那个白头发的漂亮女孩就是芽衣的...嗯哼哼,被我发现喽。
143.那是...华?唉,她交到了新的朋友,太好了。
@@ -1,9 +1,10 @@
---
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/
tags:
- wsl
---
嗨呀~让我们在 Windows10 专业版上部署 WSL2 并启动 ubuntu 20.04 虚拟机吧~
@@ -112,6 +113,8 @@ Press any key to continue...
#### 错误码 0x80370102 虚拟化技术没有开启
如果遇到这个错误,可能是因为虚拟化技术没有开启哦~如果是在真实机上操作的话,需要进入BIOS开启虚拟化技术呢~开启之后,可以在任务管理器 -> 性能 -> CPU 的详情页面中,看到下方的虚拟化状态显示为「已启用」哦~
![虚拟化技术启用](https://image.simengweb.com/blog/technology/20250930140716_251_27.png)
如果是在虚拟机中操作的话,就需要启用嵌套虚拟化技术啦~以VMware为例:
先关闭虚拟机,然后找到虚拟机的.vmx配置文件(通常在虚拟机目录下),在文件末尾添加一行:`vhv.enable = "TRUE"`
@@ -142,4 +145,5 @@ wsl --terminate Ubuntu-20.04
接下来,我们还可以通过VS Code来进行开发哦~不过需要先安装一些扩展呢:'Remote - SSH'和'WSL'
安装好扩展后,在VS Code左侧打开远程资源管理器,就可以看到Ubuntu20.04虚拟机啦~直接点击连接就可以了哦~不过第一次连接可能需要启动一下虚拟机,会有点慢呢,耐心等待一下吧~
![连接 WSL2 虚拟机](https://image.simengweb.com/blog/technology/20250930144329_252_27.png)
连接成功之后,就可以愉快地进行开发啦~是不是很简单呢~
+1 -2
View File
@@ -1,9 +1,8 @@
---
title: WSL2 核心操作指南
createTime: 2025/09/30 16:08:32
cover: https://image.simengweb.com/elysia_cover_image/2MEiWEhvsx8OtKeJ.png
permalink: /article/operate-wsl2/
tags:
- wsl
---
这篇文章主要讲WSL2虚拟机核心操作哦~它基于轻量级Hyper-V运行,像贴心小精灵默默工作~还能用命令行精细控制!接下来讲启动/关闭、实例管理、资源配置、网络操作、备份迁移这五大操作,是不是很期待呢~♪
@@ -1,84 +0,0 @@
---
title: 通过位运算快速生成所有的子序列
createTime: 2026/01/09 16:15:00
permalink: /archives/ea20bdda-0d49-4472-a647-2e305a930d11/
tags:
- algorithms
---
## 一、子序列的本质
子序列是从原字符串中选择任意数量的字符(可以是 0 个、1 个、...、所有字符),且保持这些字符的原始顺序形成的字符串。
例如:原字符串 `"abc"` 的子序列包括 `"a"`, `"b"`, `"c"`, `"ab"`, `"ac"`, `"bc"`, `"abc"` 和空字符串 `""`(共 $2^3 = 8$ 种可能性)。
## 二、位掩码(Bitmask)的引入
假设字符串长度为 `n`,我们可以用一个 `n` 位的二进制数来表示是否选择某个字符:
- 二进制数的每一位对应原字符串的一个字符。
- 如果某一位是 `1`,表示选择对应的字符;如果是 `0`,表示不选择。
例如,对于字符串 `"abc"``n=3`):
| 二进制数 | 十进制 | 选择情况 | 生成子序列 |
| :--- | :--- | :--- | :--- |
| `101` | 5 | 选择第 1 个字符 "a" 和第 3 个字符 "c" | `"ac"` |
| `010` | 2 | 选择第 2 个字符 "b" | `"b"` |
## 三、遍历所有可能的二进制数
所有可能的二进制数范围是 `0`(全 0)到 $2^n - 1$(全 1)。例如,`n=3` 时:
- 范围是 `000` (0) 到 `111` (7),共 $2^3 = 8$ 种可能。
- 每个二进制数对应一种子序列选择方式。
- 如果包含 `000` (0),对应空字符串 `""`。若不需要空字符串,可以从 `1` 开始遍历。
## 四、如何将二进制数转换为子序列?
### 1. 外层循环:遍历所有可能的二进制数
对于 `n=3`,遍历 `1` (`001`) 到 `7` (`111`)。
### 2. 内层循环:检查每一位是否为 1
- 对于每个二进制数 `mask`,遍历其每一位 `i`(从 `0``n-1`)。
- 如果 `mask` 的第 `i` 位是 `1`(即 `mask & (1 << i)` 为真),则将原字符串的第 `i` 个字符加入子序列。
## 五、代码示例
```python
def get_all_subsequences(s):
n = len(s)
subsequences = []
# 遍历 1 到 2^n - 1 (排除空字符串)
for mask in range(1, 1 << n):
subseq = []
for i in range(n):
# 检查 mask 的第 i 位是否为 1
if mask & (1 << i):
subseq.append(s[i])
subsequences.append(''.join(subseq))
return subsequences
# 测试
print(get_all_subsequences("abc"))
# 输出: ['a', 'b', 'ab', 'c', 'ac', 'bc', 'abc']
```
## 六、应用场景
在处理类似 **X 质数** 的问题时,我们需要检查一个数字的所有数字子序列。通过这种位运算的方式,可以非常高效地生成所有组合并进行判断。
```python
def solve_x_prime(num):
s = str(num)
n = len(s)
for mask in range(1, 1 << n):
subseq_str = ""
for i in range(n):
if mask & (1 << i):
subseq_str += s[i]
# 将生成的子序列转换为整数并判断是否为质数
p = int(subseq_str)
if is_prime(p):
return True
return False
```
@@ -1,77 +0,0 @@
---
title: 快速幂算法详解
createTime: 2026/01/09 16:05:00
permalink: /archives/1325a3bf-91d7-43ff-9630-e894549e12c1/
tags:
- algorithms
---
## 简介
快速幂算法是用于快速计算的算法,可以用于快速的处理大整数幂的场景。
最简单的 for 循环求数字的 n 次幂需要 $O(n)$ 的时间复杂度。快速幂方法可以达到 $O(\log N)$ 的时间复杂度。
快速幂的核心思想是将指数拆分,以达到快速计算的目的。
## 快速幂 - 二进制法
### 原理
二进制法的核心思想是将指数转换为二进制形式,通过逐位处理并结合平方运算减少乘法次数。
**二进制分解指数**
将指数 $n$ 表示为二进制形式,例如 $n=13$ 对应二进制为 `1101`,即 $13=8+4+1=2^3+2^2+2^0$。
**幂的拆分**
根据二进制分解,$a^n=a^{2^k} \times a^{2^{k-1}} \times \dots \times a^{2^0}$,其中仅当二进制位为 1 时,对应项被保留。
**逐位处理与平方加速**
- 从最低位到最高位依次处理二进制每一位。
- 若当前位为 1,则将当前的底数累乘到结果中。
- 每一步将底数平方,为处理更高位做准备。
### 代码示例
```python
def power(base, exp):
res = 1
while exp > 0:
if exp & 1:
res *= base
base *= base
exp >>= 1
return res
```
## 快速幂 - 折半法
### 原理
折半法的核心公式如下:
我们要快速计算 $a$ 的 $n$ 次方:
- 当 $n$ 为奇数的时候:$a^n = a \cdot (a^2)^{(n-1)/2}$
- 当 $n$ 为偶数的时候:$a^n = (a^2)^{n/2}$
- 当 $n$ 为 0 的时候,直接返回 1
通过递归或迭代,将大指数问题分解为小指数问题,最后合并结果。
### 代码示例
```python
def power(base, exp):
if exp == 0: return 1
half = power(base, exp // 2)
return half * half * (base if exp % 2 else 1)
```
## 两种方法对比
| 特性 | 二进制法 | 折半法 |
| :--- | :--- | :--- |
| **实现方式** | 迭代 + 位运算 | 递归/迭代 + 分治 |
| **时间复杂度** | $O(\log N)$ | $O(\log N)$ |
| **空间复杂度** | $O(1)$ | $O(\log N)$ (递归) |
两者都可以实现在指数时间解决问题,二进制方法比折半法更加的省空间。
@@ -1,300 +0,0 @@
---
title: Python 字符串格式化全指南
createTime: 2026/01/09 14:00:48
permalink: /archives/56ea3081-9c69-43d7-96c8-2812ec08be2c/
tags:
- python
---
## 字符串格式化
我们经常会输出类似“亲爱的xxx你好!你xx月的话费是xx,余额是xx”之类的字符串,而xxx的内容都是根据变量变化的,所以需要一种简便的格式化字符串的方式。
在 Python 中可以使用很多种的字符串格式化方式,下面逐个列举。
### 字符串格式化的四种方式
#### 一、 %号
在Python中,可以采用%来实现字符串格式化,%号格式化字符串的方式是从Python诞生之处就已经存在,时至今日,Python官方也未放弃使用%号,但是也不推荐使用这种格式化方式。
在字符串内部,`%s`表示用字符串替换,`%d`表示用整数替换,有几个占位符,后面就跟几个变量或值,顺序要对应。如果只有一个`%?`,括号可以省略。如果不太确定应该用什么,可以使用`%s`,它会把任何数据类型转换为字符串。
有的时候,字符串里的%是一个普通的字符,这个时候就需要转义,用`%%`来表示一个%。
下面是常见的字符串格式化替代符:
- `%c`:格式化字符以及ASCII码
- `%s`:格式化字符串
- `%d`:格式化整数
- `%u`:格式化无符号整数
- `%o`:格式化无符号八进制数
- `%x`:格式化无符号十六进制数
- `%X`:格式化无符号十六进制数(大写)
- `%f`:格式化浮点数,可指定小数点后精度
- `%e`:用科学表示法格式化浮点数
- `%E`:同 %e
- `%g`%f 和 %e 的简写
- `%G`%f 和 %E 的简写
**Python 字符串格式化的代码示例:**
```python
a=15 #定义变量a并赋值
b=12345678.1234567 #定义变量b并赋值
strs="I love Python!" #定义字符串strs并赋值
print("a=%05d"%a) #使用m控制输出位数,空位补0
print("b=%8.3f"%b) #输出b,用m.n控制输出的长度和小数点位数
print("%s"%strs) #正常输出字符串,用于做比较
print("%17s"%strs) #使用m控制输出字符串长度
print("%r"%strs) #使用%r输出字符串
print("%-17.5s"%strs) #使用-m.n进行左对齐、限制字符串长度和字符位数
print("a={0:05}".format(a)) #输出5位数字空位补0
print("b={0:,.3f}".format(b)) #输出b,用千分位分隔并保留3位小数
print("{0:*^30}".format(strs)) #居中且使用*填充
```
**运行结果:**
```text
a=00015
b=12345678.123
I love Python!
I love Python!
'I love Python!'
I lov
a=00015
b=12,345,678.123
********I love Python!********
```
需要注意的一点是,Python中的中文大小为两字符,英文为一字符,所以说在写的时候要格外留意。
#### 二、 str.format 格式化
该format方法是在Python2.6中引入的,是字符串类型的内置方法。因为str.format的方式在性能(后面测试了一下,比%要慢)和使用的灵活性上都比%更胜一筹,所以推荐使用。
**1. 使用位置参数**
```python
# 按照位置一一对应
print('{} asked {} to do something'.format("egon","lili"))
print('{} asked {} to do something'.format("lili","egon"))
```
**2. 使用索引**
```python
# 使用索引取对应位置的值
print('{0}{0}{1}{0}'.format('x','y'))
```
**3. 使用关键字参数 or 字典**
```python
# 可以通过关键字or字典的方式格式化,打破了位置带来的限制与困扰
print('我的名字是 {name}, 我的年龄是 {age}.'.format(age=18, name='egon'))
kwargs = {'name': 'egon', 'age': 18}
print('我的名字是 {name}, 我的年龄是 {age}.'.format(**kwargs)) # 使用**进行解包操作
```
关于解包详解可以参看:<https://blog.csdn.net/qq_36667170/article/details/121401668>
**4. 填充和格式化**
```python
# 先取到值,然后在冒号后设定填充格式:[填充字符][对齐方式][宽度]
# *<10:左对齐,总共10个字符,不够的用*号填充
print('{0:*<10}'.format('开始执行')) # 开始执行******
# *>10:右对齐,总共10个字符,不够的用*号填充
print('{0:*>10}'.format('开始执行')) # ******开始执行
# *^10:居中显示,总共10个字符,不够的用*号填充
print('{0:*^10}'.format('开始执行')) # ***开始执行***
```
**5. 进度和进制**
```python
print('{salary:.3f}'.format(salary=1232132.12351)) #精确到小数点后3位,四舍五入
print('{0:b}'.format(123)) # 转成二进制,结果为:1111011
print('{0:o}'.format(9)) # 转成八进制,结果为:11
print('{0:x}'.format(15)) # 转成十六进制,结果为:f
print('{0:,}'.format(99812939393931)) # 千分位格式化
```
#### 三、 f-Strings 格式化
虽然str.format()比%格式稍微高级了一些,但是它还是有自己的缺陷。当需要传入的字符串过多时,仍然会显得非常冗长。于是在Python3.6中引入了f-strings,不仅比str.format更简洁,性能上也更胜一筹。
f-string是以 f 或 F 开头的字符串,核心在于字符串中符号{}的使用。
**1. {} 中可以是变量名**
```python
name = 'egon'
age = 18
print(f'{name} {age}') # egon 18
print(F'{age} {name}') # 18 egon
```
**2. {} 中可以是表达式**
```python
# 可以在{}中放置任意合法的Python表达式,会在运行时计算
# 比如:数学表达式
print(f'{3*3/2}') # 4.5
# 比如:函数的调用
def foo(n):
print('foo say hello')
return n
print(f'{foo(10)}') # 会调用foo(10),然后打印其返回值
# 比如:调用对象的方法
name='EGON'
print(f'{name.lower()}') # egon
```
**3. 在类中的使用**
```python
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f'{self.name}:{self.age}'
def __repr__(self):
return f'===>{self.name}:{self.age}<==='
obj=Person('egon',18)
print(obj) # 触发__str__
print(obj.__repr__()) # 触发__repr__
# 在f-Strings中的使用
print(f'{obj}') # 触发__str__
print(f'{obj!r}') # 触发__repr__
```
**4. 多行 f-Strings**
```python
# 当格式化字符串过长时,如下列表info
name = 'Egon'
age = 18
gender = 'male'
hobbie1='play'
hobbie2='music'
hobbie3='read'
info = [f'名字:{name}年龄:{age}性别:{gender}',
f'第一个爱好:{hobbie1}第二个爱好:{hobbie2}第三个爱好:{hobbie3}']
# 我们可以回车分隔到多行,注意每行前都有一个f
info = [
# 第一个元素
f'名字:{name}'
f' 年龄:{age}'
f' 性别:{gender}',
# 第二个元素
f'第一个爱好:{hobbie1}'
f' 第二个爱好:{hobbie2}'
f' 第三个爱好:{hobbie3}'
]
print(info)
```
**5. 引号的嵌套**
```python
# 当字符串嵌套发送冲突时,与正常的字符串处理方式是一样的
# 1、外层为单引号,内层嵌套也为单引号,并且想要输入的内容也为单引号,那么外层需要改用双引号
print("my name is 'egon'")
# 2、外层为单引号,内层嵌套也为单引号,并且想要输入的内容也为单引号,需要用到转义
print('my name is \'egon\'')
```
**6. 括号的处理**
需要注意的是,反斜杠可以用来进行字符转义,但不能用在 {} 的表达式中,注释 # 号也不能出现在 {} 的表达式中。
```python
f'{1\2}' # 语法错误
f'{x#}' # 语法错误
```
所以当我们的输出的结果中需要包含{}时,类似于之前输出%的做法,需要在原有的基础上再套一层。
```python
print(f'{{天王盖地虎}}') # {天王盖地虎}
print(f'{{{{天王盖地虎}}}}') # {{天王盖地虎}}
```
#### 四、 三种字符串格式化方式的性能对比
```python
from timeit import timeit
def test_s():
name = 'Egon'
age = 18
return '%s:%s.' % (name, age)
def test_format():
name = 'Egon'
age = 18
return '{}:{}.'.format(name, age)
def test_f_strings():
name = 'Egon'
age = 18
return f'{name}:{age}.'
res1 = timeit(test_s, number=1000000)
res2 = timeit(test_format, number=1000000)
res3 = timeit(test_f_strings, number=1000000)
print(res1) # 0.3338866999838501
print(res2) # 0.40734450006857514
print(res3) # 0.24273910000920296 最快
```
#### 五、 标准库模版
从Python2.4起,Python标准库string引入了Template也可以用来格式化字符串,所以说,与前三种方式的一个显著的区别就是:Template属于Python语言的核心语法特征,使用方式如下。
```python
from string import Template
name='EGON'
t = Template('Hello $name!')
res=t.substitute(name=name)
print(res) # Hello EGON!
```
还有另外一个不同的地方是,这个模板字符串不支持类似str.format那样的进制转换,需要自己处理。
```python
from string import Template
name='EGON'
templ_string = 'Hello $name, there is a $error error!!!'
res=Template(templ_string).substitute(name=name, error=hex(12345))
print(res) # Hello EGON, there is a 0x3039 error!!!
```
另外稍微吐槽一下,这种方式真的慢。使用模板字符串Template的最佳的时机就是当你的程序需要处理由用户提供的输入内容时。模板字符串是最保险的选择,因为可以降低复杂性。其他一些复杂的字符串格式化技巧的可能会给你的程序带来安全漏洞。
### 总结
- 如果格式化的字符串是由用户输入的,那么基于安全性考虑,推荐使用Template。
- 如果使用的python3.6+版本的解释器,推荐使用f-Strings。
- 如果要兼容python2.x版本的python解释器,推荐使用str.format。
- 如果不是测试的代码,不推荐使用%。
@@ -1,117 +0,0 @@
---
title: 原码、反码、补码
createTime: 2026/01/08 16:34:05
permalink: /archives/6f41cabe-41e6-4a09-9f1c-af7dd709a35d/
tags:
- cs-fundamentals
---
欢迎来到 0 与 1 的魔法派对!这篇文章将带你揭开原码、反码与补码的奥秘,看计算机如何巧妙地用补码化减为加。让我们一起翻开这页,去捕捉二进制底层那份迷人的理性之美吧♪
<!-- more -->
## 一、 前置概念
计算机底层存储数据的时候使用的是二进制数字,但是计算机在存储一个数字的时候并不是直接存储该数字对应的二进制数,而是存储该数字对应的**二进制数的补码**。
在了解原码、反码和补码之前,我们要了解**机器数**和**真值**的概念。
### 1) 机器数
一个数在计算机的存储形式是二进制数,我们称这些二进制数为**机器数**。机器数是有符号的,在计算机中用机器数的最高位存放符号位,`0` 表示正数,`1` 表示负数。
### 2) 真值
因为机器数带有符号位,所以机器数的形式值不等于其真实表示的值(真值)。
- 以机器数 `1000 0001` 为例,其真正表示的值(首位为符号位)为 `-1`,而形式值(首位就是代表 1)为 `129`
- 因此将带符号的机器数的真正表示的值称为机器数的**真值**。
## 二、 原码、反码与补码
### 1) 原码
原码的表示与机器数真值表示的一样,即用第一位表示符号,其余位表示数值。
- **正数**:就是它对应的二进制数。
- **负数**:将绝对值对应的二进制最左边位变为 `1`
例如十进制的正负 1,用 8 位二进制的原码表示如下:
- `[+1]` = 原: `[ 0000 0001 ]`
- `[-1]` = 原: `[ 1000 0001 ]`
### 2) 反码
- **正数**:和原码相同。
- **负数**:在其原码的基础上,**符号位不变,其余各位取反**。
示例:
- `[+1]` = 原: `[ 0000 0001 ]` = 反: `[ 0000 0001 ]`
- `[-1]` = 原: `[ 1000 0001 ]` = 反: `[ 1111 1110 ]`
### 3) 补码
- **正数**:补码是其原码本身。
- **负数**:补码是在其原码的基础上,**符号位不变,其余各位取反后加 1**(即在反码的基础上加 1)。
示例:
- `[+1]` = 原: `[ 0000 0001 ]` = 反: `[ 0000 0001 ]` = 补: `[ 0000 0001 ]`
- `[-1]` = 原: `[ 1000 0001 ]` = 反: `[ 1111 1110 ]` = 补: `[ 1111 1111 ]`
## 三、 数据在计算机中的存储形式
计算机实际上只存储**补码**,所以说原码转换为补码的过程,也可以理解为数据存储到计算机内存中的过程。
在原、反、补码中,正数的表示是一模一样的,而负数的表示是不相同的。因此对于负数的补码来说,我们不能直接用进制转换将其转换为十进制数值,因为这样是得不到计算机真正存储的十进制数的。**应该将其转换为原码后,再将转换得到的原码进行进制转换为十进制数**(机器数包含符号位)。
## 四、 为什么会使用原码、反码、补码
对于人脑来说,知道机器数的第一位是符号位是一件很轻松的事情,但对于计算机基础电路设计来说判别第一位是符号位是非常难和复杂的事情。
为了让计算机底层设计更加简单,于是设计将符号位参与运算,并且**只保留加法**的方法,通过**加上一个负数的方式来实现减法**。这样让计算机运算更加简单,并且也让符号位参与到运算中去。
## 五、 使用原码、反码与补码进行运算
### 1) 使用原码运算
计算十进制表达式:`1 - 1 = 0`
```text
1 - 1 = 1 + (-1)
= 原:[ 0000 0001 ] + 原:[ 1000 0001 ]
= 原:[ 1000 0010 ] = -2
```
**结论**:如果用原码表示,让符号位也参与计算,对于减法来说,结果是不正确的。这也是计算机内部在存储数据时不使用原码的原因。为了解决这一问题,出现了反码。
### 2) 使用反码运算
计算十进制表达式:`1 - 1 = 0`
```text
1 - 1 = 1 + (-1)
= 原:[ 0000 0001 ] + 原:[ 1000 0001 ]
= 反:[ 0000 0001 ] + 反:[ 1111 1110 ]
= 反:[ 1111 1111 ] = 原:[ 1000 0000 ] = -0
```
**结论**:通过计算我们发现用反码计算减法,结果的真值部分是正确的。唯一的问题出现在 "0" 这个特殊的数值上。虽然人们理解上 `+0``-0` 是一样的,但是 0 带符号是没有任何意义的,而且会有 `[0000 0000]原``[1000 0000]原` 两个编码表示 0。为了解决这一问题,出现了补码。
### 3) 使用补码运算
计算十进制表达式:`1 - 1 = 0`
```text
1 - 1 = 1 + (-1)
= 原:[ 0000 0001 ] + 原:[ 1000 0001 ]
= 补:[ 0000 0001 ] + 补:[ 1111 1111 ]
= 补:[ 0000 0000 ] = 原:[ 0000 0000 ] = 0
```
**结论**:这样 0 用 `[0000 0000]` 表示,而以前出现问题的 `-0` 则不存在了。而且人们还发现可以用 `[1000 0000]` 表示 `-128`
**-128 的推算过程如下**
```text
(-1) + (-127) = -128
= 原:[ 1000 0001 ] + 原:[ 1111 1111 ]
= 补:[ 1111 1111 ] + 补:[ 1000 0001 ]
= 补:[ 1000 0000 ]
```
> **注意**:因为实际上是使用以前的 `-0` 的补码来表示 `-128`,所以 `-128` 并没有原码和反码表示。只要补码是 `[1000 0000]`,其十进制数值就为 `-128`。
### 4) 小结
因为补码能多存储一个 `-128`,而且在计算机底层中存储的是补码,所以在计算机中一个 8 位的二进制数的存储范围是用补码表示的 `[-128, 127]`,而不是用原码或反码表示的 `[-127, 127]`。这也可以解释为什么计算机中一个字节的取值范围是 `[-128, 127]`
## 六、 总结(牢记)
- **二进制的最高位是符号位**`0` 表示正数,`1` 表示负数。
- **正数三码合一**:正数的原码、反码、补码都一样。
- **负数反码**:它的原码符号位不变,其它位取反。
- **负数补码**:它的反码 + 1;反之,负数反码 = 负数补码 - 1。
- **0 的表示**`0` 的反码、补码都是 `0`
- **运算方式**:在计算机运算的时候都是以 **“补码”** 的方式来运算的。
- **查看结果**:当我们看运算结果的时候,要看它的**原码**(重点)。
+1 -2
View File
@@ -1,9 +1,8 @@
---
title: 通过 EdgeOne Pages 搭建图床
createTime: 2025/09/29 02:28:17
cover: https://image.simengweb.com/elysia_cover_image/0lQviAbmMCVGN0Y6.png
permalink: /article/8gihio2v/
tags:
- image-hosting
---
各位~今天要给大家介绍一个超棒的图床搭建方法哦!EdgeOne Pages 是腾讯云提供的静态网站托管服务,而且还有免费额度可以使用呢,对于日常需求来说完全足够啦~
-5
View File
@@ -22,9 +22,4 @@ 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天下第一!
---
-13
View File
@@ -1,13 +0,0 @@
---
title: 模型
createTime: 2026/03/29 20:00:00
permalink: /ai/
---
# 模型
这里是我和大模型、RAG、本地部署还有各种工具链打交道的地方~
和博客里的随想不同,这些笔记会更系统化一些,方便以后自己回来查的时候能一把抓到重点。左侧的目录会随着我记的东西越来越多而慢慢展开,就像「英语学习」「Web 开发」那些栏目一样,可以按专题慢慢逛。
当然啦,如果只是突然想到什么、想随手记几句碎碎念,还是会丢进 [博客](/blog/) 里,那里更适合发点动态更新的小东西~
-252
View File
@@ -1,252 +0,0 @@
---
title: 便宜免费的大模型 API 整合 ( 2025年11月11日
createTime: 2025/11/11 13:54:02
permalink: /article/free_model_api/
sidebar: '/ai/'
---
百度千帆、讯飞星火、腾讯混元均有免费在线额度,SCNet 提供 0.1 元/百万 tokens 的超低价大模型,轻量任务先薅免费,量大了再掏 0.1 元,稳!
## 免费的大模型 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 LiteToken 余量为无限。
#### 快速上手
> 小贴士:如需联网检索,启用 `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 元,让荷包和模型一起“稳稳幸福”吧!
-188
View File
@@ -1,188 +0,0 @@
---
title: MCP 与 Skills:让 AI 助手更懂你的利器
createTime: 2026/03/29 14:00:00
permalink: /article/mcp-and-skills/
sidebar: '/ai/'
---
嗨~今天来聊聊两个让 AI 助手变得更聪明、更贴心的小魔法:**MCP** 和 **Skills** 🪄
它们就像是给 AI 装上了「外挂」和「说明书」,让它不仅能聊天,还能真正帮你干活、调用工具、甚至访问你的本地知识库~
## 一、MCP 是什么?
**MCP** 全称是 **Model Context Protocol**(模型上下文协议),是由 [Anthropic](https://www.anthropic.com/) 提出的一种开放协议。
简单来说,它就像是 AI 和外部世界之间的「通用翻译官」🌐
### 为什么需要 MCP
想象一下:
- 你想让 AI 查一下你的本地数据库
- 你想让 AI 调用某个特定工具
- 你想让 AI 访问你的笔记知识库
以前,每个工具都要写一套单独的对接代码,很麻烦对吧?
MCP 的出现,就是为了让这些「对接」变得标准化——**一次配置,到处可用**。
### MCP 的工作原理
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ AI 助手 │ ◄──► │ MCP 协议 │ ◄──► │ 外部工具 │
│ (Cursor等) │ │ (标准化) │ │ (数据库/API) │
└─────────────┘ └─────────────┘ └─────────────┘
```
AI 助手通过 MCP 协议,可以:
- 🔍 **检索**(Retrieval):查询知识库、数据库
- 🛠️ **调用工具**Tools):执行特定功能
- 💾 **访问资源**(Resources):读取文件、配置等
## 二、Skills 是什么?
如果说 MCP 是「通信协议」,那 **Skills** 就是「技能说明书」📖
### Skills 的概念
Skills(技能)是封装好的、可复用的功能模块。每个 Skill 通常包含:
- **功能描述**:这个技能是干嘛的
- **调用方式**:需要哪些参数、返回什么结果
- **使用示例**:实际怎么调用
### MCP vs Skills 的关系
| 概念 | 比喻 | 作用 |
|------|------|------|
| **MCP** | 电话线/网络协议 📡 | 负责「能连上」 |
| **Skills** | 电话簿/功能菜单 📋 | 负责「知道能做什么」 |
MCP 让 AI 和工具**连得通**Skills 让 AI**知道怎么用**。
## 三、实际应用场景
### 场景 1:本地知识库检索 🗃️
就像我在 [RAGFlow 部署文章](../windows11-ragflow-deployment-mcp/) 里写的,通过 MCP 把 RAGFlow 接到 Cursor 里:
```json
// Cursor 的 MCP 配置
{
"mcpServers": {
"RAGFlow": {
"url": "http://127.0.0.1:39382/mcp/"
}
}
}
```
然后 AI 就能:
- 自动检索你的笔记
- 基于本地知识回答问题
- 不用把敏感文件上传到云端
### 场景 2:数据库查询 🗄️
配置一个数据库 MCP Server,AI 就能直接帮你:
```
用户:查一下上个月销售额最高的产品
AI:【通过 MCP 调用数据库查询工具】
SELECT product_name, SUM(sales)
FROM sales
WHERE date >= '2025-02-01'
GROUP BY product_name
ORDER BY SUM(sales) DESC
LIMIT 1;
结果是:产品 A,销售额 ¥123,456
```
### 场景 3:文件操作 📁
通过文件系统 MCPAI 可以:
- 读取项目配置文件
- 批量重命名文件
- 生成代码并保存到指定目录
## 四、在 Cursor 中使用
### 配置 MCP Server
以 Cursor 为例,在 `~/.cursor/mcp.json` 中添加:
```json
{
"mcpServers": {
"my-database": {
"url": "http://localhost:3000/mcp"
},
"file-system": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/dir"]
}
}
}
```
### 使用流程
1. **AI 发现技能**:启动时,AI 会自动获取所有可用的 Skills 列表
2. **意图识别**:当你提问时,AI 判断是否需要调用工具
3. **参数填充**AI 自动提取所需参数
4. **执行并返回**:调用 MCP Server,获取结果后呈现给你
### 交互示例
```
你:帮我总结一下项目里的 API 接口
AI:我来帮你分析一下项目中的 API 接口。
【调用 file-system skill 读取项目文件】
【调用检索 skill 查找路由定义】
找到以下接口:
1. GET /api/users - 获取用户列表
2. POST /api/users - 创建用户
3. GET /api/users/:id - 获取单个用户
...
```
## 五、MCP 生态一览
目前 MCP 生态正在快速发展,已有许多现成的 Server 可用:
| 类型 | 代表项目 | 用途 |
|------|---------|------|
| 文件系统 | `@modelcontextprotocol/server-filesystem` | 读写本地文件 |
| 数据库 | `@modelcontextprotocol/server-postgres` | PostgreSQL 查询 |
| GitHub | `@modelcontextprotocol/server-github` | 操作 GitHub |
| 浏览器 | `@browserbasehq/mcp-server-browserbase` | 自动化浏览器操作 |
| 知识库 | RAGFlow MCP | 本地文档检索 |
完整的官方列表可以在 [MCP Servers Repository](https://github.com/modelcontextprotocol/servers) 找到。
## 六、总结
| 要点 | 说明 |
|------|------|
| **MCP** | 让 AI 和工具「说同一种语言」的开放协议 |
| **Skills** | 封装好的功能模块,告诉 AI「我能做什么」 |
| **价值** | 打破信息孤岛,让 AI 真正连接你的数字世界 |
| **前景** | 越来越多的工具会支持 MCP,生态会越来越丰富 |
用一句话概括:**MCP 是桥梁,Skills 是地图,让 AI 从「聊天伙伴」变成「得力助手」** 🎯
---
> 💡 **延伸阅读**
> - [Windows 11 本地部署 RAGFlow 与 Cursor MCP](./windows11-ragflow-deployment-mcp.md)
> - [MCP 官方文档](https://modelcontextprotocol.io/)
> - [Anthropic MCP 介绍](https://www.anthropic.com/news/model-context-protocol)
File diff suppressed because it is too large Load Diff
-78
View File
@@ -1,78 +0,0 @@
---
title: ETLCloud
createTime: 2025/12/24 17:13:36
permalink: /ops/docker/other/ETLCloud/
---
## 前置环境
这里安装之前,需要先安装 mongodb 数据库,可以参考 [使用 Docker 部署 MongoDB](mongodb.md)
## 安装 ETLCloud
拉取社区版本镜像:
```bash
docker pull ccr.ccs.tencentyun.com/restcloud/restcloud-etl:V4.0
```
### 部署容器
如果您已经运行过同名容器,请先删除:
```bash
docker rm -f restcloud-etl-V4.0
```
使用以下命令进行部署(包含授权绑定、数据持久化和端口映射):
```bash
docker run -d \
--restart=always \
--privileged=true \
--name restcloud-etl-V4.0 \
--mac-address=01:D2:F4:18:B8:67 \
-v /data/tomcat:/usr/tomcat \
-p 9527:8080 \
ccr.ccs.tencentyun.com/restcloud/restcloud-etl:V4.0
```
**参数说明:**
- `--restart=always`: 容器退出时总是重启(如系统重启)。
- `--privileged=true`: 赋予容器特权模式,确保初始化正常。
- `--mac-address`: 固定 MAC 地址,用于绑定 License 授权(**注意:第一个字节必须为偶数,建议使用 02 开头**)。
- `-v /data/tomcat:/usr/tomcat`: 将 Tomcat 目录挂载到宿主机,实现数据持久化。
- `-p 9527:8080`: 访问端口映射,宿主机访问端口为 9527。
拷贝容器中的 tomcat 目录到主机上
```bash
docker cp e0419ad8a2bf31743ec17368cf4098e293c36761842a7dcff8280fbc34195fba:/usr/tomcat /data/
```
删除之前创建的简单容器
```bash
docker rm -f e0419ad8a2bf31743ec17368cf4098e293c36761842a7dcff8280fbc34195fba
```
在 /data/tomcat 路径下,编辑ETLCloud mongo相关的配置文件,这里的信息参考之前创建的 MongoDB 实例。
这里我额外修改了 server.port ,这里太容易和其他的服务端口冲突,所以这里修改为 9527。
```bash
sudo vim ./webapps/ROOT/WEB-INF/classes/application.properties
server.port=9527
...
#集群服务器之间同步用的公共配置数据库,空表示和配置库一起
spring.data.mongodb.host=127.0.0.1:27018
spring.data.mongodb.repositories.enabled=true
#MongoDb的数据库认证用户名及密码,没有可以为空
spring.data.mongodb.username=admin
spring.data.mongodb.password=admin
...
```
然后可以启动容器,样例如下:
```bash
docker run -d --restart=always --restart=on-failure:5 --privileged=true --name restcloud-etl-V4.0 --mac-address=自定义mac地址 -v /home/tomcat:/usr/tomcat -p 8080:8080 镜像id
```
具体命令,这里的MAC地址参数一定是要有的,不然每次重新创建之后MAC地址会变就需要重新生成SN码
这里的MAC地址不要和博主写一样的...自己随机一个或者随便写一个就行
```bash
docker run -d --restart=always --restart=on-failure:5 --privileged=true --name restcloud-etl-V4.0 --mac-address=02:D2:00:00:00:67 -v /data/tomcat:/usr/tomcat -p 9527:8080 4a5c0ed2a5b2
```
然后访问 服务器IP:9527/restcloud/admin/login 就可以啦
后面的话就是去官网申请一个SN码,然后就可以开始使用啦。
-69
View File
@@ -1,69 +0,0 @@
---
title: 使用 Docker 部署 Postgres
createTime: 2025/12/25 10:52:34
permalink: /ops/docker/db/postgres/
---
## 在 Ubuntu 上部署 Postgres 实例
拉取 Postgres 镜像:
```bash
docker pull postgres
```
> [!IMPORTANT] 注意事项
> 从 **PostgreSQL 18+** 版本开始,官方镜像建议将数据目录挂载到 `/var/lib/postgresql` 而非 `/var/lib/postgresql/data`。如果你是从旧版本升级镜像,直接挂载旧目录会导致启动失败。
### 极简运行 Postgres 实例
```bash
docker run --restart=always -itd --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres
```
解析:
- `--restart=always`:容器重启时自动启动。
- `-itd`:交互式模式运行容器,后台模式。
- `--name postgres`:为容器命名为 postgres。
- `-p 5432:5432`:将主机的 5432 端口映射到容器的 5432 端口。
- `-e POSTGRES_PASSWORD=postgres`:设置 Postgres 数据库的密码为 postgres。
- `postgres`:使用 Postgres 镜像。
### 配置 Postgres 持久化实例
#### 方案一:使用最新版本 (18+)
创建一个目录用于存储 Postgres 数据:
```bash
mkdir -p /data/postgres/
```
运行 Postgres 容器:
```bash
docker run --restart=always -itd \
--name postgres \
-p 5432:5432 \
-e POSTGRES_PASSWORD=postgres \
-v /data/postgres/:/var/lib/postgresql \
postgres
```
#### 方案二:固定使用旧版本 (如 17)
如果你有现存的 `/var/lib/postgresql/data` 格式数据,建议固定版本:
```bash
docker run --restart=always -itd \
--name postgres \
-p 5432:5432 \
-e POSTGRES_PASSWORD=postgres \
-v /data/postgres/:/var/lib/postgresql/data \
postgres:17
```
解析:
- `-v /data/postgres/:/var/lib/postgresql/data`:将主机的 /data/postgres/ 目录挂载到容器的 /var/lib/postgresql/data 目录,用于持久化存储数据。
#### 进入容器之后修改 postgres 用户密码
进入 Postgres 容器:
```bash
docker exec -it postgres psql -U postgres
```
解析:
- `docker exec -it postgres psql -U postgres`:进入 Postgres 容器的 psql 命令行界面,使用 postgres 用户进行登录。
修改 postgres 用户密码为 postgres
```sql
ALTER USER postgres PASSWORD 'postgres';
```
-39
View File
@@ -1,39 +0,0 @@
---
title: Docker 部署运维
createTime: 2025/12/24 16:39:34
permalink: /ops/docker/
---
欢迎来到 Docker 运维笔记!✨
在这里,我们将一起探索那些神奇的“小盒子”——Docker 容器。它们就像是装满惊喜的礼盒,把复杂的程序都整整齐齐地收纳在一起,是不是很有趣呢?♪
不管是部署数据库,还是搭建各种好玩的应用,只要有了这些小盒子,一切都会变得像魔法一样简单又优雅呢~真期待看到你在运维的道路上,也能像花朵一样绽放光彩呢。🌸
好啦,让我们开始这段美妙的旅程吧~如果遇到困难,这里会一直提供帮助的哦~
## 常用基础命令 🛠️
为了更顺畅地开启这段旅程,这里准备了一些常用的魔法指令:
### 容器管理
- `docker ps`:查看正在运行的小盒子。
- `docker ps -a`:查看所有的小盒子(包括休息中的)。
- `docker stop <ID>`:让小盒子暂时休息一下。
- `docker start <ID>`:唤醒休息中的小盒子。
- `docker rm <ID>`:送走不再需要的小盒子。
### 镜像管理
- `docker images`:查看我们收集的所有魔法镜像。
- `docker pull <name>`:从云端下载新的魔法镜像。
- `docker rmi <ID>`:清理不再需要的魔法镜像。
### 日志与调试
- `docker logs -f <ID>`:实时查看小盒子里的悄悄话。
- `docker exec -it <ID> /bin/bash`:亲自钻进小盒子里面看看。
## 部署清单 📋
- [MongoDB 部署魔法](./mongodb.md)
- 更多惊喜,敬请期待~✨
-69
View File
@@ -1,69 +0,0 @@
---
title: 使用 Docker 部署 MongoDB
createTime: 2025/12/24 16:34:00
permalink: /ops/docker/db/mongodb/
---
本教程将介绍如何使用 Docker 快速部署一个 MongoDB 实例。
## 在 Ubuntu 上部署 MongoDB:4.2 实例
我们先拉取 MongoDB:4.2 镜像:
```bash
docker pull mongo:4.2
```
创建一个目录用于存储 MongoDB 数据:
```bash
mkdir -p /data/mongo/
```
启动 MongoDB 容器:
```bash :wrap
sudo docker run --restart=always -itd --name mongo -p 27018:27017 -v /data/mongo/:/data/db mongo:4.2 --auth
```
命令详解:
- `--restart=always`:容器重启时自动启动。
- `-itd`:交互式模式运行容器,后台模式。
- `--name mongo`:为容器命名为 mongo。
- `-p 27018:27017`:将主机的 27018 端口映射到容器的 27017 端口。
- `-v /data/mongo/:/data/db`:将主机的 /data/mongo/ 目录挂载到容器的 /data/db 目录,用于持久化存储数据。
- `mongo:4.2`:使用 MongoDB:4.2 镜像。
- `--auth`:启用身份验证功能。
进入 MongoDB 容器:
```bash
docker exec -it mongo mongo admin
```
### 在 MongoDB 容器中创建管理员用户
先进入 admin 数据库
```bash
use admin;
```
创建管理员用户 admin, 密码 root, 角色为 root。
```bash
db.createUser( { user: "root", pwd: "root", roles:['root'] });
```
退出 MongoDB 容器:
```bash
exit
```
使用 root 用户进行登录
```bash
docker exec -it mongo mongo admin -u root -p root
```
这里还能创建一个 admin 用户,用密码 admin,角色为 readWriteAnyDatabase, dbAdminAnyDatabase。
```bash
db.createUser( { user: "admin", pwd: "admin", roles:['readWriteAnyDatabase','dbAdminAnyDatabase'] } );
```
验证用户,这里会登录到 admin
```bash
db.auth("admin","admin");
```
删除用户的话可以使用,注意这里要切换回 root 用户
```bash
db.dropUser("admin");
```
-12
View File
@@ -1,12 +0,0 @@
---
title: 一些零散的命令
createTime: 2025/12/31 10:00:30
permalink: /ops/linux/other/
---
## 文件处理相关
统计当前目录下的所有文件加起来有多少行
```
wc -l * | tail -n 1
```
+49
View File
@@ -0,0 +1,49 @@
---
title: C++ 学习笔记
description: 记录C++编程语言的学习心得和基础知识
createTime: 2025/09/22 09:00:00
permalink: /programming/cplusplus/
---
# C++ 学习笔记
这里是我在学习C++编程语言过程中记录的学习心得、基础知识和实战经验。通过整理这些笔记,希望能够帮助自己和他人更好地掌握C++这门强大的编程语言。
## 学习路径
C++是一门复杂而强大的编程语言,学习路径建议如下:
1. **基础语法** - 掌握C++的基本语法和编程概念
2. **面向对象编程** - 学习C++的类、继承、多态等OOP特性
3. **STL标准库** - 熟悉常用的容器和算法
4. **高级特性** - 模板、异常处理、智能指针等
5. **实战项目** - 通过实际项目巩固所学知识
## 笔记分类
### 基础语法
- 数据类型
- 运算符和表达式
- 控制流语句
- 函数
### 面向对象编程
- 类和对象
- 继承与多态
- 封装与抽象
- 构造函数与析构函数
### STL标准库
- 容器(vector, list, map等)
- 迭代器
- 算法
- 函数对象
## 学习资源推荐
- [C++ Primer Plus:中文版(第六版)](https://101su.ru/book/5442395/430bc1/c-primer-plus%E4%B8%AD%E6%96%87%E7%89%88%E7%AC%AC%E5%85%AD%E7%89%88.html) - 很好的C++入门教材
开始你的C++学习之旅吧!坚持学习,你会发现C++的魅力所在!
+10
View File
@@ -0,0 +1,10 @@
---
title: C++ 简介与环境配置
createTime: 2025/09/22 09:06:00
permalink: /programming/cplusplus/basis/
---
## C++的简介
欢迎来到C++的奇妙世界~(๑>◡<๑) 如果你之前接触过C语言的话,那真是太棒啦!C++就像是C语言穿上了漂亮的新衣裳,不仅保留了原来的优点,还添加了面向对象和泛型编程的魔法哦~不过呢,可能需要稍微调整一下之前的编程习惯呢。就算你是第一次接触C++也完全不用担心,我会用最简单可爱的方式,带着你一步一步探索这个神奇的编程世界哒!
## 环境配置
+40
View File
@@ -0,0 +1,40 @@
---
title: LeetCode 题解笔记
description: 记录LeetCode算法题的解题思路和代码实现
createTime: 2025/09/22 08:09:52
permalink: /programming/leetcode/
---
# LeetCode 题解笔记
这里是我在LeetCode刷题过程中记录的解题思路和代码实现。通过整理这些题解,希望能够提高自己的算法水平和编程能力。
## 题解分类
### 数组与字符串
- [两数之和](https://leetcode-cn.com/problems/two-sum/)
- [三数之和](https://leetcode-cn.com/problems/3sum/)
### 链表
- [反转链表](https://leetcode-cn.com/problems/reverse-linked-list/)
- [合并两个有序链表](https://leetcode-cn.com/problems/merge-two-sorted-lists/)
### 动态规划
- [爬楼梯](https://leetcode-cn.com/problems/climbing-stairs/)
- [最长回文子串](https://leetcode-cn.com/problems/longest-palindromic-substring/)
## 解题技巧
1. **双指针法**:常用于数组、链表问题,如两数之和、反转链表等
2. **滑动窗口**:处理字符串子串问题
3. **动态规划**:将原问题分解为子问题,自底向上求解
4. **分治法**:将问题分成若干子问题,分别求解后合并结果
## 学习资源
- [LeetCode官方题解](https://leetcode-cn.com/problemset/all/)
- [代码随想录](https://programmercarl.com/)
- [算法导论](https://mitpress.mit.edu/books/introduction-algorithms)
@@ -0,0 +1,13 @@
---
title: LeetCode 入门题单~(≧∇≦)ノ
description: 给算法初学者的题目推荐和学习路径
createTime: 2025年9月22日 08:52:52
permalink: /programming/leetcode/question_sheet/beginner/
---
# LeetCode 入门题单~(๑>◡<๑)
作为算法初学者,选择合适的题目开始练习真的超~级重要哦!这里给大家推荐一份超棒的入门题单——[「新」动计划 · 编程入门](https://leetcode.cn/studyplan/primers-list/) ~这份题单就像给小树苗精心准备的阳光和雨露一样,特别适合刚开始算法之旅的你~(悄悄告诉你,里面有两题是数据库基础,暂时可以跳过哦~)
我的小建议是:先自己试着挑战一下,如果遇到困难了,再来看题解也没关系~重要的是享受这个成长的过程呀~(♡˙︶˙♡)
## 基础语法 & 数据类型 ٩(๑>◡<๑)۶
-90
View File
@@ -1,90 +0,0 @@
---
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.jsExpress/NestJS)、PythonFlask/Django/FastAPI)、JavaSpring Boot)、GoGin/Fiber)。
- API 风格:REST(常见)、GraphQL(灵活查询)。
- 数据库与 ORMMySQL/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 DocsHTML/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/)
- [PrismaNode.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/`
- 后续将补充:前端工程化、接口联调、部署与运维实战等专题。
@@ -1,535 +0,0 @@
---
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">
<!-- 保留以下 idmessage / 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');
});
});
```
:::
@@ -1,468 +0,0 @@
---
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
@@ -1,424 +0,0 @@
---
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>
<!-- 创建一个名片容器 divclass 为 "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>&lt;br&gt;</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%; }
```
:::
@@ -1,606 +0,0 @@
---
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);
```
### PromiseES6
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 的强大功能和灵活性!
-202
View File
@@ -1,202 +0,0 @@
---
title: 系统分析师
createTime: 2026/03/01 12:40:00
permalink: /subject/certification/
---
# 系统分析师
软考高级资格考证笔记~
> 官网:https://www.ruankao.org.cn/
## 考试科目
| 科目 | 题型 | 分值 | 时长 |
| :--- | :--- | :--- | :--- |
| 综合知识 | 选择题 (75道) | 75分 | 150分钟 |
| 案例分析 | 问答题 (5道选3道) | 75分 | 90分钟 |
| 论文写作 | 论文题 (4选12500字) | 75分 | 120分钟 |
**及格标准**:各科目均需达到 45 分
## 考试要求
1. 具有系统工程的基础知识
2. 掌握开发信息系统的综合技术知识(硬件、软件、网络、数据库)
3. 熟悉企业和政府信息化建设,并具有组织信息化战略规划的知识
4. 熟练掌握信息系统开发过程和方法
5. 熟悉信息系统开发标准
6. 掌握信息安全的相关知识与技术
7. 理解软件质量保证的手段
8. 具有经济与管理科学的相关基础知识,熟悉有关的法律法规
9. 具有大学本科的数学基础
10. 熟练阅读和正确理解相关领域的英文文献
## 综合知识考点分布
| 知识点 | 分数 | 比例 |
| :--- | :--- | :--- |
| 信息化战略规划 | 6-9 | 8-12% |
| 需求工程 | 4-8 | 5.33-10.67% |
| 系统设计 | 2-8 | 2.67-10.67% |
| 信息安全 | 4-9 | 5.33-12% |
| 数据库系统 | 6-8 | 8-10.67% |
| 计算机网络 | 5-8 | 6.67-10.67% |
| 操作系统 | 4-6 | 5.33-8% |
| 软件工程 | 2-5 | 2.6-6.67% |
| 法律法规与标准化 | 4 | 5.33% |
| 专业英语 | 5 | 6.67% |
## 案例分析考查主题
- 系统规划
- 开发方法与开发模型
- 需求工程
- 系统分析
- 系统设计
- 系统运行和维护
- 数据库方向
- 项目管理
- 企业信息化战略与实施
- 嵌入式方向
- Web技术
- 新技术的应用
## 论文写作主题
- 系统规划与战略规划
- 需求工程
- 系统开发方法
- 系统维护和系统测试
- 项目管理
- 面向对象技术
- 应用系统分析与设计
- 数据库工程
- 应用系统集成
- 新技术的应用
## 备考攻略
### 备考周期
建议 **4-6个月**,高级科目难度较大,需尽早准备!
### 第一阶段:基础构建(1-2个月)
- 研究考试大纲,明确考试范围和重点
- 购买官方推荐教材
- 制定详细的学习计划
- 从基础知识点开始,逐步构建知识体系
### 第二阶段:深入学习(1-2个月)
- 细致阅读教材,做好学习笔记
- 加入在线课程或学习小组交流
- 实践应用所学知识
- 定期自我测试
### 第三阶段:强化训练(1-2个月)
- 大量做历年真题
- 查漏补缺,强化记忆
- 提高答题速度
- 论文写作:看范文,写框架
### 第四阶段:冲刺复习(考前1个月)
- 总结各章节重点和易错点
- 全真模拟考试
- 调整心态,保持状态
### 第五阶段:考前准备(考前1周)
- 复习笔记和提纲
- 检查考试资料(身份证、准考证)
- 调整作息,确保精力充沛
## 答题技巧
### 综合知识
- 先看问题,再看选项
- 排除干扰项,选择相对稳妥的说法
- 当两个选项截然相反时,必有一个正确答案
- 可以用选项代入计算的方式走捷径
### 案例分析
- 带着问题去看题干
- 顺势而为答题,根据题干倾向分析优劣
- 分条目答题,方便老师查看得分点
- 根据分值决定条目数量和简略程度
### 论文写作
- 提前准备 2-3 个主题的框架
- 关注论文结构:背景、问题、方案、效果、总结
- 结合实际项目经验
- 字数控制在 2500 字左右
## 2026年考试时间安排
| 时间节点 | 说明 |
| :--- | :--- |
| 报名时间 | 2026年3月中旬至4月中旬(各省差异大) |
| 考试时间 | 2026年5月23日-26日 |
| 准考证打印 | 考前一周左右(5月中旬) |
**注意**:各地报名时间差异极大,部分省份窗口期可能短至一周,请务必关注当地通知!
## 报名流程与注意事项
### 报名官网
- 中国计算机技术职业资格网:https://www.ruankao.org.cn/
- 报名平台:https://bm.ruankao.org.cn/
### 报名流程
1. **注册登录**:使用"国家网络身份认证"APP扫码登录
2. **填报信息**:选择考区、填写个人信息,报考级别选"高级",资格选"系统分析师"
3. **上传照片**:必须使用官方"照片验证工具"处理白底彩色证件照
4. **审核缴费**:等待审核(1-3个工作日),审核通过后完成网上缴费
### 注意事项
- **属地原则**:仅接受在工作地、居住地或学籍所在地报考
- **异地报考**:需提供当地社保缴纳证明(连续6个月)或有效期内居住证
- **实名认证**:需提前下载"国家网络身份认证"APP完成认证
- **警惕骗子**:勿信"代报名"、"包过"、"异地代报"等诈骗信息
## 核心能力考查
系统分析师考试强调综合分析与解决实际问题的能力:
| 能力 | 说明 |
| :--- | :--- |
| 系统思维 | 从全局视角看待信息系统与组织战略的关系 |
| 需求分析建模 | 能使用DFD、用例图、类图、活动图等工具进行系统建模 |
| 方案设计与权衡 | 分析C/S vs B/S、单体 vs 微服务等方案的优劣 |
| 项目管理与风险控制 | 制定项目计划(WBS、甘特图)、估算成本、识别风险 |
| 技术趋势理解 | 对云计算、大数据、AI、物联网等新技术有基本理解 |
| 表达与写作 | 撰写结构清晰、逻辑严谨、结合实际的论文 |
**三大核心模块**:软件工程 + 系统分析设计 + 项目管理,合计占 **45%以上**
## 论文评分标准
| 评分项 | 占比 | 档次 |
| :--- | :--- | :--- |
| 切合题意 | 30% | 非常切合、较好地切合、基本上切合 |
| 应用深度与水平 | 20% | 很强、较强、一般、较差 |
| 实践性 | 20% | 很强、较强、一般、较差 |
| 表达能力 | 15% | 很强、较强、一般、较差 |
| 书面能力 | 15% | 很强、较强、一般、较差 |
## 推荐资料
### 官方教材
- 《系统分析师教程(第2版)》(清华大学出版社,2024年10月出版)
### 备考资料
- 近5年软考系统分析师真题
- 《系统分析师考试全程指导》
- 《5天修炼》
- 在线资源:希赛网、软考真题网、B站相关课程
## 参考资料
- [中国计算机技术职业资格网](https://www.ruankao.org.cn/)
- [软考高级系统分析师备考攻略 - 知乎](https://zhuanlan.zhihu.com/p/14782824101)
- [新手一次过软考高级系统分析师 - CSDN](https://blog.csdn.net/winin2024/article/details/141386702)
- [系统分析师考试备考全面解析 - CSDN](https://blog.csdn.net/summer_fish/article/details/151296190)
- [2026上半年软考系统分析师报考指南 - 希赛网](https://www.educity.cn/rk/5454826.html)
@@ -1,11 +0,0 @@
---
title: 第一章 绪论
createTime: 2026/03/01 14:00:00
permalink: /subject/certification/sys-analyst/
---
# 第一章 绪论
> 还没有开始写呢,先占个位置~ ✨
敬请期待...
@@ -1,11 +0,0 @@
---
title: 第二章 数学与工程基础
createTime: 2026/03/01 14:00:00
permalink: /subject/certification/sys-analyst/math/
---
# 第二章 数学与工程基础
> 还没有开始写呢,先占个位置~ ✨
敬请期待...
@@ -1,11 +0,0 @@
---
title: 第十章 系统规划与分析
createTime: 2026/03/01 14:00:00
permalink: /subject/certification/sys-analyst/planning/
---
# 第十章 系统规划与分析
> 还没有开始写呢,先占个位置~ ✨
敬请期待...
+4 -76
View File
@@ -6,79 +6,7 @@ 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.
- 虚拟条件句省略 ifWere 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 / didShe 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.
### 长难句拆解策略
- 找谓语,定主干
- 划从句,标连接词
- 去插入,还省略
- 调语序,还原文
- 时态与语态
- 从句(名词性、定语、状语
- 非谓语动词与倒装虚拟
- 句式与信息焦点(强调、分裂句
@@ -10,80 +10,3 @@ 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, capcallcoatcup
```
当字母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
@@ -0,0 +1,45 @@
---
title: 学习资源与工具
createTime: 2025/10/20 16:40:00
permalink: /subject/english/resources/
---
# 学习资源与工具
- 词典与语法书:牛津、朗文、柯林斯
- 学习 App:扇贝、欧路、Grammarly
- 新闻来源:BBC、VOA、The Economist
- 社区与练习:Reddit、StackExchange English、写作论坛
## 每日读物
希望每天都能读一篇简单的小文章,将不会的单词标出,不理解的句子记下来。通过有道词典等工具查询后能够自己理解并通读。
### 下面是今日份读物推荐~
解析将稍后更新~
### 2025.10.22
```
https://web.shanbay-lifelongedu-a2.com/reading/news/ohopi/share?channel=shanbay
```
复制链接至浏览器后,点击APP内打开,点击短文,登陆注册后找到这篇文章可读性更强且自带单词查询功能
不过个人建议先盲读,尝试用自己认识的单词推理拼凑一篇文章吧~
#### Author MO Yan Regrets Time 'Wasted' on Viral Videos
In a candid talk in Zibo, Shandong province, Nobel laureate Mo Yan confessed to an unexpected habit: he's hooked on short videos.The acclaimed writer admitted spending one to two hours daily scrolling through clips — often losing track of time despite setting strict limits for himself.
"I tell myself to stop after 30 minutes, but if the content is good, I extend it to an hour.Then I put down my phone and realize three hours have passed," Mo shared with the audience.
While he believes high-quality videos can be a source of learning, Mo expressed concern about the "frightening" effect of algorithms that endlessly push repetitive content."It wastes time," he remarked, calling for more originality and regulation in online content creation.
He emphasized that widespread copying among creators is "an unhealthy trend" and urged more authentic, life-inspired works.
Mo knows the power of short videos firsthand.This spring, a casual clip of him visiting a Shandong country market went viral."I never expected such a wide reach," he reflected."It felt natural and real — unplanned and unscripted, yet it resonated more than many polished productions."
Despite his own engagement with the trend, Mo hasn't stopped advocating for books.On his social media account, he once wrote: "Every time I finish binge-watching, I scold myself.Short videos are just a phase — reading remains the most worthwhile way to spend our free time."
#### 将生词整理到纸或本子上吧~熟记这些单词和使用时的语境会在你意想不到的时候帮助到你哦!
-193
View File
@@ -1,193 +0,0 @@
---
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)
@@ -1,107 +0,0 @@
---
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)
@@ -1,170 +0,0 @@
---
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)
+2134 -4415
View File
File diff suppressed because it is too large Load Diff
+7 -16
View File
@@ -7,33 +7,24 @@
"engines": {
"node": "^20.6.0 || >=22.0.0"
},
"overrides": {
"@vuepress/helper": "2.0.0-rc.123"
},
"scripts": {
"docs:dev": "vuepress dev docs",
"docs:dev-clean": "vuepress dev docs --clean-cache --clean-temp",
"docs:clear-cache": "node scripts/clear-vuepress-cache.mjs",
"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:verify": "node scripts/verify-site.mjs",
"docs:place-ragflow-guide": "node scripts/place-ragflow-guide.mjs",
"docs:preview": "http-server docs/.vuepress/dist",
"vp-update": "npx vp-update"
},
"devDependencies": {
"@vuepress/helper": "2.0.0-rc.123",
"@vuepress/bundler-vite": "2.0.0-rc.26",
"@vuepress/plugin-umami-analytics": "2.0.0-rc.112",
"@vuepress/bundler-vite": "2.0.0-rc.24",
"@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",
"vuepress": "2.0.0-rc.26",
"vuepress-theme-plume": "1.0.0-rc.192"
"vuepress": "2.0.0-rc.24",
"vuepress-theme-plume": "1.0.0-rc.164"
},
"dependencies": {
"@vuepress/plugin-comment": "2.0.0-rc.123",
"@waline/client": "^3.13.0",
"mermaid": "^11.12.1"
"@waline/client": "^3.6.0"
}
}
-153
View File
@@ -1,153 +0,0 @@
@echo off
setlocal EnableExtensions EnableDelayedExpansion
REM ==========================================
REM Configuration
REM ==========================================
chcp 65001 >nul
REM Move to project root
cd /d "%~dp0.."
set "PROJECT_DIR=%CD%\"
set "DIST_DIR=%PROJECT_DIR%docs\.vuepress\dist"
set "CACHE_DIR=%PROJECT_DIR%docs\.vuepress\.cache"
set "TEMP_DIR=%PROJECT_DIR%docs\.vuepress\.temp"
set "PUBLISH_DIR=%PROJECT_DIR%_publish"
set "REMOTE_URL=https://gitea.simengweb.com/si-meng-spec/build_notes_simengweb.git"
set "BRANCH=main"
REM High memory limit for better performance/stability (8GB)
set "NODE_OPTIONS=--max-old-space-size=8192"
REM Disable Git SSL Verification for this session
git config --global http.sslVerify false
git config --global http.sslBackend openssl
REM Args
set "COMMIT_MSG=%~1"
if "%COMMIT_MSG%"=="" set "COMMIT_MSG=Build: %DATE% %TIME%"
echo ==========================================
echo Start Build and Publish
echo Project Dir: %PROJECT_DIR%
echo Memory Limit: 8192 MB
echo ==========================================
REM ==========================================
REM 1. Cleanup
REM ==========================================
echo [1/5] Cleaning up old artifacts...
if exist "%DIST_DIR%" (
echo - Removing %DIST_DIR%
rd /s /q "%DIST_DIR%"
)
if exist "%CACHE_DIR%" (
echo - Removing %CACHE_DIR%
rd /s /q "%CACHE_DIR%"
)
if exist "%TEMP_DIR%" (
echo - Removing %TEMP_DIR%
rd /s /q "%TEMP_DIR%"
)
REM Clean node_modules for a fresh install every time (Ensures clean state)
if exist "%PROJECT_DIR%node_modules" (
echo - Removing node_modules (Fresh Install Mode)
rd /s /q "%PROJECT_DIR%node_modules"
)
REM ==========================================
REM 2. Install Dependencies
REM ==========================================
echo [2/5] Installing dependencies (npm ci)...
call npm ci
if %ERRORLEVEL% NEQ 0 (
echo [Error] npm ci failed.
exit /b 1
)
REM ==========================================
REM 3. Build
REM ==========================================
echo [3/5] Building docs...
call npm run docs:build
if %ERRORLEVEL% NEQ 0 (
echo [Error] Build failed.
exit /b 1
)
if not exist "%DIST_DIR%" (
echo [Error] Dist directory not found after build.
exit /b 1
)
REM ==========================================
REM 4. Prepare Publish Directory
REM ==========================================
echo [4/5] Preparing publish directory...
if not exist "%PUBLISH_DIR%\.git" (
echo - Cloning publish repo...
if exist "%PUBLISH_DIR%" rd /s /q "%PUBLISH_DIR%"
git clone "%REMOTE_URL%" "%PUBLISH_DIR%"
if !ERRORLEVEL! NEQ 0 exit /b 1
) else (
echo - Updating publish repo...
pushd "%PUBLISH_DIR%"
git fetch --all
git checkout "%BRANCH%"
git reset --hard "origin/%BRANCH%"
popd
)
echo - Cleaning publish directory content (preserving .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 - Copying new build artifacts...
robocopy "%DIST_DIR%" "%PUBLISH_DIR%" *.* /E /NFL /NDL /NP /NJH /NJS >nul
if %ERRORLEVEL% GEQ 8 (
echo [Error] Robocopy failed.
exit /b 1
)
REM ==========================================
REM 5. Push to Remote
REM ==========================================
echo [5/5] Pushing changes...
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
git diff --cached --quiet
if %ERRORLEVEL% EQU 0 (
echo [Info] No changes to commit.
) else (
git commit -m "%COMMIT_MSG%"
echo - Pushing to %BRANCH%...
git push origin "%BRANCH%"
if !ERRORLEVEL! NEQ 0 (
echo [Error] Git push failed.
popd
exit /b 1
)
echo [Success] Pushed successfully.
)
popd
echo ==========================================
echo All Done!
echo ==========================================
exit /b 0
-17
View File
@@ -1,17 +0,0 @@
# 提交笔记站源码变更(尊重 .gitignore,不会加入 _publish、dist、PROJECT_BRIEF.local.md 等)
# 用法: .\script\commit-notes.ps1 -m "提交说明"
param(
[Parameter(Mandatory = $true)]
[string] $Message
)
$ErrorActionPreference = "Stop"
$root = Split-Path -Parent $PSScriptRoot
Set-Location $root
git add docs/.vuepress docs/blog .cursor/rules script/commit-notes.ps1
$staged = @(git diff --cached --name-only)
if ($staged.Count -eq 0) {
Write-Host "No staged changes."
exit 0
}
git commit -m $Message
-3
View File
@@ -1,3 +0,0 @@
@echo off
cd /d "%~dp0.."
npm run docs:dev -- --host 0.0.0.0 --port 8888
+59
View 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
Regular → Executable
-1
View File
@@ -1,2 +1 @@
cd "$(dirname "$0")/.."
npm run docs:dev -- --host 0.0.0.0 --port 8888