Python异步请求工具类

异步请求工具类 封装了一个异步请求工具类,可以自定义请求头构造和请求返回解析,并且可以控制并发大小和批次大小。 还有升级空间,比如:请求失败重试、请求失败任务保存,请求失败任务恢复等功能。 import aiohttp import asyncio import json import os import time from typing import Any, Callable, Dict, List, Optional class AdvancedAsyncScraper: def __init__( self, request_builder: Callable[[Dict], Dict[str, Any]], response_handler: Callable[[Dict, Dict], Any], task_list: List[Dict], config: Dict[str, Any] ): """ 增强版异步爬虫框架(支持复杂任务字典) :param request_builder: 请求构造器 (task -> 请求配置字典) :param response_handler: 响应处理器 (响应数据, task -> 处理结果) :param task_list: 任务字典列表 :param config: 全局配置 """ self.request_builder = request_builder self.response_handler = response_handler self.tasks = task_list self.config = config # 初始化输出目录 os.makedirs(config.get("output_dir", "results"), exist_ok=True) async def process_task( self, session: aiohttp.ClientSession, semaphore: asyncio.Semaphore, task: Dict ): """处理单个任务的完整流程""" task_id = task.get('task_id', str(task)[:50]) start_time = time.time() try: async with semaphore: self._log(f"开始处理任务: {task_id}") # 构造请求参数 request_config = self.request_builder(task) # 执行请求 response_data = await self._execute_request(session, task, request_config) if not response_data: return # 处理响应 self.response_handler(response_data, task) # 记录耗时 cost = time.time() - start_time self._log(f"任务完成: {task_id} | 耗时: {cost:.2f}s") except Exception as e: self._log(f"任务失败 [{task_id}]: {str(e)}") async def run(self): """启动任务处理器""" self._log(f"启动处理器,总任务数: {len(self.tasks)}") async with aiohttp.ClientSession( connector=aiohttp.TCPConnector(ssl=False), headers=self.config.get("default_headers") ) as session: semaphore = asyncio.Semaphore(self.config["concurrency"]) batch_size = self.config.get("batch_size", 100) # 分批处理任务 for i in range(0, len(self.tasks), batch_size): batch = self.tasks[i:i + batch_size] self._log(f"处理批次: {i + 1}-{i + len(batch)}") await asyncio.gather(*[ self.process_task(session, semaphore, task) for task in batch ]) if self.config.get("batch_delay"): await asyncio.sleep(self.config["batch_delay"]) self._log("所有任务处理完成") async def _execute_request(self, session, task, config): """执行实际请求""" try: async with session.request( method=config["method"], url=config["url"], headers=config.get("headers"), params=config.get("params"), json=config.get("json"), data=config.get("data"), timeout=aiohttp.ClientTimeout(total=self.config["request_timeout"]) ) as resp: return await self._parse_response(resp, task) except Exception as e: self._log(f"请求异常 [{task.get('task_id')}]: {str(e)}") return None async def _parse_response(self, resp, task): """解析响应数据""" try: content = await resp.text() if resp.content_type == 'application/json': return json.loads(content) return {"status": resp.status, "raw_data": content} except Exception as e: self._log(f"响应解析失败 [{task.get('task_id')}]: {str(e)}") return None def _log(self, message): """统一日志格式""" print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] {message}") # ---------------------------- # 使用示例 # ---------------------------- def complex_request_builder(task: Dict) -> Dict: """请求构造示例""" # 根据不同任务类型构建请求 base_url = "https://www.baidu.com/" # if task["type"] == "user_detail": # return { # "method": "GET", # "url": f"{base_url}/users/{task['user_id']}", # "params": {"fields": "all"} # } # elif task["type"] == "order_list": # return { # "method": "POST", # "url": f"{base_url}/orders/search", # "json": { # "status": task["status"], # "page": task.get("page", 1) # } # } # else: # raise ValueError("未知任务类型") return { "method": "GET", "url": f"{base_url}?i={task['id']}" } def response_processor(data: Dict, task: Dict) -> Dict: """响应处理示例""" print(f"任务:{task['id']} 完成: {data['status']}") if __name__ == "__main__": # 创建任务 task_pool = [] for i in range(10): task_pool.append({ "task_id": i, "id": i }) # 全局配置 config = { "concurrency": 3, # 并发 "request_timeout": 20, # Http超时 "batch_size": 10, # 批次大小 "batch_delay": 1, # 批次间延时 "default_headers": { # 请求头 "Authorization": "Bearer YOUR_TOKEN", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" } } # 初始化并运行 scraper = AdvancedAsyncScraper( request_builder=complex_request_builder, # 请求生成器 response_handler=response_processor, # 响应处理器 task_list=task_pool, # 任务列表 config=config # 配置 ) try: # win中必须使用 否则报错 asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) asyncio.run(scraper.run()) except KeyboardInterrupt: print("\n[系统] 用户中断执行")

2025-03-31 · 3 分钟 · 443 字 · Javaow

Docker Buildx跨平台构建

前言 拉取使用别人镜像时发现在不同CPU架构下都可以使用,查找后发现虽然是同一个镜像但是分不同的架构版本,拉取镜像时会拉取当前CPU架构下的镜像,所以可以全平台通用一个命令。 比如golang:1.24.1 docker pull golang:1.24.1 可以看到官方镜像是分为好多架构的 Buildx 1、Buildx 简介 Docker Buildx 是 Docker的CLI插件,来自于Moby BuildKit 。自从Docker 18.06 开始这个插件直接集成到了Docker build 中。 Buildx 是一个构建工具, 它可以帮助用户快速、高效地构建 Docker 镜像, 并支持多种平台的构建。使用 buildx, 用户可以在单个命令中构建多种架构的镜像, 例如 x86 和 ARM 架构, 而无需手动操作多个构建命令。此外, buildx 还支持 Dockerfile 的多阶段构建和缓存, 这可以大大提高镜像构建的效率和速度。 2、Buildx 安装 注意: 在Debian和Ubuntu中不要使用apt install docker.io命令安装docker,因为docker.io不是官方docker,没有内置buildx,所以安装后无法使用buildx,应该使用官方镜像安装docker才内置buildx。 debian/ubuntu官方教程:https://docs.docker.com/engine/install/debian/ 添加密钥 sudo apt-get update sudo apt-get install ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc # Add the repository to Apt sources: echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update 安装docker-ce和插件 ...

