mirror of
https://github.com/handsomezhuzhu/handsomezhuzhu.github.io.git
synced 2026-02-20 11:50:14 +00:00
一些奇怪的更改
This commit is contained in:
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -1,3 +1,3 @@
|
|||||||
[submodule "cursor-rain"]
|
[submodule "cursor-rain"]
|
||||||
path = cursor-rain
|
path = cursor-rain
|
||||||
url = https://github.com/handsomezhuzhu/cursor-rain
|
url = https://github.com/handsomezhuzhu/cursor-rain
|
||||||
|
|||||||
@@ -1,71 +1,71 @@
|
|||||||
import { defineConfig } from 'vitepress'
|
import { defineConfig } from 'vitepress'
|
||||||
|
|
||||||
// 导入主题的配置
|
// 导入主题的配置
|
||||||
import { blogTheme } from './blog-theme'
|
import { blogTheme } from './blog-theme'
|
||||||
|
|
||||||
// 如果使用 GitHub/Gitee Pages 等公共平台部署
|
// 如果使用 GitHub/Gitee Pages 等公共平台部署
|
||||||
// 通常需要修改 base 路径,通常为“/仓库名/”
|
// 通常需要修改 base 路径,通常为“/仓库名/”
|
||||||
// 如果项目名已经为 name.github.io 域名,则不需要修改!
|
// 如果项目名已经为 name.github.io 域名,则不需要修改!
|
||||||
// const base = process.env.GITHUB_ACTIONS === 'true'
|
// const base = process.env.GITHUB_ACTIONS === 'true'
|
||||||
// ? '/vitepress-blog-sugar-template/'
|
// ? '/vitepress-blog-sugar-template/'
|
||||||
// : '/'
|
// : '/'
|
||||||
|
|
||||||
// Vitepress 默认配置
|
// Vitepress 默认配置
|
||||||
// 详见文档:https://vitepress.dev/reference/site-config
|
// 详见文档:https://vitepress.dev/reference/site-config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
// 继承博客主题(@sugarat/theme)
|
// 继承博客主题(@sugarat/theme)
|
||||||
extends: blogTheme,
|
extends: blogTheme,
|
||||||
// base,
|
// base,
|
||||||
lang: 'zh-cn',
|
lang: 'zh-cn',
|
||||||
title: 'SIMON BLOG',
|
title: 'SIMON BLOG',
|
||||||
description: 'Simon的博客,基于 vitepress 实现',
|
description: 'Simon的博客,基于 vitepress 实现',
|
||||||
lastUpdated: true,
|
lastUpdated: true,
|
||||||
markdown: {
|
markdown: {
|
||||||
math: true
|
math: true
|
||||||
},
|
},
|
||||||
// 详见:https://vitepress.dev/zh/reference/site-config#head
|
// 详见:https://vitepress.dev/zh/reference/site-config#head
|
||||||
head: [
|
head: [
|
||||||
// 配置网站的图标(显示在浏览器的 tab 上)
|
// 配置网站的图标(显示在浏览器的 tab 上)
|
||||||
// ['link', { rel: 'icon', href: `${base}favicon.ico` }], // 修改了 base 这里也需要同步修改
|
// ['link', { rel: 'icon', href: `${base}favicon.ico` }], // 修改了 base 这里也需要同步修改
|
||||||
['link', { rel: 'icon', href: '/favicon.ico' }]
|
['link', { rel: 'icon', href: '/favicon.ico' }]
|
||||||
],
|
],
|
||||||
themeConfig: {
|
themeConfig: {
|
||||||
// 展示 2,3 级标题在目录中
|
// 展示 2,3 级标题在目录中
|
||||||
outline: {
|
outline: {
|
||||||
level: [2, 3],
|
level: [2, 3],
|
||||||
label: '目录'
|
label: '目录'
|
||||||
},
|
},
|
||||||
// 默认文案修改
|
// 默认文案修改
|
||||||
returnToTopLabel: '回到顶部',
|
returnToTopLabel: '回到顶部',
|
||||||
sidebarMenuLabel: '相关文章',
|
sidebarMenuLabel: '相关文章',
|
||||||
lastUpdatedText: '上次更新于',
|
lastUpdatedText: '上次更新于',
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 设置logo
|
// 设置logo
|
||||||
logo: '/logo.jpg',
|
logo: '/logo.jpg',
|
||||||
// editLink: {
|
// editLink: {
|
||||||
// pattern:
|
// pattern:
|
||||||
// 'https://github.com/ATQQ/sugar-blog/tree/master/packages/blogpress/:path',
|
// 'https://github.com/ATQQ/sugar-blog/tree/master/packages/blogpress/:path',
|
||||||
// text: '去 GitHub 上编辑内容'
|
// text: '去 GitHub 上编辑内容'
|
||||||
// },
|
// },
|
||||||
nav: [
|
nav: [
|
||||||
{ text: '首页', link: '/' },
|
{ text: '首页', link: '/' },
|
||||||
{ text: '线路一', link: 'https://zhuzihan.com' },
|
{ text: '线路一', link: 'https://zhuzihan.com' },
|
||||||
{ text: '线路二', link: 'https://zzh.codes' },
|
{ text: '线路二', link: 'https://zzh.codes' },
|
||||||
{ text: '线路三', link: 'https://zzhdsgsss.xyz' },
|
{ text: '线路三', link: 'https://zzhdsgsss.xyz' },
|
||||||
{ text: '导航页', link: 'http://home.zhuzihan.com/' },
|
{ text: '导航页', link: 'http://home.zhuzihan.com/' },
|
||||||
{ text: '主题仓库', link: 'https://github.com/ATQQ/sugar-blog/tree/master/packages/theme' },
|
{ text: '主题仓库', link: 'https://github.com/ATQQ/sugar-blog/tree/master/packages/theme' },
|
||||||
{ text: '关于作者', link: 'https://github.com/handsomezhuzhu' },
|
{ text: '关于作者', link: 'https://github.com/handsomezhuzhu' },
|
||||||
{ text: 'OpenWebUI', link: 'https://ai.zzhdsgsss.xyz/' },
|
{ text: 'OpenWebUI', link: 'https://ai.zzhdsgsss.xyz/' },
|
||||||
{ text: 'AI API测活', link: 'https://api-test.zhuzihan.com/' }
|
{ text: 'AI API测活', link: 'https://api-test.zhuzihan.com/' }
|
||||||
],
|
],
|
||||||
socialLinks: [
|
socialLinks: [
|
||||||
{
|
{
|
||||||
icon: 'github',
|
icon: 'github',
|
||||||
link: 'https://github.com/handsomezhuzhu'
|
link: 'https://github.com/handsomezhuzhu'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
import type { RainDropOptions, CursorRainEffect as ICursorRainEffect } from './types';
|
import type { RainDropOptions, CursorRainEffect as ICursorRainEffect } from './types';
|
||||||
export declare class CursorRainEffect implements ICursorRainEffect {
|
export declare class CursorRainEffect implements ICursorRainEffect {
|
||||||
private options;
|
private options;
|
||||||
private container;
|
private container;
|
||||||
private rainContainer;
|
private rainContainer;
|
||||||
private drops;
|
private drops;
|
||||||
private isInitialized;
|
private isInitialized;
|
||||||
private mouseMoveHandler;
|
private mouseMoveHandler;
|
||||||
private timeoutId;
|
private timeoutId;
|
||||||
private animationPool;
|
private animationPool;
|
||||||
constructor(options?: RainDropOptions);
|
constructor(options?: RainDropOptions);
|
||||||
init(): void;
|
init(): void;
|
||||||
destroy(): void;
|
destroy(): void;
|
||||||
enable(): void;
|
enable(): void;
|
||||||
disable(): void;
|
disable(): void;
|
||||||
updateOptions(newOptions: Partial<RainDropOptions>): void;
|
updateOptions(newOptions: Partial<RainDropOptions>): void;
|
||||||
private createRainContainer;
|
private createRainContainer;
|
||||||
private preCreateDrops;
|
private preCreateDrops;
|
||||||
private createDropElement;
|
private createDropElement;
|
||||||
private setupEventListeners;
|
private setupEventListeners;
|
||||||
private removeEventListeners;
|
private removeEventListeners;
|
||||||
private createRainAtPosition;
|
private createRainAtPosition;
|
||||||
private getAvailableDrop;
|
private getAvailableDrop;
|
||||||
private returnDropToPool;
|
private returnDropToPool;
|
||||||
private randomBetween;
|
private randomBetween;
|
||||||
private throttle;
|
private throttle;
|
||||||
private cleanup;
|
private cleanup;
|
||||||
}
|
}
|
||||||
|
|||||||
50
docs/.vitepress/cursor-rain/index.d.ts
vendored
50
docs/.vitepress/cursor-rain/index.d.ts
vendored
@@ -1,25 +1,25 @@
|
|||||||
import { CursorRainEffect } from './CursorRainEffect';
|
import { CursorRainEffect } from './CursorRainEffect';
|
||||||
import type { RainDropOptions, CursorRainEffect as ICursorRainEffect } from './types';
|
import type { RainDropOptions, CursorRainEffect as ICursorRainEffect } from './types';
|
||||||
/**
|
/**
|
||||||
* Create a new cursor rain effect instance
|
* Create a new cursor rain effect instance
|
||||||
*/
|
*/
|
||||||
export declare function createCursorRainEffect(options?: RainDropOptions): ICursorRainEffect;
|
export declare function createCursorRainEffect(options?: RainDropOptions): ICursorRainEffect;
|
||||||
/**
|
/**
|
||||||
* Initialize cursor rain effect with default options
|
* Initialize cursor rain effect with default options
|
||||||
* This is a convenience function for quick setup
|
* This is a convenience function for quick setup
|
||||||
*/
|
*/
|
||||||
export declare function initCursorRain(options?: RainDropOptions): ICursorRainEffect;
|
export declare function initCursorRain(options?: RainDropOptions): ICursorRainEffect;
|
||||||
/**
|
/**
|
||||||
* VitePress compatible initialization
|
* VitePress compatible initialization
|
||||||
* This function ensures the effect works correctly in VitePress environment
|
* This function ensures the effect works correctly in VitePress environment
|
||||||
*/
|
*/
|
||||||
export declare function initCursorRainForVitePress(options?: RainDropOptions): ICursorRainEffect;
|
export declare function initCursorRainForVitePress(options?: RainDropOptions): ICursorRainEffect;
|
||||||
export { CursorRainEffect } from './CursorRainEffect';
|
export { CursorRainEffect } from './CursorRainEffect';
|
||||||
export type { RainDropOptions, RainDrop, CursorRainEffect as ICursorRainEffect } from './types';
|
export type { RainDropOptions, RainDrop, CursorRainEffect as ICursorRainEffect } from './types';
|
||||||
declare const _default: {
|
declare const _default: {
|
||||||
createCursorRainEffect: typeof createCursorRainEffect;
|
createCursorRainEffect: typeof createCursorRainEffect;
|
||||||
initCursorRain: typeof initCursorRain;
|
initCursorRain: typeof initCursorRain;
|
||||||
initCursorRainForVitePress: typeof initCursorRainForVitePress;
|
initCursorRainForVitePress: typeof initCursorRainForVitePress;
|
||||||
CursorRainEffect: typeof CursorRainEffect;
|
CursorRainEffect: typeof CursorRainEffect;
|
||||||
};
|
};
|
||||||
export default _default;
|
export default _default;
|
||||||
|
|||||||
@@ -1,307 +1,307 @@
|
|||||||
import { gsap } from 'gsap';
|
import { gsap } from 'gsap';
|
||||||
|
|
||||||
class CursorRainEffect {
|
class CursorRainEffect {
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
this.rainContainer = null;
|
this.rainContainer = null;
|
||||||
this.drops = [];
|
this.drops = [];
|
||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
this.mouseMoveHandler = null;
|
this.mouseMoveHandler = null;
|
||||||
this.timeoutId = null;
|
this.timeoutId = null;
|
||||||
this.animationPool = [];
|
this.animationPool = [];
|
||||||
this.options = {
|
this.options = {
|
||||||
maxDrops: options.maxDrops ?? 50,
|
maxDrops: options.maxDrops ?? 50,
|
||||||
dropSize: options.dropSize ?? [2, 8],
|
dropSize: options.dropSize ?? [2, 8],
|
||||||
color: options.color ?? 'rgba(173, 216, 230, 0.8)',
|
color: options.color ?? 'rgba(173, 216, 230, 0.8)',
|
||||||
duration: options.duration ?? [0.8, 1.5],
|
duration: options.duration ?? [0.8, 1.5],
|
||||||
delay: options.delay ?? 100,
|
delay: options.delay ?? 100,
|
||||||
enabled: options.enabled ?? true,
|
enabled: options.enabled ?? true,
|
||||||
zIndex: options.zIndex ?? 9999,
|
zIndex: options.zIndex ?? 9999,
|
||||||
container: options.container ?? document.body
|
container: options.container ?? document.body
|
||||||
};
|
};
|
||||||
this.container = this.options.container;
|
this.container = this.options.container;
|
||||||
}
|
}
|
||||||
init() {
|
init() {
|
||||||
if (this.isInitialized) {
|
if (this.isInitialized) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.createRainContainer();
|
this.createRainContainer();
|
||||||
this.setupEventListeners();
|
this.setupEventListeners();
|
||||||
this.preCreateDrops();
|
this.preCreateDrops();
|
||||||
this.isInitialized = true;
|
this.isInitialized = true;
|
||||||
}
|
}
|
||||||
destroy() {
|
destroy() {
|
||||||
if (!this.isInitialized) {
|
if (!this.isInitialized) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.cleanup();
|
this.cleanup();
|
||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
}
|
}
|
||||||
enable() {
|
enable() {
|
||||||
this.options.enabled = true;
|
this.options.enabled = true;
|
||||||
if (this.isInitialized) {
|
if (this.isInitialized) {
|
||||||
this.setupEventListeners();
|
this.setupEventListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
disable() {
|
disable() {
|
||||||
this.options.enabled = false;
|
this.options.enabled = false;
|
||||||
this.removeEventListeners();
|
this.removeEventListeners();
|
||||||
}
|
}
|
||||||
updateOptions(newOptions) {
|
updateOptions(newOptions) {
|
||||||
this.options = { ...this.options, ...newOptions };
|
this.options = { ...this.options, ...newOptions };
|
||||||
if (newOptions.container && newOptions.container !== this.container) {
|
if (newOptions.container && newOptions.container !== this.container) {
|
||||||
this.container = newOptions.container;
|
this.container = newOptions.container;
|
||||||
if (this.isInitialized) {
|
if (this.isInitialized) {
|
||||||
this.destroy();
|
this.destroy();
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
createRainContainer() {
|
createRainContainer() {
|
||||||
this.rainContainer = document.createElement('div');
|
this.rainContainer = document.createElement('div');
|
||||||
this.rainContainer.className = 'cursor-rain-container';
|
this.rainContainer.className = 'cursor-rain-container';
|
||||||
this.rainContainer.style.cssText = `
|
this.rainContainer.style.cssText = `
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: ${this.options.zIndex};
|
z-index: ${this.options.zIndex};
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
`;
|
`;
|
||||||
this.container.appendChild(this.rainContainer);
|
this.container.appendChild(this.rainContainer);
|
||||||
}
|
}
|
||||||
preCreateDrops() {
|
preCreateDrops() {
|
||||||
// Pre-create drop elements for better performance
|
// Pre-create drop elements for better performance
|
||||||
for (let i = 0; i < this.options.maxDrops; i++) {
|
for (let i = 0; i < this.options.maxDrops; i++) {
|
||||||
const drop = this.createDropElement();
|
const drop = this.createDropElement();
|
||||||
this.animationPool.push(drop);
|
this.animationPool.push(drop);
|
||||||
if (this.rainContainer) {
|
if (this.rainContainer) {
|
||||||
this.rainContainer.appendChild(drop);
|
this.rainContainer.appendChild(drop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
createDropElement() {
|
createDropElement() {
|
||||||
const drop = document.createElement('div');
|
const drop = document.createElement('div');
|
||||||
drop.className = 'rain-drop';
|
drop.className = 'rain-drop';
|
||||||
drop.style.cssText = `
|
drop.style.cssText = `
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background: ${this.options.color};
|
background: ${this.options.color};
|
||||||
border-radius: 50% 50% 50% 50% / 90% 90% 10% 10%;
|
border-radius: 50% 50% 50% 50% / 90% 90% 10% 10%;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform-origin: center bottom;
|
transform-origin: center bottom;
|
||||||
`;
|
`;
|
||||||
return drop;
|
return drop;
|
||||||
}
|
}
|
||||||
setupEventListeners() {
|
setupEventListeners() {
|
||||||
if (!this.options.enabled) {
|
if (!this.options.enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.removeEventListeners();
|
this.removeEventListeners();
|
||||||
this.mouseMoveHandler = this.throttle((e) => {
|
this.mouseMoveHandler = this.throttle((e) => {
|
||||||
this.createRainAtPosition(e.clientX, e.clientY);
|
this.createRainAtPosition(e.clientX, e.clientY);
|
||||||
}, 16); // ~60fps throttling
|
}, 16); // ~60fps throttling
|
||||||
document.addEventListener('mousemove', this.mouseMoveHandler, { passive: true });
|
document.addEventListener('mousemove', this.mouseMoveHandler, { passive: true });
|
||||||
}
|
}
|
||||||
removeEventListeners() {
|
removeEventListeners() {
|
||||||
if (this.mouseMoveHandler) {
|
if (this.mouseMoveHandler) {
|
||||||
document.removeEventListener('mousemove', this.mouseMoveHandler);
|
document.removeEventListener('mousemove', this.mouseMoveHandler);
|
||||||
this.mouseMoveHandler = null;
|
this.mouseMoveHandler = null;
|
||||||
}
|
}
|
||||||
if (this.timeoutId) {
|
if (this.timeoutId) {
|
||||||
clearTimeout(this.timeoutId);
|
clearTimeout(this.timeoutId);
|
||||||
this.timeoutId = null;
|
this.timeoutId = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
createRainAtPosition(x, y) {
|
createRainAtPosition(x, y) {
|
||||||
if (!this.rainContainer || this.drops.length >= this.options.maxDrops) {
|
if (!this.rainContainer || this.drops.length >= this.options.maxDrops) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Get available drop from pool
|
// Get available drop from pool
|
||||||
const dropElement = this.getAvailableDrop();
|
const dropElement = this.getAvailableDrop();
|
||||||
if (!dropElement) {
|
if (!dropElement) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const size = this.randomBetween(this.options.dropSize[0], this.options.dropSize[1]);
|
const size = this.randomBetween(this.options.dropSize[0], this.options.dropSize[1]);
|
||||||
const duration = this.randomBetween(this.options.duration[0], this.options.duration[1]);
|
const duration = this.randomBetween(this.options.duration[0], this.options.duration[1]);
|
||||||
// Add some randomness to position
|
// Add some randomness to position
|
||||||
const offsetX = this.randomBetween(-20, 20);
|
const offsetX = this.randomBetween(-20, 20);
|
||||||
const offsetY = this.randomBetween(-10, 10);
|
const offsetY = this.randomBetween(-10, 10);
|
||||||
const finalX = x + offsetX;
|
const finalX = x + offsetX;
|
||||||
const finalY = y + offsetY;
|
const finalY = y + offsetY;
|
||||||
const drop = {
|
const drop = {
|
||||||
element: dropElement,
|
element: dropElement,
|
||||||
x: finalX,
|
x: finalX,
|
||||||
y: finalY,
|
y: finalY,
|
||||||
size,
|
size,
|
||||||
isAnimating: true
|
isAnimating: true
|
||||||
};
|
};
|
||||||
this.drops.push(drop);
|
this.drops.push(drop);
|
||||||
// Set initial position and size
|
// Set initial position and size
|
||||||
gsap.set(dropElement, {
|
gsap.set(dropElement, {
|
||||||
x: finalX - size / 4, // 调整X偏移,因为宽度变小了
|
x: finalX - size / 4, // 调整X偏移,因为宽度变小了
|
||||||
y: finalY - size / 2,
|
y: finalY - size / 2,
|
||||||
width: size * 0.3, // 宽度减小到原来的30%,让雨滴更细
|
width: size * 0.3, // 宽度减小到原来的30%,让雨滴更细
|
||||||
height: size * 4, // 高度增加到4倍,让雨滴更长
|
height: size * 4, // 高度增加到4倍,让雨滴更长
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
scaleY: 0.1,
|
scaleY: 0.1,
|
||||||
rotation: this.randomBetween(-15, 15)
|
rotation: this.randomBetween(-15, 15)
|
||||||
});
|
});
|
||||||
// Animate the raindrop - continuous fall with gradual rotation change
|
// Animate the raindrop - continuous fall with gradual rotation change
|
||||||
const initialRotation = this.randomBetween(-15, 15); // 初始随机角度
|
const initialRotation = this.randomBetween(-15, 15); // 初始随机角度
|
||||||
const fallDistance = window.innerHeight - finalY + 100;
|
const fallDistance = window.innerHeight - finalY + 100;
|
||||||
const tl = gsap.timeline({
|
const tl = gsap.timeline({
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
this.returnDropToPool(drop);
|
this.returnDropToPool(drop);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// 快速出现
|
// 快速出现
|
||||||
tl.to(dropElement, {
|
tl.to(dropElement, {
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
scaleY: 1,
|
scaleY: 1,
|
||||||
duration: 0.1,
|
duration: 0.1,
|
||||||
ease: 'power2.out'
|
ease: 'power2.out'
|
||||||
})
|
})
|
||||||
// 连续下落:一次性完成整个下落过程,同时角度逐渐变垂直
|
// 连续下落:一次性完成整个下落过程,同时角度逐渐变垂直
|
||||||
.to(dropElement, {
|
.to(dropElement, {
|
||||||
y: `+=${fallDistance}`, // 一次性完成所有下落距离
|
y: `+=${fallDistance}`, // 一次性完成所有下落距离
|
||||||
x: `+=${initialRotation * 0.3}`, // 轻微的水平漂移
|
x: `+=${initialRotation * 0.3}`, // 轻微的水平漂移
|
||||||
scaleY: 1.5, // 逐渐拉长
|
scaleY: 1.5, // 逐渐拉长
|
||||||
opacity: 0.3, // 逐渐变透明
|
opacity: 0.3, // 逐渐变透明
|
||||||
rotation: 0, // 角度从初始角度平滑变为垂直
|
rotation: 0, // 角度从初始角度平滑变为垂直
|
||||||
duration: duration,
|
duration: duration,
|
||||||
ease: 'power1.in' // 重力加速效果
|
ease: 'power1.in' // 重力加速效果
|
||||||
}, 0.05);
|
}, 0.05);
|
||||||
}
|
}
|
||||||
getAvailableDrop() {
|
getAvailableDrop() {
|
||||||
return this.animationPool.find(drop => gsap.getTweensOf(drop).length === 0) || null;
|
return this.animationPool.find(drop => gsap.getTweensOf(drop).length === 0) || null;
|
||||||
}
|
}
|
||||||
returnDropToPool(drop) {
|
returnDropToPool(drop) {
|
||||||
const index = this.drops.indexOf(drop);
|
const index = this.drops.indexOf(drop);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
this.drops.splice(index, 1);
|
this.drops.splice(index, 1);
|
||||||
}
|
}
|
||||||
drop.isAnimating = false;
|
drop.isAnimating = false;
|
||||||
// Reset the element
|
// Reset the element
|
||||||
gsap.set(drop.element, {
|
gsap.set(drop.element, {
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
scaleY: 1,
|
scaleY: 1,
|
||||||
rotation: 0
|
rotation: 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
randomBetween(min, max) {
|
randomBetween(min, max) {
|
||||||
return Math.random() * (max - min) + min;
|
return Math.random() * (max - min) + min;
|
||||||
}
|
}
|
||||||
throttle(func, delay) {
|
throttle(func, delay) {
|
||||||
let timeoutId = null;
|
let timeoutId = null;
|
||||||
let lastExecTime = 0;
|
let lastExecTime = 0;
|
||||||
return (...args) => {
|
return (...args) => {
|
||||||
const currentTime = Date.now();
|
const currentTime = Date.now();
|
||||||
if (currentTime - lastExecTime > delay) {
|
if (currentTime - lastExecTime > delay) {
|
||||||
func(...args);
|
func(...args);
|
||||||
lastExecTime = currentTime;
|
lastExecTime = currentTime;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (timeoutId) {
|
if (timeoutId) {
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
}
|
}
|
||||||
timeoutId = window.setTimeout(() => {
|
timeoutId = window.setTimeout(() => {
|
||||||
func(...args);
|
func(...args);
|
||||||
lastExecTime = Date.now();
|
lastExecTime = Date.now();
|
||||||
}, delay - (currentTime - lastExecTime));
|
}, delay - (currentTime - lastExecTime));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
cleanup() {
|
cleanup() {
|
||||||
this.removeEventListeners();
|
this.removeEventListeners();
|
||||||
// Kill all GSAP animations
|
// Kill all GSAP animations
|
||||||
this.drops.forEach(drop => {
|
this.drops.forEach(drop => {
|
||||||
gsap.killTweensOf(drop.element);
|
gsap.killTweensOf(drop.element);
|
||||||
});
|
});
|
||||||
this.drops = [];
|
this.drops = [];
|
||||||
this.animationPool = [];
|
this.animationPool = [];
|
||||||
if (this.rainContainer && this.rainContainer.parentNode) {
|
if (this.rainContainer && this.rainContainer.parentNode) {
|
||||||
this.rainContainer.parentNode.removeChild(this.rainContainer);
|
this.rainContainer.parentNode.removeChild(this.rainContainer);
|
||||||
this.rainContainer = null;
|
this.rainContainer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new cursor rain effect instance
|
* Create a new cursor rain effect instance
|
||||||
*/
|
*/
|
||||||
function createCursorRainEffect(options) {
|
function createCursorRainEffect(options) {
|
||||||
return new CursorRainEffect(options);
|
return new CursorRainEffect(options);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Initialize cursor rain effect with default options
|
* Initialize cursor rain effect with default options
|
||||||
* This is a convenience function for quick setup
|
* This is a convenience function for quick setup
|
||||||
*/
|
*/
|
||||||
function initCursorRain(options) {
|
function initCursorRain(options) {
|
||||||
const effect = createCursorRainEffect(options);
|
const effect = createCursorRainEffect(options);
|
||||||
// Auto-initialize when DOM is ready
|
// Auto-initialize when DOM is ready
|
||||||
if (document.readyState === 'loading') {
|
if (document.readyState === 'loading') {
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
effect.init();
|
effect.init();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// DOM is already ready
|
// DOM is already ready
|
||||||
effect.init();
|
effect.init();
|
||||||
}
|
}
|
||||||
return effect;
|
return effect;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* VitePress compatible initialization
|
* VitePress compatible initialization
|
||||||
* This function ensures the effect works correctly in VitePress environment
|
* This function ensures the effect works correctly in VitePress environment
|
||||||
*/
|
*/
|
||||||
function initCursorRainForVitePress(options) {
|
function initCursorRainForVitePress(options) {
|
||||||
const effect = createCursorRainEffect({
|
const effect = createCursorRainEffect({
|
||||||
container: document.body,
|
container: document.body,
|
||||||
zIndex: 1000, // Lower z-index to avoid conflicts with VitePress UI
|
zIndex: 1000, // Lower z-index to avoid conflicts with VitePress UI
|
||||||
...options
|
...options
|
||||||
});
|
});
|
||||||
// Handle VitePress page navigation
|
// Handle VitePress page navigation
|
||||||
const initEffect = () => {
|
const initEffect = () => {
|
||||||
// Small delay to ensure VitePress has finished rendering
|
// Small delay to ensure VitePress has finished rendering
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
effect.init();
|
effect.init();
|
||||||
}, 100);
|
}, 100);
|
||||||
};
|
};
|
||||||
// Handle both initial load and client-side navigation
|
// Handle both initial load and client-side navigation
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
if (document.readyState === 'loading') {
|
if (document.readyState === 'loading') {
|
||||||
document.addEventListener('DOMContentLoaded', initEffect);
|
document.addEventListener('DOMContentLoaded', initEffect);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
initEffect();
|
initEffect();
|
||||||
}
|
}
|
||||||
// Handle VitePress client-side navigation
|
// Handle VitePress client-side navigation
|
||||||
window.addEventListener('popstate', () => {
|
window.addEventListener('popstate', () => {
|
||||||
effect.destroy();
|
effect.destroy();
|
||||||
initEffect();
|
initEffect();
|
||||||
});
|
});
|
||||||
// Handle programmatic navigation (if using Vue Router)
|
// Handle programmatic navigation (if using Vue Router)
|
||||||
if (window.history && window.history.pushState) {
|
if (window.history && window.history.pushState) {
|
||||||
const originalPushState = window.history.pushState;
|
const originalPushState = window.history.pushState;
|
||||||
window.history.pushState = function (...args) {
|
window.history.pushState = function (...args) {
|
||||||
originalPushState.apply(window.history, args);
|
originalPushState.apply(window.history, args);
|
||||||
effect.destroy();
|
effect.destroy();
|
||||||
initEffect();
|
initEffect();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return effect;
|
return effect;
|
||||||
}
|
}
|
||||||
// Default export for convenience
|
// Default export for convenience
|
||||||
var index = {
|
var index = {
|
||||||
createCursorRainEffect,
|
createCursorRainEffect,
|
||||||
initCursorRain,
|
initCursorRain,
|
||||||
initCursorRainForVitePress,
|
initCursorRainForVitePress,
|
||||||
CursorRainEffect
|
CursorRainEffect
|
||||||
};
|
};
|
||||||
|
|
||||||
export { CursorRainEffect, createCursorRainEffect, index as default, initCursorRain, initCursorRainForVitePress };
|
export { CursorRainEffect, createCursorRainEffect, index as default, initCursorRain, initCursorRainForVitePress };
|
||||||
|
|||||||
@@ -1,315 +1,315 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
Object.defineProperty(exports, '__esModule', { value: true });
|
Object.defineProperty(exports, '__esModule', { value: true });
|
||||||
|
|
||||||
var gsap = require('gsap');
|
var gsap = require('gsap');
|
||||||
|
|
||||||
class CursorRainEffect {
|
class CursorRainEffect {
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
this.rainContainer = null;
|
this.rainContainer = null;
|
||||||
this.drops = [];
|
this.drops = [];
|
||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
this.mouseMoveHandler = null;
|
this.mouseMoveHandler = null;
|
||||||
this.timeoutId = null;
|
this.timeoutId = null;
|
||||||
this.animationPool = [];
|
this.animationPool = [];
|
||||||
this.options = {
|
this.options = {
|
||||||
maxDrops: options.maxDrops ?? 50,
|
maxDrops: options.maxDrops ?? 50,
|
||||||
dropSize: options.dropSize ?? [2, 8],
|
dropSize: options.dropSize ?? [2, 8],
|
||||||
color: options.color ?? 'rgba(173, 216, 230, 0.8)',
|
color: options.color ?? 'rgba(173, 216, 230, 0.8)',
|
||||||
duration: options.duration ?? [0.8, 1.5],
|
duration: options.duration ?? [0.8, 1.5],
|
||||||
delay: options.delay ?? 100,
|
delay: options.delay ?? 100,
|
||||||
enabled: options.enabled ?? true,
|
enabled: options.enabled ?? true,
|
||||||
zIndex: options.zIndex ?? 9999,
|
zIndex: options.zIndex ?? 9999,
|
||||||
container: options.container ?? document.body
|
container: options.container ?? document.body
|
||||||
};
|
};
|
||||||
this.container = this.options.container;
|
this.container = this.options.container;
|
||||||
}
|
}
|
||||||
init() {
|
init() {
|
||||||
if (this.isInitialized) {
|
if (this.isInitialized) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.createRainContainer();
|
this.createRainContainer();
|
||||||
this.setupEventListeners();
|
this.setupEventListeners();
|
||||||
this.preCreateDrops();
|
this.preCreateDrops();
|
||||||
this.isInitialized = true;
|
this.isInitialized = true;
|
||||||
}
|
}
|
||||||
destroy() {
|
destroy() {
|
||||||
if (!this.isInitialized) {
|
if (!this.isInitialized) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.cleanup();
|
this.cleanup();
|
||||||
this.isInitialized = false;
|
this.isInitialized = false;
|
||||||
}
|
}
|
||||||
enable() {
|
enable() {
|
||||||
this.options.enabled = true;
|
this.options.enabled = true;
|
||||||
if (this.isInitialized) {
|
if (this.isInitialized) {
|
||||||
this.setupEventListeners();
|
this.setupEventListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
disable() {
|
disable() {
|
||||||
this.options.enabled = false;
|
this.options.enabled = false;
|
||||||
this.removeEventListeners();
|
this.removeEventListeners();
|
||||||
}
|
}
|
||||||
updateOptions(newOptions) {
|
updateOptions(newOptions) {
|
||||||
this.options = { ...this.options, ...newOptions };
|
this.options = { ...this.options, ...newOptions };
|
||||||
if (newOptions.container && newOptions.container !== this.container) {
|
if (newOptions.container && newOptions.container !== this.container) {
|
||||||
this.container = newOptions.container;
|
this.container = newOptions.container;
|
||||||
if (this.isInitialized) {
|
if (this.isInitialized) {
|
||||||
this.destroy();
|
this.destroy();
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
createRainContainer() {
|
createRainContainer() {
|
||||||
this.rainContainer = document.createElement('div');
|
this.rainContainer = document.createElement('div');
|
||||||
this.rainContainer.className = 'cursor-rain-container';
|
this.rainContainer.className = 'cursor-rain-container';
|
||||||
this.rainContainer.style.cssText = `
|
this.rainContainer.style.cssText = `
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: ${this.options.zIndex};
|
z-index: ${this.options.zIndex};
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
`;
|
`;
|
||||||
this.container.appendChild(this.rainContainer);
|
this.container.appendChild(this.rainContainer);
|
||||||
}
|
}
|
||||||
preCreateDrops() {
|
preCreateDrops() {
|
||||||
// Pre-create drop elements for better performance
|
// Pre-create drop elements for better performance
|
||||||
for (let i = 0; i < this.options.maxDrops; i++) {
|
for (let i = 0; i < this.options.maxDrops; i++) {
|
||||||
const drop = this.createDropElement();
|
const drop = this.createDropElement();
|
||||||
this.animationPool.push(drop);
|
this.animationPool.push(drop);
|
||||||
if (this.rainContainer) {
|
if (this.rainContainer) {
|
||||||
this.rainContainer.appendChild(drop);
|
this.rainContainer.appendChild(drop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
createDropElement() {
|
createDropElement() {
|
||||||
const drop = document.createElement('div');
|
const drop = document.createElement('div');
|
||||||
drop.className = 'rain-drop';
|
drop.className = 'rain-drop';
|
||||||
drop.style.cssText = `
|
drop.style.cssText = `
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background: ${this.options.color};
|
background: ${this.options.color};
|
||||||
border-radius: 50% 50% 50% 50% / 90% 90% 10% 10%;
|
border-radius: 50% 50% 50% 50% / 90% 90% 10% 10%;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform-origin: center bottom;
|
transform-origin: center bottom;
|
||||||
`;
|
`;
|
||||||
return drop;
|
return drop;
|
||||||
}
|
}
|
||||||
setupEventListeners() {
|
setupEventListeners() {
|
||||||
if (!this.options.enabled) {
|
if (!this.options.enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.removeEventListeners();
|
this.removeEventListeners();
|
||||||
this.mouseMoveHandler = this.throttle((e) => {
|
this.mouseMoveHandler = this.throttle((e) => {
|
||||||
this.createRainAtPosition(e.clientX, e.clientY);
|
this.createRainAtPosition(e.clientX, e.clientY);
|
||||||
}, 16); // ~60fps throttling
|
}, 16); // ~60fps throttling
|
||||||
document.addEventListener('mousemove', this.mouseMoveHandler, { passive: true });
|
document.addEventListener('mousemove', this.mouseMoveHandler, { passive: true });
|
||||||
}
|
}
|
||||||
removeEventListeners() {
|
removeEventListeners() {
|
||||||
if (this.mouseMoveHandler) {
|
if (this.mouseMoveHandler) {
|
||||||
document.removeEventListener('mousemove', this.mouseMoveHandler);
|
document.removeEventListener('mousemove', this.mouseMoveHandler);
|
||||||
this.mouseMoveHandler = null;
|
this.mouseMoveHandler = null;
|
||||||
}
|
}
|
||||||
if (this.timeoutId) {
|
if (this.timeoutId) {
|
||||||
clearTimeout(this.timeoutId);
|
clearTimeout(this.timeoutId);
|
||||||
this.timeoutId = null;
|
this.timeoutId = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
createRainAtPosition(x, y) {
|
createRainAtPosition(x, y) {
|
||||||
if (!this.rainContainer || this.drops.length >= this.options.maxDrops) {
|
if (!this.rainContainer || this.drops.length >= this.options.maxDrops) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Get available drop from pool
|
// Get available drop from pool
|
||||||
const dropElement = this.getAvailableDrop();
|
const dropElement = this.getAvailableDrop();
|
||||||
if (!dropElement) {
|
if (!dropElement) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const size = this.randomBetween(this.options.dropSize[0], this.options.dropSize[1]);
|
const size = this.randomBetween(this.options.dropSize[0], this.options.dropSize[1]);
|
||||||
const duration = this.randomBetween(this.options.duration[0], this.options.duration[1]);
|
const duration = this.randomBetween(this.options.duration[0], this.options.duration[1]);
|
||||||
// Add some randomness to position
|
// Add some randomness to position
|
||||||
const offsetX = this.randomBetween(-20, 20);
|
const offsetX = this.randomBetween(-20, 20);
|
||||||
const offsetY = this.randomBetween(-10, 10);
|
const offsetY = this.randomBetween(-10, 10);
|
||||||
const finalX = x + offsetX;
|
const finalX = x + offsetX;
|
||||||
const finalY = y + offsetY;
|
const finalY = y + offsetY;
|
||||||
const drop = {
|
const drop = {
|
||||||
element: dropElement,
|
element: dropElement,
|
||||||
x: finalX,
|
x: finalX,
|
||||||
y: finalY,
|
y: finalY,
|
||||||
size,
|
size,
|
||||||
isAnimating: true
|
isAnimating: true
|
||||||
};
|
};
|
||||||
this.drops.push(drop);
|
this.drops.push(drop);
|
||||||
// Set initial position and size
|
// Set initial position and size
|
||||||
gsap.gsap.set(dropElement, {
|
gsap.gsap.set(dropElement, {
|
||||||
x: finalX - size / 4, // 调整X偏移,因为宽度变小了
|
x: finalX - size / 4, // 调整X偏移,因为宽度变小了
|
||||||
y: finalY - size / 2,
|
y: finalY - size / 2,
|
||||||
width: size * 0.3, // 宽度减小到原来的30%,让雨滴更细
|
width: size * 0.3, // 宽度减小到原来的30%,让雨滴更细
|
||||||
height: size * 4, // 高度增加到4倍,让雨滴更长
|
height: size * 4, // 高度增加到4倍,让雨滴更长
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
scaleY: 0.1,
|
scaleY: 0.1,
|
||||||
rotation: this.randomBetween(-15, 15)
|
rotation: this.randomBetween(-15, 15)
|
||||||
});
|
});
|
||||||
// Animate the raindrop - continuous fall with gradual rotation change
|
// Animate the raindrop - continuous fall with gradual rotation change
|
||||||
const initialRotation = this.randomBetween(-15, 15); // 初始随机角度
|
const initialRotation = this.randomBetween(-15, 15); // 初始随机角度
|
||||||
const fallDistance = window.innerHeight - finalY + 100;
|
const fallDistance = window.innerHeight - finalY + 100;
|
||||||
const tl = gsap.gsap.timeline({
|
const tl = gsap.gsap.timeline({
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
this.returnDropToPool(drop);
|
this.returnDropToPool(drop);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// 快速出现
|
// 快速出现
|
||||||
tl.to(dropElement, {
|
tl.to(dropElement, {
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
scaleY: 1,
|
scaleY: 1,
|
||||||
duration: 0.1,
|
duration: 0.1,
|
||||||
ease: 'power2.out'
|
ease: 'power2.out'
|
||||||
})
|
})
|
||||||
// 连续下落:一次性完成整个下落过程,同时角度逐渐变垂直
|
// 连续下落:一次性完成整个下落过程,同时角度逐渐变垂直
|
||||||
.to(dropElement, {
|
.to(dropElement, {
|
||||||
y: `+=${fallDistance}`, // 一次性完成所有下落距离
|
y: `+=${fallDistance}`, // 一次性完成所有下落距离
|
||||||
x: `+=${initialRotation * 0.3}`, // 轻微的水平漂移
|
x: `+=${initialRotation * 0.3}`, // 轻微的水平漂移
|
||||||
scaleY: 1.5, // 逐渐拉长
|
scaleY: 1.5, // 逐渐拉长
|
||||||
opacity: 0.3, // 逐渐变透明
|
opacity: 0.3, // 逐渐变透明
|
||||||
rotation: 0, // 角度从初始角度平滑变为垂直
|
rotation: 0, // 角度从初始角度平滑变为垂直
|
||||||
duration: duration,
|
duration: duration,
|
||||||
ease: 'power1.in' // 重力加速效果
|
ease: 'power1.in' // 重力加速效果
|
||||||
}, 0.05);
|
}, 0.05);
|
||||||
}
|
}
|
||||||
getAvailableDrop() {
|
getAvailableDrop() {
|
||||||
return this.animationPool.find(drop => gsap.gsap.getTweensOf(drop).length === 0) || null;
|
return this.animationPool.find(drop => gsap.gsap.getTweensOf(drop).length === 0) || null;
|
||||||
}
|
}
|
||||||
returnDropToPool(drop) {
|
returnDropToPool(drop) {
|
||||||
const index = this.drops.indexOf(drop);
|
const index = this.drops.indexOf(drop);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
this.drops.splice(index, 1);
|
this.drops.splice(index, 1);
|
||||||
}
|
}
|
||||||
drop.isAnimating = false;
|
drop.isAnimating = false;
|
||||||
// Reset the element
|
// Reset the element
|
||||||
gsap.gsap.set(drop.element, {
|
gsap.gsap.set(drop.element, {
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
scaleY: 1,
|
scaleY: 1,
|
||||||
rotation: 0
|
rotation: 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
randomBetween(min, max) {
|
randomBetween(min, max) {
|
||||||
return Math.random() * (max - min) + min;
|
return Math.random() * (max - min) + min;
|
||||||
}
|
}
|
||||||
throttle(func, delay) {
|
throttle(func, delay) {
|
||||||
let timeoutId = null;
|
let timeoutId = null;
|
||||||
let lastExecTime = 0;
|
let lastExecTime = 0;
|
||||||
return (...args) => {
|
return (...args) => {
|
||||||
const currentTime = Date.now();
|
const currentTime = Date.now();
|
||||||
if (currentTime - lastExecTime > delay) {
|
if (currentTime - lastExecTime > delay) {
|
||||||
func(...args);
|
func(...args);
|
||||||
lastExecTime = currentTime;
|
lastExecTime = currentTime;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (timeoutId) {
|
if (timeoutId) {
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
}
|
}
|
||||||
timeoutId = window.setTimeout(() => {
|
timeoutId = window.setTimeout(() => {
|
||||||
func(...args);
|
func(...args);
|
||||||
lastExecTime = Date.now();
|
lastExecTime = Date.now();
|
||||||
}, delay - (currentTime - lastExecTime));
|
}, delay - (currentTime - lastExecTime));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
cleanup() {
|
cleanup() {
|
||||||
this.removeEventListeners();
|
this.removeEventListeners();
|
||||||
// Kill all GSAP animations
|
// Kill all GSAP animations
|
||||||
this.drops.forEach(drop => {
|
this.drops.forEach(drop => {
|
||||||
gsap.gsap.killTweensOf(drop.element);
|
gsap.gsap.killTweensOf(drop.element);
|
||||||
});
|
});
|
||||||
this.drops = [];
|
this.drops = [];
|
||||||
this.animationPool = [];
|
this.animationPool = [];
|
||||||
if (this.rainContainer && this.rainContainer.parentNode) {
|
if (this.rainContainer && this.rainContainer.parentNode) {
|
||||||
this.rainContainer.parentNode.removeChild(this.rainContainer);
|
this.rainContainer.parentNode.removeChild(this.rainContainer);
|
||||||
this.rainContainer = null;
|
this.rainContainer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new cursor rain effect instance
|
* Create a new cursor rain effect instance
|
||||||
*/
|
*/
|
||||||
function createCursorRainEffect(options) {
|
function createCursorRainEffect(options) {
|
||||||
return new CursorRainEffect(options);
|
return new CursorRainEffect(options);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Initialize cursor rain effect with default options
|
* Initialize cursor rain effect with default options
|
||||||
* This is a convenience function for quick setup
|
* This is a convenience function for quick setup
|
||||||
*/
|
*/
|
||||||
function initCursorRain(options) {
|
function initCursorRain(options) {
|
||||||
const effect = createCursorRainEffect(options);
|
const effect = createCursorRainEffect(options);
|
||||||
// Auto-initialize when DOM is ready
|
// Auto-initialize when DOM is ready
|
||||||
if (document.readyState === 'loading') {
|
if (document.readyState === 'loading') {
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
effect.init();
|
effect.init();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// DOM is already ready
|
// DOM is already ready
|
||||||
effect.init();
|
effect.init();
|
||||||
}
|
}
|
||||||
return effect;
|
return effect;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* VitePress compatible initialization
|
* VitePress compatible initialization
|
||||||
* This function ensures the effect works correctly in VitePress environment
|
* This function ensures the effect works correctly in VitePress environment
|
||||||
*/
|
*/
|
||||||
function initCursorRainForVitePress(options) {
|
function initCursorRainForVitePress(options) {
|
||||||
const effect = createCursorRainEffect({
|
const effect = createCursorRainEffect({
|
||||||
container: document.body,
|
container: document.body,
|
||||||
zIndex: 1000, // Lower z-index to avoid conflicts with VitePress UI
|
zIndex: 1000, // Lower z-index to avoid conflicts with VitePress UI
|
||||||
...options
|
...options
|
||||||
});
|
});
|
||||||
// Handle VitePress page navigation
|
// Handle VitePress page navigation
|
||||||
const initEffect = () => {
|
const initEffect = () => {
|
||||||
// Small delay to ensure VitePress has finished rendering
|
// Small delay to ensure VitePress has finished rendering
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
effect.init();
|
effect.init();
|
||||||
}, 100);
|
}, 100);
|
||||||
};
|
};
|
||||||
// Handle both initial load and client-side navigation
|
// Handle both initial load and client-side navigation
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
if (document.readyState === 'loading') {
|
if (document.readyState === 'loading') {
|
||||||
document.addEventListener('DOMContentLoaded', initEffect);
|
document.addEventListener('DOMContentLoaded', initEffect);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
initEffect();
|
initEffect();
|
||||||
}
|
}
|
||||||
// Handle VitePress client-side navigation
|
// Handle VitePress client-side navigation
|
||||||
window.addEventListener('popstate', () => {
|
window.addEventListener('popstate', () => {
|
||||||
effect.destroy();
|
effect.destroy();
|
||||||
initEffect();
|
initEffect();
|
||||||
});
|
});
|
||||||
// Handle programmatic navigation (if using Vue Router)
|
// Handle programmatic navigation (if using Vue Router)
|
||||||
if (window.history && window.history.pushState) {
|
if (window.history && window.history.pushState) {
|
||||||
const originalPushState = window.history.pushState;
|
const originalPushState = window.history.pushState;
|
||||||
window.history.pushState = function (...args) {
|
window.history.pushState = function (...args) {
|
||||||
originalPushState.apply(window.history, args);
|
originalPushState.apply(window.history, args);
|
||||||
effect.destroy();
|
effect.destroy();
|
||||||
initEffect();
|
initEffect();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return effect;
|
return effect;
|
||||||
}
|
}
|
||||||
// Default export for convenience
|
// Default export for convenience
|
||||||
var index = {
|
var index = {
|
||||||
createCursorRainEffect,
|
createCursorRainEffect,
|
||||||
initCursorRain,
|
initCursorRain,
|
||||||
initCursorRainForVitePress,
|
initCursorRainForVitePress,
|
||||||
CursorRainEffect
|
CursorRainEffect
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.CursorRainEffect = CursorRainEffect;
|
exports.CursorRainEffect = CursorRainEffect;
|
||||||
exports.createCursorRainEffect = createCursorRainEffect;
|
exports.createCursorRainEffect = createCursorRainEffect;
|
||||||
exports.default = index;
|
exports.default = index;
|
||||||
exports.initCursorRain = initCursorRain;
|
exports.initCursorRain = initCursorRain;
|
||||||
exports.initCursorRainForVitePress = initCursorRainForVitePress;
|
exports.initCursorRainForVitePress = initCursorRainForVitePress;
|
||||||
|
|||||||
142
docs/.vitepress/cursor-rain/types.d.ts
vendored
142
docs/.vitepress/cursor-rain/types.d.ts
vendored
@@ -1,71 +1,71 @@
|
|||||||
export interface RainDropOptions {
|
export interface RainDropOptions {
|
||||||
/**
|
/**
|
||||||
* Maximum number of raindrops to show at once
|
* Maximum number of raindrops to show at once
|
||||||
* @default 50
|
* @default 50
|
||||||
*/
|
*/
|
||||||
maxDrops?: number;
|
maxDrops?: number;
|
||||||
/**
|
/**
|
||||||
* Size range for raindrops [min, max]
|
* Size range for raindrops [min, max]
|
||||||
* @default [2, 8]
|
* @default [2, 8]
|
||||||
*/
|
*/
|
||||||
dropSize?: [number, number];
|
dropSize?: [number, number];
|
||||||
/**
|
/**
|
||||||
* Color of the raindrops
|
* Color of the raindrops
|
||||||
* @default 'rgba(173, 216, 230, 0.8)'
|
* @default 'rgba(173, 216, 230, 0.8)'
|
||||||
*/
|
*/
|
||||||
color?: string;
|
color?: string;
|
||||||
/**
|
/**
|
||||||
* Animation duration range in seconds [min, max]
|
* Animation duration range in seconds [min, max]
|
||||||
* @default [0.8, 1.5]
|
* @default [0.8, 1.5]
|
||||||
*/
|
*/
|
||||||
duration?: [number, number];
|
duration?: [number, number];
|
||||||
/**
|
/**
|
||||||
* Delay between cursor move and rain start in milliseconds
|
* Delay between cursor move and rain start in milliseconds
|
||||||
* @default 100
|
* @default 100
|
||||||
*/
|
*/
|
||||||
delay?: number;
|
delay?: number;
|
||||||
/**
|
/**
|
||||||
* Whether to enable the effect
|
* Whether to enable the effect
|
||||||
* @default true
|
* @default true
|
||||||
*/
|
*/
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
/**
|
/**
|
||||||
* Z-index for the rain container
|
* Z-index for the rain container
|
||||||
* @default 9999
|
* @default 9999
|
||||||
*/
|
*/
|
||||||
zIndex?: number;
|
zIndex?: number;
|
||||||
/**
|
/**
|
||||||
* Container element to attach the rain effect
|
* Container element to attach the rain effect
|
||||||
* @default document.body
|
* @default document.body
|
||||||
*/
|
*/
|
||||||
container?: HTMLElement;
|
container?: HTMLElement;
|
||||||
}
|
}
|
||||||
export interface RainDrop {
|
export interface RainDrop {
|
||||||
element: HTMLElement;
|
element: HTMLElement;
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
size: number;
|
size: number;
|
||||||
isAnimating: boolean;
|
isAnimating: boolean;
|
||||||
}
|
}
|
||||||
export interface CursorRainEffect {
|
export interface CursorRainEffect {
|
||||||
/**
|
/**
|
||||||
* Initialize the rain effect
|
* Initialize the rain effect
|
||||||
*/
|
*/
|
||||||
init(): void;
|
init(): void;
|
||||||
/**
|
/**
|
||||||
* Destroy the rain effect and clean up
|
* Destroy the rain effect and clean up
|
||||||
*/
|
*/
|
||||||
destroy(): void;
|
destroy(): void;
|
||||||
/**
|
/**
|
||||||
* Enable the rain effect
|
* Enable the rain effect
|
||||||
*/
|
*/
|
||||||
enable(): void;
|
enable(): void;
|
||||||
/**
|
/**
|
||||||
* Disable the rain effect
|
* Disable the rain effect
|
||||||
*/
|
*/
|
||||||
disable(): void;
|
disable(): void;
|
||||||
/**
|
/**
|
||||||
* Update options
|
* Update options
|
||||||
*/
|
*/
|
||||||
updateOptions(options: Partial<RainDropOptions>): void;
|
updateOptions(options: Partial<RainDropOptions>): void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,125 +1,125 @@
|
|||||||
// 光标雨点效果配置文件
|
// 光标雨点效果配置文件
|
||||||
// 你可以在这里定义不同的配置预设
|
// 你可以在这里定义不同的配置预设
|
||||||
|
|
||||||
import type { RainDropOptions } from '../cursor-rain/types'
|
import type { RainDropOptions } from '../cursor-rain/types'
|
||||||
|
|
||||||
// 预设配置
|
// 预设配置
|
||||||
export const rainPresets = {
|
export const rainPresets = {
|
||||||
// 默认配置
|
// 默认配置
|
||||||
default: {
|
default: {
|
||||||
maxDrops: 25,
|
maxDrops: 25,
|
||||||
color: 'rgba(173, 216, 230, 0.6)',
|
color: 'rgba(173, 216, 230, 0.6)',
|
||||||
duration: [1.0, 2.0],
|
duration: [1.0, 2.0],
|
||||||
dropSize: [3, 8],
|
dropSize: [3, 8],
|
||||||
delay: 100,
|
delay: 100,
|
||||||
zIndex: 1000
|
zIndex: 1000
|
||||||
} as RainDropOptions,
|
} as RainDropOptions,
|
||||||
|
|
||||||
// 轻量模式(适合低性能设备)
|
// 轻量模式(适合低性能设备)
|
||||||
light: {
|
light: {
|
||||||
maxDrops: 15,
|
maxDrops: 15,
|
||||||
color: 'rgba(173, 216, 230, 0.5)',
|
color: 'rgba(173, 216, 230, 0.5)',
|
||||||
duration: [1.2, 2.5],
|
duration: [1.2, 2.5],
|
||||||
dropSize: [2, 6],
|
dropSize: [2, 6],
|
||||||
delay: 150,
|
delay: 150,
|
||||||
zIndex: 1000
|
zIndex: 1000
|
||||||
} as RainDropOptions,
|
} as RainDropOptions,
|
||||||
|
|
||||||
// 华丽模式
|
// 华丽模式
|
||||||
fancy: {
|
fancy: {
|
||||||
maxDrops: 40,
|
maxDrops: 40,
|
||||||
color: 'rgba(173, 216, 230, 0.8)',
|
color: 'rgba(173, 216, 230, 0.8)',
|
||||||
duration: [0.8, 1.5],
|
duration: [0.8, 1.5],
|
||||||
dropSize: [4, 12],
|
dropSize: [4, 12],
|
||||||
delay: 50,
|
delay: 50,
|
||||||
zIndex: 1000
|
zIndex: 1000
|
||||||
} as RainDropOptions,
|
} as RainDropOptions,
|
||||||
|
|
||||||
// 粉色主题
|
// 粉色主题
|
||||||
pink: {
|
pink: {
|
||||||
maxDrops: 30,
|
maxDrops: 30,
|
||||||
color: 'rgba(255, 182, 193, 0.7)',
|
color: 'rgba(255, 182, 193, 0.7)',
|
||||||
duration: [1.0, 2.0],
|
duration: [1.0, 2.0],
|
||||||
dropSize: [3, 9],
|
dropSize: [3, 9],
|
||||||
delay: 80,
|
delay: 80,
|
||||||
zIndex: 1000
|
zIndex: 1000
|
||||||
} as RainDropOptions,
|
} as RainDropOptions,
|
||||||
|
|
||||||
// 绿色主题
|
// 绿色主题
|
||||||
green: {
|
green: {
|
||||||
maxDrops: 25,
|
maxDrops: 25,
|
||||||
color: 'rgba(144, 238, 144, 0.7)',
|
color: 'rgba(144, 238, 144, 0.7)',
|
||||||
duration: [1.0, 2.0],
|
duration: [1.0, 2.0],
|
||||||
dropSize: [3, 8],
|
dropSize: [3, 8],
|
||||||
delay: 100,
|
delay: 100,
|
||||||
zIndex: 1000
|
zIndex: 1000
|
||||||
} as RainDropOptions,
|
} as RainDropOptions,
|
||||||
|
|
||||||
// 金色主题
|
// 金色主题
|
||||||
gold: {
|
gold: {
|
||||||
maxDrops: 20,
|
maxDrops: 20,
|
||||||
color: 'rgba(255, 215, 0, 0.6)',
|
color: 'rgba(255, 215, 0, 0.6)',
|
||||||
duration: [1.5, 2.5],
|
duration: [1.5, 2.5],
|
||||||
dropSize: [2, 6],
|
dropSize: [2, 6],
|
||||||
delay: 120,
|
delay: 120,
|
||||||
zIndex: 1000
|
zIndex: 1000
|
||||||
} as RainDropOptions,
|
} as RainDropOptions,
|
||||||
|
|
||||||
// 移动端优化配置
|
// 移动端优化配置
|
||||||
mobile: {
|
mobile: {
|
||||||
maxDrops: 10,
|
maxDrops: 10,
|
||||||
color: 'rgba(173, 216, 230, 0.5)',
|
color: 'rgba(173, 216, 230, 0.5)',
|
||||||
duration: [1.5, 3.0],
|
duration: [1.5, 3.0],
|
||||||
dropSize: [2, 5],
|
dropSize: [2, 5],
|
||||||
delay: 200,
|
delay: 200,
|
||||||
zIndex: 1000
|
zIndex: 1000
|
||||||
} as RainDropOptions
|
} as RainDropOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据设备类型自动选择配置
|
// 根据设备类型自动选择配置
|
||||||
export function getOptimalConfig(): RainDropOptions {
|
export function getOptimalConfig(): RainDropOptions {
|
||||||
if (typeof window === 'undefined') return rainPresets.default
|
if (typeof window === 'undefined') return rainPresets.default
|
||||||
|
|
||||||
// 检测移动设备
|
// 检测移动设备
|
||||||
const isMobile = window.innerWidth < 768 || /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
|
const isMobile = window.innerWidth < 768 || /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
|
||||||
|
|
||||||
// 检测低性能设备(简单的启发式检测)
|
// 检测低性能设备(简单的启发式检测)
|
||||||
const isLowPerformance = navigator.hardwareConcurrency && navigator.hardwareConcurrency < 4
|
const isLowPerformance = navigator.hardwareConcurrency && navigator.hardwareConcurrency < 4
|
||||||
|
|
||||||
if (isMobile) {
|
if (isMobile) {
|
||||||
return rainPresets.mobile
|
return rainPresets.mobile
|
||||||
} else if (isLowPerformance) {
|
} else if (isLowPerformance) {
|
||||||
return rainPresets.light
|
return rainPresets.light
|
||||||
} else {
|
} else {
|
||||||
return rainPresets.default
|
return rainPresets.default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 主题配色方案
|
// 主题配色方案
|
||||||
export const colorThemes = {
|
export const colorThemes = {
|
||||||
blue: 'rgba(100, 149, 237, 0.7)',
|
blue: 'rgba(100, 149, 237, 0.7)',
|
||||||
lightBlue: 'rgba(173, 216, 230, 0.6)',
|
lightBlue: 'rgba(173, 216, 230, 0.6)',
|
||||||
pink: 'rgba(255, 182, 193, 0.7)',
|
pink: 'rgba(255, 182, 193, 0.7)',
|
||||||
green: 'rgba(144, 238, 144, 0.7)',
|
green: 'rgba(144, 238, 144, 0.7)',
|
||||||
gold: 'rgba(255, 215, 0, 0.6)',
|
gold: 'rgba(255, 215, 0, 0.6)',
|
||||||
purple: 'rgba(147, 112, 219, 0.7)',
|
purple: 'rgba(147, 112, 219, 0.7)',
|
||||||
orange: 'rgba(255, 165, 0, 0.7)',
|
orange: 'rgba(255, 165, 0, 0.7)',
|
||||||
red: 'rgba(255, 99, 99, 0.7)'
|
red: 'rgba(255, 99, 99, 0.7)'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 动态切换主题的函数
|
// 动态切换主题的函数
|
||||||
export function switchRainTheme(effect: any, themeName: keyof typeof colorThemes) {
|
export function switchRainTheme(effect: any, themeName: keyof typeof colorThemes) {
|
||||||
const color = colorThemes[themeName]
|
const color = colorThemes[themeName]
|
||||||
if (color && effect) {
|
if (color && effect) {
|
||||||
effect.updateOptions({ color })
|
effect.updateOptions({ color })
|
||||||
|
|
||||||
// 同时更新CSS类名以应用对应的样式
|
// 同时更新CSS类名以应用对应的样式
|
||||||
const container = document.querySelector('.cursor-rain-container')
|
const container = document.querySelector('.cursor-rain-container')
|
||||||
if (container) {
|
if (container) {
|
||||||
// 移除所有主题类
|
// 移除所有主题类
|
||||||
container.classList.remove('rain-theme-blue', 'rain-theme-pink', 'rain-theme-green', 'rain-theme-gold', 'rain-theme-rainbow')
|
container.classList.remove('rain-theme-blue', 'rain-theme-pink', 'rain-theme-green', 'rain-theme-gold', 'rain-theme-rainbow')
|
||||||
// 添加新主题类
|
// 添加新主题类
|
||||||
container.classList.add(`rain-theme-${themeName}`)
|
container.classList.add(`rain-theme-${themeName}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,108 +1,108 @@
|
|||||||
/* 光标雨点效果自定义样式 */
|
/* 光标雨点效果自定义样式 */
|
||||||
|
|
||||||
/* 基础雨点样式 */
|
/* 基础雨点样式 */
|
||||||
.cursor-rain-container {
|
.cursor-rain-container {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cursor-rain-container .rain-drop {
|
.cursor-rain-container .rain-drop {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
||||||
/* 细长雨滴形状 - 更像雨丝的细长形状 - 使用!important覆盖内联样式 */
|
/* 细长雨滴形状 - 更像雨丝的细长形状 - 使用!important覆盖内联样式 */
|
||||||
border-radius: 50% 50% 50% 50% / 90% 90% 10% 10% !important;
|
border-radius: 50% 50% 50% 50% / 90% 90% 10% 10% !important;
|
||||||
|
|
||||||
/* 添加一些视觉效果 */
|
/* 添加一些视觉效果 */
|
||||||
box-shadow: 0 0 6px rgba(173, 216, 230, 0.4);
|
box-shadow: 0 0 6px rgba(173, 216, 230, 0.4);
|
||||||
filter: blur(0.5px);
|
filter: blur(0.5px);
|
||||||
|
|
||||||
/* 渐变效果 - 垂直方向的渐变更符合拉长的雨滴 */
|
/* 渐变效果 - 垂直方向的渐变更符合拉长的雨滴 */
|
||||||
background: linear-gradient(to bottom,
|
background: linear-gradient(to bottom,
|
||||||
rgba(173, 216, 230, 0.9) 0%,
|
rgba(173, 216, 230, 0.9) 0%,
|
||||||
rgba(173, 216, 230, 0.7) 50%,
|
rgba(173, 216, 230, 0.7) 50%,
|
||||||
rgba(173, 216, 230, 0.3) 100%) !important;
|
rgba(173, 216, 230, 0.3) 100%) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 深色主题适配 */
|
/* 深色主题适配 */
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
.cursor-rain-container .rain-drop {
|
.cursor-rain-container .rain-drop {
|
||||||
background: linear-gradient(to bottom,
|
background: linear-gradient(to bottom,
|
||||||
rgba(173, 216, 230, 0.7) 0%,
|
rgba(173, 216, 230, 0.7) 0%,
|
||||||
rgba(173, 216, 230, 0.5) 50%,
|
rgba(173, 216, 230, 0.5) 50%,
|
||||||
rgba(173, 216, 230, 0.2) 100%);
|
rgba(173, 216, 230, 0.2) 100%);
|
||||||
box-shadow: 0 0 8px rgba(173, 216, 230, 0.3);
|
box-shadow: 0 0 8px rgba(173, 216, 230, 0.3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 移动端优化 */
|
/* 移动端优化 */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.cursor-rain-container .rain-drop {
|
.cursor-rain-container .rain-drop {
|
||||||
/* 移动端减少模糊效果以提高性能 */
|
/* 移动端减少模糊效果以提高性能 */
|
||||||
filter: none;
|
filter: none;
|
||||||
box-shadow: 0 0 4px rgba(173, 216, 230, 0.3);
|
box-shadow: 0 0 4px rgba(173, 216, 230, 0.3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 自定义颜色主题类 */
|
/* 自定义颜色主题类 */
|
||||||
.rain-theme-blue .rain-drop {
|
.rain-theme-blue .rain-drop {
|
||||||
background: linear-gradient(to bottom,
|
background: linear-gradient(to bottom,
|
||||||
rgba(100, 149, 237, 0.9) 0%,
|
rgba(100, 149, 237, 0.9) 0%,
|
||||||
rgba(100, 149, 237, 0.7) 50%,
|
rgba(100, 149, 237, 0.7) 50%,
|
||||||
rgba(100, 149, 237, 0.3) 100%);
|
rgba(100, 149, 237, 0.3) 100%);
|
||||||
box-shadow: 0 0 6px rgba(100, 149, 237, 0.4);
|
box-shadow: 0 0 6px rgba(100, 149, 237, 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rain-theme-pink .rain-drop {
|
.rain-theme-pink .rain-drop {
|
||||||
background: linear-gradient(to bottom,
|
background: linear-gradient(to bottom,
|
||||||
rgba(255, 182, 193, 0.9) 0%,
|
rgba(255, 182, 193, 0.9) 0%,
|
||||||
rgba(255, 182, 193, 0.7) 50%,
|
rgba(255, 182, 193, 0.7) 50%,
|
||||||
rgba(255, 182, 193, 0.3) 100%);
|
rgba(255, 182, 193, 0.3) 100%);
|
||||||
box-shadow: 0 0 6px rgba(255, 182, 193, 0.4);
|
box-shadow: 0 0 6px rgba(255, 182, 193, 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rain-theme-green .rain-drop {
|
.rain-theme-green .rain-drop {
|
||||||
background: linear-gradient(to bottom,
|
background: linear-gradient(to bottom,
|
||||||
rgba(144, 238, 144, 0.9) 0%,
|
rgba(144, 238, 144, 0.9) 0%,
|
||||||
rgba(144, 238, 144, 0.7) 50%,
|
rgba(144, 238, 144, 0.7) 50%,
|
||||||
rgba(144, 238, 144, 0.3) 100%);
|
rgba(144, 238, 144, 0.3) 100%);
|
||||||
box-shadow: 0 0 6px rgba(144, 238, 144, 0.4);
|
box-shadow: 0 0 6px rgba(144, 238, 144, 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rain-theme-gold .rain-drop {
|
.rain-theme-gold .rain-drop {
|
||||||
background: linear-gradient(to bottom,
|
background: linear-gradient(to bottom,
|
||||||
rgba(255, 215, 0, 0.9) 0%,
|
rgba(255, 215, 0, 0.9) 0%,
|
||||||
rgba(255, 215, 0, 0.7) 50%,
|
rgba(255, 215, 0, 0.7) 50%,
|
||||||
rgba(255, 215, 0, 0.3) 100%);
|
rgba(255, 215, 0, 0.3) 100%);
|
||||||
box-shadow: 0 0 6px rgba(255, 215, 0, 0.4);
|
box-shadow: 0 0 6px rgba(255, 215, 0, 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 特殊效果:彩虹雨点 */
|
/* 特殊效果:彩虹雨点 */
|
||||||
.rain-theme-rainbow .rain-drop:nth-child(6n+1) {
|
.rain-theme-rainbow .rain-drop:nth-child(6n+1) {
|
||||||
background: linear-gradient(to bottom, rgba(255, 99, 99, 0.9) 0%, rgba(255, 99, 99, 0.7) 50%, rgba(255, 99, 99, 0.3) 100%);
|
background: linear-gradient(to bottom, rgba(255, 99, 99, 0.9) 0%, rgba(255, 99, 99, 0.7) 50%, rgba(255, 99, 99, 0.3) 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rain-theme-rainbow .rain-drop:nth-child(6n+2) {
|
.rain-theme-rainbow .rain-drop:nth-child(6n+2) {
|
||||||
background: linear-gradient(to bottom, rgba(255, 159, 64, 0.9) 0%, rgba(255, 159, 64, 0.7) 50%, rgba(255, 159, 64, 0.3) 100%);
|
background: linear-gradient(to bottom, rgba(255, 159, 64, 0.9) 0%, rgba(255, 159, 64, 0.7) 50%, rgba(255, 159, 64, 0.3) 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rain-theme-rainbow .rain-drop:nth-child(6n+3) {
|
.rain-theme-rainbow .rain-drop:nth-child(6n+3) {
|
||||||
background: linear-gradient(to bottom, rgba(255, 205, 86, 0.9) 0%, rgba(255, 205, 86, 0.7) 50%, rgba(255, 205, 86, 0.3) 100%);
|
background: linear-gradient(to bottom, rgba(255, 205, 86, 0.9) 0%, rgba(255, 205, 86, 0.7) 50%, rgba(255, 205, 86, 0.3) 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rain-theme-rainbow .rain-drop:nth-child(6n+4) {
|
.rain-theme-rainbow .rain-drop:nth-child(6n+4) {
|
||||||
background: linear-gradient(to bottom, rgba(75, 192, 192, 0.9) 0%, rgba(75, 192, 192, 0.7) 50%, rgba(75, 192, 192, 0.3) 100%);
|
background: linear-gradient(to bottom, rgba(75, 192, 192, 0.9) 0%, rgba(75, 192, 192, 0.7) 50%, rgba(75, 192, 192, 0.3) 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rain-theme-rainbow .rain-drop:nth-child(6n+5) {
|
.rain-theme-rainbow .rain-drop:nth-child(6n+5) {
|
||||||
background: linear-gradient(to bottom, rgba(54, 162, 235, 0.9) 0%, rgba(54, 162, 235, 0.7) 50%, rgba(54, 162, 235, 0.3) 100%);
|
background: linear-gradient(to bottom, rgba(54, 162, 235, 0.9) 0%, rgba(54, 162, 235, 0.7) 50%, rgba(54, 162, 235, 0.3) 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rain-theme-rainbow .rain-drop:nth-child(6n+6) {
|
.rain-theme-rainbow .rain-drop:nth-child(6n+6) {
|
||||||
background: linear-gradient(to bottom, rgba(153, 102, 255, 0.9) 0%, rgba(153, 102, 255, 0.7) 50%, rgba(153, 102, 255, 0.3) 100%);
|
background: linear-gradient(to bottom, rgba(153, 102, 255, 0.9) 0%, rgba(153, 102, 255, 0.7) 50%, rgba(153, 102, 255, 0.3) 100%);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,152 +1,152 @@
|
|||||||
---
|
---
|
||||||
title: 文章标题 - 副标题 # 文章标题,支持副标题格式(用 - 分隔)
|
title: 文章标题 - 副标题 # 文章标题,支持副标题格式(用 - 分隔)
|
||||||
top: 1 # 置顶级别:1-3,数字越大越靠前,0表示不置顶
|
top: 1 # 置顶级别:1-3,数字越大越靠前,0表示不置顶
|
||||||
date: 2025-01-01 12:00:00 # 发布日期和时间,格式:YYYY-MM-DD HH:MM:SS
|
date: 2025-01-01 12:00:00 # 发布日期和时间,格式:YYYY-MM-DD HH:MM:SS
|
||||||
descriptionHTML: '
|
descriptionHTML: '
|
||||||
<span style="color:var(--description-font-color);">文章描述,支持HTML格式</span>
|
<span style="color:var(--description-font-color);">文章描述,支持HTML格式</span>
|
||||||
'
|
'
|
||||||
tags: # 文章标签列表,用于分类和搜索
|
tags: # 文章标签列表,用于分类和搜索
|
||||||
- AI
|
- AI
|
||||||
- 生活
|
- 生活
|
||||||
sidebar: true # 是否显示侧边栏:true显示,false隐藏
|
sidebar: true # 是否显示侧边栏:true显示,false隐藏
|
||||||
readingTime: true # 是否显示阅读时间:true显示,false隐藏
|
readingTime: true # 是否显示阅读时间:true显示,false隐藏
|
||||||
hiddenCover: false # 是否隐藏封面图:true隐藏,false显示
|
hiddenCover: false # 是否隐藏封面图:true隐藏,false显示
|
||||||
cover: url # 封面图片路径,相对于public目录
|
cover: url # 封面图片路径,相对于public目录
|
||||||
sticky: 0 # 精选文章设置:值越大在首页展示越靠前,0表示不精选
|
sticky: 0 # 精选文章设置:值越大在首页展示越靠前,0表示不精选
|
||||||
hidden: true # 是否隐藏文章:true隐藏(模板用),false显示(正式文章用)
|
hidden: true # 是否隐藏文章:true隐藏(模板用),false显示(正式文章用)
|
||||||
recommend: false
|
recommend: false
|
||||||
publish: false
|
publish: false
|
||||||
---
|
---
|
||||||
|
|
||||||
# 文章标题
|
# 文章标题
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
## 前言
|
## 前言
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span style="font-size:0.9em; color:#1976d2;">
|
<span style="font-size:0.9em; color:#1976d2;">
|
||||||
  这是一个前言段落,使用较小的字体和蓝色文字。通常用于介绍文章的背景、目的或重要说明。
|
  这是一个前言段落,使用较小的字体和蓝色文字。通常用于介绍文章的背景、目的或重要说明。
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
## 第一章
|
## 第一章
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
  这是正文段落,使用缩进格式。您可以在这里写入主要内容。
|
  这是正文段落,使用缩进格式。您可以在这里写入主要内容。
|
||||||
|
|
||||||
  这是另一个段落,继续您的内容。
|
  这是另一个段落,继续您的内容。
|
||||||
|
|
||||||
### 小标题
|
### 小标题
|
||||||
|
|
||||||
  这是小标题下的内容。
|
  这是小标题下的内容。
|
||||||
|
|
||||||
#### 更小的标题
|
#### 更小的标题
|
||||||
|
|
||||||
  这是更小标题下的内容。
|
  这是更小标题下的内容。
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
## 第二章
|
## 第二章
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
  这是第二章的内容。
|
  这是第二章的内容。
|
||||||
|
|
||||||
### 代码示例
|
### 代码示例
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// 这是一个代码块示例
|
// 这是一个代码块示例
|
||||||
function example() {
|
function example() {
|
||||||
console.log("Hello World");
|
console.log("Hello World");
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 引用文本
|
### 引用文本
|
||||||
|
|
||||||
> 这是一个引用块,用于突出显示重要信息或引用他人的话。
|
> 这是一个引用块,用于突出显示重要信息或引用他人的话。
|
||||||
|
|
||||||
### 列表格式
|
### 列表格式
|
||||||
|
|
||||||
#### 无序列表
|
#### 无序列表
|
||||||
- **粗体项目**:这是粗体文本
|
- **粗体项目**:这是粗体文本
|
||||||
- *斜体项目*:这是斜体文本
|
- *斜体项目*:这是斜体文本
|
||||||
- <span style="color: #43a047;">绿色文本</span>:这是带颜色的文本
|
- <span style="color: #43a047;">绿色文本</span>:这是带颜色的文本
|
||||||
|
|
||||||
#### 有序列表
|
#### 有序列表
|
||||||
1. 第一项
|
1. 第一项
|
||||||
2. 第二项
|
2. 第二项
|
||||||
3. 第三项
|
3. 第三项
|
||||||
|
|
||||||
### 表格示例
|
### 表格示例
|
||||||
|
|
||||||
| 列1 | 列2 | 列3 |
|
| 列1 | 列2 | 列3 |
|
||||||
|-----|-----|-----|
|
|-----|-----|-----|
|
||||||
| 内容1 | 内容2 | 内容3 |
|
| 内容1 | 内容2 | 内容3 |
|
||||||
| 内容4 | 内容5 | 内容6 |
|
| 内容4 | 内容5 | 内容6 |
|
||||||
|
|
||||||
### 图片插入
|
### 图片插入
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
<img src="/logo.jpg" alt="示例图片" width="300"/>
|
<img src="/logo.jpg" alt="示例图片" width="300"/>
|
||||||
|
|
||||||
*图片说明文字*
|
*图片说明文字*
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
### 链接格式
|
### 链接格式
|
||||||
|
|
||||||
- [普通链接](https://example.com)
|
- [普通链接](https://example.com)
|
||||||
- <span style="color: #43a047;">[带颜色的链接](https://example.com)</span>
|
- <span style="color: #43a047;">[带颜色的链接](https://example.com)</span>
|
||||||
|
|
||||||
### 特殊格式文本
|
### 特殊格式文本
|
||||||
|
|
||||||
- <span style="color: #d32f2f;">红色警告文本</span>
|
- <span style="color: #d32f2f;">红色警告文本</span>
|
||||||
- <span style="color: #43a047;">绿色成功文本</span>
|
- <span style="color: #43a047;">绿色成功文本</span>
|
||||||
- <span style="color: #1976d2;">蓝色信息文本</span>
|
- <span style="color: #1976d2;">蓝色信息文本</span>
|
||||||
- <span style="font-size:0.8em;">小字体文本</span>
|
- <span style="font-size:0.8em;">小字体文本</span>
|
||||||
- <span style="font-weight: bold;">粗体文本</span>
|
- <span style="font-weight: bold;">粗体文本</span>
|
||||||
|
|
||||||
### 分割线
|
### 分割线
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 代码内联
|
### 代码内联
|
||||||
|
|
||||||
您可以在文本中使用 `内联代码` 来突出显示代码片段。
|
您可以在文本中使用 `内联代码` 来突出显示代码片段。
|
||||||
|
|
||||||
### 数学公式(如果支持)
|
### 数学公式(如果支持)
|
||||||
|
|
||||||
$$
|
$$
|
||||||
E = mc^2
|
E = mc^2
|
||||||
$$
|
$$
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
## 总结
|
## 总结
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
  这是文章的总结部分。
|
  这是文章的总结部分。
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
#### <span style="color: #d32f2f;">重要提示或结论</span>
|
#### <span style="color: #d32f2f;">重要提示或结论</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
<img src="/logo.jpg" alt="结束图片" width="200"/>
|
<img src="/logo.jpg" alt="结束图片" width="200"/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*文章结束,可以添加版权信息或其他说明*
|
*文章结束,可以添加版权信息或其他说明*
|
||||||
|
|
||||||
[原文链接](https://example.com)
|
[原文链接](https://example.com)
|
||||||
|
|||||||
@@ -1,37 +1,37 @@
|
|||||||
---
|
---
|
||||||
title: 今天二战钓鱼,还是空军 # 文章标题,支持副标题格式(用 - 分隔)
|
title: 今天二战钓鱼,还是空军 # 文章标题,支持副标题格式(用 - 分隔)
|
||||||
top: 0 # 置顶级别:1-3,数字越大越靠前,0表示不置顶
|
top: 0 # 置顶级别:1-3,数字越大越靠前,0表示不置顶
|
||||||
date: 2025-08-26 21:00:00 # 发布日期和时间,格式:YYYY-MM-DD HH:MM:SS
|
date: 2025-08-26 21:00:00 # 发布日期和时间,格式:YYYY-MM-DD HH:MM:SS
|
||||||
descriptionHTML: '
|
descriptionHTML: '
|
||||||
<span style="color:var(--description-font-color);">下次不来了,有机会再钓</span>
|
<span style="color:var(--description-font-color);">下次不来了,有机会再钓</span>
|
||||||
'
|
'
|
||||||
tags: # 文章标签列表,用于分类和搜索
|
tags: # 文章标签列表,用于分类和搜索
|
||||||
- 生活
|
- 生活
|
||||||
sidebar: false # 是否显示侧边栏:true显示,false隐藏
|
sidebar: false # 是否显示侧边栏:true显示,false隐藏
|
||||||
readingTime: true # 是否显示阅读时间:true显示,false隐藏
|
readingTime: true # 是否显示阅读时间:true显示,false隐藏
|
||||||
hiddenCover: true # 是否隐藏封面图:true隐藏,false显示
|
hiddenCover: true # 是否隐藏封面图:true隐藏,false显示
|
||||||
cover: url # 封面图片路径,相对于public目录
|
cover: url # 封面图片路径,相对于public目录
|
||||||
sticky: 0 # 精选文章设置:值越大在首页展示越靠前,0表示不精选
|
sticky: 0 # 精选文章设置:值越大在首页展示越靠前,0表示不精选
|
||||||
hidden: false # 是否隐藏文章:true隐藏(模板用),false显示(正式文章用)
|
hidden: false # 是否隐藏文章:true隐藏(模板用),false显示(正式文章用)
|
||||||
recommend: true
|
recommend: true
|
||||||
---
|
---
|
||||||
|
|
||||||
# 今天二战钓鱼,还是空军
|
# 今天二战钓鱼,还是空军
|
||||||
|
|
||||||
今天天气很好,附一张图,想着怎么都得整得到一两条
|
今天天气很好,附一张图,想着怎么都得整得到一两条
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
可能是技术不佳,鱼倒是有,但是就是不上钩
|
可能是技术不佳,鱼倒是有,但是就是不上钩
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
旁边的渔友也有钓到的,可是鱼很狡猾,吃了一小点就跑了
|
旁边的渔友也有钓到的,可是鱼很狡猾,吃了一小点就跑了
|
||||||
|
|
||||||
按理说应该在浮漂抖动的时候就要提一下,把鱼勾住
|
按理说应该在浮漂抖动的时候就要提一下,把鱼勾住
|
||||||
|
|
||||||
但是总想着要黑漂才拉上来
|
但是总想着要黑漂才拉上来
|
||||||
|
|
||||||
等着寒假再回来钓
|
等着寒假再回来钓
|
||||||
|
|||||||
@@ -1,49 +1,49 @@
|
|||||||
---
|
---
|
||||||
title: 今天第一次钓鱼,空军 # 文章标题,支持副标题格式(用 - 分隔)
|
title: 今天第一次钓鱼,空军 # 文章标题,支持副标题格式(用 - 分隔)
|
||||||
top: 0 # 置顶级别:1-3,数字越大越靠前,0表示不置顶
|
top: 0 # 置顶级别:1-3,数字越大越靠前,0表示不置顶
|
||||||
date: 2025-08-25 17:30:00 # 发布日期和时间,格式:YYYY-MM-DD HH:MM:SS
|
date: 2025-08-25 17:30:00 # 发布日期和时间,格式:YYYY-MM-DD HH:MM:SS
|
||||||
descriptionHTML: '
|
descriptionHTML: '
|
||||||
<span style="color:var(--description-font-color);">下次还来</span>
|
<span style="color:var(--description-font-color);">下次还来</span>
|
||||||
'
|
'
|
||||||
tags: # 文章标签列表,用于分类和搜索
|
tags: # 文章标签列表,用于分类和搜索
|
||||||
- 生活
|
- 生活
|
||||||
sidebar: false # 是否显示侧边栏:true显示,false隐藏
|
sidebar: false # 是否显示侧边栏:true显示,false隐藏
|
||||||
readingTime: true # 是否显示阅读时间:true显示,false隐藏
|
readingTime: true # 是否显示阅读时间:true显示,false隐藏
|
||||||
hiddenCover: true # 是否隐藏封面图:true隐藏,false显示
|
hiddenCover: true # 是否隐藏封面图:true隐藏,false显示
|
||||||
cover: url # 封面图片路径,相对于public目录
|
cover: url # 封面图片路径,相对于public目录
|
||||||
sticky: 0 # 精选文章设置:值越大在首页展示越靠前,0表示不精选
|
sticky: 0 # 精选文章设置:值越大在首页展示越靠前,0表示不精选
|
||||||
hidden: false # 是否隐藏文章:true隐藏(模板用),false显示(正式文章用)
|
hidden: false # 是否隐藏文章:true隐藏(模板用),false显示(正式文章用)
|
||||||
recommend: true
|
recommend: true
|
||||||
---
|
---
|
||||||
|
|
||||||
# 今天第一次钓鱼,空军
|
# 今天第一次钓鱼,空军
|
||||||
|
|
||||||
这几天在老家,由于之前一直下雨,外公没有去钓鱼,今天早上没有雨了,天气预报也是晴,索性就带上我去钓鱼 🎣
|
这几天在老家,由于之前一直下雨,外公没有去钓鱼,今天早上没有雨了,天气预报也是晴,索性就带上我去钓鱼 🎣
|
||||||
|
|
||||||
外公喜欢野钓,县城不远的村子旁有个小河道
|
外公喜欢野钓,县城不远的村子旁有个小河道
|
||||||
|
|
||||||
早上六点就起床,七点多抵达目的地
|
早上六点就起床,七点多抵达目的地
|
||||||
|
|
||||||
可能是连下了几天的雨,河水水流有点急,而且还浑
|
可能是连下了几天的雨,河水水流有点急,而且还浑
|
||||||
|
|
||||||
感觉不太好搞 😅
|
感觉不太好搞 😅
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
等到十点多还没有,只是偶尔有小鱼碰一下
|
等到十点多还没有,只是偶尔有小鱼碰一下
|
||||||
|
|
||||||
换个地点继续
|
换个地点继续
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
又过了一个小时,其实中途我看到浮漂有向下了一下(很迅速,不是水流冲下去的),但是经验不足,没有管,等着拉起来,食已经被吃了 🫠
|
又过了一个小时,其实中途我看到浮漂有向下了一下(很迅速,不是水流冲下去的),但是经验不足,没有管,等着拉起来,食已经被吃了 🫠
|
||||||
|
|
||||||
外公也是一无所获
|
外公也是一无所获
|
||||||
|
|
||||||
还是回家吧,等过两天再来,今天晚上感觉又要下大雨了 🌧️
|
还是回家吧,等过两天再来,今天晚上感觉又要下大雨了 🌧️
|
||||||
|
|
||||||
艹
|
艹
|
||||||
|
|||||||
@@ -1,48 +1,48 @@
|
|||||||
---
|
---
|
||||||
title: 他可能真的很忙吧
|
title: 他可能真的很忙吧
|
||||||
top: 0
|
top: 0
|
||||||
date: 2025-09-06 20:00:00
|
date: 2025-09-06 20:00:00
|
||||||
descriptionHTML: '
|
descriptionHTML: '
|
||||||
<span style="color:var(--description-font-color);">他在飞机上一直在用电脑</span>
|
<span style="color:var(--description-font-color);">他在飞机上一直在用电脑</span>
|
||||||
'
|
'
|
||||||
tags:
|
tags:
|
||||||
- 生活
|
- 生活
|
||||||
sidebar: true
|
sidebar: true
|
||||||
readingTime: true
|
readingTime: true
|
||||||
hiddenCover: false
|
hiddenCover: false
|
||||||
sticky: 0
|
sticky: 0
|
||||||
hidden: false
|
hidden: false
|
||||||
recommend: true
|
recommend: true
|
||||||
publish: true
|
publish: true
|
||||||
---
|
---
|
||||||
|
|
||||||
# 他可能真的很忙吧
|
# 他可能真的很忙吧
|
||||||
|
|
||||||
今天飞回广州了,因为开学了
|
今天飞回广州了,因为开学了
|
||||||
|
|
||||||
大部分大学生应该都飞回来了
|
大部分大学生应该都飞回来了
|
||||||
|
|
||||||
今天在机场遇到挺多大学生的,北京飞广州的是波音777的大飞机,我坐在C,有位同学坐在G,隔着一段距离。暂且称呼为同学,因为感觉看上去和我年龄相仿,然后起飞平稳后就一直在用电脑。
|
今天在机场遇到挺多大学生的,北京飞广州的是波音777的大飞机,我坐在C,有位同学坐在G,隔着一段距离。暂且称呼为同学,因为感觉看上去和我年龄相仿,然后起飞平稳后就一直在用电脑。
|
||||||
|
|
||||||
他可能真的很忙吧
|
他可能真的很忙吧
|
||||||
|
|
||||||
平稳后就一直在用,水也不喝,饭也不吃(空姐还告诉他要是需要用餐就告诉他们,但是最后降落前也没吃饭)
|
平稳后就一直在用,水也不喝,饭也不吃(空姐还告诉他要是需要用餐就告诉他们,但是最后降落前也没吃饭)
|
||||||
|
|
||||||
一开始我也没看清是在干什么,以为是打代码呢,但是我也偶尔写写代码,界面看着不像代码
|
一开始我也没看清是在干什么,以为是打代码呢,但是我也偶尔写写代码,界面看着不像代码
|
||||||
|
|
||||||
直到他缩放了一下,我才看清是个思维导图或者是流程图之类的东西,因为没写过,下飞机还特意查了一下
|
直到他缩放了一下,我才看清是个思维导图或者是流程图之类的东西,因为没写过,下飞机还特意查了一下
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### emmm 没别的意思就是记录一下
|
#### emmm 没别的意思就是记录一下
|
||||||
|
|
||||||
我想没必要这么夸张吧,偶尔也需要休息一下
|
我想没必要这么夸张吧,偶尔也需要休息一下
|
||||||
|
|
||||||
或者是为了炫耀?满足心里的自豪感?
|
或者是为了炫耀?满足心里的自豪感?
|
||||||
|
|
||||||
我不知道,可能是现在世间太纷繁了,连别人忙碌都能看成装X。因为我看见这样的人心里总是有种怪怪的感觉讲不上来
|
我不知道,可能是现在世间太纷繁了,连别人忙碌都能看成装X。因为我看见这样的人心里总是有种怪怪的感觉讲不上来
|
||||||
|
|
||||||
##### 我现在就是处于一种状态,看见别人过得不好很是可怜,但是看见别人过得好却有点嫉妒,然后就是有些自卑
|
##### 我现在就是处于一种状态,看见别人过得不好很是可怜,但是看见别人过得好却有点嫉妒,然后就是有些自卑
|
||||||
##### 在学校里也是,看到别人放飞自我的玩感到怜惜,自己玩的太嗨也是会有些自怜;看到别人学又有些嫉妒,自己学又学不进去了😑😶
|
##### 在学校里也是,看到别人放飞自我的玩感到怜惜,自己玩的太嗨也是会有些自怜;看到别人学又有些嫉妒,自己学又学不进去了😑😶
|
||||||
|
|
||||||
就这样吧,又是开学,不想上课
|
就这样吧,又是开学,不想上课
|
||||||
|
|||||||
@@ -1,131 +1,131 @@
|
|||||||
---
|
---
|
||||||
title: 从角色扮演到剧情聊天,翻开AI的另一面 # 文章标题,支持副标题格式(用 - 分隔)
|
title: 从角色扮演到剧情聊天,翻开AI的另一面 # 文章标题,支持副标题格式(用 - 分隔)
|
||||||
top: 3 # 置顶级别:1-3,数字越大越靠前,0表示不置顶
|
top: 3 # 置顶级别:1-3,数字越大越靠前,0表示不置顶
|
||||||
date: 2025-04-08 18:00:00 # 发布日期和时间,格式:YYYY-MM-DD HH:MM:SS
|
date: 2025-04-08 18:00:00 # 发布日期和时间,格式:YYYY-MM-DD HH:MM:SS
|
||||||
descriptionHTML: '
|
descriptionHTML: '
|
||||||
<span style="color:var(--description-font-color);">我与Silly Tavern</span>
|
<span style="color:var(--description-font-color);">我与Silly Tavern</span>
|
||||||
'
|
'
|
||||||
tags: # 文章标签列表,用于分类和搜索
|
tags: # 文章标签列表,用于分类和搜索
|
||||||
- AI
|
- AI
|
||||||
- 酒馆
|
- 酒馆
|
||||||
- 随笔
|
- 随笔
|
||||||
sidebar: true # 是否显示侧边栏:true显示,false隐藏
|
sidebar: true # 是否显示侧边栏:true显示,false隐藏
|
||||||
readingTime: true # 是否显示阅读时间:true显示,false隐藏
|
readingTime: true # 是否显示阅读时间:true显示,false隐藏
|
||||||
hiddenCover: true # 是否隐藏封面图:true隐藏,false显示
|
hiddenCover: true # 是否隐藏封面图:true隐藏,false显示
|
||||||
cover: url # 封面图片路径,相对于public目录
|
cover: url # 封面图片路径,相对于public目录
|
||||||
sticky: 3 # 精选文章设置:值越大在首页展示越靠前,0表示不精选
|
sticky: 3 # 精选文章设置:值越大在首页展示越靠前,0表示不精选
|
||||||
hidden: false # 是否隐藏文章:true隐藏(模板用),false显示(正式文章用)
|
hidden: false # 是否隐藏文章:true隐藏(模板用),false显示(正式文章用)
|
||||||
recommend: true
|
recommend: true
|
||||||
---
|
---
|
||||||
|
|
||||||
# 从角色扮演到剧情聊天,翻开AI的另一面
|
# 从角色扮演到剧情聊天,翻开AI的另一面
|
||||||
|
|
||||||
|
|
||||||
####
|
####
|
||||||
##### 写在前面:
|
##### 写在前面:
|
||||||
####
|
####
|
||||||
|
|
||||||
|
|
||||||
<span style="font-size:0.9em; color:#1976d2;">
|
<span style="font-size:0.9em; color:#1976d2;">
|
||||||
  这个合集我会整理有关大模型发展和应用的一些看法,不会很及时。但是目标是有独特的视角,有深度有温度。这些文章都是拼拼凑凑的所以没有什么配图,如果有也是AI的,或者是一些表情包。敬请谅解😥
|
  这个合集我会整理有关大模型发展和应用的一些看法,不会很及时。但是目标是有独特的视角,有深度有温度。这些文章都是拼拼凑凑的所以没有什么配图,如果有也是AI的,或者是一些表情包。敬请谅解😥
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
## 壹
|
## 壹
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
  第一篇我就写最近接触到的一些东西——AI角色扮演。这类东西其实很早就有了,一般就是通过强制性的提示词<span style="color: #43a047;">(prompt)</span> ,然后大语言模型就会展现出预定的行为或语言效果。
|
  第一篇我就写最近接触到的一些东西——AI角色扮演。这类东西其实很早就有了,一般就是通过强制性的提示词<span style="color: #43a047;">(prompt)</span> ,然后大语言模型就会展现出预定的行为或语言效果。
|
||||||
|
|
||||||
|
|
||||||
  我没有用过这个功能,现在国产很多平台都有角色扮演,从语气到风格都可以模仿。这个不是坏事,大模型发展本来就是多方面的,不是说AI只能用来解题,写代码💻。
|
  我没有用过这个功能,现在国产很多平台都有角色扮演,从语气到风格都可以模仿。这个不是坏事,大模型发展本来就是多方面的,不是说AI只能用来解题,写代码💻。
|
||||||
|
|
||||||
  我一向支持AI全面的发展。对于大模型的管控国家也有政策,现在大模型也有批准上市这个环节。但是只是中国有,国外的模型大多只有一层简单的审查机制😥。所以很多问题就出现在这个环节上。
|
  我一向支持AI全面的发展。对于大模型的管控国家也有政策,现在大模型也有批准上市这个环节。但是只是中国有,国外的模型大多只有一层简单的审查机制😥。所以很多问题就出现在这个环节上。
|
||||||
|
|
||||||
  经常能听说[酒馆](https://github.com/SillyTavern/SillyTavern)<span style="color: #43a047;">(Silly Tavern)</span>这个名字,一开始不以为然,直到有人找到我。前几天有人找到我,要我帮他充值Claude的积分,大概20刀,我只是当做一个简单的客户应付了,结果过了不到半天他就用完了😨?
|
  经常能听说[酒馆](https://github.com/SillyTavern/SillyTavern)<span style="color: #43a047;">(Silly Tavern)</span>这个名字,一开始不以为然,直到有人找到我。前几天有人找到我,要我帮他充值Claude的积分,大概20刀,我只是当做一个简单的客户应付了,结果过了不到半天他就用完了😨?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<span style="font-size:0.9em; color:#1976d2;">
|
<span style="font-size:0.9em; color:#1976d2;">
|
||||||
(大家可能对这个速度没什么概念,举个例子:Claude最贵的3.7-sonnet,每百万token输出15刀,他大约输出了一百三十万token。再说token,大致1 token对应一个中文字符,考虑符号等因素,约1.3 token对应一个汉字。也就是说,一百万汉字的输出量。半天时间,他就用大模型写了一本《红楼梦》(约96万字))!
|
(大家可能对这个速度没什么概念,举个例子:Claude最贵的3.7-sonnet,每百万token输出15刀,他大约输出了一百三十万token。再说token,大致1 token对应一个中文字符,考虑符号等因素,约1.3 token对应一个汉字。也就是说,一百万汉字的输出量。半天时间,他就用大模型写了一本《红楼梦》(约96万字))!
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
####
|
####
|
||||||
|
|
||||||
<img src="/4/1.jpg" alt="1" width="100"/>
|
<img src="/4/1.jpg" alt="1" width="100"/>
|
||||||
|
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
## 贰
|
## 贰
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
  后面他不满足,要我充值了好几个网站,比如[you.com](https://you.com),比如某海外vps。来来回回好几百RMB,其实我赚的不多,我主营就是兜售一些API罢了。后面甚至发了一堆教程给我,让我用电脑帮他建酒馆。
|
  后面他不满足,要我充值了好几个网站,比如[you.com](https://you.com),比如某海外vps。来来回回好几百RMB,其实我赚的不多,我主营就是兜售一些API罢了。后面甚至发了一堆教程给我,让我用电脑帮他建酒馆。
|
||||||
|
|
||||||
  故事到这就是正常给他搭建了,然后收点钱,这个对于我来说易如反掌,但是对于这位朋友却恰恰相反。这样一个完整的云端服务需要很多专业知识,搭建起来后还需要配置API,如果API是国外的还需要中转,API又有两种来路……他竟一窍不通🤔,这个确实颠覆了我的认知,我原以为来找我买API的都是“业内人士”,只是懒得搞海外卡。没想到一个完完全全的小白就涉足这个领域了。
|
  故事到这就是正常给他搭建了,然后收点钱,这个对于我来说易如反掌,但是对于这位朋友却恰恰相反。这样一个完整的云端服务需要很多专业知识,搭建起来后还需要配置API,如果API是国外的还需要中转,API又有两种来路……他竟一窍不通🤔,这个确实颠覆了我的认知,我原以为来找我买API的都是“业内人士”,只是懒得搞海外卡。没想到一个完完全全的小白就涉足这个领域了。
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
## 叁
|
## 叁
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
  后来深入了解,我也第一次使用了酒馆,其实就是个有着奇怪功能和高扩展性的[OpenWebUI](https://ai.zzhdsgsss.xyz/),和我那个平台没什么区别。但是就是这样一个可以用于角色扮演的平台出现了很多灰色地带。
|
  后来深入了解,我也第一次使用了酒馆,其实就是个有着奇怪功能和高扩展性的[OpenWebUI](https://ai.zzhdsgsss.xyz/),和我那个平台没什么区别。但是就是这样一个可以用于角色扮演的平台出现了很多灰色地带。
|
||||||
|
|
||||||
  首当其冲的就是涌入了很多对个性化虚拟对话有需求的玩家,他们可能是二次元,可能是颜色文学的狂热粉,AI浪潮推动他们去解锁本应被限制的功能。其次就是对海外网络的高需求,就是翻墙。
|
  首当其冲的就是涌入了很多对个性化虚拟对话有需求的玩家,他们可能是二次元,可能是颜色文学的狂热粉,AI浪潮推动他们去解锁本应被限制的功能。其次就是对海外网络的高需求,就是翻墙。
|
||||||
|
|
||||||
  最后就是生成的文章被二次转发和利用,如果只是某个正经角色的扮演那没问题,但是敢问这些对话的虚拟对象就不涉及一点黄色问题?诸如此类,那酒馆能不能解锁更多敏感话题?这些敏感话题是AI高速生成的,是不是带来了非常多的问题……
|
  最后就是生成的文章被二次转发和利用,如果只是某个正经角色的扮演那没问题,但是敢问这些对话的虚拟对象就不涉及一点黄色问题?诸如此类,那酒馆能不能解锁更多敏感话题?这些敏感话题是AI高速生成的,是不是带来了非常多的问题……
|
||||||
|
|
||||||
  不过后来我也懂了,可能更多的人都是依此来满足自身需求的。这或许是新时代逃避社会的一种方式罢了,就像上个世纪末本世纪初,青年一代成溺于游戏机,以此逃避社会;也像这几年大家抱起手机就刷短视频,同样是一种逃避社会的表现。也许在不久的将来,和AI深度的角色对话就是新一代青年逃避社会的方法。
|
  不过后来我也懂了,可能更多的人都是依此来满足自身需求的。这或许是新时代逃避社会的一种方式罢了,就像上个世纪末本世纪初,青年一代成溺于游戏机,以此逃避社会;也像这几年大家抱起手机就刷短视频,同样是一种逃避社会的表现。也许在不久的将来,和AI深度的角色对话就是新一代青年逃避社会的方法。
|
||||||
|
|
||||||
  最后也是很成功,通过反代you白嫖claude,就是延迟很高。不过一个月只要30刀就能无限畅玩,很适合酒馆。
|
  最后也是很成功,通过反代you白嫖claude,就是延迟很高。不过一个月只要30刀就能无限畅玩,很适合酒馆。
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
## 肆
|
## 肆
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
  再简单讲一下酒馆,就算当科普了。酒馆这个平台还是比较简陋,虽说是高扩展性,但是一般人都要依靠别人的预设来做一些大模型破限之类的事情。酒馆主要就是三大部分:
|
  再简单讲一下酒馆,就算当科普了。酒馆这个平台还是比较简陋,虽说是高扩展性,但是一般人都要依靠别人的预设来做一些大模型破限之类的事情。酒馆主要就是三大部分:
|
||||||
|
|
||||||
- **预设**:属于永久prompt,主要是规范提交给大模型的提示词,比如有多少上下文,模型的Temperature、Top-k和Top-p,还有一些强制性的提示词规范大模型回答。
|
- **预设**:属于永久prompt,主要是规范提交给大模型的提示词,比如有多少上下文,模型的Temperature、Top-k和Top-p,还有一些强制性的提示词规范大模型回答。
|
||||||
|
|
||||||
- **世界书**:属于永久prompt,提供故事背景和线索,也有人物和角色,为什么酒馆在对话中保持在同一个故事就是依靠这个东西。
|
- **世界书**:属于永久prompt,提供故事背景和线索,也有人物和角色,为什么酒馆在对话中保持在同一个故事就是依靠这个东西。
|
||||||
|
|
||||||
- **卡片**:一个神奇的png图片。卡片一般会自带正则表达式和世界书,我第一次去找卡片测试很幸运是JSON的,我非常确信我找对了。结果第二次发现根本没有JSON文件,帖子里面写到:“卡和说明”,然后配了两张图。后面才知道原来卡真的只是一张图,应该是在base64编码时把世界书和预设编进去了。<span style="color: #43a047;">(这招真的是绝啊)</span>
|
- **卡片**:一个神奇的png图片。卡片一般会自带正则表达式和世界书,我第一次去找卡片测试很幸运是JSON的,我非常确信我找对了。结果第二次发现根本没有JSON文件,帖子里面写到:“卡和说明”,然后配了两张图。后面才知道原来卡真的只是一张图,应该是在base64编码时把世界书和预设编进去了。<span style="color: #43a047;">(这招真的是绝啊)</span>
|
||||||
|
|
||||||
<img src="/4/2.jpg" alt="1" width="200"/>
|
<img src="/4/2.jpg" alt="1" width="200"/>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
## 伍
|
## 伍
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
  最后完整的prompt就是由世界书,用户自己定义的自我角色,预设,对话记录,当前对话组成。大模型返回的长文本由于已经格式化,之后不同的区块被记录在不同的地方,比如实时故事进展的表格,物品或者线索……
|
  最后完整的prompt就是由世界书,用户自己定义的自我角色,预设,对话记录,当前对话组成。大模型返回的长文本由于已经格式化,之后不同的区块被记录在不同的地方,比如实时故事进展的表格,物品或者线索……
|
||||||
|
|
||||||
  总的看下来这是一个非常消耗token的东西,如果真的能够提供等额的情绪价值那确实是个不错的东西,相反,如果毫无意义,那么就是给大模型厂商送钱。
|
  总的看下来这是一个非常消耗token的东西,如果真的能够提供等额的情绪价值那确实是个不错的东西,相反,如果毫无意义,那么就是给大模型厂商送钱。
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
## 陆
|
## 陆
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
#### <span style="color: #d32f2f;">所以,Anthropic,你封我号,什么时候给我退钱</span>
|
#### <span style="color: #d32f2f;">所以,Anthropic,你封我号,什么时候给我退钱</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
####
|
####
|
||||||
|
|
||||||
<img src="/4/3.gif" alt="1" width="300"/>
|
<img src="/4/3.gif" alt="1" width="300"/>
|
||||||
|
|
||||||
[文章原发布于我的微信公众号,稍有修改](https://mp.weixin.qq.com/s/3FHP6BL50yLm9E9wL4APoQ)
|
[文章原发布于我的微信公众号,稍有修改](https://mp.weixin.qq.com/s/3FHP6BL50yLm9E9wL4APoQ)
|
||||||
@@ -1,95 +1,95 @@
|
|||||||
---
|
---
|
||||||
title: 区块链·web3·虚拟币·稳定币
|
title: 区块链·web3·虚拟币·稳定币
|
||||||
top: 0
|
top: 0
|
||||||
date: 2025-09-23 12:00:00
|
date: 2025-09-23 12:00:00
|
||||||
descriptionHTML: '
|
descriptionHTML: '
|
||||||
<span style="color:var(--description-font-color);">随便聊聊区块链、web3、虚拟币和稳定币。</span>
|
<span style="color:var(--description-font-color);">随便聊聊区块链、web3、虚拟币和稳定币。</span>
|
||||||
'
|
'
|
||||||
tags:
|
tags:
|
||||||
- 区块链
|
- 区块链
|
||||||
- web3
|
- web3
|
||||||
- 随笔
|
- 随笔
|
||||||
sidebar: true
|
sidebar: true
|
||||||
readingTime: true
|
readingTime: true
|
||||||
hiddenCover: false
|
hiddenCover: false
|
||||||
sticky: 0
|
sticky: 0
|
||||||
hidden: false
|
hidden: false
|
||||||
recommend: true
|
recommend: true
|
||||||
publish: true
|
publish: true
|
||||||
---
|
---
|
||||||
|
|
||||||
# 区块链·web3·虚拟币·稳定币
|
# 区块链·web3·虚拟币·稳定币
|
||||||
|
|
||||||
####
|
####
|
||||||
##### 写在前面:
|
##### 写在前面:
|
||||||
####
|
####
|
||||||
|
|
||||||
|
|
||||||
<span style="font-size:0.9em; color:#1976d2;">
|
<span style="font-size:0.9em; color:#1976d2;">
|
||||||
  比特币这个东西炒了很久了,从中本聪,到挖矿,到区块链。现在美国和香港都在稳定币方面有所动作。
|
  比特币这个东西炒了很久了,从中本聪,到挖矿,到区块链。现在美国和香港都在稳定币方面有所动作。
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
## 文中将出现的专有名词介绍
|
## 文中将出现的专有名词介绍
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 区块链
|
### 区块链
|
||||||
|
|
||||||
  区块链是一种革命性的分布式数据库技术。想象一个由许多计算机共同维护的数字账本,任何新的交易(或数据)都会被打包成一个“区块”,并通过密码学方法安全地连接到前一个区块,形成一条不可中断的“链”。这个账本不是由任何单一实体控制,而是分布在网络中的所有参与者之间,因此具有高度的**去中心化**特性。其核心特点包括:
|
  区块链是一种革命性的分布式数据库技术。想象一个由许多计算机共同维护的数字账本,任何新的交易(或数据)都会被打包成一个“区块”,并通过密码学方法安全地连接到前一个区块,形成一条不可中断的“链”。这个账本不是由任何单一实体控制,而是分布在网络中的所有参与者之间,因此具有高度的**去中心化**特性。其核心特点包括:
|
||||||
- **不可篡改性**:一旦数据被记录到区块链上,就极难被修改或删除。
|
- **不可篡改性**:一旦数据被记录到区块链上,就极难被修改或删除。
|
||||||
- **透明性**:虽然参与者的真实身份可以是匿名的,但交易记录本身对网络中的所有参与者都是公开可见的。
|
- **透明性**:虽然参与者的真实身份可以是匿名的,但交易记录本身对网络中的所有参与者都是公开可见的。
|
||||||
- **安全性**:通过密码学和共识机制(如工作量证明PoW或权益证明PoS)来确保网络的安全和数据的一致性。
|
- **安全性**:通过密码学和共识机制(如工作量证明PoW或权益证明PoS)来确保网络的安全和数据的一致性。
|
||||||
|
|
||||||
|
|
||||||
### Web3
|
### Web3
|
||||||
|
|
||||||
  Web3被视为互联网的下一个演进阶段,旨在解决当前Web2时代由少数科技巨头主导的中心化问题。如果说Web1是“只读”的(用户只能消费内容),Web2是“读写”的(用户可以创造内容,但平台拥有数据),那么Web3就是“读-写-拥有”的。
|
  Web3被视为互联网的下一个演进阶段,旨在解决当前Web2时代由少数科技巨头主导的中心化问题。如果说Web1是“只读”的(用户只能消费内容),Web2是“读写”的(用户可以创造内容,但平台拥有数据),那么Web3就是“读-写-拥有”的。
|
||||||
|
|
||||||
  它基于区块链技术,核心理念是构建一个**去中心化**的网络。在这个网络中,用户通过自己的加密钱包管理数字身份和数据,而不是依赖于传统的用户名和密码。这催生了去中心化应用(dApps)、去中心化自治组织(DAOs)等新形态,用户不仅是使用者,更是网络的参与者和所有者。
|
  它基于区块链技术,核心理念是构建一个**去中心化**的网络。在这个网络中,用户通过自己的加密钱包管理数字身份和数据,而不是依赖于传统的用户名和密码。这催生了去中心化应用(dApps)、去中心化自治组织(DAOs)等新形态,用户不仅是使用者,更是网络的参与者和所有者。
|
||||||
|
|
||||||
|
|
||||||
### 虚拟币
|
### 虚拟币
|
||||||
|
|
||||||
  虚拟币,通常被称为加密货币,是构建在区块链技术之上的数字资产。它们使用密码学来确保交易安全并控制新单位的创建。我们可以将其分为两大类:
|
  虚拟币,通常被称为加密货币,是构建在区块链技术之上的数字资产。它们使用密码学来确保交易安全并控制新单位的创建。我们可以将其分为两大类:
|
||||||
- **原生币(Coin)**:如比特币(BTC)和以太坊(ETH),它们是各自区块链网络的原生资产,主要用于支付网络交易费用(Gas Fee)和激励网络维护者(矿工或验证者)。
|
- **原生币(Coin)**:如比特币(BTC)和以太坊(ETH),它们是各自区块链网络的原生资产,主要用于支付网络交易费用(Gas Fee)和激励网络维护者(矿工或验证者)。
|
||||||
- **代币(Token)**:它们构建在现有的区块链之上(如以太坊上的ERC-20代币),可以代表各种价值,如公司的股份、数字艺术品(NFT)、或者某个去中心化应用的功能性通证。
|
- **代币(Token)**:它们构建在现有的区块链之上(如以太坊上的ERC-20代币),可以代表各种价值,如公司的股份、数字艺术品(NFT)、或者某个去中心化应用的功能性通证。
|
||||||
|
|
||||||
|
|
||||||
### 挖矿
|
### 挖矿
|
||||||
|
|
||||||
  在区块链的世界里,“挖矿”是一个形象的比喻,它指的是验证和记录交易到区块链上的过程。在像比特币这样的网络中,计算机(矿工)需要竞争解决一个复杂的数学难题。第一个成功解决难题的矿工,就有权将最新的交易打包成一个新区块,并将其添加到链上。作为回报,该矿工会获得一定数量的新发行的虚拟币和交易手续费。这个过程不仅创造了新的货币,更重要的是,它通过去中心化的方式确保了整个网络的安全和一致性。
|
  在区块链的世界里,“挖矿”是一个形象的比喻,它指的是验证和记录交易到区块链上的过程。在像比特币这样的网络中,计算机(矿工)需要竞争解决一个复杂的数学难题。第一个成功解决难题的矿工,就有权将最新的交易打包成一个新区块,并将其添加到链上。作为回报,该矿工会获得一定数量的新发行的虚拟币和交易手续费。这个过程不仅创造了新的货币,更重要的是,它通过去中心化的方式确保了整个网络的安全和一致性。
|
||||||
|
|
||||||
### 工作量证明 (PoW) & 股权证明 (PoS)
|
### 工作量证明 (PoW) & 股权证明 (PoS)
|
||||||
|
|
||||||
这是两种最主流的区块链**共识机制**,用于确保所有参与者对账本状态达成一致。
|
这是两种最主流的区块链**共识机制**,用于确保所有参与者对账本状态达成一致。
|
||||||
|
|
||||||
  **工作量证明 (Proof of Work, PoW)**:这是比特币所采用的经典机制。矿工们需要投入大量的计算资源(工作量也就是GPU计算)来竞争解决一个数学难题。谁先解决,谁就获得了记账权。这种机制的优点是极其安全,因为攻击者需要掌握超过全网51%的算力才能篡改账本,成本极高。缺点是能源消耗巨大,被广为诟病。
|
  **工作量证明 (Proof of Work, PoW)**:这是比特币所采用的经典机制。矿工们需要投入大量的计算资源(工作量也就是GPU计算)来竞争解决一个数学难题。谁先解决,谁就获得了记账权。这种机制的优点是极其安全,因为攻击者需要掌握超过全网51%的算力才能篡改账本,成本极高。缺点是能源消耗巨大,被广为诟病。
|
||||||
|
|
||||||
  **股权证明 (Proof of Stake, PoS)**:这是以太坊等新一代区块链采用的机制。在这种模式下,不再需要进行大规模的计算竞赛。取而代之的是,用户可以质押(Stake)自己的虚拟币来成为“验证者”。系统会根据质押数量的多少和时间长短等因素,随机选择一个验证者来创建新区块。如果验证者作恶,其质押的虚拟币将被罚没。PoS机制极大地降低了能源消耗,被认为是更环保、更高效的共识方案。
|
  **股权证明 (Proof of Stake, PoS)**:这是以太坊等新一代区块链采用的机制。在这种模式下,不再需要进行大规模的计算竞赛。取而代之的是,用户可以质押(Stake)自己的虚拟币来成为“验证者”。系统会根据质押数量的多少和时间长短等因素,随机选择一个验证者来创建新区块。如果验证者作恶,其质押的虚拟币将被罚没。PoS机制极大地降低了能源消耗,被认为是更环保、更高效的共识方案。
|
||||||
|
|
||||||
### 稳定币
|
### 稳定币
|
||||||
|
|
||||||
  稳定币是一种价值相对稳定的虚拟币,通常与某种法定货币(如美元)挂钩,以减少价格波动。近年来,各国监管机构也开始密切关注稳定币的发展。
|
  稳定币是一种价值相对稳定的虚拟币,通常与某种法定货币(如美元)挂钩,以减少价格波动。近年来,各国监管机构也开始密切关注稳定币的发展。
|
||||||
|
|
||||||
  **美国方面**,国会和监管机构一直在积极探讨稳定币的监管框架。多项法案被提出,旨在为稳定币发行方建立明确的银行级或类似的监管标准,要求其具备充足的储备金并接受定期审计。此举旨在保护消费者、防范金融风险,并确保美元在数字资产时代的主导地位。像USDC的发行方Circle,就是一家受美国监管的公司。
|
  **美国方面**,国会和监管机构一直在积极探讨稳定币的监管框架。多项法案被提出,旨在为稳定币发行方建立明确的银行级或类似的监管标准,要求其具备充足的储备金并接受定期审计。此举旨在保护消费者、防范金融风险,并确保美元在数字资产时代的主导地位。像USDC的发行方Circle,就是一家受美国监管的公司。
|
||||||
|
|
||||||
  **香港方面**,则表现出更为积极和开放的态度,力图成为全球Web3和虚拟资产的中心。香港金融管理局(HKMA)已经发布了关于稳定币的监管咨询文件,并计划推出“沙盒”安排,允许机构在受控环境中试行稳定币发行。其目标是建立一个明确的许可制度,规范稳定币发行方的储备管理、所有权和赎回机制,以吸引合规的虚拟资产业务落户香港。
|
  **香港方面**,则表现出更为积极和开放的态度,力图成为全球Web3和虚拟资产的中心。香港金融管理局(HKMA)已经发布了关于稳定币的监管咨询文件,并计划推出“沙盒”安排,允许机构在受控环境中试行稳定币发行。其目标是建立一个明确的许可制度,规范稳定币发行方的储备管理、所有权和赎回机制,以吸引合规的虚拟资产业务落户香港。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
## 壹
|
## 壹
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
我第一次接触到这类虚拟货币,不是搞投资,也不是炒币。因为有很多国外的服务要充值,比如ChatGPT,Claude。有些服务虽然是白嫖的,但是还是需要卡里有钱来验证。但是实体卡是开不了的,只能找虚拟卡。常见的虚拟卡都是和虚拟币挂钩的,不过现在想想确实虚拟币解决了跨境支付的问题。
|
我第一次接触到这类虚拟货币,不是搞投资,也不是炒币。因为有很多国外的服务要充值,比如ChatGPT,Claude。有些服务虽然是白嫖的,但是还是需要卡里有钱来验证。但是实体卡是开不了的,只能找虚拟卡。常见的虚拟卡都是和虚拟币挂钩的,不过现在想想确实虚拟币解决了跨境支付的问题。
|
||||||
|
|
||||||
我唯一受益的点在于能避开各类政策和法律的围堵,然后把钱给到中介,中介又帮我把钱给到商家。但是对于炒作虚拟币,似乎不太行,因为虚拟货币的价值似乎一直是个迷。
|
我唯一受益的点在于能避开各类政策和法律的围堵,然后把钱给到中介,中介又帮我把钱给到商家。但是对于炒作虚拟币,似乎不太行,因为虚拟货币的价值似乎一直是个迷。
|
||||||
|
|
||||||
基于我浅陋的认知,我来举个小小的例子:如果我来发行一个虚拟货币,就叫辛木币,如果做成和比特币一样的机制,那么就可以通过挖矿来计算出区块,然后基于辛木币的规则给这个人发币。但是最为重点的价格何来呢?这个就是共识机制,得大家都认可他的价值才有用。比如此时我和我开的便利店店挂钩,你可以用一辛木币来换一瓶水(早期挖矿效率极高,工作量证明也越多)。后面慢慢的很多大老板都有了我的辛木币,他们也支持辛木币交易,那么辛木币的价值在这个圈子里面就慢慢升值了。只要这个圈子够大,辛木币的价值够大,就和今天的比特币一样。说到虚拟货币,几乎都知道比特币。
|
基于我浅陋的认知,我来举个小小的例子:如果我来发行一个虚拟货币,就叫辛木币,如果做成和比特币一样的机制,那么就可以通过挖矿来计算出区块,然后基于辛木币的规则给这个人发币。但是最为重点的价格何来呢?这来自于**价值共识**。技术上的共识机制(如PoW)保证了辛木币无法被伪造和双花,但它的市场价格,则需要大家都认可它的价值才有用。比如此时我和我开的便利店店挂钩,你可以用一辛木币来换一瓶水(早期挖矿效率极高,工作量证明也越多)。后面慢慢的很多大老板都有了我的辛木币,他们也支持辛木币交易,那么辛木币的价值在这个圈子里面就慢慢升值了。只要这个圈子够大,辛木币的价值够大,就和今天的比特币一样。说到虚拟货币,几乎都知道比特币。
|
||||||
|
|
||||||
那么在价值挂钩这一步,是不是可以是黄金,期权,股权,石油……现在的稳定币就是和美元挂钩,挖矿机制也和比特币的挖矿不一样了。比特币纯靠GPU计算哈希值,稳定币的挖矿就靠质押,靠股权(如USDT的PoS股权证明),也靠兑换(GUSD的美元兑换)
|
那么在价值挂钩这一步,是不是可以是黄金,期权,股权,石油……现在的稳定币就是和美元挂钩,挖矿机制也和比特币的挖矿不一样了。比特币纯靠GPU计算哈希值,稳定币的挖矿就靠质押,靠股权(如USDT的PoS股权证明),也靠兑换(GUSD的美元兑换)
|
||||||
|
|
||||||
|
|
||||||
(没写完,后面慢慢写)………………………………
|
(没写完,后面慢慢写)………………………………
|
||||||
@@ -1,158 +1,158 @@
|
|||||||
---
|
---
|
||||||
title: 身份、地位、家庭、学历是如何裹挟中国人的一生的? # 文章标题,支持副标题格式(用 - 分隔)
|
title: 身份、地位、家庭、学历是如何裹挟中国人的一生的? # 文章标题,支持副标题格式(用 - 分隔)
|
||||||
top: 2 # 置顶级别:1-3,数字越大越靠前,0表示不置顶
|
top: 2 # 置顶级别:1-3,数字越大越靠前,0表示不置顶
|
||||||
date: 2025-09-13 22:00:00 # 发布日期和时间,格式:YYYY-MM-DD HH:MM:SS
|
date: 2025-09-13 22:00:00 # 发布日期和时间,格式:YYYY-MM-DD HH:MM:SS
|
||||||
descriptionHTML: '
|
descriptionHTML: '
|
||||||
<span style="color:var(--description-font-color);">来聊聊网红户晨风</span>
|
<span style="color:var(--description-font-color);">来聊聊网红户晨风</span>
|
||||||
'
|
'
|
||||||
tags: # 文章标签列表,用于分类和搜索
|
tags: # 文章标签列表,用于分类和搜索
|
||||||
- 随笔
|
- 随笔
|
||||||
sidebar: true # 是否显示侧边栏:true显示,false隐藏
|
sidebar: true # 是否显示侧边栏:true显示,false隐藏
|
||||||
readingTime: true # 是否显示阅读时间:true显示,false隐藏
|
readingTime: true # 是否显示阅读时间:true显示,false隐藏
|
||||||
hiddenCover: false
|
hiddenCover: false
|
||||||
sticky: 4 # 精选文章设置:值越大在首页展示越靠前,0表示不精选
|
sticky: 4 # 精选文章设置:值越大在首页展示越靠前,0表示不精选
|
||||||
hidden: false # 是否隐藏文章:true隐藏(模板用),false显示(正式文章用)
|
hidden: false # 是否隐藏文章:true隐藏(模板用),false显示(正式文章用)
|
||||||
recommend: true
|
recommend: true
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
# 身份、地位、家庭、学历是如何裹挟中国人的一生的?
|
# 身份、地位、家庭、学历是如何裹挟中国人的一生的?
|
||||||
|
|
||||||
####
|
####
|
||||||
##### 写在前面:
|
##### 写在前面:
|
||||||
####
|
####
|
||||||
|
|
||||||
<span style="font-size:0.9em; color:#1976d2;">
|
<span style="font-size:0.9em; color:#1976d2;">
|
||||||
“什么学历,父母是做什么的,用什么手机?”这是网红户晨风直播连麦的灵魂三问。三个问题就可以大致能描绘一个人认知,地位,经济情况。本文将会围绕户晨风的视频直播,以及他在自媒体中发表的观点讲起,来谈谈身份、地位、家庭、学历是如何裹挟中国人的一生的?
|
“什么学历,父母是做什么的,用什么手机?”这是网红户晨风直播连麦的灵魂三问。三个问题就可以大致能描绘一个人认知,地位,经济情况。本文将会围绕户晨风的视频直播,以及他在自媒体中发表的观点讲起,来谈谈身份、地位、家庭、学历是如何裹挟中国人的一生的?
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
## 文中将出现的人物简介以及专有名词介绍
|
## 文中将出现的人物简介以及专有名词介绍
|
||||||
|
|
||||||
### 户晨风
|
### 户晨风
|
||||||
####
|
####
|
||||||
<span style="font-size:0.9em;">
|
<span style="font-size:0.9em;">
|
||||||
  国际高中肄业,干过汽修工,后投身于股市,当过私募基金研究员,后因投资失败被公司裁员,2023年开始短视频的拍摄。模仿国外博主拍摄购买力视频获取流量,后因拍摄内容涉及国内社保相关情况,部分内容违反社区规定,被封号至2024年4月。之后转战国外,拍摄国外购买力视频,同时,国内转为拍摄随机送路人钱<span style="color: #43a047;">(大多确为普通百姓)</span>。除以上两种视频内容,每个月户晨风还公开自己的收入情况。
|
  国际高中肄业,干过汽修工,后投身于股市,当过私募基金研究员,后因投资失败被公司裁员,2023年开始短视频的拍摄。模仿国外博主拍摄购买力视频获取流量,后因拍摄内容涉及国内社保相关情况,部分内容违反社区规定,被封号至2024年4月。之后转战国外,拍摄国外购买力视频,同时,国内转为拍摄随机送路人钱<span style="color: #43a047;">(大多确为普通百姓)</span>。除以上两种视频内容,每个月户晨风还公开自己的收入情况。
|
||||||
|
|
||||||
  但直播却与本人拍摄视频基本无关,户晨风在直播间发表自己的言论,包括但不限于:手机就是苹果,汽车就是特斯拉,超市就是山姆,推崇中医无用,推崇高铁私有化等。
|
  但直播却与本人拍摄视频基本无关,户晨风在直播间发表自己的言论,包括但不限于:手机就是苹果,汽车就是特斯拉,超市就是山姆,推崇中医无用,推崇高铁私有化等。
|
||||||
|
|
||||||
  连麦的网友大多是反对户晨风的,同时也有一部分网友支持户晨风给予户晨风打赏,成为户晨风收入主要来源。由于他所推崇的东西几乎都是国外的,在当今爱国主义是社会核心价值观的时代,有人对户晨风的言论表示反对。
|
  连麦的网友大多是反对户晨风的,同时也有一部分网友支持户晨风给予户晨风打赏,成为户晨风收入主要来源。由于他所推崇的东西几乎都是国外的,在当今爱国主义是社会核心价值观的时代,有人对户晨风的言论表示反对。
|
||||||
|
|
||||||
  2025年9月,户晨风在带货方面收获颇丰,同时借助知名度在淘宝售卖祝福视频,且单个视频价格不低<span style="color: #43a047;">(如图,仅有2999元档)</span>。本人在直播中表示本月收入超过60万。
|
  2025年9月,户晨风在带货方面收获颇丰,同时借助知名度在淘宝售卖祝福视频,且单个视频价格不低<span style="color: #43a047;">(如图,仅有2999元档)</span>。本人在直播中表示本月收入超过60万。
|
||||||
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
### 商品拜物教
|
### 商品拜物教
|
||||||
####
|
####
|
||||||
<span style="font-size:0.9em;">
|
<span style="font-size:0.9em;">
|
||||||
  商品拜物教是马克思在《资本论》中提出的概念,指商品的社会属性<span style="color: #43a047;">(人与人的劳动交换关系)</span>被物的自然属性掩盖,人们像崇拜神一样追逐商品,将其视为能支配生活的神秘力量,且商品交换越普遍,这种“拜物”倾向越明显。
|
  商品拜物教是马克思在《资本论》中提出的概念,指商品的社会属性<span style="color: #43a047;">(人与人的劳动交换关系)</span>被物的自然属性掩盖,人们像崇拜神一样追逐商品,将其视为能支配生活的神秘力量,且商品交换越普遍,这种“拜物”倾向越明显。
|
||||||
|
|
||||||
  它的核心是掩盖商品背后人与人的关系:商品价值源于人类抽象劳动,但在市场中,价值通过价格波动、供求关系体现,仿佛是商品自身的“魔力”,而非劳动者创造。
|
  它的核心是掩盖商品背后人与人的关系:商品价值源于人类抽象劳动,但在市场中,价值通过价格波动、供求关系体现,仿佛是商品自身的“魔力”,而非劳动者创造。
|
||||||
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
## 壹
|
## 壹
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
  我比较早就关注到户晨风了,因为他的一些理论确实很敏感,按理说国内互联网是很少有些些言论的。其实他的理论不是说简单的吹捧美国,或者西方的东西,以此来贬低国内的。只是他刻意避开中国好的一些东西,只议论西方优秀的部分和国内做的不足的部分。而后他慢慢转向为追从好的东西,追从贵的东西。
|
  我比较早就关注到户晨风了,因为他的一些理论确实很敏感,按理说国内互联网是很少有些些言论的。其实他的理论不是说简单的吹捧美国,或者西方的东西,以此来贬低国内的。只是他刻意避开中国好的一些东西,只议论西方优秀的部分和国内做的不足的部分。而后他慢慢转向为追从好的东西,追从贵的东西。
|
||||||
|
|
||||||
他的直播间从多数人看来就是<span style="color: #1976d2;">**崇洋媚外**</span>,有这几个证据,我也讲讲我的看法:
|
他的直播间从多数人看来就是<span style="color: #1976d2;">**崇洋媚外**</span>,有这几个证据,我也讲讲我的看法:
|
||||||
|
|
||||||
- 第一,他宣扬中医无用论。理由是没有通过临床双盲实验<span style="color: #43a047;">(不得不说,为了这些,一个没有什么文化的人能研究这么深,属实不易,这也是他能成功的原因之一)</span> ,这给根生于中华传统文化的中华儿女带来了冲击感。
|
- 第一,他宣扬中医无用论。理由是没有通过临床双盲实验<span style="color: #43a047;">(不得不说,为了这些,一个没有什么文化的人能研究这么深,属实不易,这也是他能成功的原因之一)</span> ,这给根生于中华传统文化的中华儿女带来了冲击感。
|
||||||
|
|
||||||
基本上所有中国人都受到过中医的治疗,只是说在西医和医学科学的理论下,中医的作用没有科学的理论性,但是不代表无法用于治疗。就像下面这个数学公式,拉马努金没法给出推到过程,但是不妨碍这是正确的等式。我第一次看到这个式子的时候就觉得他和中医很像,但是确实不妨碍这是正确的。
|
基本上所有中国人都受到过中医的治疗,只是说在西医和医学科学的理论下,中医的作用没有科学的理论性,但是不代表无法用于治疗。就像下面这个数学公式,拉马努金没法给出推到过程,但是不妨碍这是正确的等式。我第一次看到这个式子的时候就觉得他和中医很像,但是确实不妨碍这是正确的。
|
||||||
$$
|
$$
|
||||||
\frac{1}{\pi}
|
\frac{1}{\pi}
|
||||||
=\frac{2\sqrt{2}}{9801}\sum_{k=0}^{\infty}
|
=\frac{2\sqrt{2}}{9801}\sum_{k=0}^{\infty}
|
||||||
\frac{(4k)!}{(k!)^4}\,
|
\frac{(4k)!}{(k!)^4}\,
|
||||||
\frac{1103+26390k}{396^{4k}}
|
\frac{1103+26390k}{396^{4k}}
|
||||||
$$
|
$$
|
||||||
- 第二,他宣称高铁私有化。其实我是不大赞同,他可能没有考虑到铁路具有的**战略意义**。如果国家处于战时,铁路是最好的运输方式,陆运太慢,而且效率很低,空运太贵,不能让大部分的经济用于空运。至少近二十年内,铁路还是战时重要的运输路线,铁路被炸了,有抢修队,没电就烧油,没油甚至可以用蒸汽机车。所以铁路必须归国有,因为他具有战略意义。
|
- 第二,他宣称高铁私有化。其实我是不大赞同,他可能没有考虑到铁路具有的**战略意义**。如果国家处于战时,铁路是最好的运输方式,陆运太慢,而且效率很低,空运太贵,不能让大部分的经济用于空运。至少近二十年内,铁路还是战时重要的运输路线,铁路被炸了,有抢修队,没电就烧油,没油甚至可以用蒸汽机车。所以铁路必须归国有,因为他具有战略意义。
|
||||||
|
|
||||||
- 第三,他还宣称手机就用 iPhone。可能他目标的粉丝人群就是介于能买 iPhone 的用户们,因为再往上的人群可能确实选择 iPhone 较多,或者是折叠屏手机<span style="color: #43a047;">(?总之不会是两三千的手机)</span>。户晨风就抓住这批人的想法,抨击安卓机,鼓吹 iPhone。
|
- 第三,他还宣称手机就用 iPhone。可能他目标的粉丝人群就是介于能买 iPhone 的用户们,因为再往上的人群可能确实选择 iPhone 较多,或者是折叠屏手机<span style="color: #43a047;">(?总之不会是两三千的手机)</span>。户晨风就抓住这批人的想法,抨击安卓机,鼓吹 iPhone。
|
||||||
|
|
||||||
其实我们确实需要承认苹果的产品是不错的,但是起步就是 6k<span style="color: #43a047;">(最低配 256GB 内存,多半不适合很多人使用)</span>,真的是所有人能消费得起的吗?城镇居民人均可支配收入中位数 **49302** 元,农村居民人均可支配收入中位数 **19605** 元$^{[1]}$。意味着半数以上的农村居民不可能购买 iPhone,半数以内的城镇居民需要花费年收入八分之一用于支付手机费用。即使是用五年,也是一笔不小的支出。:expressionless:
|
其实我们确实需要承认苹果的产品是不错的,但是起步就是 6k<span style="color: #43a047;">(最低配 256GB 内存,多半不适合很多人使用)</span>,真的是所有人能消费得起的吗?城镇居民人均可支配收入中位数 **49302** 元,农村居民人均可支配收入中位数 **19605** 元$^{[1]}$。意味着半数以上的农村居民不可能购买 iPhone,半数以内的城镇居民需要花费年收入八分之一用于支付手机费用。即使是用五年,也是一笔不小的支出。:expressionless:
|
||||||
|
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
## 贰
|
## 贰
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
  还有很多琐碎的观点不胜枚举,户晨风的观点其实早已不在于对错与否,这样的观点是漏洞百出、以偏概全的。**但是,恰恰这样的观点才是互联网需要的**。当下的互联网各类人群聚集,能让很多人透过互联网看到不一样的世界,有人养尊处优,第一次看到别人生活清贫;有人出身并不富贵,第一次看到别人开豪车住豪宅……
|
  还有很多琐碎的观点不胜枚举,户晨风的观点其实早已不在于对错与否,这样的观点是漏洞百出、以偏概全的。**但是,恰恰这样的观点才是互联网需要的**。当下的互联网各类人群聚集,能让很多人透过互联网看到不一样的世界,有人养尊处优,第一次看到别人生活清贫;有人出身并不富贵,第一次看到别人开豪车住豪宅……
|
||||||
|
|
||||||
  时至今日,社会的差异还是存在的,贫富差异、地域差距、认知差异……。中产和中产的孩子们,是户晨风直播间连线的香饽饽,他们可能是留学,可能是展示家财万贯,因为户晨风总是投来向往的羡慕的目光和表达夸张的赞誉。反观普通人,户晨风讨厌低学历,讨厌那些家里是普普通通的人,户晨风总是展现着一种嫌弃的厌恶的目光和不断发出诋毁和说教。
|
  时至今日,社会的差异还是存在的,贫富差异、地域差距、认知差异……。中产和中产的孩子们,是户晨风直播间连线的香饽饽,他们可能是留学,可能是展示家财万贯,因为户晨风总是投来向往的羡慕的目光和表达夸张的赞誉。反观普通人,户晨风讨厌低学历,讨厌那些家里是普普通通的人,户晨风总是展现着一种嫌弃的厌恶的目光和不断发出诋毁和说教。
|
||||||
|
|
||||||
  但是户晨风的直播间却毫无意外的只有两种人连麦,他们是谈吐清晰的中产家庭,因为户晨风的反应能给他们带来欢乐,他们把户晨风当做娱乐主播;他们也会是支支吾吾的普通人,因为始终不认命,希望能扳倒这个长相和言语都怪异的主播。我想不明白为什么,可能恰恰是这些人才是户晨风的目标粉丝。
|
  但是户晨风的直播间却毫无意外的只有两种人连麦,他们是谈吐清晰的中产家庭,因为户晨风的反应能给他们带来欢乐,他们把户晨风当做娱乐主播;他们也会是支支吾吾的普通人,因为始终不认命,希望能扳倒这个长相和言语都怪异的主播。我想不明白为什么,可能恰恰是这些人才是户晨风的目标粉丝。
|
||||||
|
|
||||||
  确实,能用苹果的,能开特斯拉的,能逛山姆的已经是中产。户晨风认为自己也是这类人,因为不了解他实际资产之类的隐私信息,但是能确定的是他目前唯一收入就是做自媒体,近半年来的收入也在逐步上升且都不低。也许有一天也能开上特斯拉,也能在某个山姆会员店遇到他。但是世界上还有很多普通人,也许能给普通人更多一些鼓励和建议会更好,还是说没有反差就没法给各位“总”$^{[2]}$带来快乐,就没有收入了?我不知道。 :sleeping:
|
  确实,能用苹果的,能开特斯拉的,能逛山姆的已经是中产。户晨风认为自己也是这类人,因为不了解他实际资产之类的隐私信息,但是能确定的是他目前唯一收入就是做自媒体,近半年来的收入也在逐步上升且都不低。也许有一天也能开上特斯拉,也能在某个山姆会员店遇到他。但是世界上还有很多普通人,也许能给普通人更多一些鼓励和建议会更好,还是说没有反差就没法给各位“总”$^{[2]}$带来快乐,就没有收入了?我不知道。 :sleeping:
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
## 叁
|
## 叁
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
  户晨风在直播间还会问学历,当今的中国确实很看重学历,这是毋庸置疑的。但是学历延伸出来的还是家庭问题。先说国外,普通家庭的孩子很难出国留学,除非是非常厉害的一批作为公派留学。国内的高等教育也不乐观,大部分普通家庭的孩子,要么止步于高考,要么就是在普通本科或者专科毕业后进入就业市场。部分家庭是很难供给到研究生的,或者是希望孩子早早就业……
|
  户晨风在直播间还会问学历,当今的中国确实很看重学历,这是毋庸置疑的。但是学历延伸出来的还是家庭问题。先说国外,普通家庭的孩子很难出国留学,除非是非常厉害的一批作为公派留学。国内的高等教育也不乐观,大部分普通家庭的孩子,要么止步于高考,要么就是在普通本科或者专科毕业后进入就业市场。部分家庭是很难供给到研究生的,或者是希望孩子早早就业……
|
||||||
|
|
||||||
>“太多极有天资的小伙伴因为某次大考差了几分,或者遭遇了学业阶段转换过程中的不适应,或者家庭出现变故,走着走着就变换了人生道路。”$^{[3]}$
|
>“太多极有天资的小伙伴因为某次大考差了几分,或者遭遇了学业阶段转换过程中的不适应,或者家庭出现变故,走着走着就变换了人生道路。”$^{[3]}$
|
||||||
|
|
||||||
>“这样一条通过教育向上流动的道路越是艰辛,个体在这样一个过程中经历的制度不公和隐性歧视越是深重,越说明我们的社会流动之路并不通畅,可能有越来越多的人正在被埋没。”$^{[3]}$
|
>“这样一条通过教育向上流动的道路越是艰辛,个体在这样一个过程中经历的制度不公和隐性歧视越是深重,越说明我们的社会流动之路并不通畅,可能有越来越多的人正在被埋没。”$^{[3]}$
|
||||||
|
|
||||||
>“低阶层的父母不插手,多半是因为没有能力和见识去参与孩子的决策。他们绝大多数从未踏进大学的校门,对大学里发生的一切几乎一无所知。除了精神上的支持和经济上的帮助,他们再无法就子女高中以后的重大决策给出具体的咨询意见了,更不用说指导他们管理大学生活和确立生涯目标。实际上,他们的子女能够超越他们成为全家第一个大学生,已经在很大程度上满足了他们的期望。至于上大学的目标,已经超越了他们的认知范围。”$^{[4]}$
|
>“低阶层的父母不插手,多半是因为没有能力和见识去参与孩子的决策。他们绝大多数从未踏进大学的校门,对大学里发生的一切几乎一无所知。除了精神上的支持和经济上的帮助,他们再无法就子女高中以后的重大决策给出具体的咨询意见了,更不用说指导他们管理大学生活和确立生涯目标。实际上,他们的子女能够超越他们成为全家第一个大学生,已经在很大程度上满足了他们的期望。至于上大学的目标,已经超越了他们的认知范围。”$^{[4]}$
|
||||||
|
|
||||||
<span style="color: #43a047;">(以上摘自其他作者文章,来源已在文末参考文献标注)</span>
|
<span style="color: #43a047;">(以上摘自其他作者文章,来源已在文末参考文献标注)</span>
|
||||||
|
|
||||||
  学历对一个人的影响确实存在,但是当前的中国社会在慢慢放大这个影响,因为社会还是缺少一套标准来评判人。所以学历对个人带来的压力,不亚于经济情况对人带来的压力。社会给不同学历的人分为三教九流,所以这也不是户晨风的主观意愿,只是如果能多方面评价一个人可能会更好。低学历的人并不代表就一事无成。
|
  学历对一个人的影响确实存在,但是当前的中国社会在慢慢放大这个影响,因为社会还是缺少一套标准来评判人。所以学历对个人带来的压力,不亚于经济情况对人带来的压力。社会给不同学历的人分为三教九流,所以这也不是户晨风的主观意愿,只是如果能多方面评价一个人可能会更好。低学历的人并不代表就一事无成。
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 肆
|
## 肆
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
再来说说户晨风的视频。
|
再来说说户晨风的视频。
|
||||||
|
|
||||||
- 第一个是他的公开收入,其实没有什么问题,因为依旧可以造假,就像我也可以公开我的收入,因为互联网是虚拟世界这件事情是板上钉钉的。
|
- 第一个是他的公开收入,其实没有什么问题,因为依旧可以造假,就像我也可以公开我的收入,因为互联网是虚拟世界这件事情是板上钉钉的。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
- 第二是购买力视频,算是发家视频,让墙内$^{[5]}$的人们能看到较为真实的外面的世界。也正是因为这类视频,在国内会采访到一些特殊人群,暴露了这类人群在收入上遇到的困难。让户晨风在多个平台处处碰壁。
|
- 第二是购买力视频,算是发家视频,让墙内$^{[5]}$的人们能看到较为真实的外面的世界。也正是因为这类视频,在国内会采访到一些特殊人群,暴露了这类人群在收入上遇到的困难。让户晨风在多个平台处处碰壁。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
- 第三个是随机送路人钱。这算是几乎没有争议的视频,因为**两千块钱**是真实送出去的<span style="color: #43a047;">(户晨风在直播间中提过以后会加到五千元,可能会带来不一样的视频效果)</span>。虽然他在直播间看不起普通人,但是遇到真正困难的人确实会提供帮助。:+1:
|
- 第三个是随机送路人钱。这算是几乎没有争议的视频,因为**两千块钱**是真实送出去的<span style="color: #43a047;">(户晨风在直播间中提过以后会加到五千元,可能会带来不一样的视频效果)</span>。虽然他在直播间看不起普通人,但是遇到真正困难的人确实会提供帮助。:+1:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
  个人认为户晨风后续的视频只会是这几类,因为视频带来的收益并不可观。在各大社交媒体中,始终是以直播收入为主要来源。所以户晨风应该依旧会在直播中加码,制造更多的效果,借助流量带货,以及博得各位“总”的打赏。
|
  个人认为户晨风后续的视频只会是这几类,因为视频带来的收益并不可观。在各大社交媒体中,始终是以直播收入为主要来源。所以户晨风应该依旧会在直播中加码,制造更多的效果,借助流量带货,以及博得各位“总”的打赏。
|
||||||
|
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
## 伍
|
## 伍
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
  最后,户晨风还有一招,也是罕见的一招。公开在淘宝上售卖祝福视频,这是一个一石二鸟的方法,既宣传自己,又给自己套上了商品的属性:joy:<span style="font-size:0.9em; color:#1976d2;">(文章开头介绍了商品拜物教,但是我却仅在文末提及,如果你能看完我的文章,也看过户晨风的视频还有他的直播切片,你会发现户晨风的方方面面都透露着商品属性以及商品拜物教)</span>
|
  最后,户晨风还有一招,也是罕见的一招。公开在淘宝上售卖祝福视频,这是一个一石二鸟的方法,既宣传自己,又给自己套上了商品的属性:joy:<span style="font-size:0.9em; color:#1976d2;">(文章开头介绍了商品拜物教,但是我却仅在文末提及,如果你能看完我的文章,也看过户晨风的视频还有他的直播切片,你会发现户晨风的方方面面都透露着商品属性以及商品拜物教)</span>
|
||||||
|
|
||||||
  户晨风确实是个矛盾的人,他的视频和直播间是对立矛盾的,他的粉丝群体是对立矛盾的。可恰恰是这样的冲突让户晨风在社交媒体如鱼得水,网络世界的今天,需要的就是激烈的争论才能留住前来的客户。再把目光放回这些引起矛盾的观点,这些关于身份、地位、家庭、学历的话题,在这个时代始终裹挟着中国人,甚至伴随他们一生,倘若多年以后没有人再记得户晨风,倘若多年后户晨风还是需要就业来解决温饱,他确实只是一个高中学历。
|
  户晨风确实是个矛盾的人,他的视频和直播间是对立矛盾的,他的粉丝群体是对立矛盾的。可恰恰是这样的冲突让户晨风在社交媒体如鱼得水,网络世界的今天,需要的就是激烈的争论才能留住前来的客户。再把目光放回这些引起矛盾的观点,这些关于身份、地位、家庭、学历的话题,在这个时代始终裹挟着中国人,甚至伴随他们一生,倘若多年以后没有人再记得户晨风,倘若多年后户晨风还是需要就业来解决温饱,他确实只是一个高中学历。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 参考文献及注释
|
### 参考文献及注释
|
||||||
[1] 中华人民共和国国家统计局. 2024年居民收入和消费支出情况[EB/OL]. (2025-01-17). https://www.stats.gov.cn/sj/zxfb/202501/t20250117_1958325.html.
|
[1] 中华人民共和国国家统计局. 2024年居民收入和消费支出情况[EB/OL]. (2025-01-17). https://www.stats.gov.cn/sj/zxfb/202501/t20250117_1958325.html.
|
||||||
[2] 户晨风在直播间常常以“xx总”称呼打赏的粉丝
|
[2] 户晨风在直播间常常以“xx总”称呼打赏的粉丝
|
||||||
[3] 程猛. “教育改变农家子弟的命运”,究竟改变了什么?[EB/OL]. (2018-09-15). https://yixi.tv/speech/657.
|
[3] 程猛. “教育改变农家子弟的命运”,究竟改变了什么?[EB/OL]. (2018-09-15). https://yixi.tv/speech/657.
|
||||||
[4] 那些原本是废话的常识. 寒门大学生难改命?其实“考上”就已不容易[EB/OL]. (2024-07-22). https://mp.weixin.qq.com/s/P1zKLPHN4efzpkRoGFwDIA.
|
[4] 那些原本是废话的常识. 寒门大学生难改命?其实“考上”就已不容易[EB/OL]. (2024-07-22). https://mp.weixin.qq.com/s/P1zKLPHN4efzpkRoGFwDIA.
|
||||||
[5] 指[防火长城(Great Firewall)](https://zh.wikipedia.org/wiki/%E9%98%B2%E7%81%AB%E9%95%BF%E5%9F%8E)
|
[5] 指[防火长城(Great Firewall)](https://zh.wikipedia.org/wiki/%E9%98%B2%E7%81%AB%E9%95%BF%E5%9F%8E)
|
||||||
@@ -1,431 +1,431 @@
|
|||||||
---
|
---
|
||||||
title: 数字电路笔记
|
title: 数字电路笔记
|
||||||
date: 2025-01-20 15:00:00
|
date: 2025-01-20 15:00:00
|
||||||
descriptionHTML: '<span style="color:var(--description-font-color);">纯情男大自用数字电路基础笔记</span>'
|
descriptionHTML: '<span style="color:var(--description-font-color);">纯情男大自用数字电路基础笔记</span>'
|
||||||
tags:
|
tags:
|
||||||
- 笔记
|
- 笔记
|
||||||
- 数字电路
|
- 数字电路
|
||||||
sidebar: true
|
sidebar: true
|
||||||
readingTime: true
|
readingTime: true
|
||||||
hidden: false
|
hidden: false
|
||||||
recommend: true
|
recommend: true
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
# 数字电路笔记
|
# 数字电路笔记
|
||||||
|
|
||||||
|
|
||||||
## 资料下载
|
## 资料下载
|
||||||
|
|
||||||
|
|
||||||
#### Markdown源码版本
|
#### Markdown源码版本
|
||||||
- **文件名**:数字电路基础.md
|
- **文件名**:数字电路基础.md
|
||||||
- **下载链接**:[点击下载源码版本](https://github.com/handsomezhuzhu/other_note/raw/main/数字电路/数字电路基础.md)
|
- **下载链接**:[点击下载源码版本](https://github.com/handsomezhuzhu/other_note/raw/main/数字电路/数字电路基础.md)
|
||||||
|
|
||||||
#### PDF版本
|
#### PDF版本
|
||||||
- **文件名**:数字电路基础.pdf
|
- **文件名**:数字电路基础.pdf
|
||||||
- **下载链接**:[点击下载PDF版本](https://github.com/handsomezhuzhu/other_note/raw/main/数字电路/数字电路基础.pdf)
|
- **下载链接**:[点击下载PDF版本](https://github.com/handsomezhuzhu/other_note/raw/main/数字电路/数字电路基础.pdf)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 完整笔记
|
## 完整笔记
|
||||||
|
|
||||||
|
|
||||||
## 一、逻辑代数定律和计算规则
|
## 一、逻辑代数定律和计算规则
|
||||||
|
|
||||||
| 定律/规则名称 | 表达式 | 解释 |
|
| 定律/规则名称 | 表达式 | 解释 |
|
||||||
| --------- | ----------------------------------------------------------------------------------- | ------------------- |
|
| --------- | ----------------------------------------------------------------------------------- | ------------------- |
|
||||||
| 恒等律 | $A + 0 = A$<br>$A \cdot 1 = A$ | 任何变量与0相加或与1相乘等于自身 |
|
| 恒等律 | $A + 0 = A$<br>$A \cdot 1 = A$ | 任何变量与0相加或与1相乘等于自身 |
|
||||||
| 零律 | $A + 1 = 1$<br>$A \cdot 0 = 0$ | 任何变量与1相加或与0相乘等于1或0 |
|
| 零律 | $A + 1 = 1$<br>$A \cdot 0 = 0$ | 任何变量与1相加或与0相乘等于1或0 |
|
||||||
| 幂等律 | $A + A = A$<br>$A \cdot A = A$ | 任何变量与自身相加或相乘等于自身 |
|
| 幂等律 | $A + A = A$<br>$A \cdot A = A$ | 任何变量与自身相加或相乘等于自身 |
|
||||||
| 互补律 | $A + \overline{A} = 1$<br>$A \cdot \overline{A} = 0$ | 任何变量与其补码相加等于1,相乘等于0 |
|
| 互补律 | $A + \overline{A} = 1$<br>$A \cdot \overline{A} = 0$ | 任何变量与其补码相加等于1,相乘等于0 |
|
||||||
| **交换律** | | |
|
| **交换律** | | |
|
||||||
| 加法交换律 | $A + B = B + A$ | 加法运算的交换律 |
|
| 加法交换律 | $A + B = B + A$ | 加法运算的交换律 |
|
||||||
| 乘法交换律 | $A \cdot B = B \cdot A$ | 乘法运算的交换律 |
|
| 乘法交换律 | $A \cdot B = B \cdot A$ | 乘法运算的交换律 |
|
||||||
| **结合律** | | |
|
| **结合律** | | |
|
||||||
| 加法结合律 | $(A + B) + C = A + (B + C)$ | 加法运算的结合律 |
|
| 加法结合律 | $(A + B) + C = A + (B + C)$ | 加法运算的结合律 |
|
||||||
| 乘法结合律 | $(A \cdot B) \cdot C = A \cdot (B \cdot C)$ | 乘法运算的结合律 |
|
| 乘法结合律 | $(A \cdot B) \cdot C = A \cdot (B \cdot C)$ | 乘法运算的结合律 |
|
||||||
| **分配律** | | |
|
| **分配律** | | |
|
||||||
| 乘法分配律 | $A \cdot (B + C) = A \cdot B + A \cdot C$ | 乘法对加法的分配律 |
|
| 乘法分配律 | $A \cdot (B + C) = A \cdot B + A \cdot C$ | 乘法对加法的分配律 |
|
||||||
| 加法分配律 | $A + (B \cdot C) = (A + B) \cdot (A + C)$ | 加法对乘法的分配律 |
|
| 加法分配律 | $A + (B \cdot C) = (A + B) \cdot (A + C)$ | 加法对乘法的分配律 |
|
||||||
| **吸收律** | | |
|
| **吸收律** | | |
|
||||||
| 吸收律1 | $A + A \cdot B = A$ | 吸收律的第一种形式 |
|
| 吸收律1 | $A + A \cdot B = A$ | 吸收律的第一种形式 |
|
||||||
| 吸收律2 | $A \cdot (A + B) = A$ | 吸收律的第二种形式 |
|
| 吸收律2 | $A \cdot (A + B) = A$ | 吸收律的第二种形式 |
|
||||||
| **德摩根定律** | | |
|
| **德摩根定律** | | |
|
||||||
| 德摩根定律1 | $\overline{A + B} = \overline{A} \cdot \overline{B}$ | 逻辑加法的德摩根定律 |
|
| 德摩根定律1 | $\overline{A + B} = \overline{A} \cdot \overline{B}$ | 逻辑加法的德摩根定律 |
|
||||||
| 德摩根定律2 | $\overline{A \cdot B} = \overline{A} + \overline{B}$ | 逻辑乘法的德摩根定律 |
|
| 德摩根定律2 | $\overline{A \cdot B} = \overline{A} + \overline{B}$ | 逻辑乘法的德摩根定律 |
|
||||||
| **简化定律** | | |
|
| **简化定律** | | |
|
||||||
| 简化定律1 | $A + \overline{A} \cdot B = A + B$ | 简化逻辑表达式 |
|
| 简化定律1 | $A + \overline{A} \cdot B = A + B$ | 简化逻辑表达式 |
|
||||||
| 简化定律2 | $A \cdot (\overline{A} + B) = A \cdot B$ | 简化逻辑表达式 |
|
| 简化定律2 | $A \cdot (\overline{A} + B) = A \cdot B$ | 简化逻辑表达式 |
|
||||||
| **共识定律** | | |
|
| **共识定律** | | |
|
||||||
| 共识定律 (积之和形式) | $AB + \overline{A}C + BC = AB + \overline{A}C$ | 较难,常用于逻辑化简。项 `BC` 是 `AB` 和 `A`C 的共识项,是冗余的。 |
|
| 共识定律 (积之和形式) | $AB + \overline{A}C + BC = AB + \overline{A}C$ | 较难,常用于逻辑化简。项 `BC` 是 `AB` 和 `A`C 的共识项,是冗余的。 |
|
||||||
| 共识定律 (和之积形式) | $(A+B)(\overline{A}+C)(B+C) = (A+B)(\overline{A}+C)$ | 较难,常用于逻辑化简。项 `(B+C)` 是 `(A+B)` 和 `(A`+C) 的共识项,是冗余的。|
|
| 共识定律 (和之积形式) | $(A+B)(\overline{A}+C)(B+C) = (A+B)(\overline{A}+C)$ | 较难,常用于逻辑化简。项 `(B+C)` 是 `(A+B)` 和 `(A`+C) 的共识项,是冗余的。|
|
||||||
| **反演定律** | | |
|
| **反演定律** | | |
|
||||||
| 反演定律 | $A = \overline{\overline{A}}$ | 变量的双重否定等于自身 |
|
| 反演定律 | $A = \overline{\overline{A}}$ | 变量的双重否定等于自身 |
|
||||||
|
|
||||||
### 推导过程
|
### 推导过程
|
||||||
|
|
||||||
1. **基本定律**
|
1. **基本定律**
|
||||||
- **恒等律**:$A + 0 = A$ 和 $A \cdot 1 = A$ 是逻辑代数的基本定义。
|
- **恒等律**:$A + 0 = A$ 和 $A \cdot 1 = A$ 是逻辑代数的基本定义。
|
||||||
- **零律**:$A + 1 = 1$ 和 $A \cdot 0 = 0$ 也是逻辑代数的基本定义。
|
- **零律**:$A + 1 = 1$ 和 $A \cdot 0 = 0$ 也是逻辑代数的基本定义。
|
||||||
- **幂等律**:$A + A = A$ 和 $A \cdot A = A$ 是因为逻辑加法和乘法运算的特性。
|
- **幂等律**:$A + A = A$ 和 $A \cdot A = A$ 是因为逻辑加法和乘法运算的特性。
|
||||||
- **互补律**:$A + \overline{A} = 1$ 和 $A \cdot \overline{A} = 0$ 是逻辑变量和其补码的定义。
|
- **互补律**:$A + \overline{A} = 1$ 和 $A \cdot \overline{A} = 0$ 是逻辑变量和其补码的定义。
|
||||||
|
|
||||||
2. **交换律**
|
2. **交换律**
|
||||||
- **加法交换律**:$A + B = B + A$ 是逻辑加法的交换特性。
|
- **加法交换律**:$A + B = B + A$ 是逻辑加法的交换特性。
|
||||||
- **乘法交换律**:$A \cdot B = B \cdot A$ 是逻辑乘法的交换特性。
|
- **乘法交换律**:$A \cdot B = B \cdot A$ 是逻辑乘法的交换特性。
|
||||||
|
|
||||||
3. **结合律**
|
3. **结合律**
|
||||||
- **加法结合律**:$(A + B) + C = A + (B + C)$ 是逻辑加法的结合特性。
|
- **加法结合律**:$(A + B) + C = A + (B + C)$ 是逻辑加法的结合特性。
|
||||||
- **乘法结合律**:$(A \cdot B) \cdot C = A \cdot (B \cdot C)$ 是逻辑乘法的结合特性。
|
- **乘法结合律**:$(A \cdot B) \cdot C = A \cdot (B \cdot C)$ 是逻辑乘法的结合特性。
|
||||||
|
|
||||||
4. **分配律**
|
4. **分配律**
|
||||||
- **乘法分配律**:$A \cdot (B + C) = A \cdot B + A \cdot C$ 是逻辑乘法对加法的分配特性。
|
- **乘法分配律**:$A \cdot (B + C) = A \cdot B + A \cdot C$ 是逻辑乘法对加法的分配特性。
|
||||||
- **加法分配律**:$A + (B \cdot C) = (A + B) \cdot (A + C)$ 是逻辑加法对乘法的分配特性。
|
- **加法分配律**:$A + (B \cdot C) = (A + B) \cdot (A + C)$ 是逻辑加法对乘法的分配特性。
|
||||||
|
|
||||||
5. **吸收律**
|
5. **吸收律**
|
||||||
- **吸收律1**:$A + A \cdot B = A$ 可以从 $A + A \cdot B = A \cdot (1 + B) = A \cdot 1 = A$ 推导得出。
|
- **吸收律1**:$A + A \cdot B = A$ 可以从 $A + A \cdot B = A \cdot (1 + B) = A \cdot 1 = A$ 推导得出。
|
||||||
- **吸收律2**:$A \cdot (A + B) = A$ 可以从 $A \cdot (A + B) = A \cdot A + A \cdot B = A + A \cdot B = A$ 推导得出。
|
- **吸收律2**:$A \cdot (A + B) = A$ 可以从 $A \cdot (A + B) = A \cdot A + A \cdot B = A + A \cdot B = A$ 推导得出。
|
||||||
|
|
||||||
6. **德摩根定律**
|
6. **德摩根定律**
|
||||||
- **德摩根定律1**:$\overline{A + B} = \overline{A} \cdot \overline{B}$ 是逻辑加法的德摩根定律。
|
- **德摩根定律1**:$\overline{A + B} = \overline{A} \cdot \overline{B}$ 是逻辑加法的德摩根定律。
|
||||||
- **德摩根定律2**:$\overline{A \cdot B} = \overline{A} + \overline{B}$ 是逻辑乘法的德摩根定律。
|
- **德摩根定律2**:$\overline{A \cdot B} = \overline{A} + \overline{B}$ 是逻辑乘法的德摩根定律。
|
||||||
|
|
||||||
7. **简化定律**
|
7. **简化定律**
|
||||||
- **简化定律1**:$A + \overline{A} \cdot B = A + B$ 可以从 $A + \overline{A} \cdot B = (A + \overline{A}) \cdot (A + B) = 1 \cdot (A + B) = A + B$ 推导得出。
|
- **简化定律1**:$A + \overline{A} \cdot B = A + B$ 可以从 $A + \overline{A} \cdot B = (A + \overline{A}) \cdot (A + B) = 1 \cdot (A + B) = A + B$ 推导得出。
|
||||||
- **简化定律2**:$A \cdot (\overline{A} + B) = A \cdot B$ 可以从 $A \cdot (\overline{A} + B) = A \cdot \overline{A} + A \cdot B = 0 + A \cdot B = A \cdot B$ 推导得出。
|
- **简化定律2**:$A \cdot (\overline{A} + B) = A \cdot B$ 可以从 $A \cdot (\overline{A} + B) = A \cdot \overline{A} + A \cdot B = 0 + A \cdot B = A \cdot B$ 推导得出。
|
||||||
|
|
||||||
8. **共识定律**
|
8. **共识定律**
|
||||||
- **共识定律**:$(A + B) \cdot (\overline{A} + C) = (A + B) \cdot (\overline{A} + C) \cdot (B + C)$ 可以从 $(A + B) \cdot (\overline{A} + C) = (A + B) \cdot (\overline{A} + C) \cdot (B + C)$ 推导得出,因为 $(A + B) \cdot (\overline{A} + C) \leq (B + C)$。
|
- **共识定律**:$(A + B) \cdot (\overline{A} + C) = (A + B) \cdot (\overline{A} + C) \cdot (B + C)$ 可以从 $(A + B) \cdot (\overline{A} + C) = (A + B) \cdot (\overline{A} + C) \cdot (B + C)$ 推导得出,因为 $(A + B) \cdot (\overline{A} + C) \leq (B + C)$。
|
||||||
|
|
||||||
9. **反演定律**
|
9. **反演定律**
|
||||||
- **反演定律**:$A = \overline{\overline{A}}$ 是逻辑变量的双重否定特性。
|
- **反演定律**:$A = \overline{\overline{A}}$ 是逻辑变量的双重否定特性。
|
||||||
|
|
||||||
---
|
---
|
||||||
## 二、基本门电路
|
## 二、基本门电路
|
||||||
|
|
||||||
### 1. 非门
|
### 1. 非门
|
||||||
|
|
||||||
$$
|
$$
|
||||||
Y = \overline{A}
|
Y = \overline{A}
|
||||||
$$
|
$$
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 2. 与门
|
### 2. 与门
|
||||||
|
|
||||||
$$
|
$$
|
||||||
Y = A \cdot B
|
Y = A \cdot B
|
||||||
$$
|
$$
|
||||||
|
|
||||||
**真值表:**
|
**真值表:**
|
||||||
|
|
||||||
| 输入 A | 输入 B | 输出 Y |
|
| 输入 A | 输入 B | 输出 Y |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| 0 | 0 | 0 |
|
| 0 | 0 | 0 |
|
||||||
| 0 | 1 | 0 |
|
| 0 | 1 | 0 |
|
||||||
| 1 | 0 | 0 |
|
| 1 | 0 | 0 |
|
||||||
| 1 | 1 | 1 |
|
| 1 | 1 | 1 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 3. 或门
|
### 3. 或门
|
||||||
|
|
||||||
$$
|
$$
|
||||||
Y = A + B
|
Y = A + B
|
||||||
$$
|
$$
|
||||||
|
|
||||||
**真值表:**
|
**真值表:**
|
||||||
|
|
||||||
| 输入 A | 输入 B | 输出 Y |
|
| 输入 A | 输入 B | 输出 Y |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| 0 | 0 | 0 |
|
| 0 | 0 | 0 |
|
||||||
| 0 | 1 | 1 |
|
| 0 | 1 | 1 |
|
||||||
| 1 | 0 | 1 |
|
| 1 | 0 | 1 |
|
||||||
| 1 | 1 | 1 |
|
| 1 | 1 | 1 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 4. 与非门
|
### 4. 与非门
|
||||||
与非门是“与门”和“非门”的结合。
|
与非门是“与门”和“非门”的结合。
|
||||||
$$
|
$$
|
||||||
Y = \overline{A \cdot B}
|
Y = \overline{A \cdot B}
|
||||||
$$
|
$$
|
||||||
|
|
||||||
**真值表:**
|
**真值表:**
|
||||||
|
|
||||||
| 输入 A | 输入 B | 输出 Y |
|
| 输入 A | 输入 B | 输出 Y |
|
||||||
|:---:|:---:|:---:|
|
|:---:|:---:|:---:|
|
||||||
| 0 | 0 | 1 |
|
| 0 | 0 | 1 |
|
||||||
| 0 | 1 | 1 |
|
| 0 | 1 | 1 |
|
||||||
| 1 | 0 | 1 |
|
| 1 | 0 | 1 |
|
||||||
| 1 | 1 | 0 |
|
| 1 | 1 | 0 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 5. 或非门
|
### 5. 或非门
|
||||||
或非门是“或门”和“非门”的结合。
|
或非门是“或门”和“非门”的结合。
|
||||||
$$
|
$$
|
||||||
Y = \overline{A + B}
|
Y = \overline{A + B}
|
||||||
$$
|
$$
|
||||||
|
|
||||||
**真值表:**
|
**真值表:**
|
||||||
|
|
||||||
| 输入 A | 输入 B | 输出 Y |
|
| 输入 A | 输入 B | 输出 Y |
|
||||||
|:---:|:---:|:---:|
|
|:---:|:---:|:---:|
|
||||||
| 0 | 0 | 1 |
|
| 0 | 0 | 1 |
|
||||||
| 0 | 1 | 0 |
|
| 0 | 1 | 0 |
|
||||||
| 1 | 0 | 0 |
|
| 1 | 0 | 0 |
|
||||||
| 1 | 1 | 0 |
|
| 1 | 1 | 0 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 6. 异或门
|
### 6. 异或门
|
||||||
当两个输入不相同时,输出为高电平(1);当两个输入相同时,输出为低电平(0)。这也被称为“半加器”的求和逻辑。
|
当两个输入不相同时,输出为高电平(1);当两个输入相同时,输出为低电平(0)。这也被称为“半加器”的求和逻辑。
|
||||||
|
|
||||||
**逻辑表达式:**
|
**逻辑表达式:**
|
||||||
$$
|
$$
|
||||||
Y = A \oplus B
|
Y = A \oplus B
|
||||||
$$
|
$$
|
||||||
|
|
||||||
**真值表:**
|
**真值表:**
|
||||||
|
|
||||||
| 输入 A | 输入 B | 输出 Y |
|
| 输入 A | 输入 B | 输出 Y |
|
||||||
|:---:|:---:|:---:|
|
|:---:|:---:|:---:|
|
||||||
| 0 | 0 | 0 |
|
| 0 | 0 | 0 |
|
||||||
| 0 | 1 | 1 |
|
| 0 | 1 | 1 |
|
||||||
| 1 | 0 | 1 |
|
| 1 | 0 | 1 |
|
||||||
| 1 | 1 | 0 |
|
| 1 | 1 | 0 |
|
||||||
|
|
||||||
---
|
---
|
||||||
## 三、编码
|
## 三、编码
|
||||||
|
|
||||||
### 1. 原码、反码和补码
|
### 1. 原码、反码和补码
|
||||||
为了在二进制系统中表示正负数,我们通常会使用最高位作为**符号位**。
|
为了在二进制系统中表示正负数,我们通常会使用最高位作为**符号位**。
|
||||||
* 符号位为 **0** 代表**正数**。
|
* 符号位为 **0** 代表**正数**。
|
||||||
* 符号位为 **1** 代表**负数**。
|
* 符号位为 **1** 代表**负数**。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### **原码**
|
#### **原码**
|
||||||
|
|
||||||
|
|
||||||
* **规则**: 符号位 + 数值的绝对值的二进制表示。
|
* **规则**: 符号位 + 数值的绝对值的二进制表示。
|
||||||
* **正数**: 符号位为0,其余位表示数值。
|
* **正数**: 符号位为0,其余位表示数值。
|
||||||
* 例如,$+12$ 的原码是 **00001100**。
|
* 例如,$+12$ 的原码是 **00001100**。
|
||||||
* **负数**: 符号位为1,其余位表示数值。
|
* **负数**: 符号位为1,其余位表示数值。
|
||||||
* 例如,$-12$ 的原码是 **10001100**。
|
* 例如,$-12$ 的原码是 **10001100**。
|
||||||
* **缺点**:
|
* **缺点**:
|
||||||
1. 零的表示不唯一:$+0$ 是 **00000000**,$-0$ 是 **10000000**。
|
1. 零的表示不唯一:$+0$ 是 **00000000**,$-0$ 是 **10000000**。
|
||||||
2. 进行加减法运算时,需要单独处理符号位,硬件实现复杂。
|
2. 进行加减法运算时,需要单独处理符号位,硬件实现复杂。
|
||||||
|
|
||||||
#### **反码**
|
#### **反码**
|
||||||
|
|
||||||
反码的出现是为了简化减法运算。
|
反码的出现是为了简化减法运算。
|
||||||
|
|
||||||
* **规则**:
|
* **规则**:
|
||||||
* **正数**的反码与其原码**相同**。
|
* **正数**的反码与其原码**相同**。
|
||||||
* **负数**的反码是在其**原码**的基础上,**符号位不变**,其余各位**按位取反**。
|
* **负数**的反码是在其**原码**的基础上,**符号位不变**,其余各位**按位取反**。
|
||||||
* **示例**:
|
* **示例**:
|
||||||
* $+12$ 的原码是 `00001100`,其反码也是 **00001100**。
|
* $+12$ 的原码是 `00001100`,其反码也是 **00001100**。
|
||||||
* $-12$ 的原码是 `10001100`,其反码是 **11110011** (符号位1不变,后面7位 `0001100` 按位取反得到 `1110011`)。
|
* $-12$ 的原码是 `10001100`,其反码是 **11110011** (符号位1不变,后面7位 `0001100` 按位取反得到 `1110011`)。
|
||||||
* **缺点**:
|
* **缺点**:
|
||||||
* 仍然存在“双零”问题:$+0$ 的反码是 **00000000**,$-0$ 的反码是 **11111111**。
|
* 仍然存在“双零”问题:$+0$ 的反码是 **00000000**,$-0$ 的反码是 **11111111**。
|
||||||
* 跨零运算会产生循环进位问题。
|
* 跨零运算会产生循环进位问题。
|
||||||
|
|
||||||
#### **补码**
|
#### **补码**
|
||||||
|
|
||||||
补码是现代计算机系统中最常用的有符号数表示法,它解决了原码和反码的缺点。
|
补码是现代计算机系统中最常用的有符号数表示法,它解决了原码和反码的缺点。
|
||||||
|
|
||||||
* **规则**:
|
* **规则**:
|
||||||
* **正数**的补码与其原码**相同**。
|
* **正数**的补码与其原码**相同**。
|
||||||
* **负数**的补码是其**反码加 1**。
|
* **负数**的补码是其**反码加 1**。
|
||||||
* **求负数补码的方式**:
|
* **求负数补码的方式**:
|
||||||
* 从其原码的**最低位(最右边)**向左找,找到的**第一个 1** 保持不变,这个 1 **左边**的所有位(不含符号位)按位取反,符号位仍为1。
|
* 从其原码的**最低位(最右边)**向左找,找到的**第一个 1** 保持不变,这个 1 **左边**的所有位(不含符号位)按位取反,符号位仍为1。
|
||||||
* **示例**:
|
* **示例**:
|
||||||
* $+12$ 的补码是 **00001100**。
|
* $+12$ 的补码是 **00001100**。
|
||||||
* $-12$ 的补码求法:
|
* $-12$ 的补码求法:
|
||||||
1. 原码: `10001100`
|
1. 原码: `10001100`
|
||||||
2. 反码: `11110011`
|
2. 反码: `11110011`
|
||||||
3. 加 1: `11110011 + 1` = **11110100**。
|
3. 加 1: `11110011 + 1` = **11110100**。
|
||||||
* **优点**:
|
* **优点**:
|
||||||
1. **零的表示唯一**: **00000000**。
|
1. **零的表示唯一**: **00000000**。
|
||||||
2. **简化运算**: 可以将减法运算转换为加法运算。例如,计算 $A - B$ 等同于计算 $A + (-B)$ 的补码。
|
2. **简化运算**: 可以将减法运算转换为加法运算。例如,计算 $A - B$ 等同于计算 $A + (-B)$ 的补码。
|
||||||
3. 对于一个 $n$ 位的补码系统,其表示范围为 $[-2^{n-1}, 2^{n-1}-1]$。例如,8位补码的范围是 $[-128, 127]$。
|
3. 对于一个 $n$ 位的补码系统,其表示范围为 $[-2^{n-1}, 2^{n-1}-1]$。例如,8位补码的范围是 $[-128, 127]$。
|
||||||
|
|
||||||
**总结表格 (以 ±12 为例)**
|
**总结表格 (以 ±12 为例)**
|
||||||
|
|
||||||
| 值 | 原码 | 反码 | 补码 |
|
| 值 | 原码 | 反码 | 补码 |
|
||||||
|:---:|:---:|:---:|:---:|
|
|:---:|:---:|:---:|:---:|
|
||||||
| +12 | 00001100 | 00001100 | 00001100 |
|
| +12 | 00001100 | 00001100 | 00001100 |
|
||||||
| -12 | 10001100 | 11110011 | 11110100 |
|
| -12 | 10001100 | 11110011 | 11110100 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 2. BCD 码
|
### 2. BCD 码
|
||||||
|
|
||||||
BCD码是用**二进制**来表示**十进制**数的一种编码方式。它与直接将十进制数转换为二进制数不同。
|
BCD码是用**二进制**来表示**十进制**数的一种编码方式。它与直接将十进制数转换为二进制数不同。
|
||||||
|
|
||||||
* **规则**: 用 **4 位二进制数**来表示一位十进制数(0-9)。最常用的是 **8421 BCD 码**,其中各位的权值从高到低分别是 8、4、2、1。
|
* **规则**: 用 **4 位二进制数**来表示一位十进制数(0-9)。最常用的是 **8421 BCD 码**,其中各位的权值从高到低分别是 8、4、2、1。
|
||||||
* **特点**:
|
* **特点**:
|
||||||
* 它介于二进制和十进制之间,便于人机交互(如数码管显示、计算器)。
|
* 它介于二进制和十进制之间,便于人机交互(如数码管显示、计算器)。
|
||||||
* 运算比纯二进制复杂,但比直接处理十进制字符简单。
|
* 运算比纯二进制复杂,但比直接处理十进制字符简单。
|
||||||
* 由于用4位二进制表示一位十进制数,所以 `1010` 到 `1111` 这 6 个码是无效或非法的。
|
* 由于用4位二进制表示一位十进制数,所以 `1010` 到 `1111` 这 6 个码是无效或非法的。
|
||||||
|
|
||||||
**BCD 码对照表**
|
**BCD 码对照表**
|
||||||
|
|
||||||
| 十进制 | BCD 码 |
|
| 十进制 | BCD 码 |
|
||||||
|:---:|:---:|
|
|:---:|:---:|
|
||||||
| 0 | 0000 |
|
| 0 | 0000 |
|
||||||
| 1 | 0001 |
|
| 1 | 0001 |
|
||||||
| 2 | 0010 |
|
| 2 | 0010 |
|
||||||
| 3 | 0011 |
|
| 3 | 0011 |
|
||||||
| 4 | 0100 |
|
| 4 | 0100 |
|
||||||
| 5 | 0101 |
|
| 5 | 0101 |
|
||||||
| 6 | 0110 |
|
| 6 | 0110 |
|
||||||
| 7 | 0111 |
|
| 7 | 0111 |
|
||||||
| 8 | 1000 |
|
| 8 | 1000 |
|
||||||
| 9 | 1001 |
|
| 9 | 1001 |
|
||||||
|
|
||||||
**示例**:
|
**示例**:
|
||||||
将十进制数 **129** 转换为 BCD 码。
|
将十进制数 **129** 转换为 BCD 码。
|
||||||
|
|
||||||
1. 将每一位十进制数分开:`1`、`2`、`9`。
|
1. 将每一位十进制数分开:`1`、`2`、`9`。
|
||||||
2. 将每一位分别转换为对应的4位BCD码:
|
2. 将每一位分别转换为对应的4位BCD码:
|
||||||
* $1 \rightarrow 0001$
|
* $1 \rightarrow 0001$
|
||||||
* $2 \rightarrow 0010$
|
* $2 \rightarrow 0010$
|
||||||
* $9 \rightarrow 1001$
|
* $9 \rightarrow 1001$
|
||||||
3. 将它们组合起来:
|
3. 将它们组合起来:
|
||||||
$$
|
$$
|
||||||
(129)_{10} = (0001 \ 0010 \ 1001)_{\text{BCD}}
|
(129)_{10} = (0001 \ 0010 \ 1001)_{\text{BCD}}
|
||||||
$$
|
$$
|
||||||
**对比**: 如果将 (129)₁₀ 直接转换为纯二进制,结果是 **10000001**。这与它的 BCD 码是完全不同的。
|
**对比**: 如果将 (129)₁₀ 直接转换为纯二进制,结果是 **10000001**。这与它的 BCD 码是完全不同的。
|
||||||
---
|
---
|
||||||
## 四、加法器、编码器、译码器、选择器、比较器
|
## 四、加法器、编码器、译码器、选择器、比较器
|
||||||
---
|
---
|
||||||
## 五、触发器
|
## 五、触发器
|
||||||
|
|
||||||
### 1. RS 触发器
|
### 1. RS 触发器
|
||||||
|
|
||||||
最基本的触发器,但存在一个不确定状态,在实际应用中较少直接使用。
|
最基本的触发器,但存在一个不确定状态,在实际应用中较少直接使用。
|
||||||
|
|
||||||
* **输入**: $S$ (Set, 置位), $R$ (Reset, 复位)
|
* **输入**: $S$ (Set, 置位), $R$ (Reset, 复位)
|
||||||
* **输出**: $Q$ (状态输出), $\overline{Q}$ (反向输出)
|
* **输出**: $Q$ (状态输出), $\overline{Q}$ (反向输出)
|
||||||
|
|
||||||
#### **功能表**
|
#### **功能表**
|
||||||
这张表描述了在不同输入下,下一个状态 $Q_{n+1}$ 是什么。
|
这张表描述了在不同输入下,下一个状态 $Q_{n+1}$ 是什么。
|
||||||
|
|
||||||
| $S$ | $R$ | $Q_{n+1}$ | 功能 |
|
| $S$ | $R$ | $Q_{n+1}$ | 功能 |
|
||||||
|:---:|:---:|:---:|:---|
|
|:---:|:---:|:---:|:---|
|
||||||
| 0 | 0 | $Q_n$ | 保持 |
|
| 0 | 0 | $Q_n$ | 保持 |
|
||||||
| 0 | 1 | 0 | 复位/置0 |
|
| 0 | 1 | 0 | 复位/置0 |
|
||||||
| 1 | 0 | 1 | 置位/置1|
|
| 1 | 0 | 1 | 置位/置1|
|
||||||
| 1 | 1 | **?** | **禁止/不定** |
|
| 1 | 1 | **?** | **禁止/不定** |
|
||||||
|
|
||||||
#### **特性方程**
|
#### **特性方程**
|
||||||
$$
|
$$
|
||||||
Q_{n+1} = S + \overline{R}Q_n \quad (\text{约束条件: } S \cdot R = 0)
|
Q_{n+1} = S + \overline{R}Q_n \quad (\text{约束条件: } S \cdot R = 0)
|
||||||
$$
|
$$
|
||||||
|
|
||||||
#### **激励表**
|
#### **激励表**
|
||||||
这张表在电路设计时非常有用,它回答了“为了让状态从 $Q_n$ 变为 $Q_{n+1}$,输入 $S$ 和 $R$ 应该是什么?”。(X表示Don't Care,即0或1均可)
|
这张表在电路设计时非常有用,它回答了“为了让状态从 $Q_n$ 变为 $Q_{n+1}$,输入 $S$ 和 $R$ 应该是什么?”。(X表示Don't Care,即0或1均可)
|
||||||
|
|
||||||
| $Q_n$ | $Q_{n+1}$ | $S$ | $R$ |
|
| $Q_n$ | $Q_{n+1}$ | $S$ | $R$ |
|
||||||
|:---:|:---:|:---:|:---:|
|
|:---:|:---:|:---:|:---:|
|
||||||
| 0 | 0 | 0 | X |
|
| 0 | 0 | 0 | X |
|
||||||
| 0 | 1 | 1 | 0 |
|
| 0 | 1 | 1 | 0 |
|
||||||
| 1 | 0 | 0 | 1 |
|
| 1 | 0 | 0 | 1 |
|
||||||
| 1 | 1 | X | 0 |
|
| 1 | 1 | X | 0 |
|
||||||
|
|
||||||
|
|
||||||
### 2. JK 触发器
|
### 2. JK 触发器
|
||||||
|
|
||||||
JK 触发器是 RS 触发器的改进版,它解决了 RS 触发器的“禁止”状态问题,是最通用的触发器。
|
JK 触发器是 RS 触发器的改进版,它解决了 RS 触发器的“禁止”状态问题,是最通用的触发器。
|
||||||
|
|
||||||
* **输入**: $J$ (功能类似 $S$), $K$ (功能类似 $R$)
|
* **输入**: $J$ (功能类似 $S$), $K$ (功能类似 $R$)
|
||||||
* **输出**: $Q$, $\overline{Q}$
|
* **输出**: $Q$, $\overline{Q}$
|
||||||
|
|
||||||
#### **功能表**
|
#### **功能表**
|
||||||
|
|
||||||
| $J$ | $K$ | $Q_{n+1}$ | 功能 |
|
| $J$ | $K$ | $Q_{n+1}$ | 功能 |
|
||||||
|:---:|:---:|:---:|:---|
|
|:---:|:---:|:---:|:---|
|
||||||
| 0 | 0 | $Q_n$ | 保持 |
|
| 0 | 0 | $Q_n$ | 保持 |
|
||||||
| 0 | 1 | 0 | 复0 |
|
| 0 | 1 | 0 | 复0 |
|
||||||
| 1 | 0 | 1 | 置1 |
|
| 1 | 0 | 1 | 置1 |
|
||||||
| 1 | 1 | $\overline{Q_n}$ | **翻转 ** |
|
| 1 | 1 | $\overline{Q_n}$ | **翻转 ** |
|
||||||
|
|
||||||
*JK触发器将RS触发器的禁止状态(1,1输入)变成了一个非常有用的**翻转**功能。*
|
*JK触发器将RS触发器的禁止状态(1,1输入)变成了一个非常有用的**翻转**功能。*
|
||||||
|
|
||||||
#### **特性方程**
|
#### **特性方程**
|
||||||
$$
|
$$
|
||||||
Q_{n+1} = J\overline{Q_n} + \overline{K}Q_n
|
Q_{n+1} = J\overline{Q_n} + \overline{K}Q_n
|
||||||
$$
|
$$
|
||||||
|
|
||||||
#### **激励表**
|
#### **激励表**
|
||||||
|
|
||||||
| $Q_n$ | $Q_{n+1}$ | $J$ | $K$ |
|
| $Q_n$ | $Q_{n+1}$ | $J$ | $K$ |
|
||||||
|:---:|:---:|:---:|:---:|
|
|:---:|:---:|:---:|:---:|
|
||||||
| 0 | 0 | 0 | X |
|
| 0 | 0 | 0 | X |
|
||||||
| 0 | 1 | 1 | X |
|
| 0 | 1 | 1 | X |
|
||||||
| 1 | 0 | X | 1 |
|
| 1 | 0 | X | 1 |
|
||||||
| 1 | 1 | X | 0 |
|
| 1 | 1 | X | 0 |
|
||||||
|
|
||||||
|
|
||||||
### 3. D 触发器
|
### 3. D 触发器
|
||||||
D 触发器的功能非常直接:在时钟脉冲到来时,将输入 $D$ 的值传递给输出 $Q$。它常被用作数据锁存器或移位寄存器的基本单元。
|
D 触发器的功能非常直接:在时钟脉冲到来时,将输入 $D$ 的值传递给输出 $Q$。它常被用作数据锁存器或移位寄存器的基本单元。
|
||||||
|
|
||||||
* **输入**: $D$ (Data)
|
* **输入**: $D$ (Data)
|
||||||
* **输出**: $Q$, $\overline{Q}$
|
* **输出**: $Q$, $\overline{Q}$
|
||||||
|
|
||||||
#### **功能表**
|
#### **功能表**
|
||||||
|
|
||||||
| $D$ | $Q_{n+1}$ | 功能 |
|
| $D$ | $Q_{n+1}$ | 功能 |
|
||||||
|:---:|:---:|:---|
|
|:---:|:---:|:---|
|
||||||
| 0 | 0 | 置0 |
|
| 0 | 0 | 置0 |
|
||||||
| 1 | 1 | 置1 |
|
| 1 | 1 | 置1 |
|
||||||
|
|
||||||
*无论当前状态 $Q_n$ 是什么,下一个状态 $Q_{n+1}$ 都等于时钟边沿到来时的 $D$ 输入值。*
|
*无论当前状态 $Q_n$ 是什么,下一个状态 $Q_{n+1}$ 都等于时钟边沿到来时的 $D$ 输入值。*
|
||||||
|
|
||||||
#### **特性方程 **
|
#### **特性方程 **
|
||||||
$$
|
$$
|
||||||
Q_{n+1} = D
|
Q_{n+1} = D
|
||||||
$$
|
$$
|
||||||
|
|
||||||
#### **激励表 **
|
#### **激励表 **
|
||||||
|
|
||||||
| $Q_n$ | $Q_{n+1}$ | $D$ |
|
| $Q_n$ | $Q_{n+1}$ | $D$ |
|
||||||
|:---:|:---:|:---:|
|
|:---:|:---:|:---:|
|
||||||
| 0 | 0 | 0 |
|
| 0 | 0 | 0 |
|
||||||
| 0 | 1 | 1 |
|
| 0 | 1 | 1 |
|
||||||
| 1 | 0 | 0 |
|
| 1 | 0 | 0 |
|
||||||
| 1 | 1 | 1 |
|
| 1 | 1 | 1 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 4. T 触发器
|
### 4. T 触发器
|
||||||
|
|
||||||
T 触发器是一个翻转触发器。当输入 $T=1$ 时,状态翻转;当 $T=0$ 时,状态保持不变。它常用于构建计数器。
|
T 触发器是一个翻转触发器。当输入 $T=1$ 时,状态翻转;当 $T=0$ 时,状态保持不变。它常用于构建计数器。
|
||||||
|
|
||||||
* **输入**: $T$
|
* **输入**: $T$
|
||||||
* **输出**: $Q$, $\overline{Q}$
|
* **输出**: $Q$, $\overline{Q}$
|
||||||
|
|
||||||
#### **功能表**
|
#### **功能表**
|
||||||
|
|
||||||
| $T$ | $Q_{n+1}$ | 功能 |
|
| $T$ | $Q_{n+1}$ | 功能 |
|
||||||
|:---:|:---:|:---|
|
|:---:|:---:|:---|
|
||||||
| 0 | $Q_n$ | 保持 |
|
| 0 | $Q_n$ | 保持 |
|
||||||
| 1 | $\overline{Q_n}$ | 翻转 |
|
| 1 | $\overline{Q_n}$ | 翻转 |
|
||||||
|
|
||||||
#### **特性方程**
|
#### **特性方程**
|
||||||
$$
|
$$
|
||||||
Q_{n+1} = T \oplus Q_n = T\overline{Q_n} + \overline{T}Q_n
|
Q_{n+1} = T \oplus Q_n = T\overline{Q_n} + \overline{T}Q_n
|
||||||
$$
|
$$
|
||||||
|
|
||||||
#### **激励表**
|
#### **激励表**
|
||||||
|
|
||||||
| $Q_n$ | $Q_{n+1}$ | $T$ |
|
| $Q_n$ | $Q_{n+1}$ | $T$ |
|
||||||
|:---:|:---:|:---:|
|
|:---:|:---:|:---:|
|
||||||
| 0 | 0 | 0 |
|
| 0 | 0 | 0 |
|
||||||
| 0 | 1 | 1 |
|
| 0 | 1 | 1 |
|
||||||
| 1 | 0 | 1 |
|
| 1 | 0 | 1 |
|
||||||
| 1 | 1 | 0 |
|
| 1 | 1 | 0 |
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,268 +1,268 @@
|
|||||||
---
|
---
|
||||||
title: vllm学习笔记(壹)
|
title: vllm学习笔记(壹)
|
||||||
date: 2025-09-06 23:00:00 # 发布日期和时间,格式:YYYY-MM-DD HH:MM:SS
|
date: 2025-09-06 23:00:00 # 发布日期和时间,格式:YYYY-MM-DD HH:MM:SS
|
||||||
descriptionHTML: '<span style="color:var(--description-font-color);">学习笔记:ray介绍,vllm的作用和主要运行方式</span>'
|
descriptionHTML: '<span style="color:var(--description-font-color);">学习笔记:ray介绍,vllm的作用和主要运行方式</span>'
|
||||||
tags: # 文章标签列表,用于分类和搜索
|
tags: # 文章标签列表,用于分类和搜索
|
||||||
- AI
|
- AI
|
||||||
- 笔记
|
- 笔记
|
||||||
sidebar: true # 是否显示侧边栏:true显示,false隐藏
|
sidebar: true # 是否显示侧边栏:true显示,false隐藏
|
||||||
readingTime: true # 是否显示阅读时间:true显示,false隐藏
|
readingTime: true # 是否显示阅读时间:true显示,false隐藏
|
||||||
sticky: 0 # 精选文章设置:值越大在首页展示越靠前,0表示不精选
|
sticky: 0 # 精选文章设置:值越大在首页展示越靠前,0表示不精选
|
||||||
recommend: true
|
recommend: true
|
||||||
---
|
---
|
||||||
|
|
||||||
# vLLM学习笔记(壹)
|
# vLLM学习笔记(壹)
|
||||||
|
|
||||||
> **版本说明**: 本文基于 vLLM 0.2.7 版本进行分析
|
> **版本说明**: 本文基于 vLLM 0.2.7 版本进行分析
|
||||||
> **源码位置**: 相关代码主要位于 `vllm/engine/` 和 `vllm/worker/` 目录下
|
> **源码位置**: 相关代码主要位于 `vllm/engine/` 和 `vllm/worker/` 目录下
|
||||||
|
|
||||||
## Ray框架介绍
|
## Ray框架介绍
|
||||||
|
|
||||||
### Ray是什么
|
### Ray是什么
|
||||||
|
|
||||||
Ray是一个开源的分布式计算框架,专门为机器学习和AI工作负载设计。它提供了简单的API来构建和运行分布式应用程序。
|
Ray是一个开源的分布式计算框架,专门为机器学习和AI工作负载设计。它提供了简单的API来构建和运行分布式应用程序。
|
||||||
|
|
||||||
### Ray中的有状态和无状态
|
### Ray中的有状态和无状态
|
||||||
|
|
||||||
#### 无状态服务
|
#### 无状态服务
|
||||||
- **特点**: 每次请求都是独立的,不依赖之前的状态
|
- **特点**: 每次请求都是独立的,不依赖之前的状态
|
||||||
- **示例**: HTTP API服务,每个请求处理完就结束
|
- **示例**: HTTP API服务,每个请求处理完就结束
|
||||||
|
|
||||||
#### 有状态(Worker)服务
|
#### 有状态(Worker)服务
|
||||||
- **特点**: 需要维护内部状态,请求之间有依赖关系
|
- **特点**: 需要维护内部状态,请求之间有依赖关系
|
||||||
- **优势**: 可以缓存数据,避免重复计算
|
- **优势**: 可以缓存数据,避免重复计算
|
||||||
- **示例**: 数据库连接池,模型推理服务(需要保持模型在内存中)
|
- **示例**: 数据库连接池,模型推理服务(需要保持模型在内存中)
|
||||||
|
|
||||||
在vLLM中,Worker节点就是典型的**有状态服务**,因为它们需要:
|
在vLLM中,Worker节点就是典型的**有状态服务**,因为它们需要:
|
||||||
- 在内存中保持加载的模型
|
- 在内存中保持加载的模型
|
||||||
- 维护KV Cache状态
|
- 维护KV Cache状态
|
||||||
- 跟踪正在处理的请求状态
|
- 跟踪正在处理的请求状态
|
||||||
|
|
||||||
## vLLM的作用与价值
|
## vLLM的作用与价值
|
||||||
|
|
||||||
### 主要作用
|
### 主要作用
|
||||||
1. 专门优化大语言模型的推理速度
|
1. 专门优化大语言模型的推理速度
|
||||||
2. 通过PagedAttention技术显著减少内存占用
|
2. 通过PagedAttention技术显著减少内存占用
|
||||||
3. 支持动态批处理,提高GPU利用率
|
3. 支持动态批处理,提高GPU利用率
|
||||||
4. 支持多GPU和多节点部署
|
4. 支持多GPU和多节点部署
|
||||||
|
|
||||||
### 核心优势
|
### 核心优势
|
||||||
- **PagedAttention**: 将注意力机制的KV Cache分页管理,类似操作系统的虚拟内存
|
- **PagedAttention**: 将注意力机制的KV Cache分页管理,类似操作系统的虚拟内存
|
||||||
- **连续批处理**: 动态调整批大小,无需等待整个批次完成
|
- **连续批处理**: 动态调整批大小,无需等待整个批次完成
|
||||||
- **零拷贝**: 减少不必要的数据复制操作
|
- **零拷贝**: 减少不必要的数据复制操作
|
||||||
|
|
||||||
### KV Cache显存分配机制
|
### KV Cache显存分配机制
|
||||||
|
|
||||||
在传统的Transformer推理中,KV Cache需要预先分配连续的显存空间,这会造成大量的内存浪费。vLLM通过PagedAttention技术,将KV Cache分割成固定大小的block块进行管理。
|
在传统的Transformer推理中,KV Cache需要预先分配连续的显存空间,这会造成大量的内存浪费。vLLM通过PagedAttention技术,将KV Cache分割成固定大小的block块进行管理。
|
||||||
|
|
||||||
#### Block分配原理
|
#### Block分配原理
|
||||||
####
|
####
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
graph TB
|
graph TB
|
||||||
subgraph "GPU显存空间"
|
subgraph "GPU显存空间"
|
||||||
subgraph "KV Cache Pool"
|
subgraph "KV Cache Pool"
|
||||||
B1["Block 1<br/>16 tokens<br/>状态: 已分配"]
|
B1["Block 1<br/>16 tokens<br/>状态: 已分配"]
|
||||||
B2["Block 2<br/>16 tokens<br/>状态: 已分配"]
|
B2["Block 2<br/>16 tokens<br/>状态: 已分配"]
|
||||||
B3["Block 3<br/>16 tokens<br/>状态: 空闲"]
|
B3["Block 3<br/>16 tokens<br/>状态: 空闲"]
|
||||||
B4["Block 4<br/>16 tokens<br/>状态: 空闲"]
|
B4["Block 4<br/>16 tokens<br/>状态: 空闲"]
|
||||||
B5["Block 5<br/>16 tokens<br/>状态: 已分配"]
|
B5["Block 5<br/>16 tokens<br/>状态: 已分配"]
|
||||||
B6["Block 6<br/>16 tokens<br/>状态: 空闲"]
|
B6["Block 6<br/>16 tokens<br/>状态: 空闲"]
|
||||||
end
|
end
|
||||||
|
|
||||||
subgraph "模型权重"
|
subgraph "模型权重"
|
||||||
MW["Model Weights<br/>固定占用"]
|
MW["Model Weights<br/>固定占用"]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
subgraph "请求管理"
|
subgraph "请求管理"
|
||||||
R1["Request 1<br/>Seq ID: 001<br/>长度: 25 tokens"]
|
R1["Request 1<br/>Seq ID: 001<br/>长度: 25 tokens"]
|
||||||
R2["Request 2<br/>Seq ID: 002<br/>长度: 18 tokens"]
|
R2["Request 2<br/>Seq ID: 002<br/>长度: 18 tokens"]
|
||||||
end
|
end
|
||||||
|
|
||||||
subgraph "Block映射表"
|
subgraph "Block映射表"
|
||||||
BT["Block Table<br/>Seq 001: [Block1, Block2]<br/>Seq 002: [Block5]<br/>Free: [Block3, Block4, Block6]"]
|
BT["Block Table<br/>Seq 001: [Block1, Block2]<br/>Seq 002: [Block5]<br/>Free: [Block3, Block4, Block6]"]
|
||||||
end
|
end
|
||||||
|
|
||||||
R1 --> B1
|
R1 --> B1
|
||||||
R1 --> B2
|
R1 --> B2
|
||||||
R2 --> B5
|
R2 --> B5
|
||||||
|
|
||||||
BT --> B1
|
BT --> B1
|
||||||
BT --> B2
|
BT --> B2
|
||||||
BT --> B5
|
BT --> B5
|
||||||
|
|
||||||
style B1 fill:#ff9999,stroke:#333,stroke-width:2px,color:#000
|
style B1 fill:#ff9999,stroke:#333,stroke-width:2px,color:#000
|
||||||
style B2 fill:#ff9999,stroke:#333,stroke-width:2px,color:#000
|
style B2 fill:#ff9999,stroke:#333,stroke-width:2px,color:#000
|
||||||
style B5 fill:#ff9999,stroke:#333,stroke-width:2px,color:#000
|
style B5 fill:#ff9999,stroke:#333,stroke-width:2px,color:#000
|
||||||
style B3 fill:#99ff99,stroke:#333,stroke-width:2px,color:#000
|
style B3 fill:#99ff99,stroke:#333,stroke-width:2px,color:#000
|
||||||
style B4 fill:#99ff99,stroke:#333,stroke-width:2px,color:#000
|
style B4 fill:#99ff99,stroke:#333,stroke-width:2px,color:#000
|
||||||
style B6 fill:#99ff99,stroke:#333,stroke-width:2px,color:#000
|
style B6 fill:#99ff99,stroke:#333,stroke-width:2px,color:#000
|
||||||
style MW fill:#cce5ff,stroke:#333,stroke-width:2px,color:#000
|
style MW fill:#cce5ff,stroke:#333,stroke-width:2px,color:#000
|
||||||
style R1 fill:#fff2cc,stroke:#333,stroke-width:2px,color:#000
|
style R1 fill:#fff2cc,stroke:#333,stroke-width:2px,color:#000
|
||||||
style R2 fill:#fff2cc,stroke:#333,stroke-width:2px,color:#000
|
style R2 fill:#fff2cc,stroke:#333,stroke-width:2px,color:#000
|
||||||
style BT fill:#f0f0f0,stroke:#333,stroke-width:2px,color:#000
|
style BT fill:#f0f0f0,stroke:#333,stroke-width:2px,color:#000
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 关键特性说明
|
#### 关键特性说明
|
||||||
|
|
||||||
1. **固定Block大小**: 每个Block通常包含16个token的KV Cache
|
1. **固定Block大小**: 每个Block通常包含16个token的KV Cache
|
||||||
2. **动态分配**: 根据序列长度动态分配所需的Block数量
|
2. **动态分配**: 根据序列长度动态分配所需的Block数量
|
||||||
3. **非连续存储**: Block在物理内存中可以不连续,通过映射表管理
|
3. **非连续存储**: Block在物理内存中可以不连续,通过映射表管理
|
||||||
4. **高效回收**: 请求完成后立即回收Block,供其他请求使用
|
4. **高效回收**: 请求完成后立即回收Block,供其他请求使用
|
||||||
|
|
||||||
#### 内存利用率对比
|
#### 内存利用率对比
|
||||||
|
|
||||||
| 方案 | 内存预分配 | 实际使用率 | 浪费率 |
|
| 方案 | 内存预分配 | 实际使用率 | 浪费率 |
|
||||||
|------|------------|------------|--------|
|
|------|------------|------------|--------|
|
||||||
| 传统方案 | 最大序列长度 | 20-30% | 70-80% |
|
| 传统方案 | 最大序列长度 | 20-30% | 70-80% |
|
||||||
| PagedAttention | 按需分配 | 90-95% | 5-10% |
|
| PagedAttention | 按需分配 | 90-95% | 5-10% |
|
||||||
|
|
||||||
#### Block管理的具体流程
|
#### Block管理的具体流程
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# 位置: vllm/core/block_manager.py
|
# 位置: vllm/core/block_manager.py
|
||||||
class BlockManager:
|
class BlockManager:
|
||||||
def allocate_blocks(self, sequence_length):
|
def allocate_blocks(self, sequence_length):
|
||||||
"""为序列分配所需的Block"""
|
"""为序列分配所需的Block"""
|
||||||
blocks_needed = math.ceil(sequence_length / self.block_size)
|
blocks_needed = math.ceil(sequence_length / self.block_size)
|
||||||
allocated_blocks = []
|
allocated_blocks = []
|
||||||
|
|
||||||
for _ in range(blocks_needed):
|
for _ in range(blocks_needed):
|
||||||
if self.free_blocks:
|
if self.free_blocks:
|
||||||
block = self.free_blocks.pop()
|
block = self.free_blocks.pop()
|
||||||
allocated_blocks.append(block)
|
allocated_blocks.append(block)
|
||||||
else:
|
else:
|
||||||
# 内存不足,触发抢占机制
|
# 内存不足,触发抢占机制
|
||||||
self.preempt_sequences()
|
self.preempt_sequences()
|
||||||
|
|
||||||
return allocated_blocks
|
return allocated_blocks
|
||||||
|
|
||||||
def free_blocks(self, sequence_id):
|
def free_blocks(self, sequence_id):
|
||||||
"""释放序列占用的Block"""
|
"""释放序列占用的Block"""
|
||||||
blocks = self.sequence_to_blocks[sequence_id]
|
blocks = self.sequence_to_blocks[sequence_id]
|
||||||
self.free_blocks.extend(blocks)
|
self.free_blocks.extend(blocks)
|
||||||
del self.sequence_to_blocks[sequence_id]
|
del self.sequence_to_blocks[sequence_id]
|
||||||
```
|
```
|
||||||
|
|
||||||
这种设计的优势:
|
这种设计的优势:
|
||||||
- **内存碎片化最小**: 固定大小的Block避免了内存碎片
|
- **内存碎片化最小**: 固定大小的Block避免了内存碎片
|
||||||
- **动态扩展**: 序列可以根据需要动态申请更多Block
|
- **动态扩展**: 序列可以根据需要动态申请更多Block
|
||||||
- **共享机制**: 多个序列可以共享相同的prefix Block(如系统提示词)
|
- **共享机制**: 多个序列可以共享相同的prefix Block(如系统提示词)
|
||||||
|
|
||||||
## vLLM运作方式详解
|
## vLLM运作方式详解
|
||||||
|
|
||||||
### 整体架构流程
|
### 整体架构流程
|
||||||
|
|
||||||
```
|
```
|
||||||
用户请求 → LLMEngine → Scheduler → Workers → GPU推理 → 结果返回
|
用户请求 → LLMEngine → Scheduler → Workers → GPU推理 → 结果返回
|
||||||
```
|
```
|
||||||
|
|
||||||
### 详细运作步骤
|
### 详细运作步骤
|
||||||
|
|
||||||
1. `LLMEngine`接收用户的文本生成请求
|
1. `LLMEngine`接收用户的文本生成请求
|
||||||
2. `Scheduler`决定哪些请求可以被处理
|
2. `Scheduler`决定哪些请求可以被处理
|
||||||
3. 为请求分配GPU内存和计算资源
|
3. 为请求分配GPU内存和计算资源
|
||||||
4. 多个`Worker`并行执行推理任务
|
4. 多个`Worker`并行执行推理任务
|
||||||
5. 收集各Worker的输出并返回给用户
|
5. 收集各Worker的输出并返回给用户
|
||||||
|
|
||||||
## 调度器(Scheduler)详解
|
## 调度器(Scheduler)详解
|
||||||
|
|
||||||
### 调度器的核心职责
|
### 调度器的核心职责
|
||||||
|
|
||||||
调度器是vLLM的"大脑",主要负责:
|
调度器是vLLM的"大脑",主要负责:
|
||||||
|
|
||||||
#### 1. 请求管理
|
#### 1. 请求管理
|
||||||
```python
|
```python
|
||||||
# 位置: vllm/engine/llm_engine.py
|
# 位置: vllm/engine/llm_engine.py
|
||||||
class LLMEngine:
|
class LLMEngine:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.scheduler = Scheduler(...)
|
self.scheduler = Scheduler(...)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 2. 资源调度策略
|
#### 2. 资源调度策略
|
||||||
1. 跟踪可用的GPU内存
|
1. 跟踪可用的GPU内存
|
||||||
2. 决定哪些请求可以组成一个批次
|
2. 决定哪些请求可以组成一个批次
|
||||||
3. 根据请求的优先级和到达时间排序
|
3. 根据请求的优先级和到达时间排序
|
||||||
|
|
||||||
|
|
||||||
### 调度算法核心逻辑
|
### 调度算法核心逻辑
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# 简化的调度逻辑示例
|
# 简化的调度逻辑示例
|
||||||
def schedule_requests(self):
|
def schedule_requests(self):
|
||||||
# 1. 检查可用资源
|
# 1. 检查可用资源
|
||||||
available_memory = self.get_available_memory()
|
available_memory = self.get_available_memory()
|
||||||
|
|
||||||
# 2. 选择可执行的请求
|
# 2. 选择可执行的请求
|
||||||
executable_requests = []
|
executable_requests = []
|
||||||
for request in self.waiting_requests:
|
for request in self.waiting_requests:
|
||||||
if self.can_allocate(request, available_memory):
|
if self.can_allocate(request, available_memory):
|
||||||
executable_requests.append(request)
|
executable_requests.append(request)
|
||||||
|
|
||||||
# 3. 返回调度结果
|
# 3. 返回调度结果
|
||||||
return executable_requests
|
return executable_requests
|
||||||
```
|
```
|
||||||
|
|
||||||
## Worker的作用与机制
|
## Worker的作用与机制
|
||||||
|
|
||||||
### Worker的核心功能
|
### Worker的核心功能
|
||||||
|
|
||||||
Worker是vLLM的"执行者",每个Worker负责:
|
Worker是vLLM的"执行者",每个Worker负责:
|
||||||
|
|
||||||
#### 1. 模型加载与管理
|
#### 1. 模型加载与管理
|
||||||
```python
|
```python
|
||||||
# 位置: vllm/worker/worker.py
|
# 位置: vllm/worker/worker.py
|
||||||
class Worker:
|
class Worker:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.model_runner = ModelRunner(...)
|
self.model_runner = ModelRunner(...)
|
||||||
self.cache_engine = CacheEngine(...)
|
self.cache_engine = CacheEngine(...)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 2. 推理执行
|
#### 2. 推理执行
|
||||||
- **前向传播**: 执行模型的前向计算
|
- **前向传播**: 执行模型的前向计算
|
||||||
- **KV缓存管理**: 管理注意力机制的键值缓存
|
- **KV缓存管理**: 管理注意力机制的键值缓存
|
||||||
- **内存分配**: 为每个请求分配必要的内存空间
|
- **内存分配**: 为每个请求分配必要的内存空间
|
||||||
|
|
||||||
#### 3. 状态维护
|
#### 3. 状态维护
|
||||||
- **请求状态跟踪**: 记录每个请求的处理进度
|
- **请求状态跟踪**: 记录每个请求的处理进度
|
||||||
- **缓存状态管理**: 维护PagedAttention的页面状态
|
- **缓存状态管理**: 维护PagedAttention的页面状态
|
||||||
- **错误处理**: 处理推理过程中的异常情况
|
- **错误处理**: 处理推理过程中的异常情况
|
||||||
|
|
||||||
### Worker的工作流程
|
### Worker的工作流程
|
||||||
|
|
||||||
1. **初始化**: 加载模型权重,初始化缓存引擎
|
1. **初始化**: 加载模型权重,初始化缓存引擎
|
||||||
2. **接收任务**: 从调度器接收批处理任务
|
2. **接收任务**: 从调度器接收批处理任务
|
||||||
3. **执行推理**: 并行处理批次中的所有请求
|
3. **执行推理**: 并行处理批次中的所有请求
|
||||||
4. **返回结果**: 将推理结果返回给引擎
|
4. **返回结果**: 将推理结果返回给引擎
|
||||||
|
|
||||||
## 关键代码文件位置
|
## 关键代码文件位置
|
||||||
|
|
||||||
### 主要源码文件结构
|
### 主要源码文件结构
|
||||||
|
|
||||||
```
|
```
|
||||||
vllm/
|
vllm/
|
||||||
├── engine/
|
├── engine/
|
||||||
│ ├── llm_engine.py # 主引擎,协调整个推理流程
|
│ ├── llm_engine.py # 主引擎,协调整个推理流程
|
||||||
│ └── async_llm_engine.py # 异步版本的引擎
|
│ └── async_llm_engine.py # 异步版本的引擎
|
||||||
├── core/
|
├── core/
|
||||||
│ ├── scheduler.py # 调度器核心逻辑
|
│ ├── scheduler.py # 调度器核心逻辑
|
||||||
│ └── block_manager.py # 内存块管理器
|
│ └── block_manager.py # 内存块管理器
|
||||||
├── worker/
|
├── worker/
|
||||||
│ ├── worker.py # Worker基类实现
|
│ ├── worker.py # Worker基类实现
|
||||||
│ └── model_runner.py # 模型运行器
|
│ └── model_runner.py # 模型运行器
|
||||||
└── attention/
|
└── attention/
|
||||||
└── backends/ # PagedAttention实现
|
└── backends/ # PagedAttention实现
|
||||||
```
|
```
|
||||||
|
|
||||||
### 重要文件说明
|
### 重要文件说明
|
||||||
|
|
||||||
- **`vllm/engine/llm_engine.py`**: 整个系统的入口点和协调中心
|
- **`vllm/engine/llm_engine.py`**: 整个系统的入口点和协调中心
|
||||||
- **`vllm/core/scheduler.py`**: 实现了复杂的请求调度算法
|
- **`vllm/core/scheduler.py`**: 实现了复杂的请求调度算法
|
||||||
- **`vllm/worker/worker.py`**: Worker的具体实现逻辑
|
- **`vllm/worker/worker.py`**: Worker的具体实现逻辑
|
||||||
- **`vllm/core/block_manager.py`**: PagedAttention的内存管理实现
|
- **`vllm/core/block_manager.py`**: PagedAttention的内存管理实现
|
||||||
|
|
||||||
## 总结
|
## 总结
|
||||||
|
|
||||||
vLLM通过Ray框架实现分布式推理,采用有状态的Worker设计来保持模型和缓存状态。其核心创新在于PagedAttention技术和智能调度系统,大幅提升了大语言模型的推理效率和资源利用率。
|
vLLM通过Ray框架实现分布式推理,采用有状态的Worker设计来保持模型和缓存状态。其核心创新在于PagedAttention技术和智能调度系统,大幅提升了大语言模型的推理效率和资源利用率。
|
||||||
|
|
||||||
|
|||||||
171
docs/sop/notes/vllm-learning-notes-pre.md
Normal file
171
docs/sop/notes/vllm-learning-notes-pre.md
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
---
|
||||||
|
title: vllm汇报稿
|
||||||
|
date: 2025-09-26 23:00:00 # 发布日期和时间,格式:YYYY-MM-DD HH:MM:SS
|
||||||
|
descriptionHTML: '<span style="color:var(--description-font-color);">预汇报稿件</span>'
|
||||||
|
tags: # 文章标签列表,用于分类和搜索
|
||||||
|
- AI
|
||||||
|
- 笔记
|
||||||
|
sidebar: true # 是否显示侧边栏:true显示,false隐藏
|
||||||
|
readingTime: true # 是否显示阅读时间:true显示,false隐藏
|
||||||
|
sticky: 0 # 精选文章设置:值越大在首页展示越靠前,0表示不精选
|
||||||
|
recommend: true
|
||||||
|
---
|
||||||
|
|
||||||
|
# vLLM 报告
|
||||||
|
|
||||||
|
> 主题聚焦:**PagedAttention 分页注意力、整体架构、调度器原理、Worker 原理、PP 与 TP 的区别、预填充(Prefill)与解码(Decode)**
|
||||||
|
|
||||||
|
## 1. 为什么需要 PagedAttention
|
||||||
|
|
||||||
|
### 1.1 传统 KV Cache 的两类浪费
|
||||||
|
|
||||||
|
* **内部碎片**:必须为每个请求按“可能最长序列(prompt+output)”预留 **连续** KV 空间,未用到的预留位被浪费。
|
||||||
|
* **外部碎片**:全局连续大块分配导致“零头”拼不起来,无法切给其他请求。
|
||||||
|
* **共享缺失**:**相同前缀的 KV** 无法复用,重复存储。
|
||||||
|
|
||||||
|
|
||||||
|
### 1.2 PagedAttention 的核心思路
|
||||||
|
|
||||||
|
* 预分配一大块显存,**切成固定大小的 block**。
|
||||||
|
* 逻辑上给每个序列分配 **Logical Blocks**,实际落在 **Physical Blocks**;两者通过 **Block Table** 映射。
|
||||||
|
* 最多浪费 < block_size 个 slot,**显著减少内外部碎片**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. vLLM 的总体架构(抓主线)
|
||||||
|
|
||||||
|
|
||||||
|
* **LLMEngine**:一次迭代做三件事:`schedule()` → `execute_model()` → `process_outputs()`。
|
||||||
|
* **Scheduler**:决定本轮处理哪些请求、是否换入/换出 KV。
|
||||||
|
* **Worker / ModelRunner**:执行模型前向,读写 KV cache,采样下一个 token。
|
||||||
|
* **CacheEngine**:分配/维护 KV Blocks(GPU/CPU)、管理 **swap in/out、copy** 的 CUDA 流与事件。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 调度器原理(continuous batching)
|
||||||
|
|
||||||
|
### 3.1 核心策略
|
||||||
|
|
||||||
|
* **Iteration-level(continuous batching)**:每生成一个 token 后**重新调度**,因此 batch 大小可变。
|
||||||
|
* **阶段区分**:vLLM 将请求分为 **Prefill(填充)** 与 **Decode(生成)** 两类批次,**同一轮只处理同一阶段**。
|
||||||
|
|
||||||
|
### 3.2 三个队列
|
||||||
|
|
||||||
|
* **waiting**:刚到达的请求,尚未分配 GPU blocks(只分配逻辑块)。
|
||||||
|
* **running**:正在解码或已完成 prefill 的请求。
|
||||||
|
* **swapped**:因显存不足被抢占、KV 暂存在 CPU 的请求。
|
||||||
|
|
||||||
|
### 3.3 块管理关键路径
|
||||||
|
|
||||||
|
* **BlockSpaceManager.can_allocate()**:预判 waiting 请求的 prompt 是否能拿到足够的 GPU blocks。
|
||||||
|
* **allocate()**:为 prompt 的每个逻辑块绑定一个物理块。
|
||||||
|
* **can_append_slot() / append_slot()**(解码迭代):若最后一个物理块**独占**则直接追加,否则触发复制。
|
||||||
|
|
||||||
|
### 3.4 抢占与换入/换出
|
||||||
|
|
||||||
|
* **Recompute**:单序列分支,释放 GPU 块,下次换回后**重算** KV。
|
||||||
|
* **Swap**:多分支或不宜重算的场景,把物理块搬到 CPU;后续再 **swap-in** 回 GPU。
|
||||||
|
* **优先级**:`swapped` 队列优先于 `waiting`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Worker 原理(模型执行链路)
|
||||||
|
|
||||||
|
### 4.1 角色与初始化
|
||||||
|
|
||||||
|
* **Worker ↔ GPU**:一张卡一个 Worker;多卡时配合 **Tensor Parallel(TP)** 切分模型。
|
||||||
|
* 初始化步骤:加载权重 → 建立分布式组 → **profile** 可用块 → **init CacheEngine** →(可选)**CUDA Graph** 预捕获。
|
||||||
|
|
||||||
|
### 4.2 一次执行(`execute_model`)
|
||||||
|
|
||||||
|
1. **状态同步**:驱动 Worker 广播批次规模与内存操作。
|
||||||
|
2. **数据交换**:调用 CacheEngine 的 `swap_in/out`、`copy`。
|
||||||
|
3. **准备输入**:生成 `input_tokens / positions / input_metadata`。
|
||||||
|
4. **前向**:
|
||||||
|
|
||||||
|
* **Prefill**:走 FlashAttn;
|
||||||
|
* **Decode**:走 PagedAttention 内核。
|
||||||
|
5. **采样**:产生下一个 token。
|
||||||
|
|
||||||
|
### 4.3 CacheEngine 的数据结构
|
||||||
|
|
||||||
|
* 每层有 **key_blocks / value_blocks**。
|
||||||
|
* **Block Table**:记录 `seq_id → [block_numbers...]`。
|
||||||
|
* **slot_mapping**:映射“本轮 token”写入到物理块的哪个 slot。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Prefill vs Decode(执行特点与调优,展开版)
|
||||||
|
|
||||||
|
### Prefill(填充阶段)
|
||||||
|
|
||||||
|
* **目标**:对完整 prompt 做一次性前向传播,构建 KV 缓存,并生成第一个 token。
|
||||||
|
* **数据特征**:长序列、少批次、padding 多、计算密集。
|
||||||
|
* **实现**:FlashAttention;输入 `_prepare_prompt`,输出第一个 token。
|
||||||
|
* **瓶颈**:HBM 带宽、padding 浪费、长 prompt 拖慢 batch。
|
||||||
|
* **调优**:限制 `max_num_batched_tokens`,分批/压缩长 prompt,减少 padding。
|
||||||
|
|
||||||
|
### Decode(解码阶段)
|
||||||
|
|
||||||
|
* **目标**:逐 token 生成。
|
||||||
|
* **数据特征**:迭代频繁、短序列、并发依赖多。
|
||||||
|
* **实现**:PagedAttention;输入 `_prepare_decode`,只追加一个 slot。
|
||||||
|
* **瓶颈**:Kernel 启动开销、随机访存、并发不足。
|
||||||
|
* **调优**:提高 `max_num_seqs`、用 CUDA Graph、调整 block_size、控制采样分支。
|
||||||
|
|
||||||
|
### Prefill vs Decode 对比总结
|
||||||
|
|
||||||
|
| 维度 | Prefill | Decode |
|
||||||
|
| ---------------- | --------------------- | -------------------------- |
|
||||||
|
| **目标** | 编码完整 prompt,建立 KV 前缀 | 逐 token 生成 |
|
||||||
|
| **批次特征** | 少批次、长序列、padding 多 | 多批次、短序列、迭代频繁 |
|
||||||
|
| **Attention 路径** | FlashAttention | PagedAttention |
|
||||||
|
| **主要瓶颈** | HBM 带宽 + Padding | Kernel Overhead + 随机访存 |
|
||||||
|
| **优化抓手** | 控制 padding、限制长 prompt | 提升并发、CUDA Graph、block size |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. TP 与 PP:概念、区别与 vLLM 现状
|
||||||
|
|
||||||
|
* **TP(Tensor Parallelism)**:层内张量切分;通信频繁;适合实时推理。
|
||||||
|
* **PP(Pipeline Parallelism)**:层间切分;通信少但需流水线调度;更多见于训练。
|
||||||
|
* **vLLM 支持**:TP 是主力;PP 支持有限。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 关键流程串讲
|
||||||
|
|
||||||
|
### Prefill 批
|
||||||
|
|
||||||
|
1. waiting 进入 running;BlockSpaceManager 分配块;
|
||||||
|
2. Worker `_prepare_prompt` → FlashAttn → 写入 KV;
|
||||||
|
3. Sampler 采样首 token。
|
||||||
|
|
||||||
|
### Decode 批
|
||||||
|
|
||||||
|
1. Scheduler 选择 running 序列;
|
||||||
|
2. `_append_slot` 写 KV;
|
||||||
|
3. Worker 调 PagedAttention → 输出;
|
||||||
|
4. 采样 → EOS/长度 → 释放序列。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 参数与调优清单
|
||||||
|
|
||||||
|
* **`block_size`**:16;权衡碎片与索引开销。
|
||||||
|
* **`gpu_memory_utilization`**:估算可分配 KV;预留峰值空间。
|
||||||
|
* **`max_num_seqs`**:提升解码并发。
|
||||||
|
* **`max_num_batched_tokens`**:限制长 prompt。
|
||||||
|
* **`swap_space_bytes`**:CPU 交换空间,优先考虑 Recompute。
|
||||||
|
* **采样参数**:top-k/top-p/温度/惩罚影响解码步数。
|
||||||
|
* **CUDA Graph**:捕获稳定批,降低开销。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 可讲的亮点/考点总结
|
||||||
|
|
||||||
|
1. **PagedAttention**:block 化 + 块表管理,解决碎片问题。
|
||||||
|
2. **continuous batching**:每 token 重调度,提升吞吐。
|
||||||
|
3. **Recompute vs Swap**:计算 vs 带宽权衡。
|
||||||
|
4. **TP 优先,PP 备选**。
|
||||||
|
5. **Prefill vs Decode**:不同执行路径与瓶颈决定不同调优抓手。
|
||||||
@@ -1,117 +1,117 @@
|
|||||||
---
|
---
|
||||||
title: 如何使用 Cherry Studio # 文章标题,支持副标题格式(用 - 分隔)
|
title: 如何使用 Cherry Studio # 文章标题,支持副标题格式(用 - 分隔)
|
||||||
top: 0 # 置顶级别:1-3,数字越大越靠前,0表示不置顶
|
top: 0 # 置顶级别:1-3,数字越大越靠前,0表示不置顶
|
||||||
date: 2025-08-24 20:30:00 # 发布日期和时间,格式:YYYY-MM-DD HH:MM:SS
|
date: 2025-08-24 20:30:00 # 发布日期和时间,格式:YYYY-MM-DD HH:MM:SS
|
||||||
descriptionHTML: '
|
descriptionHTML: '
|
||||||
<span style="color:var(--description-font-color);">Cherry Studio的入门指南</span>
|
<span style="color:var(--description-font-color);">Cherry Studio的入门指南</span>
|
||||||
'
|
'
|
||||||
tags: # 文章标签列表,用于分类和搜索
|
tags: # 文章标签列表,用于分类和搜索
|
||||||
- Cherry Studio
|
- Cherry Studio
|
||||||
- 教程
|
- 教程
|
||||||
- AI
|
- AI
|
||||||
sidebar: true # 是否显示侧边栏:true显示,false隐藏
|
sidebar: true # 是否显示侧边栏:true显示,false隐藏
|
||||||
readingTime: true # 是否显示阅读时间:true显示,false隐藏
|
readingTime: true # 是否显示阅读时间:true显示,false隐藏
|
||||||
sticky: 2 # 精选文章设置:值越大在首页展示越靠前,0表示不精选
|
sticky: 2 # 精选文章设置:值越大在首页展示越靠前,0表示不精选
|
||||||
hidden: false # 是否隐藏文章:true隐藏(模板用),false显示(正式文章用)
|
hidden: false # 是否隐藏文章:true隐藏(模板用),false显示(正式文章用)
|
||||||
recommend: true
|
recommend: true
|
||||||
---
|
---
|
||||||
|
|
||||||
# 如何使用 Cherry Studio
|
# 如何使用 Cherry Studio
|
||||||
|
|
||||||
## 什么是 Cherry Studio?
|
## 什么是 Cherry Studio?
|
||||||
|
|
||||||
Cherry Studio 是一个功能强大的 AI 聚合工具,它集成了多模型对话、知识库管理、AI 绘画等多种功能。由于所有内容都存储在本地,因此它提供了出色的隐私保护。
|
Cherry Studio 是一个功能强大的 AI 聚合工具,它集成了多模型对话、知识库管理、AI 绘画等多种功能。由于所有内容都存储在本地,因此它提供了出色的隐私保护。
|
||||||
|
|
||||||
## 下载与安装
|
## 下载与安装
|
||||||
|
|
||||||
1. **下载**:
|
1. **下载**:
|
||||||
访问 [CherryStudio 官网](https://cherry-ai.com/download) 下载适用于您操作系统的客户端。(以下以Windows系统为例)
|
访问 [CherryStudio 官网](https://cherry-ai.com/download) 下载适用于您操作系统的客户端。(以下以Windows系统为例)
|
||||||
|
|
||||||
2. **安装**:
|
2. **安装**:
|
||||||
双击下载的 `.exe` 文件,然后按照安装向导的指示进行操作。建议将软件安装在C盘以外的驱动器。
|
双击下载的 `.exe` 文件,然后按照安装向导的指示进行操作。建议将软件安装在C盘以外的驱动器。
|
||||||
|
|
||||||
<div style="display:flex; gap:4%; justify-content:center; align-items:flex-start; flex-wrap:wrap;"> <img src="/1/安装1.png" alt="1-安装1" style="width:48%; max-width:420px; height:auto; display:block; margin:12px 0;" /> <img src="/1/安装2.png" alt="1-安装2" style="width:48%; max-width:420px; height:auto; display:block; margin:12px 0;" /> </div>
|
<div style="display:flex; gap:4%; justify-content:center; align-items:flex-start; flex-wrap:wrap;"> <img src="/1/安装1.png" alt="1-安装1" style="width:48%; max-width:420px; height:auto; display:block; margin:12px 0;" /> <img src="/1/安装2.png" alt="1-安装2" style="width:48%; max-width:420px; height:auto; display:block; margin:12px 0;" /> </div>
|
||||||
|
|
||||||
## 核心功能
|
## 核心功能
|
||||||
|
|
||||||
CherryStudio 提供了多种强大的功能,以下是一些核心功能介绍:
|
CherryStudio 提供了多种强大的功能,以下是一些核心功能介绍:
|
||||||
|
|
||||||
### 添加模型
|
### 添加模型
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
您可以在 CherryStudio 中添加和管理来自不同提供商的 AI 模型,支持 API 调用和本地调用两种方式。
|
您可以在 CherryStudio 中添加和管理来自不同提供商的 AI 模型,支持 API 调用和本地调用两种方式。
|
||||||
|
|
||||||
#### API 调用
|
#### API 调用
|
||||||
|
|
||||||
1. 在模型服务提供商(例如,[硅基流动](https://cloud.siliconflow.cn/i/sbwOb5XI))的网站上注册账户并创建一个 API 密钥。
|
1. 在模型服务提供商(例如,[硅基流动](https://cloud.siliconflow.cn/i/sbwOb5XI))的网站上注册账户并创建一个 API 密钥。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
2. 在 CherryStudio 的设置中,选择“模型服务”,然后添加 API 密钥。
|
2. 在 CherryStudio 的设置中,选择“模型服务”,然后添加 API 密钥。
|
||||||
3. 点击下方管理可获取模型列表。
|
3. 点击下方管理可获取模型列表。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
4. 选择模型添加。
|
4. 选择模型添加。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
5. 添加成功后,您可以选择相应的模型进行对话。
|
5. 添加成功后,您可以选择相应的模型进行对话。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
#### 本地调用
|
#### 本地调用
|
||||||
|
|
||||||
1. 如果您在本地部署了模型(例如,使用 Ollama),您也可以将其添加到 CherryStudio。
|
1. 如果您在本地部署了模型(例如,使用 Ollama),您也可以将其添加到 CherryStudio。
|
||||||
2. 在模型服务设置中,选择本地调用,并填写正确的 API 地址(通常是 `localhost`)和模型名称。
|
2. 在模型服务设置中,选择本地调用,并填写正确的 API 地址(通常是 `localhost`)和模型名称。
|
||||||
|
|
||||||
### 联网功能
|
### 联网功能
|
||||||
|
|
||||||
为了让模型能够获取最新信息,您可以为其启用联网功能。
|
为了让模型能够获取最新信息,您可以为其启用联网功能。
|
||||||
|
|
||||||
1. **添加网络搜索服务**: 在设置->工具设置中选择“网络搜索”,然后添加一个搜索服务(如 百度搜索)。
|
1. **添加网络搜索服务**: 在设置->工具设置中选择“网络搜索”,然后添加一个搜索服务(如 百度搜索)。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
2. **使用网络搜索**: 在聊天界面,点击输入框下方的网络图标(🌐)即可启用联网功能。
|
2. **使用网络搜索**: 在聊天界面,点击输入框下方的网络图标(🌐)即可启用联网功能。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 知识库
|
### 知识库
|
||||||
|
|
||||||
CherryStudio 允许您创建自己的本地知识库,让 AI 根据您的文档回答问题。
|
CherryStudio 允许您创建自己的本地知识库,让 AI 根据您的文档回答问题。
|
||||||
|
|
||||||
1. **创建知识库**: 在侧边栏选择“知识库”并创建一个新的知识库(选择一个语义向量模型)。
|
1. **创建知识库**: 在侧边栏选择“知识库”并创建一个新的知识库(选择一个语义向量模型)。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
2. **添加文档**: 将您的文档(请确保为 UTF-8 编码)拖入知识库中,系统会自动进行向量化处理。
|
2. **添加文档**: 将您的文档(请确保为 UTF-8 编码)拖入知识库中,系统会自动进行向量化处理。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
3. **使用知识库**: 在聊天时,您可以选择加载特定的知识库,AI 将会基于库中的内容进行回答,并能标注引用来源。
|
3. **使用知识库**: 在聊天时,您可以选择加载特定的知识库,AI 将会基于库中的内容进行回答,并能标注引用来源。
|
||||||
|
|
||||||
### 配置迁移
|
### 配置迁移
|
||||||
|
|
||||||
如果您需要在多台设备上使用 CherryStudio,可以使用配置迁移功能来同步您的设置。
|
如果您需要在多台设备上使用 CherryStudio,可以使用配置迁移功能来同步您的设置。
|
||||||
|
|
||||||
1. **备份**: 在“数据设置”中,您可以将当前的所有配置(包括模型、知识库等)备份为一个 ZIP 文件。
|
1. **备份**: 在“数据设置”中,您可以将当前的所有配置(包括模型、知识库等)备份为一个 ZIP 文件。
|
||||||
2. **恢复**: 在另一台设备上,通过“恢复”功能选择之前备份的 ZIP 文件,即可快速恢复您的所有配置。
|
2. **恢复**: 在另一台设备上,通过“恢复”功能选择之前备份的 ZIP 文件,即可快速恢复您的所有配置。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|||||||
12
edgeone.json
12
edgeone.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"installCommand": "npm install",
|
"installCommand": "npm install",
|
||||||
"buildCommand": "npm run build",
|
"buildCommand": "npm run build",
|
||||||
"outputDirectory": "docs/.vitepress/dist",
|
"outputDirectory": "docs/.vitepress/dist",
|
||||||
"nodeVersion": "18.20.4"
|
"nodeVersion": "18.20.4"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,195 +1,195 @@
|
|||||||
# 光标雨点效果使用指南
|
# 光标雨点效果使用指南
|
||||||
|
|
||||||
## 简介
|
## 简介
|
||||||
|
|
||||||
这个博客已经集成了美丽的光标雨点效果!当你移动鼠标时,会在光标位置产生逼真的雨滴落下动画。
|
这个博客已经集成了美丽的光标雨点效果!当你移动鼠标时,会在光标位置产生逼真的雨滴落下动画。
|
||||||
|
|
||||||
## 基础配置
|
## 基础配置
|
||||||
|
|
||||||
### 1. 预设主题
|
### 1. 预设主题
|
||||||
|
|
||||||
在 `docs/.vitepress/theme/index.ts` 文件中,你可以选择不同的预设主题:
|
在 `docs/.vitepress/theme/index.ts` 文件中,你可以选择不同的预设主题:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// 默认蓝色主题(智能配置)
|
// 默认蓝色主题(智能配置)
|
||||||
const config = getOptimalConfig()
|
const config = getOptimalConfig()
|
||||||
|
|
||||||
// 或者手动选择预设:
|
// 或者手动选择预设:
|
||||||
const config = rainPresets.default // 默认
|
const config = rainPresets.default // 默认
|
||||||
const config = rainPresets.light // 轻量模式(适合低性能设备)
|
const config = rainPresets.light // 轻量模式(适合低性能设备)
|
||||||
const config = rainPresets.fancy // 华丽模式(更多雨滴)
|
const config = rainPresets.fancy // 华丽模式(更多雨滴)
|
||||||
const config = rainPresets.pink // 粉色主题
|
const config = rainPresets.pink // 粉色主题
|
||||||
const config = rainPresets.green // 绿色主题
|
const config = rainPresets.green // 绿色主题
|
||||||
const config = rainPresets.gold // 金色主题
|
const config = rainPresets.gold // 金色主题
|
||||||
const config = rainPresets.mobile // 移动端优化
|
const config = rainPresets.mobile // 移动端优化
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. 自定义配置
|
### 2. 自定义配置
|
||||||
|
|
||||||
你也可以完全自定义配置参数:
|
你也可以完全自定义配置参数:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const customConfig = {
|
const customConfig = {
|
||||||
maxDrops: 30, // 最大雨滴数量
|
maxDrops: 30, // 最大雨滴数量
|
||||||
color: 'rgba(255, 182, 193, 0.7)', // 雨滴颜色
|
color: 'rgba(255, 182, 193, 0.7)', // 雨滴颜色
|
||||||
duration: [1.0, 2.0], // 动画持续时间范围(秒)
|
duration: [1.0, 2.0], // 动画持续时间范围(秒)
|
||||||
dropSize: [3, 8], // 雨滴大小范围
|
dropSize: [3, 8], // 雨滴大小范围
|
||||||
delay: 100, // 鼠标移动到雨滴开始的延迟(毫秒)
|
delay: 100, // 鼠标移动到雨滴开始的延迟(毫秒)
|
||||||
zIndex: 1000, // 层级
|
zIndex: 1000, // 层级
|
||||||
enabled: true // 是否启用
|
enabled: true // 是否启用
|
||||||
}
|
}
|
||||||
|
|
||||||
const rainEffect = initCursorRainForVitePress(customConfig)
|
const rainEffect = initCursorRainForVitePress(customConfig)
|
||||||
```
|
```
|
||||||
|
|
||||||
## 高级自定义
|
## 高级自定义
|
||||||
|
|
||||||
### 1. CSS 样式自定义
|
### 1. CSS 样式自定义
|
||||||
|
|
||||||
在 `docs/.vitepress/theme/cursor-rain-styles.css` 中,你可以自定义雨滴的视觉效果:
|
在 `docs/.vitepress/theme/cursor-rain-styles.css` 中,你可以自定义雨滴的视觉效果:
|
||||||
|
|
||||||
```css
|
```css
|
||||||
/* 自定义雨滴样式 */
|
/* 自定义雨滴样式 */
|
||||||
.cursor-rain-container .rain-drop {
|
.cursor-rain-container .rain-drop {
|
||||||
/* 添加发光效果 */
|
/* 添加发光效果 */
|
||||||
box-shadow: 0 0 10px rgba(173, 216, 230, 0.6);
|
box-shadow: 0 0 10px rgba(173, 216, 230, 0.6);
|
||||||
|
|
||||||
/* 添加模糊效果 */
|
/* 添加模糊效果 */
|
||||||
filter: blur(1px);
|
filter: blur(1px);
|
||||||
|
|
||||||
/* 渐变背景 */
|
/* 渐变背景 */
|
||||||
background: radial-gradient(circle,
|
background: radial-gradient(circle,
|
||||||
rgba(173, 216, 230, 0.8) 0%,
|
rgba(173, 216, 230, 0.8) 0%,
|
||||||
rgba(173, 216, 230, 0.3) 70%,
|
rgba(173, 216, 230, 0.3) 70%,
|
||||||
transparent 100%);
|
transparent 100%);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. 主题色彩
|
### 2. 主题色彩
|
||||||
|
|
||||||
已经预设了多种主题色彩,包括:
|
已经预设了多种主题色彩,包括:
|
||||||
|
|
||||||
- `blue` - 蓝色
|
- `blue` - 蓝色
|
||||||
- `lightBlue` - 浅蓝色
|
- `lightBlue` - 浅蓝色
|
||||||
- `pink` - 粉色
|
- `pink` - 粉色
|
||||||
- `green` - 绿色
|
- `green` - 绿色
|
||||||
- `gold` - 金色
|
- `gold` - 金色
|
||||||
- `purple` - 紫色
|
- `purple` - 紫色
|
||||||
- `orange` - 橙色
|
- `orange` - 橙色
|
||||||
- `red` - 红色
|
- `red` - 红色
|
||||||
- `rainbow` - 彩虹色(特殊效果)
|
- `rainbow` - 彩虹色(特殊效果)
|
||||||
|
|
||||||
### 3. 动态控制
|
### 3. 动态控制
|
||||||
|
|
||||||
雨点效果实例已挂载到全局 `window.rainEffect`,你可以在浏览器控制台中动态控制:
|
雨点效果实例已挂载到全局 `window.rainEffect`,你可以在浏览器控制台中动态控制:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// 暂停效果
|
// 暂停效果
|
||||||
window.rainEffect.disable()
|
window.rainEffect.disable()
|
||||||
|
|
||||||
// 恢复效果
|
// 恢复效果
|
||||||
window.rainEffect.enable()
|
window.rainEffect.enable()
|
||||||
|
|
||||||
// 更新配置
|
// 更新配置
|
||||||
window.rainEffect.updateOptions({
|
window.rainEffect.updateOptions({
|
||||||
maxDrops: 50,
|
maxDrops: 50,
|
||||||
color: 'rgba(255, 99, 99, 0.8)'
|
color: 'rgba(255, 99, 99, 0.8)'
|
||||||
})
|
})
|
||||||
|
|
||||||
// 切换主题(需要先导入 switchRainTheme 函数)
|
// 切换主题(需要先导入 switchRainTheme 函数)
|
||||||
switchRainTheme(window.rainEffect, 'pink')
|
switchRainTheme(window.rainEffect, 'pink')
|
||||||
```
|
```
|
||||||
|
|
||||||
## 性能优化
|
## 性能优化
|
||||||
|
|
||||||
### 1. 自动优化
|
### 1. 自动优化
|
||||||
|
|
||||||
系统会根据设备性能自动选择最佳配置:
|
系统会根据设备性能自动选择最佳配置:
|
||||||
|
|
||||||
- **移动设备**:自动使用移动端优化配置(更少雨滴,更长动画时间)
|
- **移动设备**:自动使用移动端优化配置(更少雨滴,更长动画时间)
|
||||||
- **低性能设备**:自动使用轻量模式
|
- **低性能设备**:自动使用轻量模式
|
||||||
- **高性能设备**:使用默认或华丽模式
|
- **高性能设备**:使用默认或华丽模式
|
||||||
|
|
||||||
### 2. 手动优化
|
### 2. 手动优化
|
||||||
|
|
||||||
如果遇到性能问题,可以手动调整:
|
如果遇到性能问题,可以手动调整:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// 性能友好的配置
|
// 性能友好的配置
|
||||||
const performanceConfig = {
|
const performanceConfig = {
|
||||||
maxDrops: 10, // 减少雨滴数量
|
maxDrops: 10, // 减少雨滴数量
|
||||||
duration: [2.0, 3.0], // 增加动画时间
|
duration: [2.0, 3.0], // 增加动画时间
|
||||||
delay: 200, // 增加延迟
|
delay: 200, // 增加延迟
|
||||||
dropSize: [2, 4] // 减小雨滴尺寸
|
dropSize: [2, 4] // 减小雨滴尺寸
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. 移动端适配
|
### 3. 移动端适配
|
||||||
|
|
||||||
CSS 中已包含移动端优化:
|
CSS 中已包含移动端优化:
|
||||||
|
|
||||||
```css
|
```css
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.cursor-rain-container .rain-drop {
|
.cursor-rain-container .rain-drop {
|
||||||
/* 移动端减少视觉效果以提高性能 */
|
/* 移动端减少视觉效果以提高性能 */
|
||||||
filter: none;
|
filter: none;
|
||||||
box-shadow: 0 0 4px rgba(173, 216, 230, 0.3);
|
box-shadow: 0 0 4px rgba(173, 216, 230, 0.3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 常见问题
|
## 常见问题
|
||||||
|
|
||||||
### Q: 如何完全禁用雨点效果?
|
### Q: 如何完全禁用雨点效果?
|
||||||
|
|
||||||
A: 在配置中设置 `enabled: false`:
|
A: 在配置中设置 `enabled: false`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const config = {
|
const config = {
|
||||||
...getOptimalConfig(),
|
...getOptimalConfig(),
|
||||||
enabled: false
|
enabled: false
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Q: 雨点效果影响性能怎么办?
|
### Q: 雨点效果影响性能怎么办?
|
||||||
|
|
||||||
A: 使用轻量模式:
|
A: 使用轻量模式:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const config = rainPresets.light
|
const config = rainPresets.light
|
||||||
```
|
```
|
||||||
|
|
||||||
或者手动减少雨滴数量:
|
或者手动减少雨滴数量:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const config = {
|
const config = {
|
||||||
...getOptimalConfig(),
|
...getOptimalConfig(),
|
||||||
maxDrops: 5
|
maxDrops: 5
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Q: 如何在特定页面禁用效果?
|
### Q: 如何在特定页面禁用效果?
|
||||||
|
|
||||||
A: 可以在页面的 frontmatter 中添加标识,然后在主题中根据路由判断是否启用。
|
A: 可以在页面的 frontmatter 中添加标识,然后在主题中根据路由判断是否启用。
|
||||||
|
|
||||||
### Q: 深色模式下雨点不明显怎么办?
|
### Q: 深色模式下雨点不明显怎么办?
|
||||||
|
|
||||||
A: CSS 中已包含深色模式适配,或者手动调整颜色:
|
A: CSS 中已包含深色模式适配,或者手动调整颜色:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const config = {
|
const config = {
|
||||||
...getOptimalConfig(),
|
...getOptimalConfig(),
|
||||||
color: 'rgba(173, 216, 230, 0.9)' // 增加透明度
|
color: 'rgba(173, 216, 230, 0.9)' // 增加透明度
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 开发调试
|
## 开发调试
|
||||||
|
|
||||||
在开发过程中,你可以:
|
在开发过程中,你可以:
|
||||||
|
|
||||||
1. 打开浏览器控制台
|
1. 打开浏览器控制台
|
||||||
2. 使用 `window.rainEffect` 实时调试
|
2. 使用 `window.rainEffect` 实时调试
|
||||||
3. 修改配置后刷新页面查看效果
|
3. 修改配置后刷新页面查看效果
|
||||||
4. 使用 `window.rainEffect.updateOptions()` 实时更新配置
|
4. 使用 `window.rainEffect.updateOptions()` 实时更新配置
|
||||||
|
|
||||||
享受你的个性化光标雨点效果吧!🌧️✨
|
享受你的个性化光标雨点效果吧!🌧️✨
|
||||||
|
|||||||
@@ -1,204 +1,204 @@
|
|||||||
# 🎛️ 光标雨点效果参数控制指南
|
# 🎛️ 光标雨点效果参数控制指南
|
||||||
|
|
||||||
## 📍 参数控制位置
|
## 📍 参数控制位置
|
||||||
|
|
||||||
### 1. **快速修改** - `docs/.vitepress/theme/index.ts`
|
### 1. **快速修改** - `docs/.vitepress/theme/index.ts`
|
||||||
|
|
||||||
直接在主题文件中自定义参数:
|
直接在主题文件中自定义参数:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// 完全自定义配置
|
// 完全自定义配置
|
||||||
const customConfig = {
|
const customConfig = {
|
||||||
maxDrops: 30, // 🌧️ 雨滴数量 (建议: 10-50)
|
maxDrops: 30, // 🌧️ 雨滴数量 (建议: 10-50)
|
||||||
color: 'rgba(173, 216, 230, 0.7)', // 🎨 颜色
|
color: 'rgba(173, 216, 230, 0.7)', // 🎨 颜色
|
||||||
duration: [1.0, 2.0], // ⏱️ 下落时间范围(秒)
|
duration: [1.0, 2.0], // ⏱️ 下落时间范围(秒)
|
||||||
dropSize: [3, 8], // 📏 雨滴大小范围(像素)
|
dropSize: [3, 8], // 📏 雨滴大小范围(像素)
|
||||||
delay: 100, // ⏰ 鼠标移动延迟(毫秒)
|
delay: 100, // ⏰ 鼠标移动延迟(毫秒)
|
||||||
zIndex: 1000, // 📐 层级
|
zIndex: 1000, // 📐 层级
|
||||||
enabled: true // 🔄 是否启用
|
enabled: true // 🔄 是否启用
|
||||||
}
|
}
|
||||||
|
|
||||||
const rainEffect = initCursorRainForVitePress(customConfig)
|
const rainEffect = initCursorRainForVitePress(customConfig)
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. **预设选择** - 使用现有预设
|
### 2. **预设选择** - 使用现有预设
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// 选择预设
|
// 选择预设
|
||||||
const config = rainPresets.fancy // 华丽模式
|
const config = rainPresets.fancy // 华丽模式
|
||||||
const config = rainPresets.light // 轻量模式
|
const config = rainPresets.light // 轻量模式
|
||||||
const config = rainPresets.pink // 粉色主题
|
const config = rainPresets.pink // 粉色主题
|
||||||
const config = rainPresets.green // 绿色主题
|
const config = rainPresets.green // 绿色主题
|
||||||
const config = rainPresets.gold // 金色主题
|
const config = rainPresets.gold // 金色主题
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. **预设修改** - `docs/.vitepress/theme/cursor-rain-config.ts`
|
### 3. **预设修改** - `docs/.vitepress/theme/cursor-rain-config.ts`
|
||||||
|
|
||||||
创建新预设或修改现有预设:
|
创建新预设或修改现有预设:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
export const rainPresets = {
|
export const rainPresets = {
|
||||||
// 添加你的自定义预设
|
// 添加你的自定义预设
|
||||||
myCustom: {
|
myCustom: {
|
||||||
maxDrops: 35,
|
maxDrops: 35,
|
||||||
color: 'rgba(255, 100, 100, 0.8)',
|
color: 'rgba(255, 100, 100, 0.8)',
|
||||||
duration: [0.8, 1.5],
|
duration: [0.8, 1.5],
|
||||||
dropSize: [2, 10],
|
dropSize: [2, 10],
|
||||||
delay: 80,
|
delay: 80,
|
||||||
zIndex: 1000
|
zIndex: 1000
|
||||||
} as RainDropOptions,
|
} as RainDropOptions,
|
||||||
|
|
||||||
// 修改现有预设
|
// 修改现有预设
|
||||||
default: {
|
default: {
|
||||||
maxDrops: 20, // 从25改为20
|
maxDrops: 20, // 从25改为20
|
||||||
// ... 其他参数
|
// ... 其他参数
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🎯 详细参数说明
|
## 🎯 详细参数说明
|
||||||
|
|
||||||
### 核心参数
|
### 核心参数
|
||||||
|
|
||||||
| 参数 | 类型 | 默认值 | 说明 | 推荐范围 |
|
| 参数 | 类型 | 默认值 | 说明 | 推荐范围 |
|
||||||
|------|------|--------|------|----------|
|
|------|------|--------|------|----------|
|
||||||
| `maxDrops` | number | 25 | 同时显示的最大雨滴数量 | 5-50 |
|
| `maxDrops` | number | 25 | 同时显示的最大雨滴数量 | 5-50 |
|
||||||
| `color` | string | 'rgba(173,216,230,0.6)' | 雨滴颜色(支持任何CSS颜色) | - |
|
| `color` | string | 'rgba(173,216,230,0.6)' | 雨滴颜色(支持任何CSS颜色) | - |
|
||||||
| `duration` | [min,max] | [1.0, 2.0] | 下落时间范围(秒) | [0.5, 3.0] |
|
| `duration` | [min,max] | [1.0, 2.0] | 下落时间范围(秒) | [0.5, 3.0] |
|
||||||
| `dropSize` | [min,max] | [3, 8] | 雨滴大小范围(像素) | [1, 15] |
|
| `dropSize` | [min,max] | [3, 8] | 雨滴大小范围(像素) | [1, 15] |
|
||||||
| `delay` | number | 100 | 鼠标移动到雨滴出现的延迟(毫秒) | 50-300 |
|
| `delay` | number | 100 | 鼠标移动到雨滴出现的延迟(毫秒) | 50-300 |
|
||||||
|
|
||||||
### 高级参数
|
### 高级参数
|
||||||
|
|
||||||
| 参数 | 说明 | 默认值 |
|
| 参数 | 说明 | 默认值 |
|
||||||
|------|------|--------|
|
|------|------|--------|
|
||||||
| `zIndex` | 雨滴容器的层级 | 1000 |
|
| `zIndex` | 雨滴容器的层级 | 1000 |
|
||||||
| `enabled` | 是否启用效果 | true |
|
| `enabled` | 是否启用效果 | true |
|
||||||
| `container` | 效果容器元素 | document.body |
|
| `container` | 效果容器元素 | document.body |
|
||||||
|
|
||||||
## 🎨 视觉效果参数
|
## 🎨 视觉效果参数
|
||||||
|
|
||||||
### 雨滴形状控制 (CSS)
|
### 雨滴形状控制 (CSS)
|
||||||
|
|
||||||
在 `docs/.vitepress/theme/cursor-rain-styles.css` 中:
|
在 `docs/.vitepress/theme/cursor-rain-styles.css` 中:
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.cursor-rain-container .rain-drop {
|
.cursor-rain-container .rain-drop {
|
||||||
/* 🔸 雨滴形状 - 数值越大越尖锐 */
|
/* 🔸 雨滴形状 - 数值越大越尖锐 */
|
||||||
border-radius: 50% 50% 50% 50% / 90% 90% 10% 10% !important;
|
border-radius: 50% 50% 50% 50% / 90% 90% 10% 10% !important;
|
||||||
|
|
||||||
/* 🌟 发光效果 */
|
/* 🌟 发光效果 */
|
||||||
box-shadow: 0 0 6px rgba(173, 216, 230, 0.4);
|
box-shadow: 0 0 6px rgba(173, 216, 230, 0.4);
|
||||||
|
|
||||||
/* 🌫️ 模糊效果 */
|
/* 🌫️ 模糊效果 */
|
||||||
filter: blur(0.5px);
|
filter: blur(0.5px);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 雨滴尺寸控制 (JavaScript源码)
|
### 雨滴尺寸控制 (JavaScript源码)
|
||||||
|
|
||||||
在 `cursor-rain/src/CursorRainEffect.ts` 中:
|
在 `cursor-rain/src/CursorRainEffect.ts` 中:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// 第177-178行
|
// 第177-178行
|
||||||
width: size * 0.3, // 🔸 宽度倍数 (越小越细)
|
width: size * 0.3, // 🔸 宽度倍数 (越小越细)
|
||||||
height: size * 4, // 🔸 高度倍数 (越大越长)
|
height: size * 4, // 🔸 高度倍数 (越大越长)
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🚀 实时调试
|
## 🚀 实时调试
|
||||||
|
|
||||||
### 浏览器控制台调试
|
### 浏览器控制台调试
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// 🔄 更新配置
|
// 🔄 更新配置
|
||||||
window.rainEffect.updateOptions({
|
window.rainEffect.updateOptions({
|
||||||
maxDrops: 50,
|
maxDrops: 50,
|
||||||
color: 'rgba(255, 99, 99, 0.8)',
|
color: 'rgba(255, 99, 99, 0.8)',
|
||||||
duration: [0.5, 1.0]
|
duration: [0.5, 1.0]
|
||||||
})
|
})
|
||||||
|
|
||||||
// ⏸️ 暂停效果
|
// ⏸️ 暂停效果
|
||||||
window.rainEffect.disable()
|
window.rainEffect.disable()
|
||||||
|
|
||||||
// ▶️ 恢复效果
|
// ▶️ 恢复效果
|
||||||
window.rainEffect.enable()
|
window.rainEffect.enable()
|
||||||
```
|
```
|
||||||
|
|
||||||
### 动态切换主题
|
### 动态切换主题
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
// 需要先导入switchRainTheme函数
|
// 需要先导入switchRainTheme函数
|
||||||
import { switchRainTheme } from './cursor-rain-config'
|
import { switchRainTheme } from './cursor-rain-config'
|
||||||
|
|
||||||
// 🎨 切换颜色主题
|
// 🎨 切换颜色主题
|
||||||
switchRainTheme(window.rainEffect, 'pink')
|
switchRainTheme(window.rainEffect, 'pink')
|
||||||
switchRainTheme(window.rainEffect, 'green')
|
switchRainTheme(window.rainEffect, 'green')
|
||||||
switchRainTheme(window.rainEffect, 'gold')
|
switchRainTheme(window.rainEffect, 'gold')
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🎛️ 常用调整场景
|
## 🎛️ 常用调整场景
|
||||||
|
|
||||||
### 🐌 性能优化 (减少卡顿)
|
### 🐌 性能优化 (减少卡顿)
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const performanceConfig = {
|
const performanceConfig = {
|
||||||
maxDrops: 10, // 减少数量
|
maxDrops: 10, // 减少数量
|
||||||
duration: [2.0, 3.0], // 增加时间
|
duration: [2.0, 3.0], // 增加时间
|
||||||
delay: 200, // 增加延迟
|
delay: 200, // 增加延迟
|
||||||
dropSize: [2, 4] // 减小尺寸
|
dropSize: [2, 4] // 减小尺寸
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 🌪️ 华丽效果 (更多雨滴)
|
### 🌪️ 华丽效果 (更多雨滴)
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const fancyConfig = {
|
const fancyConfig = {
|
||||||
maxDrops: 50, // 增加数量
|
maxDrops: 50, // 增加数量
|
||||||
duration: [0.5, 1.2], // 减少时间
|
duration: [0.5, 1.2], // 减少时间
|
||||||
delay: 30, // 减少延迟
|
delay: 30, // 减少延迟
|
||||||
dropSize: [4, 12] // 增大尺寸
|
dropSize: [4, 12] // 增大尺寸
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 📱 移动端优化
|
### 📱 移动端优化
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const mobileConfig = {
|
const mobileConfig = {
|
||||||
maxDrops: 8, // 大幅减少
|
maxDrops: 8, // 大幅减少
|
||||||
duration: [2.5, 4.0], // 增加时间
|
duration: [2.5, 4.0], // 增加时间
|
||||||
delay: 300, // 增加延迟
|
delay: 300, // 增加延迟
|
||||||
dropSize: [2, 5] // 减小尺寸
|
dropSize: [2, 5] // 减小尺寸
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 🌈 彩色雨滴
|
### 🌈 彩色雨滴
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// 多种颜色随机
|
// 多种颜色随机
|
||||||
const colors = [
|
const colors = [
|
||||||
'rgba(255, 99, 99, 0.7)', // 红
|
'rgba(255, 99, 99, 0.7)', // 红
|
||||||
'rgba(99, 255, 99, 0.7)', // 绿
|
'rgba(99, 255, 99, 0.7)', // 绿
|
||||||
'rgba(99, 99, 255, 0.7)', // 蓝
|
'rgba(99, 99, 255, 0.7)', // 蓝
|
||||||
'rgba(255, 255, 99, 0.7)' // 黄
|
'rgba(255, 255, 99, 0.7)' // 黄
|
||||||
]
|
]
|
||||||
|
|
||||||
// 在JavaScript中需要修改源码来支持随机颜色
|
// 在JavaScript中需要修改源码来支持随机颜色
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🔧 修改步骤
|
## 🔧 修改步骤
|
||||||
|
|
||||||
1. **选择修改方式**:
|
1. **选择修改方式**:
|
||||||
- 简单调整 → 修改 `index.ts`
|
- 简单调整 → 修改 `index.ts`
|
||||||
- 创建预设 → 修改 `cursor-rain-config.ts`
|
- 创建预设 → 修改 `cursor-rain-config.ts`
|
||||||
- 视觉效果 → 修改 `cursor-rain-styles.css`
|
- 视觉效果 → 修改 `cursor-rain-styles.css`
|
||||||
- 深度定制 → 修改源码 `CursorRainEffect.ts`
|
- 深度定制 → 修改源码 `CursorRainEffect.ts`
|
||||||
|
|
||||||
2. **测试效果**:
|
2. **测试效果**:
|
||||||
- 保存文件后VitePress会自动热重载
|
- 保存文件后VitePress会自动热重载
|
||||||
- 或在浏览器控制台实时调试
|
- 或在浏览器控制台实时调试
|
||||||
|
|
||||||
3. **优化性能**:
|
3. **优化性能**:
|
||||||
- 移动端减少 `maxDrops`
|
- 移动端减少 `maxDrops`
|
||||||
- 低性能设备增加 `delay` 和 `duration`
|
- 低性能设备增加 `delay` 和 `duration`
|
||||||
|
|
||||||
享受你的个性化雨滴效果!🌧️✨
|
享受你的个性化雨滴效果!🌧️✨
|
||||||
|
|||||||
Reference in New Issue
Block a user