2025-03-31 · 3 分钟 · 593 字 · Javaow

Dockerfile多阶段构建

前言 之前使用dockerfile构建镜像时,都是使用单个dockerfile构建,把构建好的二进制或jar包导出重写打包为镜像,这样比较麻烦无法自动化, 从其他地方了解到可以使用多阶段构建,跟GitHub的Action类似,方便快捷。 1.使用 在Dockerfile的多阶段构建中,最终生成的镜像是以最后一个阶段的镜像为准的 每个阶段都是一个FROM,以FROM为标识多个阶段 # 第一阶段:编译 # 必须用AS定义一个自定义别名 在其他阶段要使用 FROM golang:1.18 AS builder # 设置工作目录(创建并cd过去) WORKDIR /app # 从宿主机复制main.go到容器当前目录(/app/main.go) COPY main.go . # 执行编译命令 RUN go build -o myapp /app/main.go # 第二阶段:生成最终镜像 FROM alpine:latest # 设置工作目录(创建并cd过去) WORKDIR /root/ # 从第一阶段复制文件到第二阶段中 # --from 指定把builder阶段中的/app/myapp文件复制到当前镜像当前目录中(/root/myapp) COPY --from=builder /app/myapp . # 启动命令 CMD ["./myapp"] 2.构建go镜像 1.简单的go单文件 package main import ( "fmt" ) func main() { fmt.Println("我是多阶段构建出来的镜像") } 2.dockerfile # 第一阶段:编译 # 必须用AS定义一个自定义别名 在其他阶段要使用 FROM golang:1.20 AS builder # 设置工作目录(创建并cd过去) WORKDIR /apps # 从宿主机复制main.go到容器当前目录(/apps/main.go) COPY main.go . # 设置 Go 环境变量 切换模块源为中国Go模块代理服务器 RUN go env -w GOPROXY=https://goproxy.cn,direct # 在当前目录初始化创建main模块并自动解析下载依赖(构建完整模块 tidy完善go.mod) RUN go mod init main && go mod tidy # 执行编译命令 编译好的二进制是/apps/main RUN go build -o /apps/main /apps/main.go # 第二阶段:生成最终镜像 FROM alpine:latest # 设置工作目录(创建并cd过去) WORKDIR /root/ # 从第一阶段复制文件到第二阶段中 # --from 指定把builder阶段中的/app/myapp文件复制到当前镜像当前目录中(/root/main) COPY --from=builder /apps/main . # 设置时区为上海,并且创建全局访问的软链接 RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && echo 'Asia/Shanghai' > /etc/timezone \ && ln -s /root/main /usr/bin/main # 设置编码 ENV LANG C.UTF-8 # 创建软链接 解决二进制无法执行问题 amd架构必须执行 # RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2 # 运行golang程序的命令 CMD main 3.构建镜像 docker build -f dockerfile -t g1 . 打包出来的镜像只有9m,符合alpine镜像大小 ...

2025-03-31 · 1 分钟 · 189 字 · Javaow

MybatisPlus自定义一对一一对多查询

前言 最近在做一个项目,苦于每次改数据库结构都得改一遍Mybatis的xml文件,实在是太繁琐,所以就用了MybatisPlus,但是又想用association和collection没办法只能手动写一个了 1.定义工具类 项目结构 RelationType 枚举类 标识是一对多 还是一对一 public enum RelationType { ONE_TO_ONE, ONE_TO_MANY } RelationConfig 配置类,每个service如果要实现一对一 一对多都需要创建指定的配置 // 泛型T和R,一个是原始表实体类,一个是目标表实体类 @Data public class RelationConfig<T, R> { // 一对一 或 一对多 private RelationType relationType; // 使用哪个字段作为主表的关联字段 // Function函数式编程,需要目标为T类型(原始表实体类),返回值为Serializable // 对类型为T的对象应用操作,并返回结果。结果是Serializable类型的对象 // 类似重写:Serializable apply(T t) private Function<T, Serializable> sourceId; // 使用哪个字段作为主表的注入字段 // BiConsumer函数式编程,接收两个对象但是没有返回 // 类似于:T.setZbbzTest(T) private BiConsumer<T, R> sourceSetter; // 一对多数据注入方法 private BiConsumer<T, List<R>> sourceListSetter; // 副表查询返回 // Function函数式编程,需要目标为Serializable类型,返回值为R // 类似于:id -> zbbzTestService.getById(id) private Function<Serializable, R> targetLoader; // 一对多数据加载器 private Function<Serializable, List<R>> targetListLoader; } MybatisPlusBuff 工具类,实现具体的一对一 一对多查询功能 这里要区分单条和多条,单条适用于getOne,多头适用于list查询 ...

2025-03-31 · 4 分钟 · 646 字 · Javaow

RuoYi-Vue自定义Quill视频上传

前言 自定义文字大小前文已经写过了,业务需要富文本还需要上传视频,所以这里记录一下如何自定义Quill富文本的视频上传。 只拦截视频上传功能是不够的,因为默认插入的是iframe标签,还需要更改为video标签,VideoBlot.js文件的作用就是用于把默认的iframe改为video标签。 官方其实预设了一些Blot,我们可以基于这些进行扩展: Text Blot(文本) 表示普通的文本内容,是最基本的Blot类型。 Block Blot(块) 表示一个块级元素,如段落、标题等。它可以包含多个Text Blot。 Inline Blot(内联) 表示内联元素,如加粗、斜体、链接等。它可以包含多个Text Blot。 Container Blot(容器) 表示一个容器元素,可以包含其他的Blot类型。常见的容器Blot有List(列表)和Table(表格)。 除了这些基本的Blot类型,Quill还提供了一些特殊的Blot类型,用于处理特定的功能和样式,例如: Embed Blot(嵌入) 表示嵌入式内容,如图片、视频等。Embed Blot可以包含其他的Blot类型,用于表示嵌入内容的各个部分。 扩展视频,我们通过Block Blot就行了,blot有一些预设静态属性,因为它本身是一个class,其中blotName、tagName都是必填的,className可写可不写,写了他就是你配置的tagName元素的类名。 1.新建VideoBlot.js文件 从utils目录下ruoyi-ui/src/utils/VideoBlot.js文件,主要用于自定义嵌入类型的Blot用于替换默认的iframe标签。 import Quill from 'quill' let BlockEmbed = Quill.import('blots/block/embed') class VideoBlot extends BlockEmbed { static create(value) { let node = super.create() node.setAttribute('src', value.url) node.setAttribute('controls', true) node.setAttribute('width', '100%') node.setAttribute('style', 'height: auto; margin: 10px 0;') return node } static value(node) { return { url: node.getAttribute('src') } } } VideoBlot.blotName = 'video' VideoBlot.tagName = 'video' Quill.register(VideoBlot, true) 2.修改Editor组件 文件路径ruoyi-ui/src/components/Editor/index.vue 主要修改了以下几点: 引入VideoBlot.js文件 init() 方法初始化方法拦截video上传按钮,手动触发上传组件 handleBeforeUpload() 方法添加视频格式和提示内容 handleUploadSuccess() 方法添加视频插入逻辑 <template> <div> <el-upload :action="uploadUrl" :before-upload="handleBeforeUpload" :on-success="handleUploadSuccess" :on-error="handleUploadError" name="file" :show-file-list="false" :headers="headers" style="display: none" ref="upload" v-if="this.type == 'url'" > </el-upload> <div class="editor" ref="editor" :style="styles"></div> </div> </template> <script> import Quill from "quill"; import "quill/dist/quill.core.css"; import "quill/dist/quill.snow.css"; import "quill/dist/quill.bubble.css"; import "@/utils/VideoBlot" import { getToken } from "@/utils/auth"; // 定义自定义字号 let fontSize = ['10px', '12px', '14px', '16px', '18px', '20px', '24px', '36px']; // 注册自定义字号 let Size = Quill.import('attributors/style/size'); Size.whitelist = fontSize; Quill.register(Size, true); export default { name: "Editor", props: { /* 编辑器的内容 */ value: { type: String, default: "", }, /* 高度 */ height: { type: Number, default: null, }, /* 最小高度 */ minHeight: { type: Number, default: null, }, /* 只读 */ readOnly: { type: Boolean, default: false, }, /* 上传文件大小限制(MB) */ fileSize: { type: Number, default: 100, }, /* 类型(base64格式、url格式) */ type: { type: String, default: "url", } }, data() { return { uploadUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 上传的图片服务器地址 headers: { Authorization: "Bearer " + getToken() }, Quill: null, currentValue: "", options: { theme: "snow", bounds: document.body, debug: "warn", modules: { // 工具栏配置 toolbar: [ ["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线 ["blockquote", "code-block"], // 引用 代码块 [{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表 [{ indent: "-1" }, { indent: "+1" }], // 缩进 [{ 'size': ['10px', '12px', '14px', '16px', '18px', '20px', '24px', '36px'] }], // 自定义字号 [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题 [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色 [{ align: [] }], // 对齐方式 ["clean"], // 清除文本格式 ["link", "image", "video"] // 链接、图片、视频 ], }, placeholder: "请输入内容", readOnly: this.readOnly, }, }; }, computed: { styles() { let style = {}; if (this.minHeight) { style.minHeight = `${this.minHeight}px`; } if (this.height) { style.height = `${this.height}px`; } return style; }, }, watch: { value: { handler(val) { if (val !== this.currentValue) { this.currentValue = val === null ? "" : val; if (this.Quill) { this.Quill.clipboard.dangerouslyPasteHTML(this.currentValue); } } }, immediate: true, }, }, mounted() { this.init(); }, beforeDestroy() { this.Quill = null; }, methods: { init() { const editor = this.$refs.editor; this.Quill = new Quill(editor, this.options); // 如果设置了上传地址则自定义图片上传事件 if (this.type == 'url') { let toolbar = this.Quill.getModule("toolbar"); toolbar.addHandler("image", (value) => { if (value) { this.$refs.upload.$children[0].$refs.input.click(); } else { this.quill.format("image", false); } }); } // 修改工具栏的视频处理器 let toolbar = this.Quill.getModule("toolbar") toolbar.addHandler("video", () => { this.$refs.upload.$children[0].$refs.input.click() }) this.Quill.clipboard.dangerouslyPasteHTML(this.currentValue); this.Quill.on("text-change", (delta, oldDelta, source) => { const html = this.$refs.editor.children[0].innerHTML; const text = this.Quill.getText(); const quill = this.Quill; this.currentValue = html; this.$emit("input", html); this.$emit("on-change", { html, text, quill }); }); this.Quill.on("text-change", (delta, oldDelta, source) => { this.$emit("on-text-change", delta, oldDelta, source); }); this.Quill.on("selection-change", (range, oldRange, source) => { this.$emit("on-selection-change", range, oldRange, source); }); this.Quill.on("editor-change", (eventName, ...args) => { this.$emit("on-editor-change", eventName, ...args); }); }, // 上传前校检格式和大小 handleBeforeUpload(file) { const type = ["image/jpeg", "image/jpg", "image/png", "image/svg", "video/mp4"]; // 统一文件类型校验 if (!type.includes(file.type)) { this.$message.error(`仅支持 ${type.join(", ")} 格式`); return false; } // 校检文件大小 if (this.fileSize) { const isLt = file.size / 1024 / 1024 < this.fileSize; if (!isLt) { this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`); return false; } } return true; }, handleUploadSuccess(res, file) { if (res.code == 200) { const quill = this.Quill const range = quill.getSelection().index // 视频插入逻辑 if (file.raw.type.startsWith('video/')) { const videoUrl = process.env.VUE_APP_BASE_API + res.fileName quill.insertEmbed(range, 'video', { url: videoUrl }) // 关键修改 } // 图片逻辑保持不变 else { quill.insertEmbed(range, "image", process.env.VUE_APP_BASE_API + res.fileName) } quill.setSelection(range + 1) } }, handleUploadError() { this.$message.error("图片插入失败"); }, }, }; </script> <style> .editor, .ql-toolbar { white-space: pre-wrap !important; line-height: normal !important; } .quill-img { display: none; } .ql-snow .ql-tooltip[data-mode="link"]::before { content: "请输入链接地址:"; } .ql-snow .ql-tooltip.ql-editing a.ql-action::after { border-right: 0px; content: "保存"; padding-right: 0px; } .ql-snow .ql-tooltip[data-mode="video"]::before { content: "请输入视频地址:"; } .ql-snow .ql-picker.ql-size .ql-picker-label::before, .ql-snow .ql-picker.ql-size .ql-picker-item::before { content: "14px"; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before { content: "10px"; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before { content: "18px"; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before { content: "32px"; } .ql-snow .ql-picker.ql-header .ql-picker-label::before, .ql-snow .ql-picker.ql-header .ql-picker-item::before { content: "文本"; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before { content: "标题1"; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before { content: "标题2"; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before { content: "标题3"; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before { content: "标题4"; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before { content: "标题5"; } .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before, .ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before { content: "标题6"; } .ql-snow .ql-picker.ql-font .ql-picker-label::before, .ql-snow .ql-picker.ql-font .ql-picker-item::before { content: "标准字体"; } .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before, .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before { content: "衬线字体"; } .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before, .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before { content: "等宽字体"; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="10px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="10px"]::before { content: '10px'; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="12px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="12px"]::before { content: '12px'; } /* 其他字号样式 */ .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="14px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="14px"]::before { content: '14px'; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="16px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="16px"]::before { content: '16px'; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="18px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="18px"]::before { content: '18px'; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="20px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="20px"]::before { content: '20px'; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="24px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="24px"]::before { content: '24px'; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="36px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="36px"]::before { content: '36px'; } </style> 3.效果展示 ...

2025-03-29 · 5 分钟 · 909 字 · Javaow

RuoYi-Vue自定义Quill文字大小

前言 RuoYi-Vue 默认用的富文本编辑器是 Quill,但是功能不是很全,默认的文字大小只有几种预设,而且上传视频还只能使用 url,不过这些都可以自定义。 自定义文字大小 1.定义字号 修改 ruoyi-ui/src/components/Editor/index.vue 文件 import Quill from 'quill'; // 定义自定义字号 let fontSize = ['10px', '12px', '14px', '16px', '18px', '20px', '24px', '36px']; // 注册自定义字号 let Size = Quill.import('attributors/style/size'); Size.whitelist = fontSize; Quill.register(Size, true); 2.配置 Quill 编辑器 修改ruoyi-ui/src/components/Editor/index.vue中的size添加自定义的字号 modules: { // 工具栏配置 toolbar: [ ["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线 ["blockquote", "code-block"], // 引用 代码块 [{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表 [{ indent: "-1" }, { indent: "+1" }], // 缩进 // 自定义字号 [{ 'size': ['10px', '12px', '14px', '16px', '18px', '20px', '24px', '36px'] }], [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题 [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色 [{ align: [] }], // 对齐方式 ["clean"], // 清除文本格式 ["link", "image", "video"] // 链接、图片、视频 ], }, 3.样式调整 在ruoyi-ui/src/components/Editor/index.vue样式文件中添加自定义字号的显示样式 注意: 上面 size 定义了几个字号这里就要定义几个样式,一一对应 /* 自定义字号样式 */ .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="10px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="10px"]::before { content: "10px"; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="12px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="12px"]::before { content: "12px"; } /* 其他字号样式 */ .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="14px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="14px"]::before { content: "14px"; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="16px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="16px"]::before { content: "16px"; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="18px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="18px"]::before { content: "18px"; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="20px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="20px"]::before { content: "20px"; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="24px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="24px"]::before { content: "24px"; } .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="36px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="36px"]::before { content: "36px"; } 4.效果展示 ...

2025-03-29 · 2 分钟 · 226 字 · Javaow

PaperMod主题参数详解

官方配置文件 官方配置 baseURL: "https://examplesite.com/" title: ExampleSite paginate: 5 theme: PaperMod enableRobotsTXT: true buildDrafts: false buildFuture: false buildExpired: false googleAnalytics: UA-123-45 minify: disableXML: true minifyOutput: true params: env: production # to enable google analytics, opengraph, twitter-cards and schema. title: ExampleSite description: "ExampleSite description" keywords: [Blog, Portfolio, PaperMod] author: Me # author: ["Me", "You"] # multiple authors images: ["<link or path of image for opengraph, twitter-cards>"] DateFormat: "January 2, 2006" defaultTheme: auto # dark, light disableThemeToggle: false ShowReadingTime: true ShowShareButtons: true ShowPostNavLinks: true ShowBreadCrumbs: true ShowCodeCopyButtons: false ShowWordCount: true ShowRssButtonInSectionTermList: true UseHugoToc: true disableSpecial1stPost: false disableScrollToTop: false comments: false hidemeta: false hideSummary: false showtoc: false tocopen: false assets: # disableHLJS: true # to disable highlight.js # disableFingerprinting: true favicon: "<link / abs url>" favicon16x16: "<link / abs url>" favicon32x32: "<link / abs url>" apple_touch_icon: "<link / abs url>" safari_pinned_tab: "<link / abs url>" label: text: "Home" icon: /apple-touch-icon.png iconHeight: 35 # profile-mode profileMode: enabled: false # needs to be explicitly set title: ExampleSite subtitle: "This is subtitle" imageUrl: "<img location>" imageWidth: 120 imageHeight: 120 imageTitle: my image buttons: - name: Posts url: posts - name: Tags url: tags # home-info mode homeInfoParams: Title: "Hi there \U0001F44B" Content: Welcome to my blog socialIcons: - name: x url: "https://x.com/" - name: stackoverflow url: "https://stackoverflow.com" - name: github url: "https://github.com/" analytics: google: SiteVerificationTag: "XYZabc" bing: SiteVerificationTag: "XYZabc" yandex: SiteVerificationTag: "XYZabc" cover: hidden: true # hide everywhere but not in structured data hiddenInList: true # hide on list pages and home hiddenInSingle: true # hide on single page editPost: URL: "https://github.com/<path_to_repo>/content" Text: "Suggest Changes" # edit text appendFilePath: true # to append file path to Edit link # for search # https://fusejs.io/api/options.html fuseOpts: isCaseSensitive: false shouldSort: true location: 0 distance: 1000 threshold: 0.4 minMatchCharLength: 0 limit: 10 # refer: https://www.fusejs.io/api/methods.html#search keys: ["title", "permalink", "summary", "content"] menu: main: - identifier: categories name: categories url: /categories/ weight: 10 - identifier: tags name: tags url: /tags/ weight: 20 - identifier: example name: example.org url: https://example.org weight: 30 # Read: https://github.com/adityatelange/hugo-PaperMod/wiki/FAQs#using-hugos-syntax-highlighter-chroma pygmentsUseClasses: true markup: highlight: noClasses: false # anchorLineNos: true # codeFences: true # guessSyntax: true # lineNos: true # style: monokai 第一部分 1. enableRobotsTXT: true 作用:启用 robots.txt 文件。 解释:robots.txt 文件用于告诉搜索引擎哪些页面可以被爬取,哪些页面不应该被爬取。将此设置为 true 会生成该文件,从而帮助管理网站的爬虫访问权限。 2. buildDrafts: false 作用:是否构建草稿页面。 解释:如果设置为 true,Hugo 会构建那些标记为草稿的页面(即 draft: true)。将其设置为 false,表示不会构建草稿页面,只会构建已发布的页面。这是生产环境中常用的设置。 3. buildFuture: false 作用:是否构建未来的内容。 解释:如果设置为 true,Hugo 会构建那些发布日期在当前日期之后的页面(即 date 设置为未来的页面)。将其设置为 false,表示只构建已经发布的内容。 4. buildExpired: false 作用:是否构建过期的内容。 解释:如果设置为 true,Hugo 会构建那些设置了过期日期的页面(即 expire 设置为过去的页面)。将其设置为 false,表示不会构建已经过期的内容。 5. googleAnalytics: UA-123-45 作用:启用 Google Analytics。 解释:这里的 UA-123-45 是 Google Analytics 的追踪 ID。将其设置为实际的追踪 ID,可以将网站的访问数据发送到 Google Analytics,从而分析网站流量和用户行为。 6. minify: 作用:启用或禁用文件压缩(缩小)功能。 解释:minify 配置项用于压缩和优化输出的 HTML、CSS 和 JavaScript 文件,以减少文件大小并提高网站加载速度。以下是两个子配置项的作用: disableXML: true 作用:禁用 XML 文件的压缩。 解释:默认情况下,Hugo 会压缩生成的 XML 文件(例如,sitemap.xml)。将此项设置为 true,则不会对 XML 文件进行压缩。 minifyOutput: true 作用:启用输出文件压缩。 解释:如果设置为 true,Hugo 会压缩生成的所有输出文件(如 HTML、CSS 和 JavaScript),以减少文件的大小,提高加载速度。 第二部分 1. env: production 作用:设置站点的环境。 解释:env 参数通常用于区分不同的环境配置(如 production, development)。当设置为 production 时,启用一些生产环境下的功能,如 Google Analytics、OpenGraph、Twitter 卡片、以及 Schema.org 数据等。 2. title: ExampleSite 作用:站点的名称。 解释:这是站点的标题,会在网站的 <title> 标签中显示,并影响 SEO。 3. description: "ExampleSite description" 作用:站点的简短描述。 解释:该描述通常用于 SEO 优化(meta description),也会在分享网站时显示在搜索引擎和社交平台上。 4. keywords: [Blog, Portfolio, PaperMod] 作用:站点的关键词。 解释:用于 SEO 优化,帮助搜索引擎更好地理解和索引站点的内容。 5. author: Me 作用:站点的作者名称。 解释:设置作者的名字,通常会出现在文章或页面的元数据中,支持单个或多个作者。 6. images: ["<link or path of image for opengraph, twitter-cards>"] 作用:用于 OpenGraph 和 Twitter 卡片的图像链接。 解释:设置分享时显示的封面图像,通常是站点或文章的缩略图。支持 URL 或文件路径。 7. DateFormat: "January 2, 2006" 作用:设置日期格式。 解释:定义日期的显示格式,January 2, 2006 是 Go 模板语法的一种自定义格式,代表月份、日期和年份的显示顺序。 8. defaultTheme: auto # dark, light 作用:设置站点默认主题。 解释:设置主题的默认模式,可以是 dark 或 light,或设置为 auto,让主题自动根据用户设备的首选主题进行切换。 9. disableThemeToggle: false 作用:是否禁用主题切换按钮。 解释:如果设置为 true,则禁用用户手动切换主题的功能。默认情况下是 false,允许切换。 10. ShowReadingTime: true 作用:是否显示阅读时间。 解释:如果设置为 true,每篇文章将显示预计阅读时间,通常基于文章的字数来计算。 11. ShowShareButtons: true 作用:是否显示社交分享按钮。 解释:如果设置为 true,会在文章或页面上显示分享按钮,允许用户通过社交媒体分享文章。 12. ShowPostNavLinks: true 作用:是否显示文章导航链接。 解释:如果设置为 true,文章底部将显示导航链接,允许读者快速跳转到上一篇或下一篇文章。 13. ShowBreadCrumbs: true 作用:是否显示面包屑导航。 解释:如果设置为 true,会显示面包屑导航,帮助用户了解他们在站点中的位置。 14. ShowCodeCopyButtons: false 作用:是否显示代码复制按钮。 解释:如果设置为 true,在页面中的代码块旁边会显示一个复制按钮,允许用户一键复制代码。这里设置为 false,表示不显示该按钮。 15. ShowWordCount: true 作用:是否显示字数统计。 解释:如果设置为 true,文章页面会显示文章的字数,帮助用户了解文章的长度。 16. ShowRssButtonInSectionTermList: true 作用:是否在分类或标签页面中显示 RSS 订阅按钮。 解释:如果设置为 true,会在分类或标签的页面中显示一个 RSS 订阅按钮,允许用户订阅该分类或标签的文章更新。 17. UseHugoToc: true 作用:是否使用 Hugo 内置的目录功能。 解释:如果设置为 true,Hugo 会自动为文章生成目录,并显示在页面上,方便用户跳转到页面的不同部分。 18. disableSpecial1stPost: false 作用:是否禁用对第一篇文章的特殊处理。 解释:如果设置为 true,会禁用第一篇文章的一些特殊功能或样式,通常用于一些特定的定制需求。 19. disableScrollToTop: false 作用:是否禁用页面顶部滚动按钮。 解释:如果设置为 true,会禁用页面的滚动至顶部按钮,这个按钮通常出现在页面底部,帮助用户快速回到页面顶部。 20. comments: false 作用:是否启用评论功能。 解释:如果设置为 true,则会在文章页面启用评论功能,允许用户发表评论。false 表示禁用评论。 21. hidemeta: false 作用:是否隐藏元数据(如作者、发布日期等)。 解释:如果设置为 true,文章的元数据(如作者、日期等)将不会显示。默认情况下为 false,即显示这些信息。 22. hideSummary: false 作用:是否隐藏文章摘要。 解释:如果设置为 true,将不会显示文章的摘要或简介。false 表示显示。 23. showtoc: false 作用:是否显示目录(Table of Contents)。 解释:如果设置为 true,将显示文章的目录,方便读者跳转到文章的不同部分。 24. tocopen: false 作用:目录是否默认展开。 解释:如果设置为 true,文章的目录会默认展开,显示所有章节。false 表示目录默认是折叠的。 第三部分 1. assets: 这一部分配置用于设置站点的图标和图像资源。 1.1 disableHLJS: true 作用:禁用 highlight.js。 解释:highlight.js 是一个用于高亮代码的库。如果你不希望在站点中使用代码高亮功能,可以将此项设置为 true 来禁用该功能。默认情况下,highlight.js 会自动启用,提供代码块的高亮显示。 1.2 disableFingerprinting: true 作用:禁用资源指纹(Fingerprinting)。 解释:当设置为 true 时,Hugo 不会为站点的静态资源(如 CSS、JS 文件)添加版本号(指纹)。资源指纹通常用于缓存控制,通过文件名中的哈希值标识文件的版本。如果禁用指纹,文件的 URL 不会自动变更,可能影响缓存更新。 1.3 favicon: "<link / abs url>" 作用:设置站点的 favicon 图标。 解释:favicon 是网站标签页显示的小图标。你可以提供一个链接或者绝对 URL,指向站点的 favicon 图标文件。例如:favicon: "https://example.com/favicon.ico"。 1.4 favicon16x16: "<link / abs url>" 作用:设置 16x16 像素大小的 favicon 图标。 解释:这是针对小尺寸显示的 favicon 图标,常用于浏览器标签页中的显示。 1.5 favicon32x32: "<link / abs url>" 作用:设置 32x32 像素大小的 favicon 图标。 解释:这是针对较大尺寸的 favicon 图标,通常用于 Windows 系统中的任务栏图标等。 1.6 apple_touch_icon: "<link / abs url>" 作用:设置适用于 Apple 设备的触摸屏图标(如 iPhone、iPad)。 解释:当用户将站点添加到他们的主屏幕时,iOS 系统会使用这个图标。你可以提供一个链接或绝对 URL,指向该图标文件。例如:apple_touch_icon: "https://example.com/apple-touch-icon.png"。 1.7 safari_pinned_tab: "<link / abs url>" 作用:设置用于 Safari 浏览器 的固定标签页图标。 解释:这是 Safari 浏览器中特殊的标签页图标,用于固定站点在标签页上的外观。你可以设置一个链接或绝对 URL 来指定该图标。 2. label: 这一部分配置用于设置站点标签的文本和图标。 2.1 text: "Home" 作用:设置标签的文本。 解释:这是显示在标签上的文本,通常用于表示站点的主页面或主页。这里设置为 Home,意味着标签上会显示“Home”这个文本。 2.2 icon: /apple-touch-icon.png 作用:设置标签的图标。 解释:这是为标签指定的图标,通常是用于导航、按钮或应用图标的图像。在这里,/apple-touch-icon.png 指向一个图像文件,表示将这个文件作为图标使用。 2.3 iconHeight: 35 作用:设置标签图标的高度。 解释:这表示图标的高度为 35 像素。它将影响图标的显示尺寸,确保它在标签上正确显示。 第四部分 1. profileMode: 该部分配置用于启用个人资料模式,通常显示个人信息、头像和相关按钮链接,适用于用户希望在站点上展示个人介绍的场景。 1.1 enabled: false 作用:是否启用个人资料模式。 解释:如果设置为 true,启用个人资料模式,站点将显示个人信息、头像和按钮链接等。如果设置为 false,该模式将被禁用,个人资料相关内容将不显示。 1.2 title: ExampleSite 作用:个人资料页面的标题。 解释:这是显示在个人资料区域的标题,通常是站点名称或者用户的个人名字。 1.3 subtitle: "This is subtitle" 作用:个人资料页面的副标题。 解释:副标题用于提供更多关于个人或站点的描述,通常会展示一个简短的句子或引言。 1.4 imageUrl: "<img location>" 作用:设置头像的图片链接。 解释:这是用户的头像图像位置,可以是图像文件的路径或 URL 地址。例如:imageUrl: "https://example.com/avatar.png"。 1.5 imageWidth: 120 作用:设置头像图片的宽度。 解释:定义头像的显示宽度,单位是像素。这里设置为 120 像素。 1.6 imageHeight: 120 作用:设置头像图片的高度。 解释:定义头像的显示高度,单位是像素。这里设置为 120 像素。 1.7 imageTitle: my image 作用:设置头像图片的标题(alt 属性)。 解释:这是头像图像的替代文本,当图像无法加载时,浏览器会显示此文本。也有助于 SEO 和可访问性。 1.8 buttons: 该部分设置个人资料页面上要显示的按钮和链接。你可以自定义多个按钮,链接到站点的其他部分。 name: Posts 作用:按钮的名称。 解释:按钮上显示的文字,这里是 "Posts"。 url: posts 作用:按钮的链接地址。 解释:设置按钮的目标 URL,通常指向站点的某个页面。在这里,posts 表示按钮链接到站点的“文章”页面,可能是显示所有博客文章的页面。 你还可以为该 buttons 列表添加更多按钮,指向其他页面或资源。例如,Tags 按钮指向标签页。 2. homeInfoParams: 该部分配置用于设置主页的欢迎信息或自定义内容,通常显示在首页的某个位置。 2.1 Title: "Hi there \U0001F44B" 作用:设置主页的欢迎标题。 解释:这设置了首页显示的欢迎标题。在这里,"Hi there \U0001F44B" 包含一个 Unicode 表情符号(\U0001F44B 表示挥手的 emoji 👋)。这个标题可以显示在首页的显著位置,欢迎访问者。 2.2 Content: Welcome to my blog 作用:设置主页的内容/副标题。 解释:这是展示在首页的内容,通常用于进一步欢迎访客,或者提供一些关于站点的简短介绍。这里的内容是 "Welcome to my blog",即向访问者介绍网站是一个博客。 第五部分 1. socialIcons 这一部分配置用于设置站点的社交媒体图标和链接,通常在站点的头部、页脚或侧边栏显示社交媒体的图标,方便访问者访问社交平台。 1.1 - name: x 作用:指定社交平台的名称。 解释:在这个例子中,x 是社交平台的名称(通常是图标的标识符或名称)。你可以将其替换为真实平台的名称,如 "twitter"、"facebook" 等。 1.2 url: "https://x.com/" 作用:设置社交平台的链接。 解释:这是该平台的 URL 地址。当用户点击图标时,会跳转到指定的社交平台。 在这个配置中,包含了以下几个社交平台: stackoverflow:url: "https://stackoverflow.com",指向 Stack Overflow 网站。 github:url: "https://github.com/",指向 GitHub 网站。 你可以根据需要添加更多的社交平台和链接,例如 Twitter、LinkedIn、Instagram 等。 2. analytics 这一部分配置用于设置站点的分析工具(如 Google、Bing 和 Yandex)验证标签,帮助验证你的网站所有权,并启用各大搜索引擎的分析服务。 2.1 google: SiteVerificationTag: "XYZabc" 作用:为 Google Search Console 提供网站验证标签。 解释:你需要将此值替换为实际的 Google Search Console 网站验证标签,用于验证你拥有该网站的权限。 2.2 bing: SiteVerificationTag: "XYZabc" 作用:为 Bing 提供网站验证标签。 解释:与 Google 类似,Bing 也要求你提供一个网站验证标签,以证明你是该网站的所有者。 2.3 yandex: SiteVerificationTag: "XYZabc" 作用:为 Yandex 提供网站验证标签。 解释:Yandex 是俄罗斯的搜索引擎,你也可以通过提供此验证标签来验证你的网站所有权。 3. cover 这一部分配置用于控制封面图像的显示与隐藏。封面图通常是网站首页或文章页面的顶部图像。 3.1 hidden: true 作用:隐藏封面图像。 解释:当设置为 true 时,封面图会被完全隐藏,但在结构化数据中(如 JSON-LD 格式)仍然会存在。 3.2 hiddenInList: true 作用:隐藏封面图像在列表页和首页的显示。 解释:如果设置为 true,封面图像将不会显示在文章列表页和首页,通常用在某些情况下希望仅在单个页面上显示封面图。 3.3 hiddenInSingle: true 作用:隐藏封面图像在单个页面上的显示。 解释:如果设置为 true,封面图像将不会在单篇文章页面显示。 4. editPost 这一部分配置用于设置在文章页面上显示的“编辑”链接,通常用于 GitHub 存储库中的内容,允许用户建议更改文章。 4.1 URL: "https://github.com/<path_to_repo>/content" 作用:设置编辑链接的目标 URL。 解释:这是指向 GitHub 仓库中文件内容的 URL。用户点击“编辑”按钮时,将跳转到这个 URL,通常是用来在 GitHub 上编辑该页面的源文件。 4.2 Text: "Suggest Changes" 作用:设置显示在“编辑”按钮上的文本。 解释:这是编辑按钮上显示的文本,通常是 “Suggest Changes” 或类似的文字,指示用户可以对内容提出更改建议。 4.3 appendFilePath: true 作用:是否将文件路径附加到编辑链接。 解释:如果设置为 true,编辑链接将附加文件路径,便于直接跳转到文件的正确位置。 5. for search 这部分没有直接的配置,而是一个注释,指向了一个搜索库 Fuse.js 的 API 选项链接。Fuse.js 是一个轻量级的 JavaScript 库,通常用于实现客户端搜索功能。你可以根据链接中的文档调整搜索配置,以满足站点的搜索需求。 第六部分 1. fuseOpts 这部分配置用于设置 Fuse.js 搜索库的选项,Fuse.js 是一个 JavaScript 库,通常用于客户端实现模糊搜索。你可以配置搜索行为来控制搜索的精度和灵敏度。 1.1 isCaseSensitive: false 作用:是否启用区分大小写的搜索。 解释:如果设置为 true,搜索将区分大小写;如果设置为 false,搜索将不区分大小写。默认情况下设置为 false,即不区分大小写。 1.2 shouldSort: true 作用:是否启用搜索结果排序。 解释:如果设置为 true,搜索结果将按照相关度排序,最相关的结果排在前面。设置为 false 时,结果顺序将不做调整。 1.3 location: 0 作用:控制搜索匹配位置的权重。 解释:这是设置搜索匹配位置的参数,默认为 0。location 是指搜索的开始位置,0 表示从文本的开始处开始匹配。较大的值会使搜索优先匹配文本的较后部分。 1.4 distance: 1000 作用:控制模糊搜索的“距离”。 解释:distance 代表允许多少字符的差异。值越小,搜索匹配越严格。较大的值允许更多的差异,适合处理拼写错误等问题。通常,1000 可以让搜索宽松一些。 1.5 threshold: 0.4 作用:设置搜索匹配的精度阈值。 解释:threshold 是一个 0 到 1 之间的值,决定了搜索的容忍度。值越小,结果越严格,只有高精度匹配才会返回。0.4 表示 40% 的匹配度就可以返回结果,适合更宽松的匹配。 1.6 minMatchCharLength: 0 作用:设置搜索最小匹配字符长度。 解释:这是设置搜索词的最小字符数,默认为 0,即任意字符都可以触发搜索。如果设置为更大的值,只有搜索词长度超过该值时才会开始搜索。 1.7 limit: 10 作用:限制搜索返回的结果数量。 解释:limit 决定了搜索结果的最大数量。在这个例子中,最多返回 10 个结果。你可以根据需要调整结果数。 1.8 keys: ["title", "permalink", "summary", "content"] 作用:指定搜索的字段。 解释:keys 列出了搜索时要考虑的字段,这里包括 title(标题)、permalink(永久链接)、summary(摘要)、content(内容)。你可以根据需要添加或删除字段,来优化搜索结果。 2. menu 这部分配置用于定义站点的导航菜单,菜单通常显示在页面的顶部或侧边栏,提供访问不同页面或内容的链接。 2.1 main 作用:设置主导航菜单项。 解释:main 下的每一项定义了一个菜单项,包括标识符、名称、URL 和权重。 identifier: categories 作用:定义菜单项的标识符。 解释:categories 是该菜单项的标识符,用于在模板中引用。 name: categories 作用:设置菜单项的显示名称。 解释:这是菜单项显示在页面上的名称,用户点击后将进入分类页面。 url: /categories/ 作用:设置菜单项的链接地址。 解释:这是点击该菜单项时跳转的 URL,这里链接到站点的分类页面。 weight: 10 作用:设置菜单项的权重。 解释:weight 决定了菜单项在导航中的显示顺序,数字越小,菜单项越靠前。这里的 10 表示该菜单项的优先级为 10。 其他菜单项包括 tags(标签页)和 example(示例链接,指向外部 URL)。你可以根据需要自定义更多的菜单项。 3. pygmentsUseClasses 这部分配置涉及到 Hugo 语法高亮的相关设置。 3.1 pygmentsUseClasses: true 作用:是否启用 Pygments 使用 CSS 类来应用代码高亮。 解释:true 表示启用 CSS 类来应用代码高亮,false 则使用内联样式。这有助于控制代码高亮的样式和外观。 4. markup: highlight 这部分配置用于控制代码高亮的设置。 4.1 noClasses: false 作用:是否禁用 CSS 类用于代码高亮。 解释:false 表示启用 CSS 类来应用代码高亮。true 则禁用,使用内联样式进行高亮。 4.2 anchorLineNos: true(注释掉) 作用:是否在代码块的行号旁边显示锚点链接。 解释:如果设置为 true,每行的行号旁将显示一个锚点链接,用户可以通过点击行号跳转到该行的具体位置。这里被注释掉,意味着没有启用这个功能。 4.3 codeFences: true(注释掉) 作用:是否启用代码围栏(fenced code blocks)语法。 解释:true 表示启用 Markdown 的代码围栏语法(即 ```)。这里被注释掉,表示默认启用该功能。 4.4 guessSyntax: true(注释掉) 作用:是否自动推断代码块的语法。 解释:true 表示 Hugo 会尝试根据代码块内容自动推测代码的语言类型。这里被注释掉,表示该功能默认启用。 4.5 lineNos: true(注释掉) 作用:是否显示代码块的行号。 解释:true 表示显示代码行号。这里被注释掉,表示默认启用该功能。 4.6 style: monokai(注释掉) 作用:设置代码高亮的样式。 解释:monokai 是一种流行的高亮样式。这里被注释掉,意味着没有指定样式,默认使用主题提供的样式。 文章模板 文章页的单独配置 ...

2025-03-28 · 7 分钟 · 1462 字 · Javaow